FN-8917: add telemetry seams to merger test stores
Ensure merger test fixtures model session-usage telemetry so user-hold release coverage exercises the production lane. - Add emitUsageEvent fakes across merger AI test stores. - Assert the user-held branch-group member emits merger session telemetry when explicitly released. - Document fixture requirements and expected hold-path stderr. Files changed: .../src/__tests__/group-merge-coordinator.test.ts | 21 +++++++++++++++++++++ .../engine/src/__tests__/merger-ai-cleanup.test.ts | 1 + .../merger-ai-dependency-install.slow.test.ts | 1 + .../__tests__/merger-ai-push-after-merge.test.ts | 1 + .../src/__tests__/merger-ai-renamed-columns.test.ts | 6 ++++++ .../ai-merge-cleanup-enoent-idempotent.test.ts | 1 + 6 files changed, 31 insertions(+) Fusion-Task-Id: FN-8917 Fusion-Task-Lineage: aab96cdb-50ec-441f-80f5-944e8e1d70ab Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -1318,8 +1318,14 @@ function createPostReviewStore(task: Record<string, any>, branchGroup: Record<st
|
||||
The production drain calls these methods for token-budget enforcement and branch-group promotion
|
||||
evaluation inside catch-and-warn wrappers. Supply the real, budget-free seams so a missing method
|
||||
cannot silently remove coverage while leaving this prototype fixture green.
|
||||
|
||||
FNXC:BranchGroupAutoMergeGate 2026-08-09-22:51:
|
||||
The production merger drain emits session-start telemetry in both its review and merge passes.
|
||||
Telemetry failures are swallowed by design, so this fake must implement emitUsageEvent or a missing
|
||||
seam degrades coverage into warnings that the user-hold regression guard catches.
|
||||
*/
|
||||
getSettingsByScope: vi.fn(async () => ({ global: {}, project: settings })),
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
listTasksByBranchGroup: vi.fn(async () => (branchGroup ? [task] : [])),
|
||||
getBranchGroup: vi.fn(() => branchGroup),
|
||||
updateTask: vi.fn(async (_id: string, patch: Record<string, unknown>) => Object.assign(task, patch)),
|
||||
@@ -1477,6 +1483,11 @@ describe("resolveBranchGroupMergeRouting", () => {
|
||||
expect(held).toMatchObject({ merged: false, noOp: true });
|
||||
expect(blockedMerge).not.toHaveBeenCalled();
|
||||
expect(git(repo, "git rev-parse main")).toBe(mainBefore);
|
||||
/*
|
||||
FNXC:BranchGroupAutoMergeGate 2026-08-09-22:51:
|
||||
The expected fatal-path stderr is the proof that the automatic hold did not land this member;
|
||||
it is not a missing fixture path.
|
||||
*/
|
||||
expect(() => git(repo, "git show mission/M-8811:user-hold-feature.txt")).toThrow();
|
||||
|
||||
let mergeAttempts = 0;
|
||||
@@ -1539,6 +1550,16 @@ describe("resolveBranchGroupMergeRouting", () => {
|
||||
}
|
||||
|
||||
expect(offendingWarnings, "merge drain emitted missing-store-seam warnings").toEqual([]);
|
||||
/*
|
||||
FNXC:BranchGroupAutoMergeGate 2026-08-09-22:51:
|
||||
An empty warning list is insufficient when a future path skips telemetry entirely. Assert the
|
||||
production merger lane exercised the fake-store seam during the explicit release.
|
||||
*/
|
||||
expect(store.emitUsageEvent).toHaveBeenCalledWith(expect.objectContaining({
|
||||
kind: "session_start",
|
||||
category: "agent-session",
|
||||
meta: expect.objectContaining({ lane: "merger" }),
|
||||
}));
|
||||
expect(released.merged).toBe(true);
|
||||
expect(store.listTasksByBranchGroup).toHaveBeenCalledWith("BG-user-hold");
|
||||
expect(mergeAttempts).toBe(1);
|
||||
|
||||
@@ -111,6 +111,7 @@ function makeStore(taskId = "FN-1") {
|
||||
emit: vi.fn(),
|
||||
logEntry: vi.fn(async (_id: string, message: string) => { logs.push(message); }),
|
||||
appendAgentLog: vi.fn(async (_id: string, message: string) => { logs.push(message); }),
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
recordRunAuditEvent: vi.fn(async (event: any) => { audits.push(event); }),
|
||||
};
|
||||
return { store, audits, logs };
|
||||
|
||||
@@ -54,6 +54,7 @@ function makeStore(settingsOverrides: Record<string, unknown> = {}) {
|
||||
emit: vi.fn(),
|
||||
logEntry: vi.fn(async () => undefined),
|
||||
appendAgentLog: vi.fn(async () => undefined),
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
};
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ function makeStore(settingsOverrides: Record<string, unknown> = {}) {
|
||||
emit: vi.fn(),
|
||||
logEntry: vi.fn(async (_id: string, message: string, action?: string) => { logs.push({ message, action }); }),
|
||||
appendAgentLog: vi.fn(async (_id: string, message: string) => { logs.push({ message }); }),
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
getBranchGroup: vi.fn(() => null),
|
||||
recordRunAuditEvent: vi.fn(),
|
||||
};
|
||||
|
||||
@@ -102,6 +102,12 @@ function storeWith(current: Task, ir: WorkflowIr | undefined): TaskStore {
|
||||
updateTask: vi.fn(async () => current),
|
||||
moveTask: vi.fn(async () => current),
|
||||
logEntry: vi.fn(async () => undefined),
|
||||
/*
|
||||
FNXC:MergeQueue 2026-08-09-22:51:
|
||||
A fake store that drives runAiMerge into the merger AI lane must expose emitUsageEvent because
|
||||
session telemetry is defensive in production. Stores rejected at the workspace guard do not reach it.
|
||||
*/
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
recordRunAuditEvent: vi.fn(async () => undefined),
|
||||
getTaskWorkflowSelection: vi.fn(() => selection),
|
||||
getTaskWorkflowSelectionAsync: vi.fn(async () => selection),
|
||||
|
||||
@@ -63,6 +63,7 @@ function makeStore(taskId: string, branch: string) {
|
||||
emit: vi.fn(),
|
||||
logEntry: vi.fn(async (_id: string, message: string) => { logs.push(message); }),
|
||||
appendAgentLog: vi.fn(async (_id: string, message: string) => { logs.push(message); }),
|
||||
emitUsageEvent: vi.fn(async () => true),
|
||||
recordRunAuditEvent: vi.fn(async (event: any) => { audits.push(event); }),
|
||||
};
|
||||
return { store, task, audits, logs };
|
||||
|
||||
Reference in New Issue
Block a user