Files
fusion/.changeset/fn-4939-contamination-preserve-worktree.md
gsxdsm 14c5a17844 fix(FN-4939): preserve worktree on contamination auto-recovery
The in-line branch-cross-contamination auto-recovery in executor.ts had
two related bugs that produced transient "no-worktree-no-merge-confirmed"
stall signals in the dashboard while a live worktree was still mapped
on disk:

1. autoRecoverCrossContamination was called with repoDir=this.rootDir.
   The recovery does: git checkout --detach <baseSha> → cherry-pick
   wanted commits → git update-ref → git checkout <branch>. When the
   branch is checked out in a worktree (the normal case), that final
   recheckout in rootDir is blocked by git with "branch already used
   by worktree at ...", so the in-line happy path silently failed for
   every contaminated task that had a real worktree. Pass the task's
   worktree as repoDir when available so the operations stay internal
   to the worktree and the recheckout succeeds.

2. The successful-recovery branch called
       moveTask(taskId, 'todo', { preserveResumeState: true })
   without preserveWorktree:true. moveTask defaults to nulling
   task.worktree on requeue. The worktree directory and git mapping
   were still live — the dashboard's in-review-stall classifier
   (no-worktree-no-merge-confirmed) and TaskChangesTab both keyed off
   task.worktree being null and lied about the worktree being gone.
   Sibling recovery paths (auto-recovery-handlers/contamination.ts,
   tryBootstrapMisbindingRecovery, self-healing.ts:1639) all already
   pass preserveWorktree:true; this site was inconsistent.

Updated the existing FN-4428 regression test and added a new
FN-4939 test asserting repoDir uses task.worktree (with fallback
to rootDir when the task has no worktree pointer).

Refs: packages/core/src/in-review-stall.ts:116
2026-05-17 12:03:55 -07:00

770 B

@runfusion/fusion
@runfusion/fusion
patch

Fix contamination auto-recovery nulling task.worktree while leaving a live worktree mapped on disk, which triggered transient no-worktree-no-merge-confirmed stall signals in the dashboard. The in-line recovery in executor.ts now:

  • Runs autoRecoverCrossContamination inside the task's worktree (when one exists) so the final git checkout <branch> doesn't collide with the branch already being checked out elsewhere — the previous repoDir: this.rootDir call would silently fail for any task that had a real worktree.
  • Passes preserveWorktree: true when requeueing to todo, matching the sibling recovery paths in auto-recovery-handlers/contamination.ts, tryBootstrapMisbindingRecovery, and self-healing reclaim.