test(engine): pin #3047's archive-sweep conversion — measured uncovered (825 tests passed against the reverted fix) (#3115)
Not a conversion — the fleet's conversions are landing faster than their coverage, and this is the audit that shows which ones actually have any. ## Method For each of today's fleet commits to `self-healing.ts`: revert that single commit, re-run the file's suites, see whether anything fails. If nothing fails, the conversion has no regression protection and the "N tests passed" cited on its PR was measuring something else. | commit | reverted | verdict | |---|---|---| | #3075 pause-abort recovery | suites **fail** | covered | | **#3047 archiveStaleDoneTasks** | **825 tests all pass** | **uncovered** | | #3078 (mine) | 204 tests all passed | was uncovered — closed by #3090, #3102 | Every fixture in the `archiveStaleDoneTasks` describe block uses the id `done`, where the literal is correct, so none of them could see the conversion at all. ## What the literal cost The sweep's dependent scan skips tasks in terminal lanes. On a renamed board **nothing matched `done`/`archived`, so every task read as active** — which means every archive candidate looked like it had active dependents, and the sweep archived **nothing**. The board quietly stops auto-archiving: no error, no log line, no failing test. ## The case covers both halves of #3047 - a stale card in a **renamed complete lane** is archived — the `complete` role - a card whose dependent is still live in the **renamed wip lane** is **not** archived, and a dependent already in the **renamed archive lane** does not count as live — the `terminal` role That second assertion is the one that matters: it stops the fix from degenerating into "archive everything", which is the failure mode a one-sided test would miss. ## Measured **413 pass** on current main; reverting #3047 fails **exactly this test**. ## Remaining audit I have now audited 3 of ~13 fleet conversions to this file this way. The method is cheap (one revert, one 17s suite run) and I will keep working through the rest unless someone else picks it up. #3049 could not be auto-reverted — later commits overlap its hunks — so it needs a manual read rather than a mechanical revert. ## Verification `self-healing.test.ts` **413 passed** · `pnpm test:gate` 13 + 161 + 487 + 71 · lint — green.
This commit is contained in:
@@ -2310,6 +2310,53 @@ describe("SelfHealingManager", () => {
|
||||
expect(store.archiveTaskAndCleanup).not.toHaveBeenCalledWith("FN-002");
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:WorkflowResolvedColumns 2026-07-31-20:10:
|
||||
#3047 converted this sweep's two lane guards to the COMPLETE and TERMINAL roles and merged with no
|
||||
case that could see the difference — measured: reverting that commit leaves all 825 self-healing
|
||||
tests passing, because every fixture above uses the id `done`, where the literal is correct.
|
||||
|
||||
What the literal cost on a renamed board: the dependent scan treated EVERY task as active (nothing
|
||||
matched `done`/`archived`), so every candidate looked like it had active dependents and the sweep
|
||||
archived nothing. A silent no-op — the board just quietly stops auto-archiving.
|
||||
*/
|
||||
it("archives a stale card in a RENAMED complete lane, and skips one whose dependent is still live", async () => {
|
||||
vi.setSystemTime(new Date("2026-01-04T00:00:00.000Z"));
|
||||
(store.getSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
autoArchiveDoneTasksEnabled: true,
|
||||
autoArchiveDoneAfterMs: 24 * 60 * 60 * 1000,
|
||||
doneAutoArchiveDays: 0,
|
||||
} as unknown as Settings);
|
||||
(store.listWorkflowDefinitions as ReturnType<typeof vi.fn> | undefined)?.mockResolvedValue?.([]);
|
||||
(store as unknown as { listWorkflowDefinitions: unknown }).listWorkflowDefinitions = vi.fn(async () => [{
|
||||
ir: {
|
||||
version: "v2",
|
||||
id: "custom:renamed",
|
||||
nodes: [],
|
||||
edges: [],
|
||||
columns: [
|
||||
{ id: "building", name: "building", traits: [{ trait: "wip", config: { limitSetting: "maxConcurrent" } }] },
|
||||
{ id: "shipped", name: "shipped", traits: [{ trait: "complete" }] },
|
||||
{ id: "vault", name: "vault", traits: [{ trait: "archived" }] },
|
||||
],
|
||||
},
|
||||
}]);
|
||||
(store.listTasks as ReturnType<typeof vi.fn>).mockResolvedValue([
|
||||
{ id: "FN-OLD", column: "shipped", columnMovedAt: "2026-01-02T00:00:00.000Z", updatedAt: "2026-01-02T00:00:00.000Z" },
|
||||
{ id: "FN-BLOCKED", column: "shipped", columnMovedAt: "2026-01-02T00:00:00.000Z", updatedAt: "2026-01-02T00:00:00.000Z" },
|
||||
/* A LIVE dependent in the renamed wip lane must still protect its blocker from archiving. */
|
||||
{ id: "FN-LIVE", column: "building", dependencies: ["FN-BLOCKED"], updatedAt: "2026-01-03T00:00:00.000Z" },
|
||||
/* Already in the renamed archive lane: terminal, so neither a candidate nor an active dependent. */
|
||||
{ id: "FN-FILED", column: "vault", dependencies: ["FN-OLD"], updatedAt: "2026-01-03T00:00:00.000Z" },
|
||||
]);
|
||||
|
||||
const result = await manager.archiveStaleDoneTasks();
|
||||
|
||||
expect(result).toBe(1);
|
||||
expect(store.archiveTaskAndCleanup).toHaveBeenCalledWith("FN-OLD");
|
||||
expect(store.archiveTaskAndCleanup).not.toHaveBeenCalledWith("FN-BLOCKED");
|
||||
});
|
||||
|
||||
it("uses doneAutoArchiveDays threshold and logs task age", async () => {
|
||||
vi.setSystemTime(new Date("2026-03-01T00:00:00.000Z"));
|
||||
(store.getSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user