feat(FN-4701): add no-changes-finalized reliability interaction test

Adds reliability interaction test coverage for the `no-changes-finalized` outcome (FN-4701), covering the benign case where verification-only done tasks complete with no owned commits or surviving branch.

Fusion-Task-Id: FN-4701
This commit is contained in:
Fusion (runfusion.ai)
2026-05-15 20:33:21 -07:00
committed by gsxdsm
parent 06810e44e6
commit 296203443b
2 changed files with 84 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ export type ReliabilityFixture = {
store: TaskStore;
task: Task;
settings: Settings;
manager: SelfHealingManager;
cleanup: () => Promise<void>;
writeAndCommit: (file: string, content: string, message: string) => Promise<string>;
createBranch: (branch: string) => Promise<void>;
@@ -26,6 +27,7 @@ export type ReliabilityFixture = {
recoverAlreadyMergedReviewTasks: () => Promise<number>;
recoverMisclassifiedFailures: () => Promise<number>;
clearStaleBlockedBy: () => Promise<number>;
reconcileDoneTaskIntegrity: () => Promise<number>;
};
};
@@ -76,7 +78,9 @@ export async function makeReliabilityFixture(input: {
store,
task,
settings,
manager,
cleanup: async () => {
manager.stop();
store.close();
await rm(rootDir, { recursive: true, force: true });
},
@@ -99,6 +103,7 @@ export async function makeReliabilityFixture(input: {
recoverAlreadyMergedReviewTasks: async () => manager.recoverAlreadyMergedReviewTasks(),
recoverMisclassifiedFailures: async () => manager.recoverMisclassifiedFailures(),
clearStaleBlockedBy: async () => manager.clearStaleBlockedBy(),
reconcileDoneTaskIntegrity: async () => manager.reconcileDoneTaskIntegrity(),
},
};
}

View File

@@ -0,0 +1,79 @@
import { describe, it, expect, vi } from "vitest";
import { classifyOwnedLandedEvidence } from "../../merger.js";
import { makeReliabilityFixture, hasGit } from "./_helpers.js";
describe("no-changes-finalized reliability interactions (real git)", () => {
it.skipIf(!hasGit)("reconciles verification-only done task without unproven warning", async () => {
const fixture = await makeReliabilityFixture({
taskId: "FN-4701-RI",
task: {
column: "done",
branch: undefined,
baseCommitSha: undefined,
mergeDetails: {},
modifiedFiles: ["docs/some-note.md"],
},
});
const { rootDir, task, store } = fixture;
await store.moveTask(task.id, "done");
await store.updateTask(task.id, {
branch: undefined,
baseCommitSha: undefined,
mergeDetails: {},
modifiedFiles: ["docs/some-note.md"],
});
const seededTask = (await store.getTask(task.id))!;
const logSpy = vi.spyOn(store, "logEntry");
const updateSpy = vi.spyOn(store, "updateTask");
const auditSpy = vi.spyOn(store, "recordRunAuditEvent");
try {
const classification = await classifyOwnedLandedEvidence(rootDir, seededTask, { mergeTargetBranch: "main" });
expect(classification.kind).toBe("no-changes-finalized");
expect(classification).toMatchObject({
baseRef: "main",
details: {
branchExists: false,
aheadCount: null,
baseReachableFromTarget: false,
},
});
const reconciled = await fixture.selfHeal.reconcileDoneTaskIntegrity();
expect(reconciled).toBeGreaterThanOrEqual(1);
const taskLogCalls = logSpy.mock.calls.filter((call) => call[0] === seededTask.id);
expect(taskLogCalls.some((call) => /done-task finalize evidence is unproven/.test(String(call[1] ?? "")))).toBe(false);
expect(updateSpy).toHaveBeenCalledWith(seededTask.id, expect.objectContaining({
modifiedFiles: [],
mergeDetails: expect.objectContaining({
mergeConfirmed: true,
noOpMerge: true,
noOpReason: "verification-only finalize: no branch and no owned commits",
landedFiles: [],
}),
}));
expect(
auditSpy.mock.calls.some(([event]) =>
(event as any)?.mutationType === "task:integrity-reconcile-modified-files" &&
(event as any)?.metadata?.reason === "verification-only-finalize"
),
).toBe(true);
const finalizeWarned = (fixture.manager as unknown as { finalizeUnprovenWarned: Set<string> }).finalizeUnprovenWarned;
expect(finalizeWarned.has(seededTask.id)).toBe(false);
await fixture.selfHeal.reconcileDoneTaskIntegrity();
const taskLogCallsAfterSecondRun = logSpy.mock.calls.filter((call) => call[0] === seededTask.id);
expect(
taskLogCallsAfterSecondRun.some((call) => /done-task finalize evidence is unproven/.test(String(call[1] ?? ""))),
).toBe(false);
} finally {
await fixture.cleanup();
}
});
});