test(triage): the mock store could not be ASKED for a selection — 231 cases exercised a shape production cannot produce (#3189)
`createMockStore` in `triage.test.ts` defined **neither** `getTaskWorkflowSelection` nor its async twin. So `resolveWorkflowIrForTaskWithProvenance` **threw** calling them and took its catch branch, reporting `source: "default"` in the sense of *"the lookup failed"*. Production stores always expose both readers — every case in this file was exercising a store shape that cannot exist. Returning `undefined` models the real answer: the store **can** be asked and says there is no selection row, which is what a pre-U11 card actually presents. ## Why it mattered `triage.ts`'s post-U11 intake recovery gates on that provenance. A *failed* lookup correctly refuses to claim a workflow lacks `triage`, so the orphan arm stayed off and the recovery depended on `resolvePlannerLanes` **failing** and falling back to legacy ids — correctness resting on a resolver's failure mode. In #3141 I measured the async conversion of that site as failing 13 cases and **twice reported it as a production constraint**. It was this harness. That is the concrete cost of a mock that cannot answer a question production always can. ## Behaviour-preserving on its own **380 passed across 26 triage/recovery suites.** ## What this deliberately does NOT do It does not convert the site. I prototyped the full unblock — a `selectionAbsent` flag on the determinate `!workflowId` branch, its single consumer, and the async conversion — and it works: the previously-failing suite goes **237 passed**. But with a realistic store the orphan arm starts firing for no-selection rows, which changes recovery flow in **5 `triage-stuck-requeue-preserve-draft` cases** that currently assert the refusing behaviour. Whether accepting a legacy `triage` row there is correct is a lifecycle-semantics decision about migration, not a harness fix. So it is reverted and reported rather than bundled. Findings and the measured branch table are on #3141. ## One correction carried from this work I filed #3187 claiming provenance verifies resolution via `ir.id === workflowId`, which cannot pass for builtins. **That was wrong** — the live code uses a symbol marker, and the text I quoted was historical prose describing what was removed. Closed with the measurement: ``` store with NO selection readers -> source: default (catch: could not ask) store answering builtin selection -> source: selection ✓ ``` That is the same class of error this PR fixes — reasoning from what something says rather than what it does. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Improved workflow-resolution test coverage by supporting stores with no selected workflow. * Added synchronous and asynchronous test readers for workflow selection. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,27 @@ async function cleanupTriageFixtureRoot(rootDir: string | undefined): Promise<vo
|
||||
function createMockStore(overrides: Partial<TaskStore> = {}): TaskStore {
|
||||
let store: Partial<TaskStore>;
|
||||
store = {
|
||||
/*
|
||||
FNXC:WorkflowResolvedColumns 2026-07-31-23:59:
|
||||
THE MOCK MUST BE ABLE TO ANSWER "no selection" — it could not even be ASKED.
|
||||
|
||||
Neither `getTaskWorkflowSelection` nor its async twin was defined here, so
|
||||
`resolveWorkflowIrForTaskWithProvenance` threw calling them and took its CATCH branch, reporting
|
||||
`source: "default"` in the sense of "the lookup failed". Production stores always expose both
|
||||
readers, so that shape cannot occur there — every case in this file was exercising a store that
|
||||
does not exist.
|
||||
|
||||
It matters because `triage.ts`'s post-U11 intake recovery gates on that provenance: a failed
|
||||
lookup correctly refuses to claim a workflow lacks `triage`, so the orphan arm stayed off and the
|
||||
recovery depended on `resolvePlannerLanes` FAILING and falling back to legacy ids. Measured in
|
||||
#3141: converting that site to the async resolver failed 13 cases against this harness, and I
|
||||
twice mistook that for a production constraint.
|
||||
|
||||
Returning `undefined` models the real "no selection row" answer — the store CAN be asked and says
|
||||
there is none — which is the case a pre-U11 row actually presents.
|
||||
*/
|
||||
getTaskWorkflowSelection: vi.fn(() => undefined),
|
||||
getTaskWorkflowSelectionAsync: vi.fn(async () => undefined),
|
||||
getTask: vi.fn(),
|
||||
listTasks: vi.fn().mockResolvedValue([]),
|
||||
createTask: vi.fn(),
|
||||
|
||||
Reference in New Issue
Block a user