test(FN-4956): complete Step 4 — add layer3 file-scope regressions
Fusion-Task-Id: FN-4956 Fusion-Task-Lineage: 7105cd5e-27f4-4e84-b2ae-e811a183803f
This commit is contained in:
committed by
gsxdsm
parent
8072554650
commit
78737841dd
@@ -0,0 +1,129 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { execSync, spawnSync } from "node:child_process";
|
||||
import { assertSquashOverlapsFileScope, applyLayer3ConflictScopePartition, getConflictedFiles } from "../../merger.js";
|
||||
|
||||
const hasGit = spawnSync("git", ["--version"], { stdio: "pipe" }).status === 0;
|
||||
const describeIfGit = hasGit ? describe : describe.skip;
|
||||
|
||||
function git(cwd: string, cmd: string): string {
|
||||
return execSync(cmd, { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
||||
}
|
||||
|
||||
async function setupConflictRepo() {
|
||||
const rootDir = await mkdtemp(join(tmpdir(), "fn-4956-ri-"));
|
||||
git(rootDir, "git init -b main");
|
||||
git(rootDir, 'git config user.email "test@example.com"');
|
||||
git(rootDir, 'git config user.name "Test User"');
|
||||
|
||||
await mkdir(join(rootDir, "packages/desktop/src"), { recursive: true });
|
||||
await writeFile(join(rootDir, "AGENTS.md"), "line\nshared\n", "utf-8");
|
||||
await writeFile(join(rootDir, "packages/desktop/src/foo.ts"), "export const value = 'base';\n", "utf-8");
|
||||
git(rootDir, "git add AGENTS.md packages/desktop/src/foo.ts");
|
||||
git(rootDir, "git commit -m 'chore: base'");
|
||||
|
||||
git(rootDir, "git checkout -b fusion/fn-4956");
|
||||
await writeFile(join(rootDir, "AGENTS.md"), "line\nbranch\n", "utf-8");
|
||||
await writeFile(join(rootDir, "packages/desktop/src/foo.ts"), "export const value = 'branch';\n", "utf-8");
|
||||
git(rootDir, "git add AGENTS.md packages/desktop/src/foo.ts");
|
||||
git(rootDir, "git commit -m 'feat: branch edits'");
|
||||
|
||||
git(rootDir, "git checkout main");
|
||||
await writeFile(join(rootDir, "AGENTS.md"), "line\nmain\n", "utf-8");
|
||||
await writeFile(join(rootDir, "packages/desktop/src/foo.ts"), "export const value = 'main';\n", "utf-8");
|
||||
git(rootDir, "git add AGENTS.md packages/desktop/src/foo.ts");
|
||||
git(rootDir, "git commit -m 'feat: main edits'");
|
||||
|
||||
git(rootDir, "git merge --squash fusion/fn-4956 || true");
|
||||
return rootDir;
|
||||
}
|
||||
|
||||
describeIfGit("reliability interactions: layer3 ai arbiter file scope", () => {
|
||||
const roots: string[] = [];
|
||||
afterEach(async () => {
|
||||
while (roots.length > 0) {
|
||||
await rm(roots.pop()!, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("skips foreign conflicted files and keeps squash in scope", async () => {
|
||||
const rootDir = await setupConflictRepo();
|
||||
roots.push(rootDir);
|
||||
|
||||
const auditEvents: Array<{ type: string; metadata: any }> = [];
|
||||
const task = { id: "FN-4956", scopeOverride: false } as any;
|
||||
const store = {
|
||||
parseFileScopeFromPrompt: async () => ["packages/desktop/src/**"],
|
||||
appendAgentLog: async () => undefined,
|
||||
logEntry: async () => undefined,
|
||||
} as any;
|
||||
|
||||
const conflicted = await getConflictedFiles(rootDir);
|
||||
expect(conflicted.sort()).toEqual(["AGENTS.md", "packages/desktop/src/foo.ts"].sort());
|
||||
|
||||
const partitioned = await applyLayer3ConflictScopePartition({
|
||||
store,
|
||||
task,
|
||||
taskId: "FN-4956",
|
||||
rootDir,
|
||||
branch: "fusion/fn-4956",
|
||||
conflictFiles: conflicted,
|
||||
auditor: {
|
||||
git: async (event: any) => {
|
||||
auditEvents.push({ type: event.type, metadata: event.metadata });
|
||||
},
|
||||
} as any,
|
||||
});
|
||||
|
||||
expect(partitioned.inScopeConflicts).toEqual(["packages/desktop/src/foo.ts"]);
|
||||
expect(partitioned.skippedFiles).toEqual(["AGENTS.md"]);
|
||||
|
||||
const staged = git(rootDir, "git diff --cached --name-only").split("\n").filter(Boolean);
|
||||
expect(staged).toContain("packages/desktop/src/foo.ts");
|
||||
expect(staged).not.toContain("AGENTS.md");
|
||||
|
||||
await expect(assertSquashOverlapsFileScope({
|
||||
store,
|
||||
taskId: "FN-4956",
|
||||
rootDir,
|
||||
task,
|
||||
} as any)).resolves.toBeUndefined();
|
||||
|
||||
expect(auditEvents.some((event) => event.type === "merge:layer3:foreign-file-skipped" && event.metadata.skippedFiles.includes("AGENTS.md"))).toBe(true);
|
||||
});
|
||||
|
||||
it("emits scope-override bypass and does not skip foreign files", async () => {
|
||||
const rootDir = await setupConflictRepo();
|
||||
roots.push(rootDir);
|
||||
|
||||
const auditEvents: Array<{ type: string; metadata: any }> = [];
|
||||
const task = { id: "FN-4956", scopeOverride: true, scopeOverrideReason: "interaction-test" } as any;
|
||||
const store = {
|
||||
parseFileScopeFromPrompt: async () => ["packages/desktop/src/**"],
|
||||
appendAgentLog: async () => undefined,
|
||||
logEntry: async () => undefined,
|
||||
} as any;
|
||||
|
||||
const conflicted = await getConflictedFiles(rootDir);
|
||||
const partitioned = await applyLayer3ConflictScopePartition({
|
||||
store,
|
||||
task,
|
||||
taskId: "FN-4956",
|
||||
rootDir,
|
||||
branch: "fusion/fn-4956",
|
||||
conflictFiles: conflicted,
|
||||
auditor: {
|
||||
git: async (event: any) => {
|
||||
auditEvents.push({ type: event.type, metadata: event.metadata });
|
||||
},
|
||||
} as any,
|
||||
});
|
||||
|
||||
expect(partitioned.inScopeConflicts.sort()).toEqual(conflicted.sort());
|
||||
expect(partitioned.skippedFiles).toEqual([]);
|
||||
expect(auditEvents.some((event) => event.type === "merge:layer3:scope-override-bypass")).toBe(true);
|
||||
expect(auditEvents.some((event) => event.type === "merge:layer3:foreign-file-skipped")).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user