From 73bff5f88cf2db1a75ca7ff7235758fdc4b2ceaf Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 31 Jul 2026 09:38:54 -0700 Subject: [PATCH] =?UTF-8?q?test(engine):=20pin=20the=20orphan-only=20sweep?= =?UTF-8?q?'s=20project=20query=20=E2=80=94=20the=20harness=20could=20not?= =?UTF-8?q?=20see=20a=20filter=20bug=20(#3196)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eighteenth resolver from the coverage map on #3115, and **why** it was uncovered is the interesting part. ## A fake that ignores its own filter cannot see a filter bug Every case in this file stubs `listTasks` to return the same task **whatever column is asked for**: ```ts (store.listTasks as ...).mockResolvedValue([failedReviewTask()]); ``` So the project query is never exercised. Blinding `orphanReviewColumns` changes which column is *requested*, the fake answers identically, and nothing fails. Eight passing tests, and the selection logic among them was untested. That is the same blindness the production sweep had — querying a column that does not exist and finding nothing — reproduced in the harness that was supposed to catch it. ## The case `listTasks` honours the column, so a card resting in a renamed review lane is found **only if the query asked for that lane**. Keyed on the id, the sweep asked for `in-review`, got nothing, and a failed orphan-only card **stayed failed forever**. ## Measured 9 pass; blinding `orphanReviewColumns` fails exactly this case. **18 of 26 pinned** across 17 merged PRs. ## Generalisation worth checking elsewhere Any sweep whose test stubs `listTasks` with a flat `mockResolvedValue` has this hole. The fix is a store fake that filters on `options.column` — the shape `self-healing-query-filter-blindness.test.ts` already uses. I would look there first for the remaining map entries. ## Verification `self-healing-orphan-only-scope` **9 passed** · `pnpm test:gate` full pass · lint — green. --- .../self-healing-orphan-only-scope.test.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/engine/src/__tests__/self-healing-orphan-only-scope.test.ts b/packages/engine/src/__tests__/self-healing-orphan-only-scope.test.ts index 0c4df8e381..6c8eac77cf 100644 --- a/packages/engine/src/__tests__/self-healing-orphan-only-scope.test.ts +++ b/packages/engine/src/__tests__/self-healing-orphan-only-scope.test.ts @@ -107,6 +107,53 @@ describe("recoverOrphanOnlyScopeViolations (FN-4379 / FN-4350)", () => { expect(store.logEntry).toHaveBeenCalledWith("FN-4350", expect.stringContaining("Auto-finalized from in-review/paused: content proven on main")); }); + /* + FNXC:WorkflowResolvedColumns 2026-07-31-20:50: + `orphanReviewColumns` — the PROJECT-level query that selects candidates — was UNCOVERED on the + #3115 map, and the reason is worth stating: every case in this file stubs `listTasks` to return the + same task whatever column is asked for, so the query is never exercised. Blinding the resolver + changes which column is requested and the fake answers identically, so nothing fails. + + A fake that ignores its own filter cannot see a filter bug. That is the same blindness this sweep's + production code had, reproduced in the harness. + + Here `listTasks` HONOURS the column, so a card resting in a renamed review lane is found only if + the query asked for that lane. Keyed on the id it asked for `in-review`, got nothing, and a failed + orphan-only card stayed failed forever. + */ + it("finds a candidate resting in a RENAMED review lane (the project query)", async () => { + const renamed = failedReviewTask({ id: "FN-RENAMED", column: "checking", branch: "fusion/fn-renamed" }); + const RENAMED_IR = { + version: "v2", + id: "custom:renamed", + nodes: [], + edges: [], + columns: [ + { id: "building", name: "building", traits: [{ trait: "wip", config: { limitSetting: "maxConcurrent" } }] }, + { id: "checking", name: "checking", traits: [{ trait: "merge" }] }, + ], + }; + (store.listTasks as ReturnType).mockImplementation( + async (opts?: { column?: string }) => (opts?.column === "checking" ? [renamed] : []), + ); + Object.assign(store as unknown as Record, { + listWorkflowDefinitions: vi.fn(async () => [{ id: "custom:renamed", ir: RENAMED_IR }]), + getTaskWorkflowSelection: vi.fn(() => ({ workflowId: "custom:renamed", stepIds: [] })), + getTaskWorkflowSelectionAsync: vi.fn(async () => ({ workflowId: "custom:renamed", stepIds: [] })), + getWorkflowDefinition: vi.fn(async () => ({ ir: RENAMED_IR })), + }); + (store.getAgentLogs as ReturnType).mockResolvedValue([ + { type: "tool_error", detail: DETAIL.replace("FN-4350", "FN-RENAMED") }, + ]); + mockedExecSync.mockImplementation((command: string | Buffer) => { + if (String(command).includes("Fusion-Task-Id: FN-RENAMED")) return "abc123456789\n" as any; + return "" as any; + }); + + expect(await manager.recoverOrphanOnlyScopeViolations()).toBe(1); + expect(store.moveTask).toHaveBeenCalledWith("FN-RENAMED", "done"); + }); + it("does NOT recover when landed commit cannot be verified (FN-4280)", async () => { (store.listTasks as ReturnType).mockResolvedValue([failedReviewTask()]); (store.getAgentLogs as ReturnType).mockResolvedValue([{ type: "tool_error", detail: DETAIL }]);