{"version":3,"file":"eval-live.d.ts","sourceRoot":"","sources":["../../../src/core/search/eval-live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACxB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb;6EACyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yDAAyD;IACzD,OAAO,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAExE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,eAAe,GACtB;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAY5C","sourcesContent":["/**\n * Live-edit evaluation: the one thing the main gold set structurally cannot\n * measure.\n *\n * The eval corpus is a pinned checkout that exactly matches the embedding\n * index, so every retriever sees the same content and the grep leg looks\n * redundant — measurably so, since it is a significant regression once BM25 is\n * present. But an agent's corpus is *not* a clean checkout: it edits files as\n * it works, and the daemon has no file watcher, so anything written during a\n * session is invisible to both dense and BM25 until the next index build.\n * Grep is the only leg that sees it.\n *\n * This applies edits to the corpus **after** indexing and then asks queries\n * that only those edits can answer. A retriever backed by the index scores 0\n * by construction; grep scores what it can actually find. That is the number\n * the decision to keep or drop the grep leg rests on, and nothing in the main\n * sweep produces it.\n *\n * Gold line ranges are resolved from anchors after the edits land, so the\n * fixture never hardcodes line numbers for content it also defines.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { readFileSync } from \"fs\";\nimport type { EvalQuery } from \"./eval.js\";\nimport { resolveGoldSet } from \"./eval-gold.js\";\n\n/** A file written into the corpus after indexing. */\nexport interface LiveEdit {\n\t/** Repo-relative POSIX path. Created if absent, overwritten if present. */\n\tpath: string;\n\t/** Full file contents. Held inline so the edit is reproducible from the\n\t *  fixture alone, with no dependency on what the corpus already held. */\n\tcontent: string;\n\t/** Why this edit exists — reporting only. */\n\tnote?: string;\n}\n\nexport interface LiveEditFixture {\n\tedits: LiveEdit[];\n\t/** Queries answerable *only* from the edited content. */\n\tqueries: EvalQuery[];\n}\n\nexport function loadLiveEditFixture(fixturePath: string): LiveEditFixture {\n\treturn JSON.parse(readFileSync(fixturePath, \"utf-8\")) as LiveEditFixture;\n}\n\n/**\n * Write the edits into `corpusRoot`, then resolve the queries' gold ranges\n * against the resulting tree.\n *\n * Order matters: resolving before the write would look for anchors in content\n * that does not exist yet.\n */\nexport function applyLiveEdits(\n\tcorpusRoot: string,\n\tfixture: LiveEditFixture,\n): { queries: EvalQuery[]; issues: string[] } {\n\tfor (const edit of fixture.edits) {\n\t\tconst target = path.resolve(corpusRoot, edit.path);\n\t\tmkdirSync(path.dirname(target), { recursive: true });\n\t\twriteFileSync(target, edit.content);\n\t}\n\n\tconst { dataset, issues } = resolveGoldSet(corpusRoot, fixture.queries);\n\treturn {\n\t\tqueries: dataset,\n\t\tissues: issues.map((i) => `${i.queryId} [${i.path}]: ${i.problem}`),\n\t};\n}\n"]}