Files
fusion/scripts/lib/lifecycle-column-census-baseline.json
gsxdsm a8cfce8fbd executor: stale merge evidence re-entering execution, and a live checkout that read as unowned (12 → 8) (#2805)
Two executor conversions with real operator consequences, one census
false positive, and three sites deliberately left with their reasons
recorded.

## Census

| file | main | here |
| --- | ---: | ---: |
| `packages/engine/src/executor.ts` | 12 | **8** |

Of the 4: three genuine conversions, one reclassification.

## What was broken

**`resetMergeStateIfNeeded` — cards re-entered execution carrying stale
merge evidence.** Merge state is cleared when a card *leaves* a lane
where a merge could have been recorded. Keyed on `in-review`/`done`, a
renamed board matched neither, so a card bouncing back into execution
kept `mergeDetails` — including a **commit sha from its previous pass**
— into its next run. `review` is not a trait, so this resolves through
the same five flags (`complete`, `mergeOrchestration`, `mergeBlocker`,
`humanReview`) the dependency gates in this file already use; two gates
answering "is this a merge-bearing lane?" differently would be a split
brain.

**The worktree-owner scan — a live checkout read as unowned.**
`findActiveWorktreeOwner` asks "is anyone else working in this
checkout?". Its in-memory `activeWorktrees` leg is
vocabulary-independent, but the **durable** leg — the one that answers
after an engine restart, when the in-memory map is empty — filtered with
`t.column !== "in-progress"`. On a renamed board that matched nobody, so
the worktree read as free and a second task could be handed a checkout
another task is live in. Post-restart is exactly when this function
matters.

Not the query-filter class: that `listTasks` call passes no `column`, so
the predicate is the only lane gate on the path.

## A third census false positive in this package

Line 16094's `to` is a **review-addressing record status** — the method
signature is `to: "queued" | "in-progress" | "addressed" | "failed"`,
and the next two lines test it against `"addressed"` and `"failed"`,
which are not columns at all. Marked `DELIBERATE-LITERAL`.

That is the third in `packages/engine` after the two `cli-agent`
`CliMachineState` ones (#2797). The backlog total includes non-columns;
a sweep that "converts" them turns a status machine into a workflow
role.

## Revert results (measured, each run independently)

| conversion | reverted → |
| --- | --- |
| worktree-owner wip predicate | RENAMED case fails — checkout reads as
**free** while another task is live in it |
| `resetMergeStateIfNeeded` lanes | RENAMED case fails — card keeps
`commitSha: "abc123"` from its previous pass |

Both DEFAULT cases pass before and after, which is why both vocabularies
run. Each has a non-vacuous companion (holder sitting in the complete
lane; a return from the hold lane) so a predicate matching every column
would not pass.

**Both reach their seam directly through a cast.** The public routes are
`handleBranchConflict` (needs a real `BranchConflictError` plus a git
repo) and the `task:moved` listener (drags in the whole `execute()`
path); going through either would make these tests about a git fixture
rather than about the lane predicate. The alternative was the status quo
— all 91 `executor-worktree*.test.ts` cases seed `column:
"in-progress"`, so they assert the legacy fallback and pass either way.
I shipped the conversions in one commit *stating* they were unproven,
then closed that gap in the next; the history shows both.

### Two fake defects found while writing those tests

Worth naming, because both are the documented green-for-the-wrong-reason
shape:

1. The first fake had no `updateTask`, so the cleanup **threw** rather
than asserting anything.
2. The second returned a new object without persisting — and
`cleanupMergeStateForReverification` **re-reads through `getTask`**. The
re-read handed back the stale row, so *both* vocabularies reported
"nothing changed" and it would have read as a passing negative test.

## Deliberately NOT converted, with reasons

- **The `task:moved` listener cluster** (`3521`/`3545`/`3596`/`3606`),
including the AGENTS Move-Task hard-cancel contract `userCanceled:
source === "user" && to === "todo"`. Its prologue is synchronous
(`userCanceledTaskIds.delete`, watchdog clear) and deferring it to a
microtask changes hard-cancel ordering. The sync IR reader is not an
option — it returns the DEFAULT workflow for every task in production. A
safe conversion needs lanes resolved on an earlier async boundary: new
machinery plus an ordering change, which is out of fleet scope and not a
guess worth making on a hard-cancel path.
- **`17081`** pairs `latestColumn === "in-progress"` with a
**hardcoded** `moveTask(taskId, "in-progress")` two lines above —
census-invisible, the same shape as the branch-worktree requeue bug in
#2797. They have to convert together, and the move needs the same
rejection guard.
- **`5903`** is the query-filter class: `listTasks({ column:
"in-progress" })` followed by a re-assertion of the same literal.
Converting it drops a count and changes nothing — see
`docs/solutions/architecture-patterns/self-healing-sweeps-are-blind-on-a-renamed-board.md`
(#2800).

## Verification

- `pnpm test:gate` — 161 + 487 + 13 + 71, green
- `npx tsc -p packages/engine/tsconfig.json --noEmit` — clean
- `pnpm lint` — clean
- `--strict` exits 0

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 12:02:41 -07:00

183 lines
10 KiB
JSON

{
"generatedFrom": "node scripts/lifecycle-column-census.mjs --strict --update-baseline",
"byFile": {
"packages/engine/src/self-healing.ts": 97,
"packages/engine/src/scheduler.ts": 12,
"packages/core/src/task-store/async-comments-attachments.ts": 9,
"packages/dashboard/app/components/TaskContextMenu.tsx": 9,
"packages/engine/src/executor.ts": 8,
"packages/dashboard/app/components/Column.tsx": 7,
"packages/dashboard/app/components/ListView.tsx": 6,
"packages/engine/src/notification/notification-service.ts": 5,
"packages/engine/src/restart-recovery-coordinator.ts": 5,
"packages/dashboard/app/components/TaskDetailModal.tsx": 4,
"packages/engine/src/replan-target.ts": 4,
"packages/core/src/async-mission-store-queries.ts": 3,
"packages/core/src/task-store/async-merge-coordination.ts": 3,
"packages/core/src/task-store/task-artifacts-ops.ts": 3,
"packages/dashboard/app/components/DockTaskList.tsx": 3,
"packages/dashboard/app/components/TaskCard.tsx": 3,
"packages/dashboard/app/components/TaskChangesTab.tsx": 3,
"packages/dashboard/app/components/TaskChatTab.tsx": 3,
"packages/dashboard/app/hooks/useTaskDiffStats.ts": 3,
"packages/dashboard/app/utils/taskActivity.ts": 3,
"packages/dashboard/app/utils/worktreeGrouping.ts": 3,
"packages/dashboard/src/chat.ts": 3,
"packages/dashboard/src/routes/register-task-workflow-routes.ts": 3,
"packages/engine/src/planner-overseer.ts": 3,
"packages/core/src/agent-store.ts": 2,
"packages/core/src/async-mission-store.ts": 2,
"packages/core/src/node-override-guard.ts": 2,
"packages/core/src/task-move-disposer.ts": 2,
"packages/core/src/task-store/archive-lifecycle-2.ts": 2,
"packages/core/src/task-store/audit-ops.ts": 2,
"packages/core/src/task-store/comments-ops.ts": 2,
"packages/core/src/task-store/moves.ts": 2,
"packages/core/src/task-store/project-store-ops.ts": 2,
"packages/core/src/task-store/reads.ts": 2,
"packages/core/src/task-store/symbol-locks.ts": 2,
"packages/core/src/task-store/task-id-integrity.ts": 2,
"packages/dashboard/app/components/Board.tsx": 2,
"packages/dashboard/app/components/DocumentsView.tsx": 2,
"packages/dashboard/app/components/effective-model-resolution.ts": 2,
"packages/dashboard/app/components/WorkflowResultsTab.tsx": 2,
"packages/dashboard/app/utils/taskRevert.ts": 2,
"packages/dashboard/app/utils/taskTiming.ts": 2,
"packages/dashboard/src/github-tracking-state.ts": 2,
"packages/dashboard/src/server.ts": 2,
"packages/engine/src/auto-merge-finalization.ts": 2,
"packages/core/src/eval-automation.ts": 1,
"packages/core/src/eval-signal-collector.ts": 1,
"packages/core/src/in-review-stall.ts": 1,
"packages/core/src/mission-store.ts": 1,
"packages/core/src/plugin-store.ts": 1,
"packages/core/src/stalled-review-detector.ts": 1,
"packages/core/src/task-store/branch-and-pr-entities.ts": 1,
"packages/core/src/task-store/lifecycle-ops.ts": 1,
"packages/core/src/task-store/merge-queue-ops-2.ts": 1,
"packages/core/src/task-store/merge-queue-ops.ts": 1,
"packages/dashboard/app/components/ChangesDiffModal.tsx": 1,
"packages/dashboard/app/components/command-center/liveSnapshotMetrics.ts": 1,
"packages/dashboard/app/components/DevServerView.tsx": 1,
"packages/dashboard/app/components/MergeDetails.tsx": 1,
"packages/dashboard/app/components/PrPanel.tsx": 1,
"packages/dashboard/app/components/ResearchTaskActionModal.tsx": 1,
"packages/dashboard/app/components/RoutingTab.tsx": 1,
"packages/dashboard/app/components/TaskPlannerChatTab.tsx": 1,
"packages/dashboard/app/hooks/useExecutorStats.ts": 1,
"packages/dashboard/app/hooks/useTasks.ts": 1,
"packages/dashboard/app/utils/inReviewStallCopy.ts": 1,
"packages/dashboard/app/utils/quickAddStart.ts": 1,
"packages/dashboard/app/utils/stalePausedReviewCopy.ts": 1,
"packages/dashboard/app/utils/taskStuck.ts": 1,
"packages/dashboard/src/github-issue-comment.ts": 1,
"packages/dashboard/src/github-tracking-comments.ts": 1,
"packages/dashboard/src/gitlab-issue-comment.ts": 1,
"packages/dashboard/src/gitlab-source-issue-reconciler.ts": 1,
"packages/dashboard/src/gitlab-tracking-comments.ts": 1,
"packages/dashboard/src/knowledge-index-refresh.ts": 1,
"packages/dashboard/src/planning-board-tools.ts": 1,
"packages/dashboard/src/research-routes.ts": 1,
"packages/dashboard/src/routes/register-agent-core-routes.ts": 1,
"packages/dashboard/src/routes/register-chat-routes.ts": 1,
"packages/dashboard/src/task-planner-chat-context.ts": 1,
"packages/dashboard/src/task-planner-chat-metrics.ts": 1,
"packages/dashboard/src/test/mockCoreEngine.ts": 1,
"packages/engine/src/backlog-pressure-reporter.ts": 1,
"packages/engine/src/ephemeral-worker-manager.ts": 1,
"packages/engine/src/merger.ts": 1,
"packages/engine/src/pr-comment-handler.ts": 1,
"packages/engine/src/runtimes/in-process-runtime.ts": 1,
"packages/engine/src/triage.ts": 1
},
"deliberateByFile": {
"packages/dashboard/src/reliability-metrics.ts\u0000in-review": 4,
"packages/core/src/live-agent-count.ts\u0000in-progress": 2,
"packages/core/src/live-agent-count.ts\u0000in-review": 2,
"packages/core/src/store.ts\u0000in-review": 2,
"packages/core/src/task-merge.ts\u0000archived": 2,
"packages/core/src/task-merge.ts\u0000done": 2,
"packages/core/src/task-merge.ts\u0000in-review": 2,
"packages/dashboard/app/components/TaskCard.tsx\u0000triage": 2,
"packages/dashboard/app/components/TaskDetailModal.tsx\u0000triage": 2,
"packages/engine/src/cli-agent/state-machine.ts\u0000done": 2,
"packages/engine/src/scheduler.ts\u0000in-progress": 2,
"packages/engine/src/scheduler.ts\u0000in-review": 2,
"packages/engine/src/usage-limit-detector.ts\u0000archived": 2,
"packages/engine/src/usage-limit-detector.ts\u0000done": 2,
"plugins/fusion-plugin-reports/src/store/report-store.ts\u0000archived": 2,
"packages/cli/src/commands/task.ts\u0000archived": 1,
"packages/cli/src/commands/task.ts\u0000done": 1,
"packages/cli/src/extension.ts\u0000archived": 1,
"packages/cli/src/extension.ts\u0000done": 1,
"packages/core/src/live-agent-count.ts\u0000archived": 1,
"packages/core/src/live-agent-count.ts\u0000done": 1,
"packages/core/src/store.ts\u0000archived": 1,
"packages/core/src/store.ts\u0000done": 1,
"packages/core/src/store.ts\u0000in-progress": 1,
"packages/core/src/store.ts\u0000todo": 1,
"packages/core/src/task-store/task-store-helpers.ts\u0000in-progress": 1,
"packages/core/src/task-store/task-store-helpers.ts\u0000todo": 1,
"packages/core/src/task-store/task-update.ts\u0000in-progress": 1,
"packages/core/src/task-store/task-update.ts\u0000in-review": 1,
"packages/core/src/task-store/update-task-deps.ts\u0000archived": 1,
"packages/core/src/task-store/update-task-deps.ts\u0000done": 1,
"packages/dashboard/app/components/command-center/MissionControlPanel.tsx\u0000done": 1,
"packages/dashboard/app/components/command-center/MissionControlPanel.tsx\u0000in-review": 1,
"packages/dashboard/app/components/command-center/MissionControlPanel.tsx\u0000todo": 1,
"packages/dashboard/app/components/RoutineEditor.tsx\u0000triage": 1,
"packages/dashboard/app/components/ScheduleForm.tsx\u0000triage": 1,
"packages/dashboard/app/components/ScheduleStepsEditor.tsx\u0000triage": 1,
"packages/dashboard/app/components/TaskCard.tsx\u0000todo": 1,
"packages/dashboard/app/components/TaskContextMenu.tsx\u0000triage": 1,
"packages/dashboard/app/components/TaskDetailModal.tsx\u0000todo": 1,
"packages/dashboard/app/utils/columnRoles.ts\u0000todo": 1,
"packages/dashboard/src/github-tracking-state.ts\u0000archived": 1,
"packages/dashboard/src/github-tracking-state.ts\u0000done": 1,
"packages/dashboard/src/reliability-metrics.ts\u0000done": 1,
"packages/dashboard/src/reliability-metrics.ts\u0000in-progress": 1,
"packages/dashboard/src/routes/register-task-workflow-routes.ts\u0000todo": 1,
"packages/dashboard/src/routes/register-task-workflow-routes.ts\u0000triage": 1,
"packages/engine/src/agent-heartbeat.ts\u0000archived": 1,
"packages/engine/src/agent-heartbeat.ts\u0000done": 1,
"packages/engine/src/cli-agent/task-session.ts\u0000done": 1,
"packages/engine/src/executor.ts\u0000in-progress": 1,
"packages/engine/src/hold-release.ts\u0000archived": 1,
"packages/engine/src/hold-release.ts\u0000done": 1,
"packages/engine/src/hold-release.ts\u0000in-review": 1,
"packages/engine/src/project-engine.ts\u0000in-review": 1,
"packages/engine/src/scheduler.ts\u0000archived": 1,
"packages/engine/src/scheduler.ts\u0000done": 1,
"packages/engine/src/triage.ts\u0000triage": 1,
"plugins/fusion-plugin-even-cards/src/cards/board-cards.ts\u0000archived": 1,
"plugins/fusion-plugin-even-cards/src/cards/board-cards.ts\u0000done": 1,
"plugins/fusion-plugin-even-realities-glasses/src/notifications/diff.ts\u0000done": 1,
"plugins/fusion-plugin-reports/src/store/report-types.ts\u0000archived": 1
},
"queryByFile": {
"packages/engine/src/self-healing.ts": 48,
"packages/engine/src/project-engine.ts": 7,
"packages/engine/src/backlog-pressure-reporter.ts": 3,
"packages/core/src/task-store/async-persistence.ts": 2,
"packages/core/src/task-store/merge-queue-ops.ts": 2,
"packages/core/src/task-store/moves.ts": 2,
"packages/engine/src/executor.ts": 2,
"packages/engine/src/stale-task-reporter.ts": 2,
"packages/cli/src/extension.ts": 1,
"packages/core/src/async-mission-store.ts": 1,
"packages/core/src/eval-automation.ts": 1,
"packages/core/src/store.ts": 1,
"packages/core/src/task-store/archive-lifecycle-2.ts": 1,
"packages/core/src/task-store/async-archive-lineage.ts": 1,
"packages/core/src/task-store/async-self-healing.ts": 1,
"packages/core/src/task-store/task-artifacts-ops.ts": 1,
"packages/core/src/task-store/task-store-helpers.ts": 1,
"packages/dashboard/src/routes/register-gitlab.ts": 1,
"packages/engine/src/agent-tools.ts": 1,
"packages/engine/src/auto-merge-finalization.ts": 1,
"packages/engine/src/restart-recovery-coordinator.ts": 1,
"packages/engine/src/scheduler.ts": 1,
"packages/engine/src/workflow-node-handlers.ts": 1
}
}