test(engine): pin the contamination sweep's WIP bucket (15th resolver) (#3188)
Fifteenth resolver from the coverage map on #3115. Every case in this file seeds the candidate in `in-review`, so only the review bucket was exercised — blinding `contaminationWipColumns` left the file green. ## Why the WIP bucket matters A card sent back for a fix **re-enters execution while its branch still carries the foreign commits**, so contamination is discovered there as often as in review. Keyed on the id, that bucket read nothing on a renamed board and the card kept a branch built on someone else's work — which is what this sweep exists to re-anchor. ## Two facts the fixture had to learn, both from failing first - **This is an ACTION site and deliberately skips a card whose own board cannot be read**, rather than guessing from the project union. A fake with only `listWorkflowDefinitions` resolves the default IR, the card is reported unclassifiable, and the case fails for a reason unrelated to the resolver under test. The per-task selection readers are required. - **The WIP bucket's predicate is not the review bucket's.** It additionally requires `paused === true` with `pausedReason` of `branch-cross-contamination` or `branch-conflict-unrecoverable`. A card merely resting in the wip lane is not a candidate — the FN-5704 manual-review contract this sweep mirrors. Neither is guessable from the resolver. Both came from the test failing twice, and I would have shipped something that exercised nothing had the first version passed. ## Measured 3 pass; blinding `contaminationWipColumns` fails exactly this case. **15 of 26 pinned** across 14 merged PRs. ## Verification `self-healing-foreign-only-contamination` **3 passed** · `pnpm test:gate` full pass · lint — green.
This commit is contained in:
@@ -47,6 +47,52 @@ describe("SelfHealingManager.recoverForeignOnlyContaminatedInReviewTasks", () =>
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:WorkflowResolvedColumns 2026-07-31-18:50:
|
||||
`contaminationWipColumns` was UNCOVERED on the #3115 map. Every case in this file seeds the
|
||||
candidate in `in-review`, so only the review bucket is exercised and blinding the WIP resolver back
|
||||
to `["in-progress"]` leaves the file green.
|
||||
|
||||
The WIP bucket is a real source of candidates: a card sent back for a fix re-enters execution while
|
||||
its branch still carries the foreign commits, so contamination is discovered there as often as in
|
||||
review. Keyed on the id that bucket read nothing on a renamed board, and the card kept a branch
|
||||
built on someone else's work — which is what this sweep exists to re-anchor.
|
||||
*/
|
||||
it("recovers a foreign-only candidate resting in a RENAMED wip lane", async () => {
|
||||
store.listTasks.mockImplementation(async ({ column }: { column: string }) => (
|
||||
column === "building"
|
||||
? [mkTask({ id: "FN-WIP", column: "building", paused: true, pausedReason: "branch-cross-contamination" })]
|
||||
: []
|
||||
));
|
||||
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" }] },
|
||||
],
|
||||
};
|
||||
/*
|
||||
The per-task readers are REQUIRED, not incidental. This sweep is an ACTION site: it deliberately
|
||||
SKIPS a card whose own board cannot be read rather than guessing from the project union, so a fake
|
||||
with only `listWorkflowDefinitions` resolves the default IR, the card is reported unresolvable, and
|
||||
the case would fail for a reason that has nothing to do with the resolver under test.
|
||||
*/
|
||||
store.listWorkflowDefinitions = vi.fn(async () => [{ id: "custom:renamed", ir: RENAMED_IR }]);
|
||||
store.getTaskWorkflowSelection = vi.fn(() => ({ workflowId: "custom:renamed", stepIds: [] }));
|
||||
store.getTaskWorkflowSelectionAsync = vi.fn(async () => ({ workflowId: "custom:renamed", stepIds: [] }));
|
||||
store.getWorkflowDefinition = vi.fn(async () => ({ ir: RENAMED_IR }));
|
||||
mocked.classifyForeignOnlyContamination.mockResolvedValue({ kind: "foreign-only-no-own-work" });
|
||||
mocked.recoverForeignOnlyContamination.mockResolvedValue({ recovered: true, subtype: "reanchor" });
|
||||
|
||||
const manager = new SelfHealingManager(store, { rootDir: process.cwd() });
|
||||
|
||||
expect(await manager.recoverForeignOnlyContaminatedInReviewTasks()).toBe(1);
|
||||
expect(mocked.recoverForeignOnlyContamination).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("recovers foreign-only in-review candidates", async () => {
|
||||
store.listTasks.mockImplementation(async ({ column }: { column: string }) => column === "in-review" ? [mkTask()] : []);
|
||||
mocked.classifyForeignOnlyContamination.mockResolvedValue({ kind: "foreign-only-no-own-work" });
|
||||
|
||||
Reference in New Issue
Block a user