FN-8895: harden group merge coordinator store fakes

Ensure group-merge coordinator tests exercise the production store seams without warning suppression.

- Provide scoped settings and branch-group task fake methods used by promotion evaluation
- Await promotion evaluation and fail the fixture on missing-store-method warnings
- Assert branch-group task lookup is reached during the merge drain

Files changed:
 packages/engine/src/__tests__/group-merge-coordinator.test.ts | 59 ++++++++++++++++++----
 1 file changed, 49 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-8895

Fusion-Task-Lineage: 99748c07-2083-41f9-b776-da644bf1857a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-09 02:28:33 -07:00
parent ef99dcd1b0
commit 7c4b29f642

View File

@@ -1300,17 +1300,27 @@ function createPostReviewTask(groupId: string): Record<string, any> {
}
function createPostReviewStore(task: Record<string, any>, branchGroup: Record<string, any> | null) {
const settings = {
autoMerge: false,
merger: { maxReviewPasses: 0 },
includeTaskIdInCommit: false,
mergeIntegrationWorktree: "cwd-main",
mergeStrategy: "direct",
directMergeCommitStrategy: "auto",
};
return {
getTask: vi.fn(async () => task),
listTasks: vi.fn(async () => [task]),
getSettings: vi.fn(async () => ({
autoMerge: false,
merger: { maxReviewPasses: 0 },
includeTaskIdInCommit: false,
mergeIntegrationWorktree: "cwd-main",
mergeStrategy: "direct",
directMergeCommitStrategy: "auto",
})),
getSettings: vi.fn(async () => settings),
/*
FNXC:BranchGroupAutoMergeGate 2026-08-09-08:55:
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.
*/
getSettingsByScope: vi.fn(async () => ({ global: {}, project: settings })),
listTasksByBranchGroup: vi.fn(async () => (branchGroup ? [task] : [])),
getBranchGroup: vi.fn(() => branchGroup),
updateTask: vi.fn(async (_id: string, patch: Record<string, unknown>) => Object.assign(task, patch)),
moveTask: vi.fn(async (_id: string, column: string) => { task.column = column; return task; }),
@@ -1498,10 +1508,39 @@ describe("resolveBranchGroupMergeRouting", () => {
*/
seedMergeLaneState(engine);
const released = await ProjectEngine.prototype.onMerge.call(engine, "FN-3324");
createResolvedAgentSessionMock.mockReset();
let resolvePromotionEvaluation!: () => void;
const promotionEvaluationReached = new Promise<void>((resolve) => {
resolvePromotionEvaluation = resolve;
});
store.recordRunAuditEvent.mockImplementation(async (event: { target?: string; mutationType?: string }) => {
if (event.target === "BG-user-hold" && event.mutationType?.startsWith("merge:branch-group-promotion")) {
resolvePromotionEvaluation();
}
});
/*
FNXC:BranchGroupAutoMergeGate 2026-08-09-09:00:
The drain's catch-and-warn wrappers can turn a missing fake-store seam into silent coverage loss.
This fixture therefore treats an `is not a function` warning as a failure after its asynchronous
promotion continuation completes, rather than allowing stderr noise to hide the skipped path.
*/
const warnSpy = vi.spyOn(console, "warn");
let released: any;
let offendingWarnings: string[] = [];
try {
released = await ProjectEngine.prototype.onMerge.call(engine, "FN-3324");
await promotionEvaluationReached;
offendingWarnings = warnSpy.mock.calls
.map((args) => args.map((arg) => String(arg)).join(" "))
.filter((message) => message.includes("is not a function"));
} finally {
warnSpy.mockRestore();
createResolvedAgentSessionMock.mockReset();
}
expect(offendingWarnings, "merge drain emitted missing-store-seam warnings").toEqual([]);
expect(released.merged).toBe(true);
expect(store.listTasksByBranchGroup).toHaveBeenCalledWith("BG-user-hold");
expect(mergeAttempts).toBe(1);
expect(git(repo, "git rev-parse main")).toBe(mainBefore);
expect(git(repo, "git show mission/M-8811:user-hold-feature.txt")).toBe("release only after operator confirmation");