Instead of immediately parking the task as failed when the auto-merge
fast-path detects a non-ancestor commitSha (the symptom of a pre-FN-5627
TOCTOU poisoning), clear the poisoned mergeDetails fields and re-enqueue
for a fresh aiMergeTask attempt. The branch typically still has the work
intact; the merger just needs to redo the squash + ref-advance with the
now-fixed flow.
Recovery semantics:
- mergeRetries < MAX_AUTO_MERGE_RETRIES (3): clear poisoned fields
(commitSha, mergedAt, landedFiles, filesChanged, insertions, deletions,
noOpVerifiedShortCircuit, landedFilesAttributionRestricted, mergeConfirmed),
increment mergeRetries, clear status/error, re-enqueue via
internalEnqueueMerge. Emit new merger:fast-path-auto-recovered audit event.
- mergeRetries >= MAX_AUTO_MERGE_RETRIES: terminal park as failed (existing
behavior), with merger:fast-path-blocked-foreign-commit audit event
carrying budgetExhausted=true.
The recoverable path keeps the task in in-review with status=null, so
downstream consumers (dashboard banner, ntfy notifications) don't surface
a transient failure for what should be a self-healing event. The terminal
path remains FN-4538/FN-5488 compatible: status=failed at retry ceiling
on in-review is recognized by clearStaleBlockedBy fast paths so
downstream todos don't deadlock.
Tests updated and added:
- FN-5627 auto-recover test: asserts mergeRetries=1, status=null, all
poisoned fields cleared, no moveTask('done'), no task:merged emit.
- FN-5627 budget-exhausted test: asserts status=failed with descriptive
error, mergeRetries=3 input, no moveTask('done').
Fusion-Task-Id: FN-5627