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
Adds a title-id drift detection and reconciliation system to prevent duplicate tasks when task titles change after initial creation. Core adds the `task-title-id-drift.ts` module with `markTitleIdStable` and `resolveTitleIdDrift` logic, wired through `db.ts`, `store.ts`, and `archive-db.ts`, with co
Fusion-Task-Id: FN-4898
Production failure shape:
Auto-recovery failed: branch conflict unrecoverable \u2014
Branch fusion/fn-4847 is already checked out at /.../deft-crane
(tip a881ccc86660, 24 stranded commits since 0b28388876).
Run branch recovery and explicitly choose whether to reclaim or
discard prior work.
The 24 stranded commits are cross-task contamination residue from the
FN-4781/FN-4804/FN-4814 worktree-race era \u2014 they are NOT FN-4847's work.
Previously this paused the task with pausedReason='branch-conflict-
unrecoverable' and the task got stuck forever waiting for human
adjudication.
User intent (FN-4847): 'just create a new branch and keep going and
discard the old one'. Implementation:
1. auto-recovery.ts:actionForMode \u2014 in 'deterministic-only' mode (the
default), branch-conflict-unrecoverable now returns 'retry' (was
'pause'). This routes the failure to the handler instead of pausing.
2. auto-recovery-handlers/branch-worktree.ts \u2014 'live-foreign' inspection
no longer emits irreducible-pause. Instead:
- Check FN-4811 active-session registry. If the foreign worktree is
bound to a live executor/merger session, do NOT force-remove it
(would yank the live agent's filesystem). Just requeue and let
downstream conflict-recovery handle it.
- Otherwise: force-delete the foreign worktree (--force) + prune git
worktree admin entries + force-delete the branch. Errors at each
step are best-effort and logged.
- Emit new audit event 'branch-worktree:foreign-branch-discarded'
with stranded-commit count, live-ownership flag, success flags.
- Requeue task to 'todo' with preserveProgress, clearing
branch+baseCommitSha.
3. run-audit.ts \u2014 register new DatabaseMutationType.
4. executor-worktree.test.ts \u2014 update the 'records recovery context'
test to assert the new retry+requeue contract (was asserting the old
pause-with-status-failed contract).
Verification:
- Targeted suite (4 files, 343 tests): pass.
- pnpm --filter @fusion/engine build: clean.
- pnpm lint: clean.
Fusion-Task-Id: FN-4847
Adds a new secrets store module to `@fusion/core` (277 lines in `secrets-store.ts`) and exports it from the package index.
Fusion-Task-Id: FN-4791
Fusion-Task-Lineage: 7ff20b8a-37e1-46c6-8003-b542df9f98b1
Refactors the settings store tests in `packages/core` by consolidating round-trip and default value coverage into structured `it.each` matrices, trimming the test file by roughly 60 lines while maintaining equivalent coverage.
Fusion-Task-Id: FN-4836
Hardens test timeouts across 12 reliability and integration test files (branch-conflict recovery, merger diff/overlap guards, self-healing, worktree hydration, workflow/file-scope interactions), covering both real-git and mock-based test lanes with consistent timeout adjustments to reduce flakiness.
Fusion-Task-Id: FN-4839