/** * Hashline (hash-anchored edits) vs current string-match edit — real-API * measurement of whether Feature #2 is worth building. * * Two strategies produce the SAME edit against the SAME file, measured against * live gpt-5.5: * * BASELINE (what ggcoder does today): the model emits { old_text, new_text } * edits where old_text must be copied VERBATIM from the file with enough * surrounding context to match uniquely (this is exactly our edit tool's * contract — see tools/edit.ts). The reproduced context is what costs output * tokens, and a non-unique / drifted old_text is what causes apply failures. * * HASHLINE (the proposed feature): every line is shown with a short content- * hash anchor (`a3f1│`). The model references anchors instead of * reproducing text — it emits { from, to, lines } where from/to are anchors. * Anchors are unique by construction, so an edit either resolves exactly or is * rejected (never silently corrupts), and the model writes far fewer tokens. * * We measure, per task: model OUTPUT tokens (the headline -61% claim), whether * the edit applied cleanly + produced the correct file, and an anchor-uniqueness * / safety check. Edits are graded deterministically — no second model needed. * * The BASELINE apply path runs ggcoder's REAL edit ladder (fuzzy match + * indent-flex + blank-edge strip + dotdotdots — the same edit-diff functions * tools/edit.ts uses), so baseline numbers reflect what our tool actually * recovers, not a naive exact-replace. * * Usage: * npx tsx src/core/hashline-edit-benchmark.ts * * Env overrides: * GG_HL_PROVIDER / GG_HL_MODEL (default anthropic / claude-sonnet-5) * GG_HL_REPEAT (runs per task, default 1 — raise to average noise) */ import { type AnchoredFile } from "./hashline.js"; export interface EditTask { name: string; approxLines: number; file: string; instruction: string; /** Substrings that MUST appear in the correctly-edited file. */ mustContain: string[]; /** Substrings that MUST still be present (unchanged anchors far from the edit). */ mustPreserve: string[]; /** Optional extra validator for tasks where substring checks are too weak. */ validate?: (file: string) => boolean; } export declare function genFile(lines: number): string; /** Near-identical handler blocks — uniqueness pressure for string matching. */ export declare function genRepetitiveFile(blocks: number): string; export declare function buildTasks(): EditTask[]; export interface ApplyOutcome { applied: boolean; correct: boolean; /** edits whose locator was non-unique / unresolvable (would error in the real tool). */ ambiguousEdits: number; parsedEdits: number; } export declare function stripFence(s: string): string; /** * Parse the model's JSON envelope, tolerating literal (unescaped) newlines and * tabs inside string values. In production, edits arrive as STRUCTURED * tool-call arguments — the JSON envelope is a benchmark artifact — so both * strategies get the same repair to keep the comparison about the EDIT FORMAT, * not about JSON string-escaping discipline. */ export declare function parseEnvelope(raw: string): T | null; export declare function checkAnchors(file: string, task: EditTask): boolean; /** * ggcoder's REAL apply ladder, mirroring tools/edit.ts: * 1. exact + smart-quote/dash fuzzy * 2. indent-flex * 3. blank-edge strip, retry 1+2 * 4. dotdotdots elision * Returns the new working buffer or a failure reason. */ export declare function applyLadder(working: string, oldText: string, newText: string): { ok: true; working: string; } | { ok: false; reason: "not_found" | "ambiguous"; }; export declare function applyBaseline(raw: string, task: EditTask): ApplyOutcome; export declare function applyHashline(raw: string, task: EditTask, anchored: AnchoredFile): ApplyOutcome; //# sourceMappingURL=hashline-edit-benchmark.d.ts.map