Files
fusion/packages/core/src
gsxdsm 627bdcfb0a fix(review): Phase C merge-loop hardening — double-land, lease clobber, retry storm
5-persona review of the Phase-C per-repo merge loop. No P0; the no-push invariant
and retry/park accounting verified clean. Fixed:

Land mechanics (merger-ai.ts / active-session-registry.ts):
- persistRepoLandedSha no longer swallows the DB write: a failed landedSha write
  after the ref advanced now escalates to WorkspacePartialLandError so the engine
  parks/retries instead of silently re-landing (duplicate squash). isRepoLanded
  gains a landedSha-independent fallback — it scans the integration ref for this
  task's Fusion-Task-Id trailer (a squash commit is NOT a branch descendant, so a
  branch-ancestor check is provably wrong), so an actually-landed repo is skipped
  on retry.
- The land lease is now taskId-aware across kinds: any foreign-task holder on a
  sub-repo path is contention (a merging task can't run over an executing task's
  acquire lease), and registerPath throws ActiveSessionPathHeldByForeignTaskError
  instead of silently clobbering a different task's entry.
- The per-repo loop is wrapped in try/finally(setStatus(null)) so the busy/partial
  throws can't leave the task stuck 'merging'. WorkspacePartialLandError is a real
  exported class (not a .name-mutated Error). finalizeWorkspaceTask re-reads fresh
  and no longer swallows the mergeDetails write (TOCTOU). isRepoLanded exported for
  Phase D.

Dispatch + doors (project-engine.ts / dashboard.ts / task.ts / @fusion/core):
- getTask-null in the partial-land catch fails closed (park) instead of defaulting
  retries to 0 and scheduling an indefinite retry storm.
- The merge-confirmed reachability fast-path skips workspace tasks (its
  representative commitSha is a sub-repo squash sha, unreachable in the root cwd —
  it was demoting fully-merged tasks); they're verified by per-repo landedSha.
- The CLI/dashboard merge doors now return merged:true on full land (were hardcoded
  merged:false). WorkspaceRepoLandBusyError re-enqueues with backoff WITHOUT burning
  the mergeRetries quota (bounded busy counter) so contention can't park a healthy
  task. Backoff capped at 60s. shouldRetryWorkspacePartialLand folded into
  shouldRetryAutoMergeConflict. Catch switched to instanceof. New canonical
  isWorkspaceTask predicate in @fusion/core.

Gate green: build, typecheck, lint, test:gate (649+58); workspace-merger + oracle
+ project-engine 174.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:11:52 -07:00
..
2026-06-21 09:00:40 -07:00