test(FN-4434): complete Step 3 — cover recovery audit emission

Fusion-Task-Id: FN-4434
Fusion-Task-Lineage: 547a5663-114c-49c8-bd0c-dddfb280c4ef
This commit is contained in:
Fusion
2026-05-13 22:47:49 -07:00
committed by gsxdsm
parent 97e17d037d
commit 0c8e233d40
2 changed files with 118 additions and 0 deletions

View File

@@ -75,6 +75,7 @@ function createStore(tasks: TaskMap, settings: Partial<Settings> = {}): TaskStor
updateSettings: vi.fn(async () => mergedSettings),
mergeTask: vi.fn(async () => undefined),
getRootDir: vi.fn(() => ""),
recordRunAuditEvent: vi.fn(async () => undefined),
}) as unknown as TaskStore & EventEmitter;
return store;
@@ -126,6 +127,14 @@ describeIfGit("SelfHealingManager recoverAlreadyMergedReviewTasks (real git)", (
expect(task.mergeDetails?.mergeConfirmed).toBe(true);
expect(existsSync(worktreePath)).toBe(false);
expect(git(repo, "git worktree list")).not.toContain(worktreePath);
expect((store as any).recordRunAuditEvent).toHaveBeenCalledTimes(1);
expect((store as any).recordRunAuditEvent).toHaveBeenCalledWith(
expect.objectContaining({
domain: "database",
mutationType: "task:auto-recover-already-merged",
target: "FN-TEST-1",
}),
);
});
it(

View File

@@ -3719,6 +3719,115 @@ describe("SelfHealingManager", () => {
});
});
describe("recoverAlreadyMergedReviewTasks — run-audit emission", () => {
it("emits task:auto-recover-already-merged when recovery succeeds", async () => {
const recordRunAuditEvent = vi.fn().mockResolvedValue(undefined);
const storeWithAudit = createMockStore({
getSettings: vi.fn().mockResolvedValue({ globalPause: false, enginePaused: false }),
listTasks: vi.fn().mockResolvedValue([
{
id: "FN-audit",
column: "in-review",
paused: false,
status: "failed",
mergeRetries: 4,
mergeDetails: undefined,
baseBranch: "main",
branch: "fusion/fn-audit",
steps: [],
log: [],
},
]),
recordRunAuditEvent,
});
const managerWithRecovery = new SelfHealingManager(storeWithAudit, { rootDir: "/tmp/test-project" });
vi.spyOn(managerWithRecovery as any, "findAlreadyMergedTaskCommit").mockResolvedValue({ sha: "abc1234def5678", strategy: "trailer" });
const recovered = await managerWithRecovery.recoverAlreadyMergedReviewTasks();
expect(recovered).toBe(1);
expect(recordRunAuditEvent).toHaveBeenCalledTimes(1);
expect(recordRunAuditEvent).toHaveBeenCalledWith(
expect.objectContaining({
domain: "database",
mutationType: "task:auto-recover-already-merged",
target: "FN-audit",
metadata: expect.objectContaining({
mergeSha: "abc1234def5678",
mergeStrategy: "trailer",
baseBranch: "main",
mergeRetries: 4,
}),
}),
);
managerWithRecovery.stop();
});
it("does not emit when no landed commit is detected", async () => {
const recordRunAuditEvent = vi.fn().mockResolvedValue(undefined);
const storeWithAudit = createMockStore({
getSettings: vi.fn().mockResolvedValue({ globalPause: false, enginePaused: false }),
listTasks: vi.fn().mockResolvedValue([
{
id: "FN-no-hit",
column: "in-review",
paused: false,
status: "failed",
mergeRetries: 3,
mergeDetails: undefined,
baseBranch: "main",
branch: "fusion/fn-no-hit",
steps: [],
log: [],
},
]),
recordRunAuditEvent,
});
const managerWithRecovery = new SelfHealingManager(storeWithAudit, { rootDir: "/tmp/test-project" });
vi.spyOn(managerWithRecovery as any, "findAlreadyMergedTaskCommit").mockResolvedValue(null);
const recovered = await managerWithRecovery.recoverAlreadyMergedReviewTasks();
expect(recovered).toBe(0);
expect(recordRunAuditEvent).not.toHaveBeenCalled();
managerWithRecovery.stop();
});
it("continues recovery when run-audit persistence throws", async () => {
const recordRunAuditEvent = vi.fn().mockRejectedValueOnce(new Error("audit write failed"));
const storeWithAudit = createMockStore({
getSettings: vi.fn().mockResolvedValue({ globalPause: false, enginePaused: false }),
listTasks: vi.fn().mockResolvedValue([
{
id: "FN-audit-throw",
column: "in-review",
paused: false,
status: "failed",
mergeRetries: 5,
mergeDetails: undefined,
baseBranch: "main",
branch: "fusion/fn-audit-throw",
steps: [],
log: [],
},
]),
recordRunAuditEvent,
});
const managerWithRecovery = new SelfHealingManager(storeWithAudit, { rootDir: "/tmp/test-project" });
vi.spyOn(managerWithRecovery as any, "findAlreadyMergedTaskCommit").mockResolvedValue({ sha: "def5678abc1234", strategy: "trailer" });
const recovered = await managerWithRecovery.recoverAlreadyMergedReviewTasks();
expect(recovered).toBe(1);
expect(storeWithAudit.moveTask).toHaveBeenCalledWith("FN-audit-throw", "done");
expect(recordRunAuditEvent).toHaveBeenCalledTimes(1);
managerWithRecovery.stop();
});
});
describe("recoverReviewTasksWithFailedPreMergeSteps", () => {
const baseTask = {
id: "FN-1572",