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>