From 3092c9c2bb34f2d2196b928ae19808f5a01d52e8 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 30 Jul 2026 08:57:52 -0700 Subject: [PATCH] =?UTF-8?q?fleet:=20live-agent-count.ts=206=20=E2=86=92=20?= =?UTF-8?q?0=20=E2=80=94=20the=20no-enrichment=20fallback,=20marked=20not?= =?UTF-8?q?=20converted=20(#2762)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unclaimed file, no overlap with any open fleet PR. Previous PR (#2756) is merged, so this is my one open PR. ## Census | | before | after | |---|---|---| | backlog | 447 | **441** | | reviewed | 38 | 44 | | this file | 6 | **0** | `--strict` exit 0, baseline re-recorded in the same commit. ## Why marked, not converted All six literals sit after a `??` or a `flags ? … :`. Each is reached **only** when the caller supplied no trait flags and no enriched shape — precisely the case `enrichRunningAgentTaskShape` (takes the IR) and `enrichRunningAgentTaskShapeFromFlags` (takes board flags) exist to remove. There is nothing to resolve from there, so the choice is not convert-vs-literal; it is **known legacy answer vs a different guess.** **And the guess is not neutral.** Running and Waiting are *complements* over the same rows: ```ts isWaitingAgentTask = !running && (columnIsIntakeOrHold ?? isLegacyPreImplementationColumn(column)) ``` A card matching neither arm is reported as **neither running nor waiting**, so the footer's queued total silently under-reports it. Guessing "not WIP" or "not review" loses cards from the count; the legacy id at least matches every pre-rename board. That is why this file already carries a `DELIBERATE-LITERAL` marker above `isLegacyPreImplementationColumn` with the same argument — this PR extends it to the three functions holding the remaining fallbacks (`enrichRunningAgentTaskShapeFromFlags`, `terminalKind`, `isRunningAgentTask`). **The fix for a renamed board is at the CALLER** — pass flags, or use the IR-taking enricher. Noted at the site. ## Pattern note for the fleet This is the third file I have taken where `N → 0` is reached by marking rather than converting, and they share a shape worth naming: **a literal after `??` or in the `else` of a `flags ?` ternary is a degraded-mode answer, not an unconverted guard.** The trait path is already there and already correct; the literal is what runs when the trait path has no input. Deleting it does not remove a decision — it substitutes a different one, silently, in exactly the states where nobody is looking (first paint, un-enriched callers, pre-rename data). ## Verification Core typecheck clean · `live-agent-count.test.ts` 11/11 · `--strict` exit 0 · comments only, no behavior change. --------- Co-authored-by: Claude Opus 5 (1M context) --- packages/core/src/live-agent-count.ts | 28 +++++++++++++++++++ .../lib/lifecycle-column-census-baseline.json | 5 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/core/src/live-agent-count.ts b/packages/core/src/live-agent-count.ts index 0a8659a263..5bf368a6e6 100644 --- a/packages/core/src/live-agent-count.ts +++ b/packages/core/src/live-agent-count.ts @@ -108,6 +108,22 @@ export function enrichRunningAgentTaskShape(tas } /** Attach the same traits from dashboard board-column flags without loading an IR. */ +/* +FNXC:ConcurrencyIndicators 2026-07-30-03:40 DELIBERATE-LITERAL: the no-enrichment fallback only. +Every literal below sits after a `??` or a `flags ? … :` — it is reached ONLY when the caller +supplied no trait flags and no enriched shape, which is the case the enrichers exist to remove. +There is nothing to resolve from in that state, so converting is not possible; the choice is only +between the known legacy answer and a different guess. + +That choice is not neutral here. Running and Waiting are COMPLEMENTS over the same rows, so a card +matching neither arm is reported as neither running nor waiting and the footer's queued total +silently under-reports it. Guessing "not WIP" or "not review" is therefore worse than the legacy id, +which at least matches every pre-rename board. + +The fix for a renamed board is at the CALLER — pass flags, or use `enrichRunningAgentTaskShape`, +which takes the IR and resolves every role by trait. Same reasoning as the marker above +`isLegacyPreImplementationColumn`, which this file already records. +*/ export function enrichRunningAgentTaskShapeFromFlags(task: T, flags?: Pick): T & Required> { return { ...task, @@ -137,6 +153,12 @@ function hasLiveWorkflowStepLease(task: RunningAgentTaskShape): boolean { return task.workflowStepResults?.some((result) => result.status === "pending") === true; } +/* +FNXC:ConcurrencyIndicators 2026-07-30-03:40 DELIBERATE-LITERAL: the no-enrichment fallback only. +Full rationale at the first marker of this name above (enrichRunningAgentTaskShapeFromFlags): these +legacy-id literals are the flag-less fallback the enrichers exist to remove; converting here would +guess, and a wrong guess under-reports the queued total. Fix at the CALLER by passing flags/IR. +*/ function terminalKind(task: RunningAgentTaskShape): ColumnTerminalKind { // Legacy literals are intentionally fixture-only degradation when workflow IR is unavailable. return task.columnTerminalKind ?? (task.column === "done" ? "complete" : task.column === "archived" ? "archived" : "none"); @@ -150,6 +172,12 @@ function terminalKind(task: RunningAgentTaskShape): ColumnTerminalKind { * A live `pending` workflow-step lease (e.g. an in-flight Code Review gate) * counts in any non-terminal column, since gate sessions run with null status. */ +/* +FNXC:ConcurrencyIndicators 2026-07-30-03:40 DELIBERATE-LITERAL: the no-enrichment fallback only. +Full rationale at the first marker of this name above (enrichRunningAgentTaskShapeFromFlags): these +legacy-id literals are the flag-less fallback the enrichers exist to remove; converting here would +guess, and a wrong guess under-reports the queued total. Fix at the CALLER by passing flags/IR. +*/ export function isRunningAgentTask(task: RunningAgentTaskShape): boolean { if (task.paused || task.userPaused || terminalKind(task) !== "none") return false; if (task.status === "planning") return true; diff --git a/scripts/lib/lifecycle-column-census-baseline.json b/scripts/lib/lifecycle-column-census-baseline.json index b0d9d84ec8..8f2ee876d3 100644 --- a/scripts/lib/lifecycle-column-census-baseline.json +++ b/scripts/lib/lifecycle-column-census-baseline.json @@ -8,7 +8,6 @@ "packages/core/src/task-store/async-comments-attachments.ts": 9, "packages/dashboard/app/components/TaskContextMenu.tsx": 9, "packages/dashboard/app/components/Column.tsx": 7, - "packages/core/src/live-agent-count.ts": 6, "packages/core/src/task-merge.ts": 6, "packages/dashboard/app/components/ListView.tsx": 6, "packages/dashboard/src/routes/register-task-workflow-routes.ts": 5, @@ -125,6 +124,8 @@ }, "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/dashboard/app/components/TaskCard.tsx\u0000triage": 2, "packages/dashboard/app/components/TaskDetailModal.tsx\u0000triage": 2, "packages/engine/src/scheduler.ts\u0000in-progress": 2, @@ -135,6 +136,8 @@ "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/task-store/task-store-helpers.ts\u0000in-progress": 1, "packages/core/src/task-store/task-store-helpers.ts\u0000todo": 1, "packages/dashboard/app/components/command-center/MissionControlPanel.tsx\u0000done": 1,