FN-6797: harden in-review dependency rebound audits

Harden in-review dependency drift reconciliation with explicit guarded no-action audit evidence.

- Emit no-action run-audit events when pause, auto-merge, live execution, checkout, or rebound mutation guards prevent an in-review dependency rebound.
- Preserve scheduler dependency satisfaction semantics so in-review dependencies remain non-blocking under merge-request shadow mode without accepted markers.
- Extend regression coverage and run-audit documentation for guarded in-review rebounds.

Files changed:
 .changeset/fn-6797-in-review-dependency-drift.md   |   5 +
 AGENTS.md                                          |   2 +-
 docs/architecture.md                               |   4 +-
 .../in-review-unmet-dependency-reconcile.test.ts   |  18 ++-
 packages/engine/src/__tests__/self-healing.test.ts |  79 +++++++++++--
 packages/engine/src/self-healing.ts                | 129 ++++++++++++++++-----
 6 files changed, 190 insertions(+), 47 deletions(-)

Fusion-Task-Id: FN-6797

Fusion-Task-Lineage: f94c7875-619a-47be-88f5-320a4dda3b34
This commit is contained in:
gsxdsm
2026-06-20 10:21:26 -07:00
parent 438cd75eaf
commit 61ff17a057
6 changed files with 190 additions and 47 deletions

View File

@@ -628,7 +628,7 @@ See [Memory Plugin Contract](./memory-plugin-contract.md) for the full plan.
- Writes are idempotent: scheduler updates `status/blockedBy` only when values change, reducing per-tick churn and audit noise.
- Self-healing remains responsible for terminal/missing blocker cleanup (`clearStaleBlockedBy()`), while scheduler overlap stamping now focuses on stable active-overlap attribution.
- `reconcileDependencyBlockingLeases()` (FN-6292) unwinds existing dependency/lease circular waits: when an `in-progress` holder has unmet scheduling dependencies and an unmet dependency is blocked by the holder's stale file-scope lease, self-healing gates the backward move with triple proof, moves the holder back to `todo` with progress/worktree/resume state preserved, and emits `task:reconcile-dependency-blocking-lease` (or `task:reconcile-dependency-blocking-lease-no-action` when proof fails). Engine rebounds do not set `userPaused`.
- `reconcileInReviewUnmetDependencies()` (FN-6793) enforces the same dependency invariant after accidental review advancement: unpaused, auto-merge-eligible `in-review` tasks with live unmet dependencies move back to `todo` with `status: "queued"`, `blockedBy` set to the first unmet dependency, and worktree/progress/resume state preserved; global/engine pause, user pause, `autoMerge:false`, live execution, and checkout guards leave the task untouched with a no-action audit when applicable. Engine rebounds do not set `userPaused`.
- `reconcileInReviewUnmetDependencies()` (FN-6793/FN-6797) enforces the same dependency invariant after accidental review advancement: unpaused, auto-merge-eligible `in-review` tasks with live unmet dependencies move back to `todo` with `status: "queued"`, `blockedBy` set to the first unmet dependency, and worktree/progress/resume state preserved. Global/engine pause short-circuits the sweep; task pause/user-pause, `autoMerge:false`, live execution, checkout guards, and failed rebound mutations leave the task untouched with a no-action audit when applicable. Engine rebounds do not set `userPaused`.
- `StepSessionExecutor` (`step-session-executor.ts`) — per-step sessions + parallel wave execution
- `createTaskUpdateTool()` (`executor.ts`) emits a diagnostic warning when an agent marks step N `in-progress` while another step on the same task is already `in-progress`; the update still proceeds so operators get evidence without changing task semantics.
- `TaskCompletion` (`task-completion.ts`) — completion gate helpers
@@ -1088,7 +1088,7 @@ The run-audit system records every mutation performed by the engine across four
- **Database / `task:soft-delete-column-reconciled`** — emitted by `reconcileSoftDeletedColumnDrift` (FN-5566, re-land FN-5446) when a soft-deleted row (`deletedAt IS NOT NULL`) is found with legacy `column != 'archived'`; rewrites only `column` (no resurrection), with metadata `{ previousColumn }`.
- **Database / `session:runtime-resolved`** — emitted once per `createResolvedAgentSession` call with metadata `{ sessionPurpose, runtimeId, wasConfigured, provider, modelId, mockProviderActive, testModeActive, runtimeHint? }` for per-lane runtime/provider attribution.
- **Database / `task:reconcile-dependency-blocking-lease`** — emitted by `reconcileDependencyBlockingLeases()` (FN-6292) when self-healing rebounds an `in-progress` holder to `todo` because an unmet dependency is blocked by the holder's stale file-scope lease. Metadata includes the dependency ID, blocked-by marker, and unmet dependency list.
- **Database / `task:reconcile-in-review-unmet-dependencies`** — emitted by `reconcileInReviewUnmetDependencies()` (FN-6793) when self-healing rebounds an `in-review` task to blocked `todo` because one or more declared dependencies are still unmet. Metadata includes `unmetDeps`, `blockedBy`, and prior review status; the `-no-action` companion is emitted when live execution or checkout evidence prevents the backward move.
- **Database / `task:reconcile-in-review-unmet-dependencies`** — emitted by `reconcileInReviewUnmetDependencies()` (FN-6793/FN-6797) when self-healing rebounds an `in-review` task to blocked `todo` because one or more declared dependencies are still unmet. Metadata includes `unmetDeps`, `blockedBy`, and prior review status; the `-no-action` companion is emitted when task pause/user-pause, `autoMerge:false`, live execution/checkout proof, or a failed rebound mutation prevents the backward move.
- **Database / `task:reconcile-orphaned-task-dir`** — emitted by `TaskStore.reconcileOrphanedTaskDirs()` (FN-6783) when store open or self-healing Batch 1 re-imports a valid live `.fusion/tasks/{ID}/task.json` directory with no SQLite task row anywhere. Metadata includes the recovered ID, column, status, and task JSON path.
- **Database / `task:*-no-action` backward-move family (FN-5335)** — backward self-healing sweeps now emit annotation-only events when triple proof fails instead of mutating lifecycle state. New mutation types: `task:reclaim-pr-conflict-no-action`, `task:reclaim-self-owned-branch-conflict-no-action`, `task:auto-rebound-scope-decay-no-action`, `task:finalize-no-op-review-no-action`, `task:stale-incomplete-review-no-action`, `task:ghost-review-no-action`, `task:stuck-merge-deadlock-no-action`, `task:no-progress-no-task-done-no-action`, `task:missing-worktree-review-no-action`, `task:partial-progress-no-task-done-no-action`, `task:reconcile-dependency-blocking-lease-no-action`. See `docs/self-healing-backward-move-audit.md` for per-stage disposition.
- **Filesystem** — file:write, prompt:write, attachment:create, etc.