Files
fusion/packages/core
gsxdsm 26dcccb7c3 fix(workflow): harden review-gate lifecycle interactions in In review
Follow-ups to running the pre-merge review gates in `in-review`. Each was
verified against the code before being fixed; one reported issue was
refuted and is noted below.

1. Symbol locks (packages/core/src/task-store/moves.ts)
   FN-8306 made the lifecycle transition the symbol-lock RELEASE authority
   but wrote no counterpart. That was harmless while a task only left WIP
   at handoff/terminal; the gate crossing now releases the task's declared
   symbols and the remediation node re-enters `in-progress` to edit the
   same files in the same live worktree with its locks gone. Neither
   acquire site (scheduler dispatch, claimDueWorkflowWorkItem) is on the
   graph re-entry path. Adds a symmetric re-acquire on `!wip -> wip`.
   Best-effort by design: a contended symbol logs and proceeds, which is
   exactly the pre-fix posture, rather than parking the remediation behind
   another holder and re-creating the stranding this change set removed.

2. Premature merge (packages/engine/src/self-healing.ts)
   `recoverMergeableReviewTasks` was the only in-review sweep with no
   liveness gate. The graph commits the column crossing at node entry and
   writes the gate's pending lease two DB round trips later, and
   `getTaskMergeBlocker` has no notion of "enabled but resultless", so in
   that window the sweep could enqueue a merge with Code Review never run.
   Filters `executingIds`, matching recoverGhostReviewTasks.

3. Orphan sweep (packages/engine/src/self-healing.ts)
   The reported restart hazard is REFUTED: nothing re-attaches an in-review
   graph run, so those leases are genuinely dead and marking them failed is
   correct FN-8492 behavior. But the sweep also runs from periodic
   maintenance in the same live process, where a tick between the lease
   write and session registration could fail a gate that just started.
   Honors a within-floor `classifyReviewLease`, matching the semantics Plan
   Review already had. Cleanup of dead leases is delayed by the staleness
   floor, not defeated. The audit event gains `needsOperatorBypass` for
   `autoMerge:false` rows, which self-healing deliberately skips and only
   fn_task_bypass_review can clear — previously indistinguishable from an
   auto-recoverable rewrite.

4. Stall detection (packages/engine/src/planner-overseer.ts)
   The `reviewer` and `merger` stages had no time-based check at all and
   returned `progressing` unconditionally, so a hung gate produced no
   signal however long it sat. Adds gate-anchored detection on both (a
   plain in-review card with no reviewState resolves to `merger`, not
   `reviewer`), keyed on the pending lease's own `startedAt` rather than
   `columnMovedAt` so it cannot fire during a legitimate human merge-wait.

`cumulativeActiveMs` is documented, not changed: it now excludes gate
runtime, but adding the `timing` trait to `in-review` would count arbitrary
human merge-wait as active work — a worse distortion than the omission.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 02:28:04 -07:00
..
2026-07-25 21:06:33 -07:00
2026-07-25 21:06:33 -07:00