test(engine): pin the archive skip in branch reclaim — the first uncovered resolver whose failure deletes a branch (#3144)
Next entry from the verified coverage map on #3115 — and the first one whose failure mode is **irreversible**. ## The gap `reclaimArchivedColumns` was uncovered: blinding it back to the id `archived` leaves all 825 self-healing tests green, because no fixture in this suite puts a card in a renamed archive lane. ## Why it matters more than the other 22 That guard **skips** archived cards — their branches belong to archive cleanup, not to branch reclaim. Keyed on the id, a card filed in a renamed archive lane fails the skip, and this sweep reaches: ``` git branch -D "fusion/<id>" ``` Every other uncovered resolver I have pinned so far causes a wrong lifecycle decision — a card not requeued, a lease not released, a diagnostic not surfaced. All of those are recoverable from the task row. **A deleted branch is not.** ## Measured 415 pass. Blinding `reclaimArchivedColumns` fails exactly this case, and the assertion that fails is the one checking `git branch -D` was never called — so the failure *is* the branch being deleted, not a proxy for it. ## Progress on the map Closed so far: `archiveStaleDoneTasks` ×2 (#3115), `reconcileOrphanedPendingStepResults` (#3090), `recoverDriftedAgentTaskLinks` (#3102), `reconcileTaskWorktreeMetadata` wip (#3132), `reconcileDependencyBlockingLeases` ×2 (#3138), and this one. **22 uncovered resolvers remain.** Every sweep probed so far has been uncovered, and one (`reconcileDependencyBlockingLeases`) was only half-covered by its own first test — the branch short-circuited before the second resolver was ever consulted. That is why I now blind each resolver separately rather than trusting a single revert. Next: `reconcileInReviewBranchRebind` (rebinds branches of live cards) and the two remaining `reconcileTaskWorktreeMetadata` resolvers (terminal, review). ## Verification `self-healing.test.ts` **415 passed** · `pnpm test:gate` 13 + 161 + 487 + 71 · lint — green.
This commit is contained in:
@@ -11003,6 +11003,45 @@ describe("SelfHealingManager reclaimStaleActiveBranches (FN-4546)", () => {
|
||||
}));
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:WorkflowResolvedColumns 2026-07-31-23:10:
|
||||
`reclaimArchivedColumns` was UNCOVERED on the #3115 map: blinding it back to the id `archived` leaves
|
||||
all 825 self-healing tests green, because no fixture here puts a card in a renamed archive lane.
|
||||
|
||||
This guard SKIPS archived cards — their branches belong to archive cleanup, not to branch reclaim.
|
||||
Keyed on the id, a card filed in a renamed archive lane fails the skip and this sweep DELETES its
|
||||
branch (`git branch -D`), which is not recoverable from the task row.
|
||||
*/
|
||||
it("does not reclaim the branch of a card filed in a RENAMED archive lane", async () => {
|
||||
(store.listTasks as any).mockResolvedValueOnce([
|
||||
{ id: "FN-1001", column: "vault", checkedOutBy: null, userPaused: false, worktree: null, branch: null },
|
||||
]);
|
||||
(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: "vault", name: "vault", traits: [{ trait: "archived" }] },
|
||||
],
|
||||
},
|
||||
}]);
|
||||
mockedExecSync.mockImplementation((command: string) => {
|
||||
if (command.includes("git branch --list 'fusion/*'")) return Buffer.from(" fusion/fn-1001\n");
|
||||
if (command.includes("git rev-parse --verify") && command.includes("fusion/fn-1001")) return Buffer.from("abc123\n");
|
||||
if (command.includes("git rev-list --count") && command.includes("fusion/fn-1001")) return Buffer.from("0\n");
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const recovered = await manager.reclaimStaleActiveBranches();
|
||||
|
||||
expect(recovered).toBe(0);
|
||||
/* The branch survives: deleting it is not recoverable from the task row. */
|
||||
expect(mockedExecSync).not.toHaveBeenCalledWith(expect.stringContaining("git branch -D"), expect.anything());
|
||||
});
|
||||
|
||||
it("does not delete branch with unique commits", async () => {
|
||||
(store.listTasks as any).mockResolvedValueOnce([
|
||||
{ id: "FN-1001", column: "todo", checkedOutBy: null, userPaused: false, worktree: null, branch: null },
|
||||
|
||||
Reference in New Issue
Block a user