F2 SLICE-2: Anchorer (fingerprint, resolution ladder, live shift) (#4)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-06-10 06:50:29 -07:00
parent 9d93ccca19
commit e5817eef0a
2 changed files with 182 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
import { describe, it, expect } from "vitest";
import { buildFingerprint, resolve, shift, type OffsetRange } from "../src/anchorer";
const DOC = "line0\nline1 needle here\nline2\nneedle again on line3\n";
describe("buildFingerprint", () => {
it("captures the exact text, bounded context, and 0-based lineHint", () => {
const start = DOC.indexOf("needle here");
const range: OffsetRange = { start, end: start + "needle".length };
const fp = buildFingerprint(DOC, range);
expect(fp.text).toBe("needle");
expect(fp.lineHint).toBe(1);
expect(fp.before.endsWith("line1 ")).toBe(true);
expect(fp.after.startsWith(" here")).toBe(true);
expect(fp.before.length).toBeLessThanOrEqual(120);
expect(fp.after.length).toBeLessThanOrEqual(120);
});
});
describe("resolve", () => {
it("exact-unique: returns the single occurrence's range", () => {
const fp = { text: "line2", before: "", after: "", lineHint: 0 };
const start = DOC.indexOf("line2");
expect(resolve(DOC, fp)).toEqual({ start, end: start + 5 });
});
it("context-disambiguated: picks the occurrence whose before/after match", () => {
const fp = { text: "needle", before: "line1 ", after: " here", lineHint: 99 };
const start = DOC.indexOf("needle here");
expect(resolve(DOC, fp)).toEqual({ start, end: start + 6 });
});
it("lineHint tiebreak: when context does not disambiguate, the closest line wins", () => {
// both occurrences of 'needle', no usable context, hint points at line 3
const fp = { text: "needle", before: "", after: "", lineHint: 3 };
const start = DOC.indexOf("needle again");
expect(resolve(DOC, fp)).toEqual({ start, end: start + 6 });
});
it("orphaned: returns 'orphaned' when the text is gone", () => {
const fp = { text: "absent-text", before: "", after: "", lineHint: 0 };
expect(resolve(DOC, fp)).toBe("orphaned");
});
it("orphaned: returns 'orphaned' rather than guessing on an unbreakable tie (INV-1)", () => {
const doc = "needle\n....\nneedle\n"; // two identical occurrences, equidistant from hint
const fp = { text: "needle", before: "", after: "", lineHint: 1 };
expect(resolve(doc, fp)).toBe("orphaned");
});
});
describe("shift", () => {
it("edit entirely before the range shifts both endpoints by the delta", () => {
const r: OffsetRange = { start: 10, end: 15 };
// insert 2 chars at offset 0 (replace [0,0) with len 2)
expect(shift(r, { start: 0, end: 0, newLength: 2 })).toEqual({ start: 12, end: 17 });
});
it("edit entirely after the range leaves it unchanged", () => {
const r: OffsetRange = { start: 2, end: 5 };
expect(shift(r, { start: 10, end: 12, newLength: 0 })).toEqual({ start: 2, end: 5 });
});
it("edit overlapping the range clamps the touched endpoints to the edit start", () => {
const r: OffsetRange = { start: 5, end: 10 };
// replace [3,7) with 1 char (delta = -3)
expect(shift(r, { start: 3, end: 7, newLength: 1 })).toEqual({ start: 3, end: 7 });
});
});