import { describe, it, expect } from "vitest"; import { minimizeReplace, PendingEditRegistry } from "../src/pendingEdits"; import type { Provenance } from "../src/model"; const AGENT: Provenance = { kind: "agent", id: "claude", agent: { sdk: "@cline/sdk", model: "sonnet", sessionId: "run-1" }, }; describe("PendingEditRegistry (INV-9)", () => { it("matches and consumes a single-hunk event equal to the registration", () => { const reg = new PendingEditRegistry(); reg.register({ docPath: "d.md", start: 3, end: 7, newText: "new", provenance: AGENT, turnId: "t1", full: { start: 3, end: 7, newLength: 3 }, }); const hit = reg.matchEvent("d.md", [{ start: 3, end: 7, newLength: 3 }]); expect(hit?.turnId).toBe("t1"); expect(reg.matchEvent("d.md", [{ start: 3, end: 7, newLength: 3 }])).toBeNull(); }); it("matches a HOST-SPLIT event: several hunks inside the full range with the same net delta", () => { // The host word-diffs one applied replace into multiple minimal hunks // (observed on F4 accept) — per-hunk equality misses; net-effect matches. const reg = new PendingEditRegistry(); reg.register({ docPath: "d.md", start: 10, end: 50, newText: "x".repeat(45), provenance: AGENT, turnId: "t2", full: { start: 10, end: 50, newLength: 45 }, }); const hit = reg.matchEvent("d.md", [ { start: 12, end: 20, newLength: 9 }, { start: 25, end: 30, newLength: 6 }, { start: 40, end: 48, newLength: 11 }, ]); expect(hit?.turnId).toBe("t2"); }); it("does not match a different doc, hunks outside the full range, or a different delta", () => { const reg = new PendingEditRegistry(); reg.register({ docPath: "d.md", start: 3, end: 7, newText: "new", provenance: AGENT, full: { start: 3, end: 7, newLength: 3 }, }); expect(reg.matchEvent("other.md", [{ start: 3, end: 7, newLength: 3 }])).toBeNull(); expect(reg.matchEvent("d.md", [{ start: 3, end: 8, newLength: 4 }])).toBeNull(); expect(reg.matchEvent("d.md", [{ start: 3, end: 7, newLength: 4 }])).toBeNull(); expect(reg.matchEvent("d.md", [])).toBeNull(); }); it("falls back to the minimized range when no full extent was registered", () => { const reg = new PendingEditRegistry(); reg.register({ docPath: "d.md", start: 3, end: 7, newText: "new", provenance: AGENT }); expect(reg.matchEvent("d.md", [{ start: 3, end: 7, newLength: 3 }])).not.toBeNull(); }); it("unregister removes a failed application", () => { const reg = new PendingEditRegistry(); const p = { docPath: "d.md", start: 0, end: 0, newText: "x", provenance: AGENT }; reg.register(p); reg.unregister(p); expect(reg.matchEvent("d.md", [{ start: 0, end: 0, newLength: 1 }])).toBeNull(); }); it("unregister reports whether the registration was still pending", () => { const reg = new PendingEditRegistry(); const p = { docPath: "d.md", start: 0, end: 0, newText: "x", provenance: AGENT }; reg.register(p); expect(reg.unregister(p)).toBe(true); reg.register(p); reg.matchEvent("d.md", [{ start: 0, end: 0, newLength: 1 }]); expect(reg.unregister(p)).toBe(false); }); }); describe("minimizeReplace (host diff-minimization mirror)", () => { it("trims a common suffix (the E2E-observed case)", () => { expect(minimizeReplace("target sentence", "REWRITTEN-BY-CLAUDE sentence")).toEqual({ prefix: 0, suffix: 9 }); }); it("trims a common prefix", () => { expect(minimizeReplace("Hello world", "Hello there")).toEqual({ prefix: 6, suffix: 0 }); }); it("trims both, never overlapping", () => { expect(minimizeReplace("aba", "aa")).toEqual({ prefix: 1, suffix: 1 }); expect(minimizeReplace("aaaa", "aa")).toEqual({ prefix: 2, suffix: 0 }); }); it("identical texts minimize to nothing", () => { expect(minimizeReplace("same", "same")).toEqual({ prefix: 4, suffix: 0 }); }); it("disjoint texts trim nothing", () => { expect(minimizeReplace("abc", "xyz")).toEqual({ prefix: 0, suffix: 0 }); }); });