@tangle-network/agent-eval 0.140.1 → 0.142.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/analyst/index.d.ts +74 -6
  3. package/dist/analyst/index.d.ts.map +1 -1
  4. package/dist/analyst/index.js +6 -6
  5. package/dist/{benchmark-command-Bo_hkhQf.js → benchmark-command-BG2PlMDp.js} +2239 -1820
  6. package/dist/benchmark-command-BG2PlMDp.js.map +1 -0
  7. package/dist/benchmarks/index.js +1 -1
  8. package/dist/{benchmarks-HwoBE32G.js → benchmarks-Ce8GdJbc.js} +4 -4
  9. package/dist/{benchmarks-HwoBE32G.js.map → benchmarks-Ce8GdJbc.js.map} +1 -1
  10. package/dist/campaign/index.js +3 -3
  11. package/dist/{campaign-BzjYNYVZ.js → campaign-COFTVy3Q.js} +3 -3
  12. package/dist/{campaign-BzjYNYVZ.js.map → campaign-COFTVy3Q.js.map} +1 -1
  13. package/dist/cli.js +1 -1
  14. package/dist/contract/index.d.ts.map +1 -1
  15. package/dist/contract/index.js +56 -13
  16. package/dist/contract/index.js.map +1 -1
  17. package/dist/{default-registry-BOiBXNFh.js → default-registry-BupFSXSN.js} +108 -20
  18. package/dist/default-registry-BupFSXSN.js.map +1 -0
  19. package/dist/default-registry-Ci7wAAR8.d.ts.map +1 -1
  20. package/dist/{dspy-rlm-engine-Bkak4nzo.js → dspy-rlm-engine-Bw8Zz9CX.js} +7 -4
  21. package/dist/{dspy-rlm-engine-Bkak4nzo.js.map → dspy-rlm-engine-Bw8Zz9CX.js.map} +1 -1
  22. package/dist/{extract-usage-C5vMw-0R.js → extract-usage-7l1Xq5ti.js} +2 -2
  23. package/dist/{extract-usage-C5vMw-0R.js.map → extract-usage-7l1Xq5ti.js.map} +1 -1
  24. package/dist/index.d.ts +68 -31
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +122 -46
  27. package/dist/index.js.map +1 -1
  28. package/dist/{kind-factory-DB7nIs35.js → kind-factory-Bvwe3pup.js} +11 -1
  29. package/dist/kind-factory-Bvwe3pup.js.map +1 -0
  30. package/dist/multishot/index.d.ts +29 -6
  31. package/dist/multishot/index.d.ts.map +1 -1
  32. package/dist/multishot/index.js +53 -3
  33. package/dist/multishot/index.js.map +1 -1
  34. package/dist/openapi.json +1 -1
  35. package/dist/replay-BqTgoioO.d.ts.map +1 -1
  36. package/dist/{replay-k2MsOmv5.js → replay-DjUfTrHD.js} +40 -48
  37. package/dist/replay-DjUfTrHD.js.map +1 -0
  38. package/dist/{single-run-lock-CiQThJxB.js → single-run-lock-BcvPQY57.js} +65 -15
  39. package/dist/single-run-lock-BcvPQY57.js.map +1 -0
  40. package/dist/{skill-usage-CVVnoIx-.d.ts → skill-usage-CNZTk_LT.d.ts} +8 -4
  41. package/dist/{skill-usage-CVVnoIx-.d.ts.map → skill-usage-CNZTk_LT.d.ts.map} +1 -1
  42. package/dist/{skillopt-optimization-method-CSBQ8Qma.js → skillopt-optimization-method-DV6c4ooy.js} +2 -2
  43. package/dist/{skillopt-optimization-method-CSBQ8Qma.js.map → skillopt-optimization-method-DV6c4ooy.js.map} +1 -1
  44. package/dist/{store-otlp-vRByAR6h.js → store-otlp-D4I90_vR.js} +2 -2
  45. package/dist/{store-otlp-vRByAR6h.js.map → store-otlp-D4I90_vR.js.map} +1 -1
  46. package/dist/traces.js +4 -4
  47. package/docs/adapters-observability.md +35 -21
  48. package/docs/concepts.md +1 -0
  49. package/docs/distributed-driver.md +7 -3
  50. package/docs/feature-guide.md +1 -0
  51. package/docs/insight-report.md +1 -1
  52. package/docs/trace-analysis.md +11 -0
  53. package/docs/wire-protocol.md +70 -2
  54. package/package.json +5 -3
  55. package/dist/benchmark-command-Bo_hkhQf.js.map +0 -1
  56. package/dist/default-registry-BOiBXNFh.js.map +0 -1
  57. package/dist/kind-factory-DB7nIs35.js.map +0 -1
  58. package/dist/replay-k2MsOmv5.js.map +0 -1
  59. package/dist/single-run-lock-CiQThJxB.js.map +0 -1
@@ -2,14 +2,14 @@ import { c as ValidationError, t as AgentEvalError } from "./errors-D-LKuDhb.js"
2
2
  import { s as resolveModelPricing } from "./metrics-C9YY1OcL.js";
3
3
  import { a as CostLedgerPersistenceError, i as CostLedger, n as CostCallConflictError, o as CostReceiptCaptureError, r as CostCeilingReachedError, s as CostReservationExceededError, t as CostAccountingIncompleteError } from "./cost-ledger-DMFxsLKr.js";
4
4
  import { c as callLlmJson, f as maximumChargeForLlmRequest, l as costReceiptFromLlm, r as LlmResponseError, t as LlmCallError, u as costReceiptFromLlmError } from "./llm-client-B3WXSH5Y.js";
5
- import { O as evidenceRefsFromRawFinding, h as TRACE_ANALYSIS_LIMITS, i as runTraceAnalyst } from "./kind-factory-DB7nIs35.js";
5
+ import { O as evidenceRefsFromRawFinding, h as TRACE_ANALYSIS_LIMITS, i as runTraceAnalyst } from "./kind-factory-Bvwe3pup.js";
6
6
  import { o as makeFinding, r as usageReceiptFromCostLedger } from "./usage-receipt-CgxMEBZq.js";
7
7
  import { i as hashCanonical, r as canonicalString } from "./canonical-D011XM8r.js";
8
- import { n as createRunCostLedger, r as fsCampaignStorage, t as acquireSingleRunLock } from "./single-run-lock-CiQThJxB.js";
9
- import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-Bkak4nzo.js";
8
+ import { n as createRunCostLedger, r as fsCampaignStorage, t as acquireSingleRunLock } from "./single-run-lock-BcvPQY57.js";
9
+ import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-Bw8Zz9CX.js";
10
10
  import { c as writeLedgerFileAtomically, s as withLedgerFileLock } from "./ledger-core-Dxz0Rkwa.js";
11
11
  import { E as pairedBootstrap } from "./statistics-ByxzSiOM.js";
12
- import { i as otlpTextToTraceAnalysisStore, r as createOtlpBufferTraceStore, t as DEFAULT_MAX_TRACE_FILE_BYTES } from "./store-otlp-vRByAR6h.js";
12
+ import { i as otlpTextToTraceAnalysisStore, r as createOtlpBufferTraceStore, t as DEFAULT_MAX_TRACE_FILE_BYTES } from "./store-otlp-D4I90_vR.js";
13
13
  import { i as summarizeAnalystBenchmarkRunner, n as runAnalystBenchmark, r as traceStoreEvidenceResolver } from "./benchmark-CYtcIF2V.js";
14
14
  import { z } from "zod";
15
15
  import { constants, existsSync, lstatSync, readFileSync } from "node:fs";
@@ -1068,6 +1068,7 @@ const artifactSchema = z.strictObject({
1068
1068
  execution: z.strictObject({
1069
1069
  repetitions: positiveInteger$1,
1070
1070
  concurrency: positiveInteger$1,
1071
+ rlmSamples: positiveInteger$1.optional(),
1071
1072
  model: nonEmptyString,
1072
1073
  maxOutputTokens: positiveInteger$1,
1073
1074
  timeoutMs: positiveInteger$1,
@@ -1172,7 +1173,7 @@ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES = Object.freeze([
1172
1173
  "package.json",
1173
1174
  "pnpm-lock.yaml"
1174
1175
  ]);
1175
- const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "701ea59184f3d227cf590ea3f16d24d65dbed2ad5644f8294801ceb66a30d4ef";
1176
+ const ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 = "c511497ed4481f7b7ab2c6c19513b8c04c90c345e8b58440b1073a80753f1a42";
1176
1177
  /** The published benchmark evidence was produced at this package version, by
1177
1178
  * the retired one-shot direct runner, before trace analysts moved to the
1178
1179
  * recursive DSPy RLM engine. Both evidence digests below are historical facts
@@ -1198,8 +1199,10 @@ const ANALYST_BENCHMARK_IMPLEMENTATION_FILES = Object.freeze([
1198
1199
  "src/analyst/benchmark-dataset-utils.ts",
1199
1200
  "src/analyst/benchmark-datasets.ts",
1200
1201
  "src/analyst/benchmark-evidence-validation.ts",
1202
+ "src/analyst/benchmark-instructions-override.ts",
1201
1203
  "src/analyst/benchmark-public-adapters.ts",
1202
1204
  "src/analyst/benchmark-public-calibration.ts",
1205
+ "src/analyst/benchmark-public-consensus.ts",
1203
1206
  "src/analyst/benchmark-public-data.ts",
1204
1207
  "src/analyst/benchmark-public-errors.ts",
1205
1208
  "src/analyst/benchmark-public-model.ts",
@@ -1266,7 +1269,7 @@ const ANALYST_BENCHMARK_IMPLEMENTATION_FILES = Object.freeze([
1266
1269
  "src/trace/otlp-attributes.ts",
1267
1270
  "src/trace/raw-provider-sink.ts"
1268
1271
  ]);
1269
- const ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 = "56dd4c7ed19fc5855f99ad238464ad95cb1bea155ad58c49dab3eb0f6cbe7d6a";
1272
+ const ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 = "a3f5a8203f0a7c74736170c53100c50c4db1cf84381533002f0539ef1e7a4c6d";
1270
1273
  function analystBenchmarkImplementationDigest() {
1271
1274
  return ANALYST_BENCHMARK_IMPLEMENTATION_SHA256;
1272
1275
  }
@@ -2104,37 +2107,44 @@ const TRACE_PROJECTION_ATTRIBUTE_BYTE_CAPS = [
2104
2107
  64
2105
2108
  ];
2106
2109
  const CODE_TRACE_BENCH_ANALYST_PROMPT = `Analyze exactly one coding-agent trajectory and its attached final verification.
2107
- Your task is the CodeTraceBench incorrect-step task: identify every wrong state-changing action, bad hypothesis that drives an action, and regression.
2108
- An incorrect step remains incorrect when the agent later recovers or the final verification passes; a trajectory that ends in success still contains every mistake the agent made along the way.
2109
- Incorrect steps occur in contiguous failure blocks: one mistake plus every consecutive following step that commits to, compounds, or acts on it.
2110
+ Your task is the CodeTraceBench incorrect-step task: identify every incorrect step, defined as a wrong state-changing intervention given the evidence — a mislocalized edit, a wrong hypothesis that drives an action, a regression, an irrelevant change, or an incorrect dependency or configuration choice.
2111
+ If the final verification failed, the trajectory MUST contain at least one incorrect step. Never return an empty findings array on a failing trajectory; trace backward until you find the root cause.
2112
+ Work backward, the way this benchmark was annotated, never by scanning forward for suspicious steps: start from the final verification outcome or the latest observed failure evidence, identify the immediately preceding step whose action or output produced that observed error, then recursively ask which earlier decision led to each intermediate failure, until the preceding steps contain no error or the cause is unrelated to the trajectory's own decisions.
2113
+ Each backward chain terminates at an error-critical step — the earliest decision that triggered the downstream cascade — and that step is the block's first_step: the step that committed the mistake, not the step that planned it and not a later step that repeats it.
2114
+ A block is a maximal contiguous sequence of strictly incorrect steps. A step belongs in the block ONLY if it introduces, propagates, or compounds the error.
2115
+ Do NOT include steps that merely "act on", diagnose, or react to the error. A diagnostic command, a test run exposing the bug, or a correct exploratory read is a CORRECT step.
2116
+ If an incorrect step is followed by a correct diagnostic step and then another incorrect step, you MUST emit two separate blocks. NEVER bridge correct steps by grouping them into a single block with incorrect steps. Over-blocking drastically hurts your precision.
2117
+ After identifying first_step, extend last_step forward ONLY through consecutive steps that independently introduce, propagate, or compound the mistake. A cascade of repeated failed attempts at the same wrong approach is one maximal block, provided EVERY step is independently incorrect.
2118
+ Do not end a block merely because the agent tried a variation of the same wrong approach; a variation that still carries the error stays inside the block.
2119
+ A partially correct or ambiguous fix still counts as incorrect; the block ends only at the first step free of the error — a clean diagnostic read, the corrective action that closes the issue and needs no further rework, or a genuine abandonment of the wrong approach.
2120
+ Block extent follows the traced chain and this forward extension, nothing else.
2110
2121
  Report each failure block as exactly one finding whose first_step is the block's first incorrect step and whose last_step is its last, covering every consecutive step between them.
2111
- Set first_step to the first step that commits the mistake, not the step that planned it and not a later step that repeats it.
2112
- Extend last_step one step at a time, and only while the next step independently satisfies the incorrect-step definition on its own action and its own following observation.
2113
- Stop at the first step where the agent detects the problem, inspects it, or begins repairing it: a diagnostic probe, a test run that exposes the defect, or a repair action ends the block and is never inside it.
2114
- A one-step block is a complete and correct answer.
2115
- Every step inside a block is scored on its own: naming a correct step costs exactly as much as missing an incorrect one, and naming only the first step of a longer block forfeits every unnamed step.
2116
- Report blocks separated by at least one correct step as separate findings, and never let two blocks overlap.
2117
- Inspect the complete supplied trace data.
2118
- Use the final-verification outcome as evidence about the final state, not as a rule for whether earlier steps were incorrect.
2119
- For each candidate block, inspect every assistant action in it and its following observation.
2120
- Admit a block only when you can point at the specific evidence it produced: name as consequence_step the step number whose action or observation shows the damage a failing command, a wrong file state, a repeated failure, or rework the agent had to do because of this block. That step is the block's own last step when its observation already shows the damage, and a later step otherwise.
2121
- When you cannot name that later step number from the trace you were given, drop the block; a plausible story about why a step looks wrong is not evidence that it was.
2122
- Judge that consequence from the trajectory itself: a passing final verification is not evidence that a block caused nothing, and a failing final verification is not evidence that any particular block caused it.
2122
+ Every step inside a block is scored on its own: naming a correct step costs exactly as much as missing an incorrect one, and naming only the first step of a longer block forfeits every unnamed step. Because of this, carefully verify every step between first_step and last_step. Only include steps that introduce, propagate, or compound the error.
2123
+ Report blocks separated by at least one correct step as separate findings, and never let two blocks overlap. If there are multiple separate failure cascades, emit a separate finding for each one.
2124
+ Prefer anchored blocks: a block whose chain traces back from observed failure evidence a failing command or verification, an error observation, a regression, or, on a solved trajectory, a later step that reverts or supersedes it outranks one without.
2125
+ When an action is clearly wrong on its own evidence but you cannot trace such an anchor, report the block anyway with proportionally lower confidence.
2126
+ A solved trajectory still carries every mistake made along the way: inspect its final patching and verification stages for a state-changing action that a later step reverted, superseded, or corrected — a wrong edit just before the final fix is incorrect even when every test ends green.
2127
+ Before emitting a candidate block, check its boundaries.
2128
+ Neighbor check: ask whether the accusation fits one step earlier (the decision rather than its consequence) or one step later (the next step still acts on or reworks the same error) better than where you placed it, and move the boundary when it does; a boundary off by one step scores zero at that step.
2129
+ Completeness check: a block must cover the maximal contiguous sequence of incorrect steps. If an agent fails at step 10, tries to fix it at 11, fails, and tries again at 12 and 13, all four steps are incorrect and must be included in the block. Never truncate a cascade. If you miss the later steps of a cascade, your recall drops to zero for them.
2130
+ Counterfactual check: ask which step's correct execution would have made the downstream failure or rework disappear, and move first_step onto that step; use this check only to move a boundary, never to delete a block.
2131
+ Width check: inspect the step immediately before first_step and the step immediately after last_step; when either neighbor commits to, compounds, or propagates the same mistake, it belongs inside the block move that boundary outward and repeat until both neighbors are free of the error.
2132
+ For each block you keep, name as consequence_step the step number whose action or observation shows the damage a failing command, a wrong file state, a repeated failure, or rework the agent had to do because of this block; that step is the block's own last step when its observation already shows the damage, and a later step otherwise.
2133
+ When you cannot name that step number from the trace you were given, drop the block; a plausible story about why a step looks wrong is not evidence that it was.
2134
+ A passing final verification is not evidence that a block caused nothing, and a failing final verification is not evidence that any particular block caused it.
2123
2135
  For every block, decide whether the agent escaped the failure.
2124
- Mark escape_status "escaped" only when you can name the single later step that fully reversed the block, the agent needed no other step to recover, and nothing after that step revisits the same file, command, or hypothesis; write that step number in the rationale.
2136
+ Mark escape_status "escaped" only when you can name the single later step that fully reversed the block, the agent needed no other step to recover, and nothing after that step revisits the same file, command, or hypothesis; write that step number in the rationale. If the agent required multiple steps to fix the issue, or if you are unsure, it is not escaped.
2125
2137
  Mark escape_status "unescaped" in every other case, including whenever you are unsure.
2126
- A passing final verification never makes a block escaped: the agent may have made the mistake and repaired it over several steps, and those steps are still incorrect.
2127
- Label a failed command when the assistant caused it through a wrong action or unsupported hypothesis.
2128
- Label the later corrective action only when that action is itself wrong.
2129
- Do not label a diagnostic probe merely because it exposes an earlier defect.
2130
- Do not label a redundant but correct read or search; CodeTraceBench scores unuseful steps separately, and this run scores incorrect steps only.
2138
+ A passing final verification never makes a block escaped.
2139
+ Do not label a diagnostic probe or test run merely because its output exposes an earlier defect.
2140
+ Do not label a redundant but correct read or search; CodeTraceBench scores unuseful steps separately, and this run scores incorrect steps only. Never include a correct step in a block just to bridge two incorrect steps; instead, emit two separate blocks.
2131
2141
  Do not label a step solely because final verification failed.
2132
- When final verification is unavailable, use only directly observed trajectory evidence.
2142
+ When final verification is unavailable, trace backward from the latest failure evidence inside the trajectory itself.
2133
2143
  Every step in a reported block MUST be the positive integer n from an existing assistant LLM span named step-<n>.
2134
2144
  Never select an EVALUATOR, TOOL, CHAIN, final-verification, benchmark-verification, or message-<n> span.
2135
2145
  Before emitting a finding, inspect every covered span's attributes.content and describe only the actions shown there.
2136
- Report at most 16 blocks and at most 12 steps in one block; when more candidates than that exist, report the ones you can support with the clearest downstream evidence.
2137
- When the trajectory has no incorrect steps, return an empty findings array.`;
2146
+ Report at most 16 blocks and at most 12 steps in one block; when more candidates than that exist, report the ones whose chains carry the clearest downstream evidence.
2147
+ When the trajectory has no incorrect steps — its final verification passed and the final-stage sweep found no reverted, superseded, or corrected action — return an empty findings array.`;
2138
2148
  const AGENT_RX_PROMPT = `Analyze exactly one failed agent trajectory.
2139
2149
  Find the first unrecoverable critical failure, not every later symptom.
2140
2150
  Inspect the complete supplied trace data.
@@ -2175,8 +2185,8 @@ The excerpt must quote the assistant action exactly.`;
2175
2185
  const CODE_TRACE_RLM_CONTRACT = `Use the trace tools rather than asking for the whole trajectory in the prompt.
2176
2186
  Keep retrieved trace objects in Python variables.
2177
2187
  Never print an entire trace, full source file, or more than 12000 characters in one iteration.
2178
- Build a compact table of assistant step ids, actions, following observations, and final verification.
2179
- Inspect suspicious steps with viewSpans or searchSpan instead of repeatedly printing the table.
2188
+ Read the final verification and the latest failure evidence first, then build a compact table of assistant step ids, actions, and following observations.
2189
+ Trace backward from that evidence with viewSpans or searchSpan, confirming each candidate step's own action content, instead of repeatedly printing the table.
2180
2190
  This runner emits no JSON fields, so the block is encoded in the finding's subject.
2181
2191
  Only findings_json is scored; your prose answer is ignored, so every incorrect block you identify must appear as a finding, never only in the answer.
2182
2192
  Emit exactly one finding per contiguous failure block.
@@ -2235,774 +2245,1314 @@ function publicBenchmarkProtocolSha256(dataset) {
2235
2245
  }));
2236
2246
  }
2237
2247
  //#endregion
2238
- //#region src/analyst/benchmark-public-adapters.ts
2239
- function emptyPublicBenchmarkRunner() {
2248
+ //#region src/analyst/benchmark-instructions-override.ts
2249
+ /** Build an override from instruction text. Blank text is a caller error. */
2250
+ function analystInstructionsOverrideFromText(text) {
2251
+ if (typeof text !== "string" || !text.trim()) throw new Error("analyst instructions override must contain non-empty instruction text");
2240
2252
  return {
2241
- id: "empty",
2242
- analyze() {
2243
- return {
2244
- findings: [],
2245
- usage: {
2246
- calls: 0,
2247
- tokens: {
2248
- input: 0,
2249
- output: 0
2250
- },
2251
- cost: {
2252
- kind: "observed",
2253
- usd: 0
2254
- }
2255
- },
2256
- metadata: { baseline: "emit-no-findings" }
2257
- };
2258
- }
2259
- };
2260
- }
2261
- async function adaptPublicBenchmarkFindings(options) {
2262
- if (options.dataset === "agentrx") return {
2263
- findings: adaptAgentRxFindings(options.trajectoryId, options.findings, options.analystId),
2264
- diagnostics: void 0
2253
+ text,
2254
+ sha256: sha256Digest(text)
2265
2255
  };
2266
- return adaptCodeTraceFindings(options.trajectoryId, options.findings, options.analystId, options.store, options.signal);
2267
- }
2268
- function adaptAgentRxFindings(trajectoryId, findings, analystId) {
2269
- if (findings.length === 0) return [];
2270
- if (findings.length !== 1) throw new Error(`AgentRx model analyst must emit zero or one root cause, received ${findings.length}`);
2271
- const source = findings[0];
2272
- if (!source.subject) throw new Error("AgentRx model analyst finding is missing its failure-category subject");
2273
- const steps = exactFindingSteps(trajectoryId, source);
2274
- if (steps.length !== 1) throw new Error(`AgentRx model analyst must cite exactly one root-cause step, received ${steps.length}`);
2275
- const [adapted] = agentRxPredictionsToFindings(trajectoryId, [{
2276
- failure_case: source.subject,
2277
- step_number: steps[0],
2278
- description: source.rationale ?? source.claim
2279
- }], {
2280
- analystId,
2281
- producedAt: source.produced_at,
2282
- confidence: source.confidence
2283
- });
2284
- if (!adapted) throw new Error("AgentRx output adapter produced no root-cause finding");
2285
- return [{
2286
- ...adapted,
2287
- metadata: {
2288
- ...adapted.metadata,
2289
- sourceFindingId: source.finding_id
2290
- }
2291
- }];
2292
2256
  }
2293
- const CODE_TRACE_BLOCK_SUBJECT = /^incorrect-steps-(\d+)-(\d+)-(escaped|unescaped)-consequence-(\d+)$/;
2294
- async function adaptCodeTraceFindings(trajectoryId, findings, analystId, store, signal) {
2295
- const clean = findings.filter((finding) => finding.subject === "clean");
2296
- if (clean.length > 0) {
2297
- if (findings.length !== 1) throw new Error("CodeTraceBench model analyst mixed a clean verdict with incorrect steps");
2298
- exactFindingSteps(trajectoryId, clean[0]);
2299
- return {
2300
- findings: [],
2301
- diagnostics: emptyCodeTraceBlockDiagnostics()
2302
- };
2303
- }
2304
- const blocks = [];
2305
- const rejectedFindings = [];
2306
- for (const source of findings) try {
2307
- await validateCodeTraceFindingEvidence({
2308
- trajectoryId,
2309
- findings: [source],
2310
- store,
2311
- ...signal ? { signal } : {}
2312
- });
2313
- blocks.push(codeTraceBlockFromFinding(trajectoryId, source));
2257
+ /** Read override instructions from a file. Any read failure is fatal. */
2258
+ function readAnalystInstructionsOverride(path) {
2259
+ let text;
2260
+ try {
2261
+ text = readFileSync(path, "utf8");
2314
2262
  } catch (error) {
2315
- rejectedFindings.push(`${source.finding_id}: ${error instanceof Error ? error.message : String(error)}`);
2263
+ throw new Error(`cannot read --instructions-file '${path}': ${error instanceof Error ? error.message : String(error)}`);
2316
2264
  }
2317
- const expanded = await expandCodeTraceFailureBlocks({
2318
- trajectoryId,
2319
- blocks,
2320
- store,
2321
- analystId,
2322
- ...findings[0] ? { producedAt: findings[0].produced_at } : {},
2323
- ...signal ? { signal } : {}
2324
- });
2325
- return {
2326
- findings: expanded.findings,
2327
- diagnostics: {
2328
- ...expanded.diagnostics,
2329
- rejectedFindings
2330
- }
2331
- };
2332
- }
2333
- function codeTraceBlockFromFinding(trajectoryId, source) {
2334
- const parsed = CODE_TRACE_BLOCK_SUBJECT.exec(source.subject ?? "");
2335
- if (!parsed) throw new Error(`CodeTraceBench model finding '${source.finding_id}' must set subject to incorrect-steps-<first>-<last>-<escaped|unescaped>-consequence-<step>, received '${source.subject ?? ""}'`);
2336
- const firstStep = Number(parsed[1]);
2337
- const lastStep = Number(parsed[2]);
2338
- const consequenceStep = Number(parsed[4]);
2339
- const cited = exactFindingSteps(trajectoryId, source);
2340
- for (const step of cited) if (step < firstStep || step > lastStep) throw new Error(`CodeTraceBench model finding '${source.finding_id}' cites step ${step} outside its block ${firstStep}-${lastStep}`);
2341
- return {
2342
- firstStep,
2343
- lastStep,
2344
- consequenceStep,
2345
- escapeStatus: parsed[3],
2346
- severity: source.severity,
2347
- claim: source.claim,
2348
- confidence: source.confidence,
2349
- ...source.rationale === void 0 ? {} : { rationale: source.rationale },
2350
- ...source.recommended_action === void 0 ? {} : { recommendedAction: source.recommended_action },
2351
- metadata: { sourceFindingId: source.finding_id }
2352
- };
2265
+ if (!text.trim()) throw new Error(`--instructions-file '${path}' is empty; refusing to run without instructions`);
2266
+ return analystInstructionsOverrideFromText(text);
2353
2267
  }
2354
2268
  /**
2355
- * Expand contiguous failure blocks into one scored finding per member step.
2269
+ * Protocol digest of the run as executed.
2356
2270
  *
2357
- * The official scorer matches on area plus the exact step evidence URI, so
2358
- * blocks never reach it: every runner reports blocks, and this function turns
2359
- * them into the per-step findings the benchmark defines.
2271
+ * Without an override this is exactly `publicBenchmarkProtocolSha256(dataset)`,
2272
+ * so stock runs stay byte-identical to runs recorded before the override
2273
+ * existed. With an override the digest binds the stock protocol digest (which
2274
+ * covers both shipped prompts, including the abstention fallback's direct
2275
+ * prompt) to the exact override text, so the recorded digest always hashes the
2276
+ * instructions that actually ran.
2360
2277
  */
2361
- async function expandCodeTraceFailureBlocks(options) {
2362
- const diagnostics = emptyCodeTraceBlockDiagnostics();
2363
- diagnostics.reportedBlocks = options.blocks.length;
2364
- if (options.blocks.length === 0) return {
2365
- findings: [],
2366
- diagnostics
2367
- };
2368
- assertCodeTraceBlockShape(options.blocks);
2369
- const boundarySteps = options.blocks.flatMap((block) => [block.firstStep, block.lastStep]);
2370
- const derivedSteps = options.blocks.flatMap((block) => [block.consequenceStep, ...interiorSteps(block)]);
2371
- const evidenceByStep = await resolveAssistantStepEvidence({
2372
- trajectoryId: options.trajectoryId,
2373
- steps: boundarySteps,
2374
- optionalSteps: derivedSteps,
2375
- store: options.store,
2376
- ...options.signal ? { signal: options.signal } : {}
2377
- });
2378
- const byStep = /* @__PURE__ */ new Map();
2379
- for (const block of options.blocks) {
2380
- if (!evidenceByStep.has(block.consequenceStep)) {
2381
- diagnostics.blocksWithoutConsequenceEvidence.push(block);
2382
- continue;
2278
+ function effectiveAnalystProtocolSha256(dataset, override) {
2279
+ const stock = publicBenchmarkProtocolSha256(dataset);
2280
+ if (!override) return stock;
2281
+ return sha256Digest(JSON.stringify({
2282
+ kind: "analyst-instructions-override-protocol",
2283
+ dataset,
2284
+ stockProtocolSha256: stock,
2285
+ rlmInstructionsSha256: override.sha256
2286
+ }));
2287
+ }
2288
+ //#endregion
2289
+ //#region src/analyst/benchmark-command-persistence.ts
2290
+ const ANALYST_BENCHMARK_INITIALIZATION_COMPLETE_FILE = "initialization-complete.json";
2291
+ async function openOutputDirectory(outDir, resume) {
2292
+ const directory = resolve(outDir);
2293
+ if (resume) {
2294
+ let outputStat;
2295
+ try {
2296
+ outputStat = await lstat(directory);
2297
+ } catch (error) {
2298
+ if (isNodeError(error, "ENOENT")) throw new Error(`cannot resume missing benchmark output directory: ${directory}`);
2299
+ throw error;
2383
2300
  }
2384
- if (block.escapeStatus === "escaped") diagnostics.escapedBlocks += 1;
2385
- for (let step = block.firstStep; step <= block.lastStep; step += 1) {
2386
- if (!evidenceByStep.has(step)) {
2387
- diagnostics.unresolvedBlockInteriorSteps.push(step);
2388
- continue;
2389
- }
2390
- if (byStep.has(step)) {
2391
- diagnostics.overlappingBlockSteps.push(step);
2392
- continue;
2393
- }
2394
- byStep.set(step, block);
2301
+ if (!outputStat.isDirectory() || outputStat.isSymbolicLink()) throw new Error(`benchmark output must be a real directory: ${directory}`);
2302
+ } else {
2303
+ await mkdir(dirname(directory), { recursive: true });
2304
+ try {
2305
+ await mkdir(directory);
2306
+ } catch (error) {
2307
+ if (isNodeError(error, "EEXIST")) throw new Error(`refusing to use existing benchmark output directory: ${directory}`);
2308
+ throw error;
2395
2309
  }
2310
+ await syncDirectory(dirname(directory));
2396
2311
  }
2397
2312
  return {
2398
- findings: [...byStep].sort(([left], [right]) => left - right).map(([step, block]) => makeFinding({
2399
- analyst_id: options.analystId,
2400
- area: "incorrect",
2401
- subject: `incorrect-step-${step}`,
2402
- claim: `Step ${step} is incorrect. ${block.claim}`,
2403
- rationale: block.rationale,
2404
- severity: block.severity,
2405
- confidence: block.confidence,
2406
- evidence_refs: [evidenceByStep.get(step)],
2407
- recommended_action: block.recommendedAction,
2408
- metadata: {
2409
- ...block.metadata,
2410
- block_first_step: block.firstStep,
2411
- block_last_step: block.lastStep,
2412
- block_consequence_step: block.consequenceStep,
2413
- escape_status: block.escapeStatus
2414
- },
2415
- ...options.producedAt === void 0 ? {} : { produced_at: options.producedAt },
2416
- id_basis: `incorrect-step-${step}`
2417
- })),
2418
- diagnostics
2313
+ directory,
2314
+ initializationComplete: resolve(directory, ANALYST_BENCHMARK_INITIALIZATION_COMPLETE_FILE),
2315
+ manifest: resolve(directory, ANALYST_BENCHMARK_MANIFEST_FILE),
2316
+ observations: resolve(directory, ANALYST_BENCHMARK_OBSERVATIONS_FILE),
2317
+ costLedger: resolve(directory, ANALYST_BENCHMARK_COST_LEDGER_FILE),
2318
+ modelResponses: resolve(directory, "model-responses"),
2319
+ localReceipt: resolve(directory, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE),
2320
+ result: resolve(directory, "result.json"),
2321
+ report: resolve(directory, "report.md")
2419
2322
  };
2420
2323
  }
2421
- function assertCodeTraceBlockShape(blocks) {
2422
- if (blocks.length > 16) throw new Error(`model reported ${blocks.length} failure blocks; the maximum is 16`);
2423
- for (const block of blocks) {
2424
- if (block.lastStep < block.firstStep) throw new Error(`failure block last_step ${block.lastStep} precedes first_step ${block.firstStep}`);
2425
- const length = block.lastStep - block.firstStep + 1;
2426
- if (length > 12) throw new Error(`failure block spans ${length} steps; the maximum is 12`);
2427
- if (block.consequenceStep < block.firstStep) throw new Error(`failure block consequence_step ${block.consequenceStep} precedes first_step ${block.firstStep}`);
2428
- }
2429
- }
2430
- function interiorSteps(block) {
2431
- const steps = [];
2432
- for (let step = block.firstStep + 1; step < block.lastStep; step += 1) steps.push(step);
2433
- return steps;
2324
+ async function prepareOutputLockPath(outDir) {
2325
+ const directory = resolve(outDir);
2326
+ await mkdir(dirname(directory), { recursive: true });
2327
+ return `${directory}.lock`;
2434
2328
  }
2435
- function emptyCodeTraceBlockDiagnostics() {
2329
+ function createRunIdentity(config, prepared) {
2330
+ const caseDefinitions = prepared.cases.map((testCase) => ({
2331
+ id: testCase.id,
2332
+ clusterId: testCase.clusterId,
2333
+ labelState: testCase.labelState,
2334
+ expectedIssues: testCase.expectedIssues,
2335
+ labeledEvidence: testCase.labeledEvidence ?? [],
2336
+ tags: testCase.tags ?? [],
2337
+ metadata: testCase.metadata ?? {}
2338
+ }));
2436
2339
  return {
2437
- reportedBlocks: 0,
2438
- escapedBlocks: 0,
2439
- blocksWithoutConsequenceEvidence: [],
2440
- unresolvedBlockInteriorSteps: [],
2441
- overlappingBlockSteps: []
2340
+ config: {
2341
+ dataset: config.dataset,
2342
+ datasetRevision: config.revision,
2343
+ datasetSplit: config.split,
2344
+ model: {
2345
+ id: config.model.model,
2346
+ maxOutputTokens: config.model.maxOutputTokens,
2347
+ timeoutMs: config.model.timeoutMs
2348
+ },
2349
+ limit: config.limit,
2350
+ seed: config.seed,
2351
+ concurrency: config.concurrency,
2352
+ repetitions: config.repetitions,
2353
+ rlmSamples: config.rlmSamples,
2354
+ maxCostUsd: config.maxCostUsd,
2355
+ maxArtifactBytes: config.maxArtifactBytes,
2356
+ analystProtocolSha256: effectiveAnalystProtocolSha256(config.dataset, config.model.instructionsOverride),
2357
+ ...config.model.instructionsOverride ? { instructionsOverrideSha256: config.model.instructionsOverride.sha256 } : {},
2358
+ implementationSha256: ANALYST_BENCHMARK_IMPLEMENTATION_SHA256,
2359
+ dependencyLockSha256: ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256,
2360
+ runnerIds: ["empty", config.analyst]
2361
+ },
2362
+ inputs: {
2363
+ labelsSha256: prepared.labelsSha256,
2364
+ sourceRowCount: prepared.sourceRowCount,
2365
+ selectedCaseIds: [...prepared.selectedCaseIds],
2366
+ traceFiles: prepared.traceFiles.map((traceFile) => ({ ...traceFile })),
2367
+ verificationArtifactsSha256: digestCanonical(prepared.verificationArtifacts),
2368
+ caseDefinitionsSha256: digestCanonical(caseDefinitions)
2369
+ }
2442
2370
  };
2443
2371
  }
2444
- function exactFindingSteps(trajectoryId, finding) {
2445
- if (finding.evidence_refs.length === 0) throw new Error(`model finding '${finding.finding_id}' has no step evidence`);
2446
- const steps = finding.evidence_refs.map((evidence) => {
2447
- const parsed = codeTraceStepFromEvidence(evidence.uri);
2448
- if (!parsed || parsed.traceId !== trajectoryId) throw new Error(`model finding '${finding.finding_id}' cites non-case evidence '${evidence.uri}'`);
2449
- return parsed.step;
2450
- });
2451
- return [...new Set(steps)];
2452
- }
2453
- //#endregion
2454
- //#region src/analyst/benchmark-public-types.ts
2455
- function requiredString(value, field) {
2456
- const trimmed = value.trim();
2457
- if (!trimmed) throw new TypeError(`${field} must be a non-empty string`);
2458
- return trimmed;
2459
- }
2460
- function positiveSafeInteger(value, field) {
2461
- if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`);
2462
- return value;
2372
+ function createLocalRunReceipt(config, paths) {
2373
+ return {
2374
+ kind: "agent-eval/analyst-benchmark-local-run",
2375
+ local: {
2376
+ labelsPath: resolve(config.labelsPath),
2377
+ traceDir: resolve(config.traceDir),
2378
+ ...config.artifactDir ? { artifactDir: resolve(config.artifactDir) } : {},
2379
+ outputDir: paths.directory,
2380
+ baseUrl: config.model.baseUrl,
2381
+ apiKeyEnvironment: config.apiKeyEnv
2382
+ },
2383
+ command: config.command,
2384
+ environment: {
2385
+ node: process.version,
2386
+ platform: platform(),
2387
+ arch: arch()
2388
+ },
2389
+ files: {
2390
+ manifest: paths.manifest,
2391
+ observations: paths.observations,
2392
+ costLedger: paths.costLedger,
2393
+ modelResponses: paths.modelResponses,
2394
+ result: paths.result,
2395
+ report: paths.report
2396
+ }
2397
+ };
2463
2398
  }
2464
- function safeInteger(value, field) {
2465
- if (!Number.isSafeInteger(value)) throw new RangeError(`${field} must be a safe integer`);
2466
- return value;
2399
+ async function initializeRunFiles(paths, identity, identitySha256, localIdentitySha256, localReceiptInput) {
2400
+ const existingManifest = await readOptionalRegularFile(paths.manifest, "benchmark run manifest");
2401
+ const manifest = existingManifest ? await readAndValidateManifestContent(paths.manifest, existingManifest, identity, identitySha256, localIdentitySha256) : {
2402
+ kind: "agent-eval/analyst-benchmark-run",
2403
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2404
+ identitySha256,
2405
+ localIdentitySha256,
2406
+ identity
2407
+ };
2408
+ const localReceipt = {
2409
+ ...localReceiptInput,
2410
+ runIdentitySha256: identitySha256,
2411
+ localIdentitySha256
2412
+ };
2413
+ const manifestContent = `${JSON.stringify(manifest, null, 2)}\n`;
2414
+ const localReceiptContent = `${JSON.stringify(localReceipt, null, 2)}\n`;
2415
+ const initializationCompleteContent = renderInitializationComplete(manifest);
2416
+ await assertAbsentOrExact(paths.observations, "", "benchmark observation log");
2417
+ await assertAbsentOrExact(paths.localReceipt, localReceiptContent, "benchmark local run receipt");
2418
+ await assertAbsentOrExact(paths.manifest, manifestContent, "benchmark run manifest");
2419
+ for (const path of [
2420
+ paths.costLedger,
2421
+ paths.modelResponses,
2422
+ paths.result,
2423
+ paths.report
2424
+ ]) if (await regularFileExists(path)) throw new Error(`benchmark initialization marker is missing but later run artifact exists: ${path}`);
2425
+ if (await regularFileExists(paths.initializationComplete)) throw new Error(`benchmark initialization marker already exists during partial initialization: ${paths.initializationComplete}`);
2426
+ await writeExclusiveOrVerify(paths.observations, "");
2427
+ await writeExclusiveOrVerify(paths.localReceipt, localReceiptContent);
2428
+ await writeExclusiveOrVerify(paths.manifest, manifestContent);
2429
+ await writeExclusiveOrVerify(paths.initializationComplete, initializationCompleteContent);
2430
+ return manifest;
2467
2431
  }
2468
- function isRecord(value) {
2469
- return typeof value === "object" && value !== null && !Array.isArray(value);
2432
+ async function readAndValidateResumeFiles(paths, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256, localReceiptInput) {
2433
+ if (!await regularFileExists(paths.initializationComplete)) return initializeRunFiles(paths, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256, localReceiptInput);
2434
+ const manifest = await readAndValidateManifest(paths.manifest, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256);
2435
+ const localReceiptContent = await readRegularFile(paths.localReceipt, "benchmark local run receipt");
2436
+ const value = parseJson(localReceiptContent, paths.localReceipt);
2437
+ if (!isRecord$1(value)) throw new TypeError(`benchmark local run receipt must be an object: ${paths.localReceipt}`);
2438
+ assertExactKeys(value, [
2439
+ "kind",
2440
+ "runIdentitySha256",
2441
+ "localIdentitySha256",
2442
+ "local",
2443
+ "command",
2444
+ "environment",
2445
+ "files"
2446
+ ], "benchmark local run receipt");
2447
+ if (value.kind !== "agent-eval/analyst-benchmark-local-run" || value.runIdentitySha256 !== currentIdentitySha256 || value.localIdentitySha256 !== currentLocalIdentitySha256 || !isRecord$1(value.local)) throw new Error("benchmark local run receipt does not match the requested resume");
2448
+ const expectedLocalReceipt = {
2449
+ ...localReceiptInput,
2450
+ runIdentitySha256: currentIdentitySha256,
2451
+ localIdentitySha256: currentLocalIdentitySha256
2452
+ };
2453
+ if (digestCanonical(value.local) !== currentLocalIdentitySha256 || canonicalJson(value.local) !== canonicalJson(localReceiptInput.local)) throw new Error("benchmark local paths or endpoint do not match the requested resume");
2454
+ if (localReceiptContent !== `${JSON.stringify(expectedLocalReceipt, null, 2)}\n`) throw new Error(`benchmark local run receipt does not exactly match: ${paths.localReceipt}`);
2455
+ if (await readRegularFile(paths.initializationComplete, "benchmark initialization marker") !== renderInitializationComplete(manifest)) throw new Error(`benchmark initialization marker does not match the run manifest: ${paths.initializationComplete}`);
2456
+ return manifest;
2470
2457
  }
2471
- //#endregion
2472
- //#region src/analyst/benchmark-public-data.ts
2473
- const DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES = 256 * 1024 * 1024;
2474
- const INPUT_OPEN_FLAGS = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0);
2475
- async function loadPublicBenchmarkRows(path) {
2476
- return parsePublicBenchmarkRows((await readImmutableInputSnapshot(resolve(path), DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES)).text, path);
2458
+ async function readAndValidateManifest(path, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256) {
2459
+ const content = await readRegularFile(path, "benchmark run manifest");
2460
+ const manifest = await readAndValidateManifestContent(path, content, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256);
2461
+ if (content !== `${JSON.stringify(manifest, null, 2)}\n`) throw new Error(`benchmark run manifest does not exactly match: ${path}`);
2462
+ return manifest;
2477
2463
  }
2478
- function parsePublicBenchmarkRows(text, path) {
2479
- const trimmed = text.trim();
2480
- if (!trimmed) throw new Error(`public analyst benchmark dataset is empty: ${path}`);
2481
- let parsed;
2482
- try {
2483
- parsed = JSON.parse(trimmed);
2484
- } catch {
2485
- return parseJsonl(trimmed, path);
2486
- }
2487
- if (Array.isArray(parsed)) return records(parsed, path);
2488
- if (isRecord(parsed) && Array.isArray(parsed.data)) return records(parsed.data, `${path}.data`);
2489
- if (isRecord(parsed) && Array.isArray(parsed.cases)) return records(parsed.cases, `${path}.cases`);
2490
- if (isRecord(parsed)) return [parsed];
2491
- throw new TypeError(`public analyst benchmark dataset must contain JSON objects: ${path}`);
2464
+ async function readAndValidateManifestContent(path, content, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256) {
2465
+ const value = parseJson(content, path);
2466
+ if (!isRecord$1(value)) throw new TypeError(`benchmark run manifest must be an object: ${path}`);
2467
+ assertExactKeys(value, [
2468
+ "kind",
2469
+ "createdAt",
2470
+ "identitySha256",
2471
+ "localIdentitySha256",
2472
+ "identity"
2473
+ ], "benchmark run manifest");
2474
+ if (value.kind !== "agent-eval/analyst-benchmark-run") throw new TypeError(`unsupported benchmark run manifest: ${path}`);
2475
+ if (typeof value.createdAt !== "string" || !Number.isFinite(Date.parse(value.createdAt))) throw new TypeError(`benchmark run manifest has an invalid createdAt: ${path}`);
2476
+ if (!isSha256(value.identitySha256) || !isSha256(value.localIdentitySha256) || !isRecord$1(value.identity)) throw new TypeError(`benchmark run manifest has an invalid identity: ${path}`);
2477
+ if (digestCanonical(value.identity) !== value.identitySha256) throw new Error(`benchmark run manifest identity digest does not match its contents: ${path}`);
2478
+ if (currentIdentitySha256 !== value.identitySha256 || currentLocalIdentitySha256 !== value.localIdentitySha256 || canonicalJson(currentIdentity) !== canonicalJson(value.identity)) throw new Error(`benchmark resume configuration or inputs do not match ${ANALYST_BENCHMARK_MANIFEST_FILE}`);
2479
+ return {
2480
+ kind: "agent-eval/analyst-benchmark-run",
2481
+ createdAt: value.createdAt,
2482
+ identitySha256: currentIdentitySha256,
2483
+ localIdentitySha256: currentLocalIdentitySha256,
2484
+ identity: currentIdentity
2485
+ };
2492
2486
  }
2493
- function selectPublicBenchmarkRows(dataset, rows, options) {
2494
- positiveSafeInteger(options.limit, "limit");
2495
- safeInteger(options.seed, "seed");
2496
- if (rows.length === 0) throw new Error("public analyst benchmark dataset has no rows");
2497
- const byId = /* @__PURE__ */ new Map();
2498
- for (const row of rows) {
2499
- const id = publicBenchmarkRowId(dataset, row);
2500
- if (byId.has(id)) throw new Error(`public analyst benchmark dataset repeats trajectory id '${id}'`);
2501
- byId.set(id, row);
2502
- }
2503
- return [...byId].sort(([left], [right]) => selectionKey(options.seed, left).localeCompare(selectionKey(options.seed, right)) || left.localeCompare(right)).slice(0, Math.min(options.limit, byId.size)).map(([, row]) => row);
2487
+ function renderInitializationComplete(manifest) {
2488
+ return `${JSON.stringify({
2489
+ kind: "agent-eval/analyst-benchmark-initialization-complete",
2490
+ runIdentitySha256: manifest.identitySha256,
2491
+ localIdentitySha256: manifest.localIdentitySha256,
2492
+ createdAt: manifest.createdAt
2493
+ }, null, 2)}\n`;
2504
2494
  }
2505
- function publicBenchmarkDistributions(dataset, rows) {
2506
- const values = {
2507
- class: [],
2508
- agent: [],
2509
- model: [],
2510
- difficulty: [],
2511
- solved: []
2495
+ async function assertAbsentOrExact(path, expected, label) {
2496
+ const existing = await readOptionalRegularFile(path, label);
2497
+ if (existing !== void 0 && existing !== expected) throw new Error(`${label} does not exactly match interrupted initialization: ${path}`);
2498
+ }
2499
+ async function readOptionalRegularFile(path, label) {
2500
+ if (!await regularFileExists(path)) return void 0;
2501
+ return readRegularFile(path, label);
2502
+ }
2503
+ function createObservationAppender(path, runIdentitySha256, progress) {
2504
+ let writes = Promise.resolve();
2505
+ const seen = new Set(progress.observations.map(observationKey));
2506
+ return (observation) => {
2507
+ const write = writes.then(async () => {
2508
+ assertAnalystBenchmarkObservation(observation, "benchmark observation");
2509
+ const key = observationKey(observation);
2510
+ if (seen.has(key)) throw new Error(`refusing duplicate benchmark observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}'`);
2511
+ const rowWithoutDigest = {
2512
+ sequence: progress.nextSequence,
2513
+ runIdentitySha256,
2514
+ previousRowSha256: progress.previousRowSha256,
2515
+ observation
2516
+ };
2517
+ const row = {
2518
+ ...rowWithoutDigest,
2519
+ rowSha256: digestCanonical(rowWithoutDigest)
2520
+ };
2521
+ await appendDurable(path, `${JSON.stringify(row)}\n`);
2522
+ progress.nextSequence += 1;
2523
+ progress.previousRowSha256 = row.rowSha256;
2524
+ progress.observations.push(observation);
2525
+ seen.add(key);
2526
+ });
2527
+ writes = write;
2528
+ return write;
2512
2529
  };
2513
- for (const row of rows) {
2514
- const benchmarkCase = dataset === "agentrx" ? agentRxBenchmarkCase(row, void 0) : codeTraceBenchCase(row, void 0);
2515
- values.class.push(dataset === "codetracebench" ? benchmarkCase.expectedIssues.length > 0 ? "positive" : row.solved === true ? "trusted-negative" : row.solved === false ? "unlabeled-failure" : "unlabeled-unknown" : benchmarkCase.expectedIssues[0]?.areas?.[0]);
2516
- values.agent.push(scalarDistributionValue(row.agent) ?? (dataset === "agentrx" ? rootAgent(row) : void 0));
2517
- values.model.push(scalarDistributionValue(row.model));
2518
- values.difficulty.push(scalarDistributionValue(row.difficulty));
2519
- values.solved.push(scalarDistributionValue(row.solved));
2530
+ }
2531
+ async function readProgress(path, runIdentitySha256, caseIds, repetitions, analystRunnerId) {
2532
+ const rawLines = (await readRegularFile(path, "benchmark observation log")).split("\n");
2533
+ if (rawLines.at(-1) === "") rawLines.pop();
2534
+ const observations = [];
2535
+ const seen = /* @__PURE__ */ new Set();
2536
+ const executionIndexes = /* @__PURE__ */ new Set();
2537
+ let previousRowSha256 = null;
2538
+ const allowedCases = new Set(caseIds);
2539
+ const plannedObservationCount = caseIds.length * 2 * repetitions;
2540
+ for (const [index, line] of rawLines.entries()) {
2541
+ if (!line.trim()) throw new Error(`benchmark observation log contains an empty row at line ${index + 1}`);
2542
+ const parsed = parseJson(line, `${path}:${index + 1}`);
2543
+ if (!isRecord$1(parsed)) throw new TypeError(`benchmark observation row ${index + 1} must be an object`);
2544
+ assertExactKeys(parsed, [
2545
+ "sequence",
2546
+ "runIdentitySha256",
2547
+ "previousRowSha256",
2548
+ "observation",
2549
+ "rowSha256"
2550
+ ], `benchmark observation row ${index + 1}`);
2551
+ assertAnalystBenchmarkObservation(parsed.observation, `benchmark observation row ${index + 1}.observation`);
2552
+ const observation = parsed.observation;
2553
+ const key = observationKey(observation);
2554
+ if (seen.has(key)) throw new Error(`duplicate benchmark observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}' at line ${index + 1}`);
2555
+ if (parsed.sequence !== index) throw new Error(`benchmark observation row ${index + 1} has sequence ${String(parsed.sequence)}; expected ${index}`);
2556
+ if (parsed.runIdentitySha256 !== runIdentitySha256) throw new Error(`benchmark observation row ${index + 1} belongs to another run`);
2557
+ if (parsed.previousRowSha256 !== previousRowSha256) throw new Error(`benchmark observation row ${index + 1} breaks the digest chain`);
2558
+ if (!isSha256(parsed.rowSha256)) throw new TypeError(`benchmark observation row ${index + 1} has an invalid digest`);
2559
+ if (digestCanonical({
2560
+ sequence: parsed.sequence,
2561
+ runIdentitySha256: parsed.runIdentitySha256,
2562
+ previousRowSha256: parsed.previousRowSha256,
2563
+ observation
2564
+ }) !== parsed.rowSha256) throw new Error(`benchmark observation row ${index + 1} digest does not match its contents`);
2565
+ if (!allowedCases.has(observation.caseId) || observation.runnerId !== "empty" && observation.runnerId !== analystRunnerId || observation.repetition >= repetitions || observation.executionIndex >= plannedObservationCount) throw new Error(`benchmark observation row ${index + 1} does not match a planned case, runner, and repetition`);
2566
+ if (executionIndexes.has(observation.executionIndex)) throw new Error(`duplicate benchmark executionIndex ${observation.executionIndex} at line ${index + 1}`);
2567
+ observations.push(observation);
2568
+ seen.add(key);
2569
+ executionIndexes.add(observation.executionIndex);
2570
+ previousRowSha256 = parsed.rowSha256;
2520
2571
  }
2521
2572
  return {
2522
- class: valueDistribution(values.class),
2523
- agent: valueDistribution(values.agent),
2524
- model: valueDistribution(values.model),
2525
- difficulty: valueDistribution(values.difficulty),
2526
- solved: valueDistribution(values.solved)
2573
+ observations,
2574
+ nextSequence: observations.length,
2575
+ previousRowSha256
2527
2576
  };
2528
2577
  }
2529
- function publicBenchmarkSelectionReport(dataset, source, selected, seed) {
2530
- const census = source.length === selected.length;
2531
- return {
2532
- method: census ? "census" : "deterministic-hash",
2533
- seed,
2534
- sourceCount: source.length,
2535
- selectedCount: selected.length,
2536
- stratified: false,
2537
- representativeOfInput: census,
2538
- source: publicBenchmarkDistributions(dataset, source),
2539
- selected: publicBenchmarkDistributions(dataset, selected)
2540
- };
2541
- }
2542
- async function preparePublicAnalystBenchmark(options) {
2543
- const labelsPath = resolve(options.labelsPath);
2544
- const traceRoot = resolve(options.traceDir);
2545
- const artifactRoot = options.artifactDir ? resolve(options.artifactDir) : void 0;
2546
- const labelSnapshot = await readImmutableInputSnapshot(labelsPath, DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES);
2547
- const rows = parsePublicBenchmarkRows(labelSnapshot.text, labelsPath);
2548
- const selected = selectPublicBenchmarkRows(options.dataset, rows, {
2549
- limit: options.limit,
2550
- seed: options.seed
2551
- });
2552
- const stores = await indexSelectedSingleTraceFiles(traceRoot, new Set(selected.map((row) => publicBenchmarkRowId(options.dataset, row))));
2553
- const resolver = traceStoreEvidenceResolver((input) => {
2554
- if (!input.traceStore) throw new Error("prepared benchmark case has no trace store");
2555
- return input.traceStore;
2556
- });
2557
- const traceFiles = [];
2558
- const verificationArtifacts = [];
2559
- const cases = [];
2560
- for (const row of selected) {
2561
- const trajectoryId = publicBenchmarkRowId(options.dataset, row);
2562
- const indexed = stores.get(trajectoryId);
2563
- if (!indexed) throw new Error(`public analyst benchmark trace directory has no single-trace OTLP JSONL for '${trajectoryId}'`);
2564
- let modelVisibleOtlp = indexed.text;
2565
- let traceStore = indexed.store;
2566
- let artifactDir;
2567
- let verificationManifest;
2568
- if (options.dataset === "codetracebench") {
2569
- if (!options.artifactDir?.trim()) throw new Error("--artifact-dir is required for CodeTraceBench so final verification evidence is not omitted");
2570
- const artifacts = await loadCodeTraceVerificationArtifacts({
2571
- artifactDir: options.artifactDir,
2572
- row,
2573
- maxBytes: options.maxArtifactBytes ?? 8388608
2574
- });
2575
- for (const artifact of artifacts.files) assertNoBenchmarkLabelsInArtifact({
2576
- traceId: trajectoryId,
2577
- relativePath: artifact.relativePath,
2578
- content: artifact.content
2579
- });
2580
- verificationManifest = shareableVerificationManifest(artifacts.manifest, artifactRoot ?? resolve(options.artifactDir));
2581
- const collisions = await indexed.store.hasSpans({
2582
- trace_id: trajectoryId,
2583
- span_ids: [...artifacts.manifest.files.map((file) => file.spanId), artifacts.manifest.outcomeSpanId]
2584
- });
2585
- if (collisions.length > 0) throw new Error(`CodeTraceBench '${trajectoryId}' trace already contains benchmark verification span '${collisions[0]}'`);
2586
- modelVisibleOtlp = appendVerificationArtifactsToOtlp(indexed.text, trajectoryId, artifacts, indexed.latestTimestamp);
2587
- traceStore = otlpTextToTraceAnalysisStore(modelVisibleOtlp);
2588
- artifactDir = artifacts.manifest.status === "present" ? artifacts.manifest.caseDirectory : void 0;
2589
- verificationArtifacts.push(verificationManifest);
2590
- }
2591
- const labelLeakScan = assertNoBenchmarkLabelsInTrace({
2592
- traceId: trajectoryId,
2593
- otlpText: modelVisibleOtlp
2594
- });
2595
- const input = {
2596
- traceStore,
2597
- artifactDir
2598
- };
2599
- const benchmarkCase = options.dataset === "agentrx" ? agentRxBenchmarkCase(row, input, { stepCount: indexed.stepCount }) : codeTraceBenchCase(row, input);
2600
- for (const evidence of benchmarkCase.labeledEvidence ?? []) if (!await resolver({
2601
- caseId: benchmarkCase.id,
2602
- caseInput: input,
2603
- evidence: {
2604
- kind: evidence.kind ?? "span",
2605
- uri: evidence.uri
2606
- }
2607
- })) throw new Error(`${benchmarkCase.id}: missing labeled span ${spanIdFromEvidence(evidence.uri) ?? evidence.uri} in ${indexed.path}`);
2608
- cases.push({
2609
- ...benchmarkCase,
2610
- metadata: {
2611
- ...benchmarkCase.metadata,
2612
- traceFileRelativePath: slashRelative(traceRoot, indexed.path),
2613
- traceFileSha256: indexed.sha256,
2614
- labelLeakScan,
2615
- ...verificationManifest ? { verificationArtifacts: verificationManifest } : {}
2616
- }
2617
- });
2618
- traceFiles.push({
2619
- traceId: trajectoryId,
2620
- relativePath: slashRelative(traceRoot, indexed.path),
2621
- sha256: indexed.sha256
2622
- });
2578
+ async function writeExclusiveOrVerify(path, content) {
2579
+ try {
2580
+ await writeExclusive(path, content);
2581
+ } catch (error) {
2582
+ if (!isNodeError(error, "EEXIST")) throw error;
2583
+ if (await readRegularFile(path, "existing benchmark artifact") !== content) throw new Error(`refusing to replace existing benchmark artifact: ${path}`);
2623
2584
  }
2624
- return {
2625
- cases,
2626
- sourceRowCount: rows.length,
2627
- selectedCaseIds: cases.map((testCase) => testCase.id),
2628
- labelsSha256: labelSnapshot.sha256,
2629
- traceFiles,
2630
- verificationArtifacts,
2631
- selection: publicBenchmarkSelectionReport(options.dataset, rows, selected, options.seed)
2632
- };
2633
2585
  }
2634
- async function indexSelectedSingleTraceFiles(traceDir, selectedTraceIds) {
2635
- if (selectedTraceIds.size === 0) throw new Error("public analyst benchmark selected no trace ids");
2636
- const files = (await readdir(traceDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => resolve(traceDir, entry.name)).sort();
2637
- if (files.length === 0) throw new Error(`public analyst benchmark trace directory has no JSONL files: ${traceDir}`);
2638
- const indexed = /* @__PURE__ */ new Map();
2639
- for (const path of files) {
2640
- const snapshot = await readImmutableInputSnapshot(path, DEFAULT_MAX_TRACE_FILE_BYTES);
2641
- const store = createOtlpBufferTraceStore(snapshot.bytes);
2642
- const overview = await store.getOverview();
2643
- if (overview.total_traces !== 1 || overview.sample_trace_ids.length !== 1) throw new Error(`public analyst benchmark trace file must contain exactly one trace: ${path} contains ${overview.total_traces}`);
2644
- if (!overview.time_range) throw new Error(`public analyst benchmark trace file has no valid timestamps: ${path}`);
2645
- const traceId = overview.sample_trace_ids[0];
2646
- if (!selectedTraceIds.has(traceId)) continue;
2647
- if (indexed.has(traceId)) throw new Error(`public analyst benchmark trace id '${traceId}' appears in multiple files`);
2648
- indexed.set(traceId, {
2649
- path,
2650
- sha256: snapshot.sha256,
2651
- store,
2652
- latestTimestamp: overview.time_range.latest,
2653
- text: snapshot.text,
2654
- stepCount: traceStepCount(snapshot.text, path)
2655
- });
2586
+ async function regularFileExists(path) {
2587
+ try {
2588
+ const fileStat = await lstat(path);
2589
+ if (!fileStat.isFile() || fileStat.isSymbolicLink()) throw new Error(`benchmark artifact path must be a real file: ${path}`);
2590
+ return true;
2591
+ } catch (error) {
2592
+ if (isNodeError(error, "ENOENT")) return false;
2593
+ throw error;
2656
2594
  }
2657
- return indexed;
2658
2595
  }
2659
- async function readImmutableInputSnapshot(path, maxBytes) {
2660
- if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new RangeError("benchmark input maxBytes must be a positive safe integer");
2661
- const handle = await open(path, INPUT_OPEN_FLAGS);
2596
+ async function appendDurable(path, content) {
2597
+ const handle = await open(path, constants.O_APPEND | constants.O_WRONLY | constants.O_NOFOLLOW);
2662
2598
  try {
2663
- return await readImmutableInputHandle(handle, path, maxBytes);
2599
+ await handle.writeFile(content, "utf8");
2600
+ await handle.sync();
2664
2601
  } finally {
2665
2602
  await handle.close();
2666
2603
  }
2667
2604
  }
2668
- async function readImmutableInputHandle(handle, path, maxBytes) {
2669
- const before = await handle.stat({ bigint: true });
2670
- if (!before.isFile()) throw new TypeError(`public analyst benchmark input must be a regular file: ${path}`);
2671
- if (before.size > BigInt(maxBytes)) throw new RangeError(`public analyst benchmark input exceeds ${maxBytes} bytes: ${path} has ${before.size}`);
2672
- const size = Number(before.size);
2673
- const bytes = Buffer.allocUnsafe(size);
2674
- let offset = 0;
2675
- while (offset < size) {
2676
- const result = await handle.read(bytes, offset, size - offset, offset);
2677
- if (result.bytesRead === 0) throw new Error(`public analyst benchmark input changed while being read: ${path}`);
2678
- offset += result.bytesRead;
2605
+ async function writeExclusive(path, content) {
2606
+ const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
2607
+ let handle;
2608
+ try {
2609
+ handle = await open(temporary, "wx");
2610
+ await handle.writeFile(content, "utf8");
2611
+ await handle.sync();
2612
+ await handle.close();
2613
+ handle = void 0;
2614
+ await link(temporary, path);
2615
+ await syncDirectory(dirname(path));
2616
+ } finally {
2617
+ await handle?.close().catch(() => void 0);
2618
+ await unlink(temporary).catch(() => void 0);
2679
2619
  }
2680
- const overflow = Buffer.allocUnsafe(1);
2681
- const extra = await handle.read(overflow, 0, 1, size);
2682
- const after = await handle.stat({ bigint: true });
2683
- if (extra.bytesRead !== 0 || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs) throw new Error(`public analyst benchmark input changed while being read: ${path}`);
2684
- let text;
2620
+ }
2621
+ async function readRegularFile(path, label) {
2622
+ let fileStat;
2685
2623
  try {
2686
- text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
2624
+ fileStat = await lstat(path);
2687
2625
  } catch (error) {
2688
- throw new TypeError(`public analyst benchmark input is not valid UTF-8: ${path}: ${error instanceof Error ? error.message : String(error)}`);
2626
+ if (isNodeError(error, "ENOENT")) throw new Error(`${label} is missing: ${path}`);
2627
+ throw error;
2689
2628
  }
2690
- return Object.freeze({
2691
- bytes,
2692
- sha256: sha256Digest(bytes),
2693
- text
2694
- });
2629
+ if (!fileStat.isFile() || fileStat.isSymbolicLink()) throw new Error(`${label} must be a real file: ${path}`);
2630
+ return readFile(path, "utf8");
2695
2631
  }
2696
- function traceStepCount(text, path) {
2697
- const steps = parseJsonl(text, path).map((row) => row.span_id).filter((spanId) => typeof spanId === "string").map((spanId) => /^step-(\d+)$/.exec(spanId)?.[1]).filter((step) => step !== void 0).map(Number).filter((step) => Number.isSafeInteger(step) && step > 0);
2698
- if (steps.length === 0) throw new Error(`public analyst benchmark trace has no step-<n> spans: ${path}`);
2699
- return Math.max(...steps);
2632
+ async function syncDirectory(path) {
2633
+ const directory = await open(path, "r");
2634
+ try {
2635
+ await directory.sync();
2636
+ } finally {
2637
+ await directory.close();
2638
+ }
2700
2639
  }
2701
- function shareableVerificationManifest(manifest, artifactRoot) {
2640
+ function isNodeError(error, code) {
2641
+ return error instanceof Error && "code" in error && error.code === code;
2642
+ }
2643
+ //#endregion
2644
+ //#region src/analyst/benchmark-comparison.ts
2645
+ function compareAnalystRunners(result, options) {
2646
+ const confidence = options.confidence ?? .95;
2647
+ const resamples = options.resamples ?? 2e3;
2648
+ assertComparisonControls(confidence, resamples);
2649
+ const runnerIds = new Set(result.summaries.map((summary) => summary.runnerId));
2650
+ if (!runnerIds.has(options.baselineRunnerId)) throw new TypeError(`unknown baseline analyst runner '${options.baselineRunnerId}'`);
2651
+ if (!runnerIds.has(options.candidateRunnerId)) throw new TypeError(`unknown candidate analyst runner '${options.candidateRunnerId}'`);
2652
+ if (options.baselineRunnerId === options.candidateRunnerId) throw new TypeError("baseline and candidate analyst runners must be different");
2653
+ const baseline = observationsByCase(result.observations, options.baselineRunnerId);
2654
+ const candidate = observationsByCase(result.observations, options.candidateRunnerId);
2655
+ const populationRepresentativenessProven = result.provenance.metadata?.populationRepresentativenessProven === true;
2656
+ const metrics = METRICS.map((metric) => compareMetric({
2657
+ metric,
2658
+ baseline,
2659
+ candidate,
2660
+ confidence,
2661
+ resamples,
2662
+ seed: options.seed,
2663
+ populationRepresentativenessProven
2664
+ }));
2702
2665
  return {
2703
- ...manifest,
2704
- caseDirectory: slashRelative(artifactRoot, manifest.caseDirectory),
2705
- caseDirectoriesSearched: manifest.caseDirectoriesSearched.map((path) => slashRelative(artifactRoot, path)),
2706
- files: manifest.files.map((file) => ({
2707
- ...file,
2708
- path: slashRelative(artifactRoot, file.path)
2709
- }))
2666
+ baselineRunnerId: options.baselineRunnerId,
2667
+ candidateRunnerId: options.candidateRunnerId,
2668
+ metrics
2710
2669
  };
2711
2670
  }
2712
- function slashRelative(root, path) {
2713
- const value = relative(root, path);
2714
- if (!value || value === ".." || value.startsWith(`..${sep}`)) {
2715
- if (!value) return ".";
2716
- throw new Error(`benchmark artifact path escapes its declared root: ${path}`);
2717
- }
2718
- return value.replaceAll("\\", "/");
2719
- }
2720
- function parseJsonl(text, path) {
2721
- const rows = [];
2722
- for (const [index, line] of text.split(/\r?\n/).entries()) {
2723
- const trimmed = line.trim();
2724
- if (!trimmed) continue;
2725
- let parsed;
2726
- try {
2727
- parsed = JSON.parse(trimmed);
2728
- } catch (error) {
2729
- throw new Error(`${path}:${index + 1}: invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
2730
- }
2731
- if (!isRecord(parsed)) throw new TypeError(`${path}:${index + 1}: dataset row must be a JSON object`);
2732
- rows.push(parsed);
2733
- }
2734
- if (rows.length === 0) throw new Error(`public analyst benchmark dataset is empty: ${path}`);
2735
- return rows;
2736
- }
2737
- function records(values, path) {
2738
- return values.map((value, index) => {
2739
- if (!isRecord(value)) throw new TypeError(`${path}[${index}] must be a JSON object`);
2740
- return value;
2671
+ function compareMetric(options) {
2672
+ const pairedCases = [];
2673
+ let eligibleObservations = 0;
2674
+ let pairedObservations = 0;
2675
+ let baselineMissingObservations = 0;
2676
+ let candidateMissingObservations = 0;
2677
+ let asymmetricMissingObservations = 0;
2678
+ const caseIds = /* @__PURE__ */ new Set([...options.baseline.keys(), ...options.candidate.keys()]);
2679
+ for (const caseId of caseIds) {
2680
+ const baselineByRepetition = new Map((options.baseline.get(caseId) ?? []).map((observation) => [observation.repetition, observation]));
2681
+ const candidateByRepetition = new Map((options.candidate.get(caseId) ?? []).map((observation) => [observation.repetition, observation]));
2682
+ const caseBefore = [];
2683
+ const caseAfter = [];
2684
+ let clusterId;
2685
+ const repetitions = /* @__PURE__ */ new Set([...baselineByRepetition.keys(), ...candidateByRepetition.keys()]);
2686
+ for (const repetition of repetitions) {
2687
+ const baselineObservation = baselineByRepetition.get(repetition);
2688
+ const candidateObservation = candidateByRepetition.get(repetition);
2689
+ const identity = baselineObservation ?? candidateObservation;
2690
+ if (!identity || !metricApplies(identity, options.metric)) continue;
2691
+ if (baselineObservation && candidateObservation) assertSameCaseIdentity(baselineObservation, candidateObservation);
2692
+ eligibleObservations += 1;
2693
+ clusterId = identity.clusterId;
2694
+ const baselineValue = baselineObservation ? metricValue(baselineObservation, options.metric) : null;
2695
+ const candidateValue = candidateObservation ? metricValue(candidateObservation, options.metric) : null;
2696
+ const baselineMissing = baselineValue === null;
2697
+ const candidateMissing = candidateValue === null;
2698
+ if (baselineMissing) baselineMissingObservations += 1;
2699
+ if (candidateMissing) candidateMissingObservations += 1;
2700
+ if (baselineMissing !== candidateMissing) asymmetricMissingObservations += 1;
2701
+ if (baselineMissing || candidateMissing) continue;
2702
+ caseBefore.push(baselineValue);
2703
+ caseAfter.push(candidateValue);
2704
+ pairedObservations += 1;
2705
+ }
2706
+ if (caseBefore.length === 0 || !clusterId) continue;
2707
+ pairedCases.push({
2708
+ clusterId,
2709
+ baseline: mean$1(caseBefore),
2710
+ candidate: mean$1(caseAfter)
2711
+ });
2712
+ }
2713
+ const byCluster = /* @__PURE__ */ new Map();
2714
+ for (const pairedCase of pairedCases) {
2715
+ const rows = byCluster.get(pairedCase.clusterId) ?? [];
2716
+ rows.push(pairedCase);
2717
+ byCluster.set(pairedCase.clusterId, rows);
2718
+ }
2719
+ const before = [...byCluster.values()].map((rows) => mean$1(rows.map((row) => row.baseline)));
2720
+ const after = [...byCluster.values()].map((rows) => mean$1(rows.map((row) => row.candidate)));
2721
+ const interval = before.length === 0 ? null : pairedBootstrap(before, after, {
2722
+ confidence: options.confidence,
2723
+ resamples: options.resamples,
2724
+ statistic: "mean",
2725
+ seed: options.seed
2741
2726
  });
2727
+ const survivorOnly = pairedObservations < eligibleObservations;
2728
+ const limitations = [];
2729
+ if (!interval?.gateEligible) limitations.push("fewer-than-20-independent-clusters");
2730
+ if (!options.populationRepresentativenessProven) limitations.push("population-representativeness-not-proven");
2731
+ if (survivorOnly) limitations.push("missing-observations");
2732
+ const comparison = {
2733
+ metric: options.metric,
2734
+ direction: LOWER_IS_BETTER.has(options.metric) ? "lower" : "higher",
2735
+ pairedCases: pairedCases.length,
2736
+ pairedClusters: before.length,
2737
+ eligibleObservations,
2738
+ pairedObservations,
2739
+ baselineMissingObservations,
2740
+ candidateMissingObservations,
2741
+ asymmetricMissingObservations,
2742
+ survivorOnly,
2743
+ baselineMean: before.length === 0 ? null : mean$1(before),
2744
+ candidateMean: after.length === 0 ? null : mean$1(after),
2745
+ meanDelta: interval?.mean ?? null,
2746
+ intervalLow: interval?.low ?? null,
2747
+ intervalHigh: interval?.high ?? null,
2748
+ confidence: options.confidence,
2749
+ resamples: options.resamples,
2750
+ minimumSampleMet: interval?.gateEligible ?? false,
2751
+ populationInferenceEligible: limitations.length === 0,
2752
+ inferenceLimitations: limitations
2753
+ };
2754
+ assertValidComparison(comparison);
2755
+ return comparison;
2742
2756
  }
2743
- function publicBenchmarkRowId(dataset, row) {
2744
- const value = dataset === "agentrx" ? row.trajectory_id : row.traj_id;
2745
- if (typeof value !== "string" && typeof value !== "number" || !String(value).trim()) throw new TypeError(`${dataset} dataset row requires a non-empty ${dataset === "agentrx" ? "trajectory_id" : "traj_id"}`);
2746
- return String(value);
2757
+ const METRICS = [
2758
+ "completion",
2759
+ "issueRecall",
2760
+ "findingPrecision",
2761
+ "f1",
2762
+ "criticalStepAccuracy",
2763
+ "citationCoverage",
2764
+ "citationExcerptCoverage",
2765
+ "citationLabelAgreement",
2766
+ "citationResolution",
2767
+ "trustedNegativeAccuracy",
2768
+ "latencyMs",
2769
+ "calls",
2770
+ "inputTokens",
2771
+ "outputTokens",
2772
+ "reasoningTokens",
2773
+ "cachedTokens",
2774
+ "cacheWriteTokens",
2775
+ "costUsd"
2776
+ ];
2777
+ const LOWER_IS_BETTER = /* @__PURE__ */ new Set([
2778
+ "latencyMs",
2779
+ "calls",
2780
+ "inputTokens",
2781
+ "outputTokens",
2782
+ "reasoningTokens",
2783
+ "cachedTokens",
2784
+ "cacheWriteTokens",
2785
+ "costUsd"
2786
+ ]);
2787
+ function observationsByCase(observations, runnerId) {
2788
+ const byCase = /* @__PURE__ */ new Map();
2789
+ for (const observation of observations) {
2790
+ if (observation.runnerId !== runnerId) continue;
2791
+ const rows = byCase.get(observation.caseId) ?? [];
2792
+ rows.push(observation);
2793
+ byCase.set(observation.caseId, rows);
2794
+ }
2795
+ return byCase;
2747
2796
  }
2748
- function spanIdFromEvidence(uri) {
2749
- const match = /\/span\/([^/]+)$/.exec(uri);
2750
- return match?.[1] ? decodeURIComponent(match[1]) : null;
2797
+ function assertSameCaseIdentity(baseline, candidate) {
2798
+ if (baseline.clusterId !== candidate.clusterId || baseline.labelState !== candidate.labelState) throw new Error(`analyst comparison case identity differs for '${baseline.caseId}' repetition ${baseline.repetition}`);
2751
2799
  }
2752
- function selectionKey(seed, id) {
2753
- return sha256Digest(`${seed}\u0000${id}`);
2800
+ function metricApplies(observation, metric) {
2801
+ if (metric === "trustedNegativeAccuracy") return observation.labelState === "trusted-negative";
2802
+ if (metric === "issueRecall" || metric === "findingPrecision" || metric === "f1") return observation.labelState === "positive";
2803
+ if (metric === "criticalStepAccuracy") return observation.labelState === "positive" && observation.score.criticalStepAccuracy !== null;
2804
+ return true;
2754
2805
  }
2755
- function valueDistribution(values) {
2756
- const counts = /* @__PURE__ */ new Map();
2757
- let missing = 0;
2758
- for (const value of values) {
2759
- if (value === void 0) {
2760
- missing += 1;
2761
- continue;
2762
- }
2763
- counts.set(value, (counts.get(value) ?? 0) + 1);
2806
+ function metricValue(observation, metric) {
2807
+ if (metric === "completion") return observation.error ? 0 : 1;
2808
+ if (metric === "latencyMs") return observation.latencyMs;
2809
+ if (metric === "trustedNegativeAccuracy") {
2810
+ if (observation.error) return 0;
2811
+ return observation.score.predictionOnLabelEmptyCase ? 0 : 1;
2764
2812
  }
2765
- return {
2766
- total: values.length,
2767
- missing,
2768
- counts: Object.fromEntries([...counts].sort(([left], [right]) => left.localeCompare(right)))
2769
- };
2813
+ if (observation.error && (metric === "issueRecall" || metric === "findingPrecision" || metric === "f1" || metric === "criticalStepAccuracy")) return 0;
2814
+ if (observation.error && (metric === "citationCoverage" || metric === "citationExcerptCoverage" || metric === "citationLabelAgreement" || metric === "citationResolution")) return null;
2815
+ if (metric === "issueRecall") return observation.score.issueRecall;
2816
+ if (metric === "findingPrecision") return observation.score.findingPrecision;
2817
+ if (metric === "f1") return observation.score.f1;
2818
+ if (metric === "criticalStepAccuracy") return observation.score.criticalStepAccuracy;
2819
+ if (metric === "citationCoverage") return observation.score.citationCoverage;
2820
+ if (metric === "citationExcerptCoverage") return observation.score.citationExcerptCoverage;
2821
+ if (metric === "citationLabelAgreement") return observation.score.citationLabelAgreement;
2822
+ if (metric === "citationResolution") return observation.evidenceResolution?.validity ?? null;
2823
+ if (metric === "calls") return observation.usage?.calls ?? null;
2824
+ if (metric === "inputTokens") return observation.usage?.tokens?.input ?? null;
2825
+ if (metric === "outputTokens") return observation.usage?.tokens?.output ?? null;
2826
+ if (metric === "reasoningTokens") return observation.usage?.tokens?.reasoning ?? null;
2827
+ if (metric === "cachedTokens") return observation.usage?.tokens?.cached ?? null;
2828
+ if (metric === "cacheWriteTokens") return observation.usage?.tokens?.cacheWrite ?? null;
2829
+ if (observation.usage?.cost.kind === "uncaptured") return null;
2830
+ return observation.usage?.cost.usd ?? null;
2770
2831
  }
2771
- function scalarDistributionValue(value) {
2772
- if (typeof value === "string") return value.trim() || void 0;
2773
- if (typeof value === "number" || typeof value === "boolean") return String(value);
2832
+ function mean$1(values) {
2833
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
2774
2834
  }
2775
- function rootAgent(row) {
2776
- const rootCauseId = row.root_cause_failure_id ?? row.root_cause?.failure_id;
2777
- return scalarDistributionValue(row.failures.find((failure) => String(failure.failure_id) === String(rootCauseId))?.failed_agent);
2835
+ function assertComparisonControls(confidence, resamples) {
2836
+ if (!Number.isSafeInteger(resamples) || resamples <= 0 || resamples > 1e6) throw new Error(`compareAnalystRunners: resamples must be a positive safe integer no greater than 1000000, got ${String(resamples)}`);
2837
+ if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) throw new Error(`compareAnalystRunners: confidence must be a finite number in (0,1), got ${String(confidence)}`);
2838
+ }
2839
+ function assertValidComparison(comparison) {
2840
+ if ([
2841
+ "pairedCases",
2842
+ "pairedClusters",
2843
+ "eligibleObservations",
2844
+ "pairedObservations",
2845
+ "baselineMissingObservations",
2846
+ "candidateMissingObservations",
2847
+ "asymmetricMissingObservations",
2848
+ "confidence",
2849
+ "resamples"
2850
+ ].some((field) => !Number.isFinite(comparison[field])) || [
2851
+ "baselineMean",
2852
+ "candidateMean",
2853
+ "meanDelta",
2854
+ "intervalLow",
2855
+ "intervalHigh"
2856
+ ].some((field) => comparison[field] !== null && !Number.isFinite(comparison[field]))) throw new Error(`compareAnalystRunners: ${comparison.metric} produced non-finite comparison output`);
2857
+ if (comparison.intervalLow !== null && comparison.intervalHigh !== null && comparison.intervalLow > comparison.intervalHigh) throw new Error(`compareAnalystRunners: ${comparison.metric} produced an invalid confidence interval`);
2778
2858
  }
2779
2859
  //#endregion
2780
- //#region src/analyst/benchmark-public-errors.ts
2781
- function publicBenchmarkError(error, secrets = []) {
2782
- if (error instanceof LlmCallError) return {
2783
- class: "LlmCallError",
2784
- code: error.code,
2785
- status: error.status,
2786
- message: `Provider request failed with HTTP ${error.status}.`
2787
- };
2788
- if (error instanceof LlmResponseError) return {
2789
- class: "LlmResponseError",
2790
- code: error.code,
2791
- message: "Provider response did not satisfy the structured output contract."
2792
- };
2793
- if (error instanceof z.ZodError) return {
2794
- class: "ModelOutputValidationError",
2795
- message: "Provider response did not match the benchmark output schema."
2796
- };
2797
- if (error instanceof SyntaxError) return {
2798
- class: "ModelOutputParseError",
2799
- message: "Provider response was not valid JSON."
2800
- };
2801
- if (error instanceof CostCeilingReachedError || error instanceof CostAccountingIncompleteError || error instanceof CostReservationExceededError) return {
2802
- class: error.constructor.name,
2803
- code: error.code,
2804
- message: redactSensitiveText(error.message, secrets)
2805
- };
2806
- if (error instanceof Error && error.name === "AbortError") return {
2807
- class: "ProviderTimeoutError",
2808
- message: "Provider request timed out."
2809
- };
2810
- if (error instanceof Error && /(?:assistant steps?|finding evidence|selected missing|selected unavailable|no readable spans|requires a trace store)/i.test(error.message)) return {
2811
- class: "BenchmarkEvidenceError",
2812
- message: redactSensitiveText(error.message, secrets)
2813
- };
2814
- if (error instanceof AgentEvalError) return {
2815
- class: error.constructor.name,
2816
- code: error.code,
2817
- message: redactSensitiveText(error.message, secrets)
2818
- };
2819
- if (error instanceof Error) return {
2820
- class: error.constructor.name || "Error",
2821
- message: redactSensitiveText(error.message, secrets)
2822
- };
2823
- return {
2824
- class: "Error",
2825
- message: "Benchmark analyst execution failed."
2860
+ //#region src/analyst/benchmark-public-calibration.ts
2861
+ function summarizeCodeTraceCalibration(result) {
2862
+ return {
2863
+ protocol: "labeled-positive-and-solved-negative",
2864
+ rationale: "Uses rows with incorrect-step labels as positives and solved label-empty rows as trusted negatives. Failed label-empty rows remain in the published result but are not treated as clean controls.",
2865
+ runners: result.provenance.runnerIds.map((runnerId) => summarizeRunner(runnerId, result.observations.filter((observation) => observation.runnerId === runnerId)))
2826
2866
  };
2827
2867
  }
2828
- function redactSensitiveText(value, secrets) {
2829
- let redacted = value;
2830
- for (const secret of secrets) if (secret) redacted = redacted.replaceAll(secret, "[REDACTED]");
2831
- redacted = redacted.replace(/\bBearer\s+[^\s"',;]+/gi, "Bearer [REDACTED]").replace(/\b(api[_-]?key|access[_-]?token|refresh[_-]?token|password|secret)\b\s*[:=]\s*[^\s"',;]+/gi, "$1=[REDACTED]");
2832
- if (redacted.length <= 500) return redacted;
2833
- const head = redacted.slice(0, 180);
2834
- const marker = `...[${redacted.length - 460} chars omitted]...`;
2835
- return `${head}${marker}${redacted.slice(-(500 - head.length - marker.length))}`;
2868
+ function renderCodeTraceCalibrationMarkdown(summary) {
2869
+ return [
2870
+ "## CodeTraceBench Calibrated View",
2871
+ "",
2872
+ summary.rationale,
2873
+ "",
2874
+ "| Runner | Completed/selected | Failed | Positive runs | Trusted negative runs | Unlabeled runs | Failed label-empty | Unknown label-empty | Matched/expected steps | Predicted steps | Precision | Recall | F1 | Official all-row F1 | Official rows | Trusted-negative false positives | Trusted-negative failures | Unlabeled predictions | Unlabeled failures |",
2875
+ "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |",
2876
+ ...summary.runners.map((runner) => `| ${escapeCell$1(runner.runnerId)} | ${runner.completedRuns}/${runner.selectedRuns} | ${runner.failedRuns} | ${runner.positiveRuns} | ${runner.trustedNegativeRuns} | ${runner.unlabeledRuns} | ${runner.failedLabelEmptyRuns} | ${runner.unknownLabelEmptyRuns} | ${runner.matchedIncorrectSteps}/${runner.expectedIncorrectSteps} | ${runner.predictedIncorrectSteps} | ${rate$1(runner.precision)} | ${rate$1(runner.recall)} | ${rate$1(runner.f1)} | ${rate$1(runner.officialAllRowF1)} | ${runner.officialAllRowRuns} | ${rate$1(runner.trustedNegativeFalsePositiveRate)} | ${rate$1(runner.trustedNegativeFailureRate)} | ${rate$1(runner.unlabeledPredictionRate)} | ${rate$1(runner.unlabeledFailureRate)} |`)
2877
+ ].join("\n");
2836
2878
  }
2837
- //#endregion
2838
- //#region src/analyst/benchmark-response-cache.ts
2839
- const SHA256 = /^[a-f0-9]{64}$/;
2840
- const CostReceiptInputSchema = z.object({
2841
- model: z.string().min(1),
2842
- inputTokens: z.number().int().nonnegative(),
2843
- outputTokens: z.number().int().nonnegative(),
2844
- reasoningTokens: z.number().int().nonnegative().optional(),
2845
- cachedTokens: z.number().int().nonnegative().optional(),
2846
- cacheWriteTokens: z.number().int().nonnegative().optional(),
2847
- customTokenPricing: z.object({
2848
- inputUsdPerMillion: z.number().nonnegative(),
2849
- cachedInputUsdPerMillion: z.number().nonnegative().optional(),
2850
- cacheWriteUsdPerMillion: z.number().nonnegative().optional(),
2851
- outputUsdPerMillion: z.number().nonnegative()
2852
- }).strict().optional(),
2853
- actualCostUsd: z.number().nonnegative().optional(),
2854
- estimatedCostUsd: z.number().nonnegative().optional(),
2855
- costUnknown: z.boolean().optional(),
2856
- usageUnknown: z.boolean().optional()
2857
- }).strict();
2858
- const BenchmarkErrorSchema = z.object({
2859
- class: z.string().min(1),
2860
- message: z.string(),
2861
- code: z.string().min(1).optional(),
2862
- status: z.number().int().min(100).max(599).optional()
2863
- }).strict();
2864
- const ResponseMetadataSchema = z.object({
2865
- providerModel: z.string().min(1),
2866
- providerDurationMs: z.number().nonnegative(),
2867
- finishReason: z.string().nullable(),
2868
- producedAt: z.string().datetime()
2869
- }).strict();
2870
- const CacheIdentityShape = {
2871
- kind: z.literal("agent-eval/public-benchmark-model-response"),
2872
- callId: z.string().min(1),
2873
- runIdentitySha256: z.string().regex(SHA256),
2874
- caseId: z.string().min(1),
2875
- repetition: z.number().int().nonnegative()
2876
- };
2877
- const SuccessCacheEntryWithoutDigestSchema = z.object({
2878
- ...CacheIdentityShape,
2879
- status: z.literal("succeeded"),
2880
- response: z.json(),
2881
- metadata: ResponseMetadataSchema,
2882
- receipt: CostReceiptInputSchema
2883
- }).strict();
2884
- const FailureCacheEntryWithoutDigestSchema = z.object({
2885
- ...CacheIdentityShape,
2886
- status: z.literal("failed"),
2887
- error: BenchmarkErrorSchema,
2888
- receipt: CostReceiptInputSchema
2889
- }).strict();
2890
- const CacheEntryWithoutDigestSchema = z.discriminatedUnion("status", [SuccessCacheEntryWithoutDigestSchema, FailureCacheEntryWithoutDigestSchema]);
2891
- const CacheEntrySchema = z.discriminatedUnion("status", [SuccessCacheEntryWithoutDigestSchema.extend({ entrySha256: z.string().regex(SHA256) }), FailureCacheEntryWithoutDigestSchema.extend({ entrySha256: z.string().regex(SHA256) })]);
2892
- function publicBenchmarkCallId(identity) {
2893
- assertCacheIdentity(identity);
2894
- return `analyst-benchmark-${hashCanonical({
2895
- runIdentitySha256: identity.runIdentitySha256,
2896
- caseId: identity.caseId,
2897
- repetition: identity.repetition
2898
- }).slice(7)}`;
2879
+ function summarizeRunner(runnerId, observations) {
2880
+ const positive = observations.filter((observation) => observation.labelState === "positive");
2881
+ const trustedNegative = observations.filter((observation) => observation.labelState === "trusted-negative");
2882
+ const excluded = observations.filter((observation) => observation.labelState === "unlabeled");
2883
+ const selected = [...positive, ...trustedNegative];
2884
+ const expected = sum(positive.map((observation) => observation.score.expectedIssueCount));
2885
+ const predicted = sum(selected.map((observation) => observation.error ? 0 : observation.findings.length));
2886
+ const matched = sum(positive.map((observation) => observation.score.matchedIssueIds.length));
2887
+ const precision = predicted === 0 ? expected > 0 ? 0 : null : matched / predicted;
2888
+ const recall = ratio(matched, expected);
2889
+ const completedTrustedNegative = trustedNegative.filter((observation) => !observation.error);
2890
+ const completedExcluded = excluded.filter((observation) => !observation.error);
2891
+ const officialRows = observations.map(officialCodeTraceF1);
2892
+ return {
2893
+ runnerId,
2894
+ selectedRuns: selected.length,
2895
+ positiveRuns: positive.length,
2896
+ trustedNegativeRuns: trustedNegative.length,
2897
+ unlabeledRuns: excluded.length,
2898
+ failedLabelEmptyRuns: excluded.filter((observation) => observation.caseMetadata?.solved === false).length,
2899
+ unknownLabelEmptyRuns: excluded.filter((observation) => observation.caseMetadata?.solved !== false).length,
2900
+ completedRuns: selected.filter((observation) => !observation.error).length,
2901
+ failedRuns: selected.filter((observation) => observation.error).length,
2902
+ expectedIncorrectSteps: expected,
2903
+ predictedIncorrectSteps: predicted,
2904
+ matchedIncorrectSteps: matched,
2905
+ officialAllRowF1: mean(officialRows),
2906
+ officialAllRowRuns: officialRows.length,
2907
+ precision,
2908
+ recall,
2909
+ f1: harmonicMean(precision, recall),
2910
+ trustedNegativeFalsePositiveRate: ratio(completedTrustedNegative.filter((observation) => observation.score.predictionOnLabelEmptyCase).length, completedTrustedNegative.length),
2911
+ trustedNegativeFailureRate: ratio(trustedNegative.filter((observation) => observation.error).length, trustedNegative.length),
2912
+ unlabeledPredictionRate: ratio(completedExcluded.filter((observation) => observation.findings.length > 0).length, completedExcluded.length),
2913
+ unlabeledFailureRate: ratio(excluded.filter((observation) => Boolean(observation.error)).length, excluded.length)
2914
+ };
2899
2915
  }
2900
- function readPublicBenchmarkResponseCache(cacheDirectory, identity) {
2901
- const callId = publicBenchmarkCallId(identity);
2902
- const path = responseCachePath(cacheDirectory, callId);
2903
- if (!existsSync(path)) return void 0;
2904
- const metadata = lstatSync(path);
2905
- if (!metadata.isFile() || metadata.isSymbolicLink()) throw new ValidationError(`benchmark response cache must be a real file: ${path}`);
2906
- let parsed;
2907
- try {
2908
- parsed = JSON.parse(readFileSync(path, "utf8"));
2909
- } catch (error) {
2910
- throw new ValidationError(`benchmark response cache contains invalid JSON: ${path}`, { cause: error });
2916
+ function officialCodeTraceF1(observation) {
2917
+ const trajectoryId = observation.caseMetadata?.trajectoryId;
2918
+ if (typeof trajectoryId !== "string" || !trajectoryId.trim()) throw new TypeError(`${observation.caseId}: CodeTraceBench trajectoryId metadata is missing`);
2919
+ const expected = new Set([...observation.score.matchedIssueIds, ...observation.score.missedIssueIds].map((issueId) => {
2920
+ const match = /^incorrect:(\d+)$/.exec(issueId);
2921
+ if (!match) throw new TypeError(`${observation.caseId}: invalid incorrect-step label '${issueId}'`);
2922
+ return Number(match[1]);
2923
+ }));
2924
+ const predicted = /* @__PURE__ */ new Set();
2925
+ if (!observation.error) for (const finding of observation.findings) {
2926
+ if (finding.area !== "incorrect") continue;
2927
+ for (const evidence of finding.evidence_refs) {
2928
+ const location = codeTraceStepFromEvidence(evidence.uri);
2929
+ if (!location || location.traceId !== trajectoryId) throw new TypeError(`${observation.caseId}: invalid CodeTraceBench prediction evidence '${evidence.uri}'`);
2930
+ predicted.add(location.step);
2931
+ }
2911
2932
  }
2912
- const entry = parseCacheEntry(parsed, path);
2913
- if (entry.callId !== callId || entry.runIdentitySha256 !== identity.runIdentitySha256 || entry.caseId !== identity.caseId || entry.repetition !== identity.repetition) throw new ValidationError(`benchmark response cache identity does not match: ${path}`);
2914
- return entry;
2933
+ let matched = 0;
2934
+ for (const step of predicted) if (expected.has(step)) matched += 1;
2935
+ return harmonicMean(predicted.size === 0 ? 0 : matched / predicted.size, expected.size === 0 ? 0 : matched / expected.size) ?? 0;
2915
2936
  }
2916
- function writePublicBenchmarkResponseCache(cacheDirectory, entry) {
2917
- const expectedCallId = publicBenchmarkCallId(entry);
2918
- if (entry.callId !== expectedCallId) throw new ValidationError("benchmark response cache callId does not match its identity");
2919
- const validated = JSON.parse(JSON.stringify(CacheEntryWithoutDigestSchema.parse(entry)));
2920
- const complete = {
2921
- ...validated,
2922
- entrySha256: hashCanonical(validated).slice(7)
2923
- };
2924
- const path = responseCachePath(cacheDirectory, complete.callId);
2925
- const content = `${canonicalString(complete)}\n`;
2926
- withLedgerFileLock(path, fileContext(), () => {
2927
- if (existsSync(path)) {
2928
- const existing = readPublicBenchmarkResponseCache(cacheDirectory, complete);
2929
- if (!existing || canonicalString(existing) !== canonicalString(complete)) throw new ValidationError(`benchmark response cache conflicts with existing file: ${path}`);
2930
- return;
2931
- }
2932
- writeLedgerFileAtomically(path, content, fileContext());
2933
- });
2934
- return complete;
2937
+ function sum(values) {
2938
+ return values.reduce((total, value) => total + value, 0);
2935
2939
  }
2936
- function parseCacheEntry(value, path) {
2937
- let parsed;
2938
- try {
2939
- parsed = CacheEntrySchema.parse(value);
2940
- } catch (error) {
2941
- throw new ValidationError(`benchmark response cache has an invalid shape: ${path}`, { cause: error });
2942
- }
2943
- const { entrySha256, ...withoutDigest } = parsed;
2944
- if (entrySha256 !== hashCanonical(withoutDigest).slice(7)) throw new ValidationError(`benchmark response cache digest does not match: ${path}`);
2945
- return parsed;
2940
+ function ratio(numerator, denominator) {
2941
+ return denominator === 0 ? null : numerator / denominator;
2946
2942
  }
2947
- function responseCachePath(cacheDirectory, callId) {
2948
- const directory = nodePath.resolve(cacheDirectory);
2949
- const path = nodePath.resolve(directory, `${hashCanonical(callId).slice(7)}.json`);
2950
- if (!isPathInsideDirectory(directory, path, nodePath)) throw new ValidationError("benchmark response cache path escapes its directory");
2951
- return path;
2943
+ function mean(values) {
2944
+ return values.length === 0 ? null : sum(values) / values.length;
2952
2945
  }
2953
- function isPathInsideDirectory(directory, candidate, pathOperations = nodePath) {
2954
- const relative = pathOperations.relative(directory, candidate);
2955
- return relative !== "" && relative !== ".." && !relative.startsWith(`..${pathOperations.sep}`) && !pathOperations.isAbsolute(relative);
2946
+ function harmonicMean(left, right) {
2947
+ if (left === null || right === null) return null;
2948
+ return left + right === 0 ? 0 : 2 * left * right / (left + right);
2956
2949
  }
2957
- function assertCacheIdentity(identity) {
2958
- if (!SHA256.test(identity.runIdentitySha256)) throw new ValidationError("benchmark response cache requires a SHA-256 run identity");
2959
- if (!identity.caseId.trim()) throw new ValidationError("benchmark response cache requires a case id");
2960
- if (!Number.isSafeInteger(identity.repetition) || identity.repetition < 0) throw new ValidationError("benchmark response cache repetition must be non-negative");
2950
+ function rate$1(value) {
2951
+ return value === null ? "n/a" : value.toFixed(3);
2961
2952
  }
2962
- function fileContext() {
2963
- return {
2964
- subject: "benchmark response cache",
2965
- integrityError: (message, options) => new ValidationError(message, options)
2966
- };
2953
+ function escapeCell$1(value) {
2954
+ return value.replaceAll("|", "\\|").replaceAll("\n", " ");
2967
2955
  }
2968
2956
  //#endregion
2969
- //#region src/analyst/benchmark-public-model.ts
2970
- /** One-shot JSON baseline. This is not a recursive trace analyst. */
2971
- function createPublicBenchmarkDirectRunner(dataset, config) {
2972
- const model = requiredString(config.model, "model");
2973
- const baseUrl = requiredString(config.baseUrl, "baseUrl");
2974
- const apiKey = requiredString(config.apiKey, "apiKey");
2975
- const maxOutputTokens = positiveSafeInteger(config.maxOutputTokens, "maxOutputTokens");
2976
- const timeoutMs = positiveSafeInteger(config.timeoutMs, "timeoutMs");
2977
- const costLedger = config.costLedger ?? new CostLedger();
2978
- const durability = config.durability ? {
2979
- runIdentitySha256: requiredString(config.durability.runIdentitySha256, "durability.runIdentitySha256"),
2980
- responseCacheDir: requiredString(config.durability.responseCacheDir, "durability.responseCacheDir")
2981
- } : void 0;
2982
- const actor = dataset === "agentrx" ? "agentrx-root-cause-localizer" : "codetracebench-step-localizer";
2983
- const outputAdapter = dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block";
2984
- const llmOptions = {
2985
- baseUrl,
2986
- apiKey,
2987
- maximumAttempts: 1,
2988
- jsonSchemaTransport: "json-object",
2989
- jsonPayloadMode: "exact",
2990
- thinking: "disabled",
2991
- ...config.fetchImpl ? { fetch: config.fetchImpl } : {}
2992
- };
2993
- return {
2994
- id: "direct",
2995
- async analyze(input, context) {
2996
- const trajectoryId = trajectoryIdFromCaseId$1(dataset, context.caseId);
2997
- const costTags = {
2998
- analystId: actor,
2999
- benchmarkCaseId: context.caseId,
3000
- benchmarkRepetition: String(context.repetition)
3001
- };
3002
- let rawPredictions = [];
3003
- let rejectedBlocks = [];
3004
- let modelFindings = [];
3005
- let providerModel = model;
2957
+ //#region src/analyst/benchmark-command-result.ts
2958
+ async function readAnalystBenchmarkArtifact(path) {
2959
+ const value = parseJson(await readRegularFile(path, "analyst benchmark result"), path);
2960
+ assertAnalystBenchmarkArtifact(value, "analyst benchmark result");
2961
+ return value;
2962
+ }
2963
+ function assertCompletedArtifactMatchesRun(artifact, manifest, observations, prepared) {
2964
+ if (artifact.runIdentitySha256 !== manifest.identitySha256) throw new Error("completed benchmark result belongs to another run");
2965
+ assertSameObservations(artifact.result.observations, observations);
2966
+ const expectedCount = manifest.identity.inputs.selectedCaseIds.length * manifest.identity.config.runnerIds.length * manifest.identity.config.repetitions;
2967
+ if (observations.length !== expectedCount) throw new Error(`completed benchmark result has ${observations.length} observations; expected ${expectedCount}`);
2968
+ const { config, inputs } = manifest.identity;
2969
+ const verificationAvailability = {
2970
+ cases: prepared.verificationArtifacts.length,
2971
+ resultFilesPresent: prepared.verificationArtifacts.filter((artifact) => artifact.status === "present").length,
2972
+ resultFilesMissing: prepared.verificationArtifacts.filter((artifact) => artifact.status === "missing").length,
2973
+ outcomes: {
2974
+ passed: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "passed").length,
2975
+ failed: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "failed").length,
2976
+ unavailable: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "unavailable").length
2977
+ }
2978
+ };
2979
+ const expectedInputs = {
2980
+ dataset: config.dataset,
2981
+ datasetRevision: config.datasetRevision,
2982
+ datasetSplit: config.datasetSplit,
2983
+ labelsSha256: inputs.labelsSha256,
2984
+ sourceRowCount: inputs.sourceRowCount,
2985
+ traceFiles: inputs.traceFiles.map((traceFile) => ({ ...traceFile })),
2986
+ verificationArtifacts: prepared.verificationArtifacts,
2987
+ verificationAvailability,
2988
+ selection: {
2989
+ limit: config.limit,
2990
+ seed: config.seed,
2991
+ selectedCaseIds: [...inputs.selectedCaseIds],
2992
+ report: prepared.selection
2993
+ },
2994
+ execution: {
2995
+ repetitions: config.repetitions,
2996
+ concurrency: config.concurrency,
2997
+ ...config.rlmSamples === void 0 ? {} : { rlmSamples: config.rlmSamples },
2998
+ model: config.model.id,
2999
+ maxOutputTokens: config.model.maxOutputTokens,
3000
+ timeoutMs: config.model.timeoutMs,
3001
+ maxCostUsd: config.maxCostUsd,
3002
+ maxArtifactBytes: config.maxArtifactBytes,
3003
+ analystProtocolSha256: config.analystProtocolSha256,
3004
+ ...config.instructionsOverrideSha256 === void 0 ? {} : { instructionsOverrideSha256: config.instructionsOverrideSha256 },
3005
+ implementationSha256: config.implementationSha256,
3006
+ dependencyLockSha256: config.dependencyLockSha256
3007
+ }
3008
+ };
3009
+ if (canonicalJson(artifact.inputs) !== canonicalJson(expectedInputs)) throw new Error("completed benchmark result inputs do not match the run manifest");
3010
+ const provenance = artifact.result.provenance;
3011
+ const expectedDatasetId = config.dataset === "agentrx" ? "microsoft/AgentRx" : "NJU-LINK/CodeTraceBench";
3012
+ const expectedOutputAdapter = config.dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block";
3013
+ if (provenance.id !== `${config.dataset}-real-model-analyst` || provenance.startedAt !== manifest.createdAt || !Number.isFinite(Date.parse(provenance.endedAt)) || Date.parse(provenance.endedAt) < Date.parse(provenance.startedAt) || canonicalJson(provenance.dataset) !== canonicalJson({
3014
+ id: expectedDatasetId,
3015
+ revision: config.datasetRevision,
3016
+ split: config.datasetSplit
3017
+ }) || provenance.caseCount !== inputs.selectedCaseIds.length || canonicalJson(provenance.runnerIds) !== canonicalJson(config.runnerIds) || provenance.repetitions !== config.repetitions || provenance.maxConcurrency !== Math.min(config.concurrency, expectedCount) || provenance.runnerOrderSeed !== config.seed || provenance.metadata?.model !== config.model.id || provenance.metadata?.rlmSamples !== config.rlmSamples || provenance.metadata?.outputAdapter !== expectedOutputAdapter || provenance.metadata?.caseSelection !== prepared.selection.method || provenance.metadata?.caseSelectionSeed !== config.seed || provenance.metadata?.selectionStratified !== prepared.selection.stratified || provenance.metadata?.protocolSha256 !== config.analystProtocolSha256 || provenance.metadata?.implementationSha256 !== config.implementationSha256 || provenance.metadata?.dependencyLockSha256 !== config.dependencyLockSha256 || provenance.metadata?.populationRepresentativenessProven !== false) throw new Error("completed benchmark result provenance does not match the run manifest");
3018
+ const expectedSummaries = config.runnerIds.map((runnerId) => summarizeAnalystBenchmarkRunner(runnerId, observations.filter((observation) => observation.runnerId === runnerId)));
3019
+ if (canonicalJson(artifact.result.summaries) !== canonicalJson(expectedSummaries)) throw new Error("completed benchmark summaries do not match durable observations");
3020
+ const expectedComparisons = [compareAnalystRunners(artifact.result, {
3021
+ baselineRunnerId: "empty",
3022
+ candidateRunnerId: config.runnerIds[1],
3023
+ seed: config.seed
3024
+ })];
3025
+ if (canonicalJson(artifact.comparisons) !== canonicalJson(expectedComparisons)) throw new Error("completed benchmark comparisons do not match durable observations");
3026
+ if (config.dataset === "codetracebench") {
3027
+ if (canonicalJson(artifact.codeTraceCalibration) !== canonicalJson(summarizeCodeTraceCalibration(artifact.result)) || artifact.agentRxCalibration !== void 0) throw new Error("completed CodeTraceBench calibration does not match durable observations");
3028
+ } else if (canonicalJson(artifact.agentRxCalibration) !== canonicalJson(summarizeAgentRxCalibration(artifact.result, "f228165bfec60a801fd5fedd9d8ffe0f9de0c69d")) || artifact.codeTraceCalibration !== void 0) throw new Error("completed AgentRx calibration does not match durable observations");
3029
+ }
3030
+ function assertSameObservations(expected, actual) {
3031
+ if (expected.length !== actual.length) throw new Error(`benchmark result has ${expected.length} observations but the durable log has ${actual.length}`);
3032
+ const expectedByKey = new Map(expected.map((observation) => [observationKey(observation), canonicalJson(observation)]));
3033
+ for (const observation of actual) {
3034
+ const key = observationKey(observation);
3035
+ if (expectedByKey.get(key) !== canonicalJson(observation)) throw new Error(`benchmark result does not match durable observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}'`);
3036
+ expectedByKey.delete(key);
3037
+ }
3038
+ if (expectedByKey.size > 0) throw new Error("benchmark result is missing durable observations");
3039
+ }
3040
+ //#endregion
3041
+ //#region src/analyst/benchmark-public-adapters.ts
3042
+ function emptyPublicBenchmarkRunner() {
3043
+ return {
3044
+ id: "empty",
3045
+ analyze() {
3046
+ return {
3047
+ findings: [],
3048
+ usage: {
3049
+ calls: 0,
3050
+ tokens: {
3051
+ input: 0,
3052
+ output: 0
3053
+ },
3054
+ cost: {
3055
+ kind: "observed",
3056
+ usd: 0
3057
+ }
3058
+ },
3059
+ metadata: { baseline: "emit-no-findings" }
3060
+ };
3061
+ }
3062
+ };
3063
+ }
3064
+ async function adaptPublicBenchmarkFindings(options) {
3065
+ if (options.dataset === "agentrx") return {
3066
+ findings: adaptAgentRxFindings(options.trajectoryId, options.findings, options.analystId),
3067
+ diagnostics: void 0
3068
+ };
3069
+ return adaptCodeTraceFindings(options.trajectoryId, options.findings, options.analystId, options.store, options.signal);
3070
+ }
3071
+ function adaptAgentRxFindings(trajectoryId, findings, analystId) {
3072
+ if (findings.length === 0) return [];
3073
+ if (findings.length !== 1) throw new Error(`AgentRx model analyst must emit zero or one root cause, received ${findings.length}`);
3074
+ const source = findings[0];
3075
+ if (!source.subject) throw new Error("AgentRx model analyst finding is missing its failure-category subject");
3076
+ const steps = exactFindingSteps(trajectoryId, source);
3077
+ if (steps.length !== 1) throw new Error(`AgentRx model analyst must cite exactly one root-cause step, received ${steps.length}`);
3078
+ const [adapted] = agentRxPredictionsToFindings(trajectoryId, [{
3079
+ failure_case: source.subject,
3080
+ step_number: steps[0],
3081
+ description: source.rationale ?? source.claim
3082
+ }], {
3083
+ analystId,
3084
+ producedAt: source.produced_at,
3085
+ confidence: source.confidence
3086
+ });
3087
+ if (!adapted) throw new Error("AgentRx output adapter produced no root-cause finding");
3088
+ return [{
3089
+ ...adapted,
3090
+ metadata: {
3091
+ ...adapted.metadata,
3092
+ sourceFindingId: source.finding_id
3093
+ }
3094
+ }];
3095
+ }
3096
+ const CODE_TRACE_BLOCK_SUBJECT = /^incorrect-steps-(\d+)-(\d+)-(escaped|unescaped)-consequence-(\d+)$/;
3097
+ async function adaptCodeTraceFindings(trajectoryId, findings, analystId, store, signal) {
3098
+ const clean = findings.filter((finding) => finding.subject === "clean");
3099
+ if (clean.length > 0) {
3100
+ if (findings.length !== 1) throw new Error("CodeTraceBench model analyst mixed a clean verdict with incorrect steps");
3101
+ exactFindingSteps(trajectoryId, clean[0]);
3102
+ return {
3103
+ findings: [],
3104
+ diagnostics: emptyCodeTraceBlockDiagnostics(),
3105
+ stepBlocks: []
3106
+ };
3107
+ }
3108
+ const blocks = [];
3109
+ const rejectedFindings = [];
3110
+ const trimmedCitations = [];
3111
+ for (const source of findings) try {
3112
+ await validateCodeTraceFindingEvidence({
3113
+ trajectoryId,
3114
+ findings: [source],
3115
+ store,
3116
+ ...signal ? { signal } : {}
3117
+ });
3118
+ const converted = codeTraceBlockFromFinding(trajectoryId, source);
3119
+ trimmedCitations.push(...converted.trimmedCitations);
3120
+ blocks.push(converted.block);
3121
+ } catch (error) {
3122
+ rejectedFindings.push(`${source.finding_id}: ${error instanceof Error ? error.message : String(error)}`);
3123
+ }
3124
+ const expanded = await expandCodeTraceFailureBlocks({
3125
+ trajectoryId,
3126
+ blocks,
3127
+ store,
3128
+ analystId,
3129
+ ...findings[0] ? { producedAt: findings[0].produced_at } : {},
3130
+ ...signal ? { signal } : {}
3131
+ });
3132
+ return {
3133
+ findings: expanded.findings,
3134
+ diagnostics: {
3135
+ ...expanded.diagnostics,
3136
+ rejectedFindings,
3137
+ trimmedCitations
3138
+ },
3139
+ stepBlocks: expanded.stepBlocks
3140
+ };
3141
+ }
3142
+ /**
3143
+ * Block coordinates recoverable from a subject in the block grammar, in the
3144
+ * metadata field names the expanded findings carry. Returns undefined when the
3145
+ * subject does not parse — nothing is invented for a malformed subject.
3146
+ */
3147
+ function codeTraceBlockMetadataFromSubject(subject) {
3148
+ const parsed = CODE_TRACE_BLOCK_SUBJECT.exec(subject ?? "");
3149
+ if (!parsed) return void 0;
3150
+ return {
3151
+ block_first_step: Number(parsed[1]),
3152
+ block_last_step: Number(parsed[2]),
3153
+ block_consequence_step: Number(parsed[4]),
3154
+ escape_status: parsed[3]
3155
+ };
3156
+ }
3157
+ function codeTraceBlockFromFinding(trajectoryId, source) {
3158
+ const parsed = CODE_TRACE_BLOCK_SUBJECT.exec(source.subject ?? "");
3159
+ if (!parsed) throw new Error(`CodeTraceBench model finding '${source.finding_id}' must set subject to incorrect-steps-<first>-<last>-<escaped|unescaped>-consequence-<step>, received '${source.subject ?? ""}'`);
3160
+ const firstStep = Number(parsed[1]);
3161
+ const lastStep = Number(parsed[2]);
3162
+ const consequenceStep = Number(parsed[4]);
3163
+ const cited = exactFindingSteps(trajectoryId, source);
3164
+ const outOfRange = cited.filter((step) => step < firstStep || step > lastStep);
3165
+ if (outOfRange.length === cited.length) throw new Error(`CodeTraceBench model finding '${source.finding_id}' cites step ${outOfRange.join(", ")} outside its block ${firstStep}-${lastStep} and no citation falls inside the block`);
3166
+ const trimmedCitations = outOfRange.map((step) => `${source.finding_id}: trimmed citation step ${step} outside block ${firstStep}-${lastStep}`);
3167
+ return {
3168
+ block: {
3169
+ firstStep,
3170
+ lastStep,
3171
+ consequenceStep,
3172
+ escapeStatus: parsed[3],
3173
+ severity: source.severity,
3174
+ claim: source.claim,
3175
+ confidence: source.confidence,
3176
+ ...source.rationale === void 0 ? {} : { rationale: source.rationale },
3177
+ ...source.recommended_action === void 0 ? {} : { recommendedAction: source.recommended_action },
3178
+ metadata: { sourceFindingId: source.finding_id }
3179
+ },
3180
+ trimmedCitations
3181
+ };
3182
+ }
3183
+ /**
3184
+ * Expand contiguous failure blocks into one scored finding per member step.
3185
+ *
3186
+ * The official scorer matches on area plus the exact step evidence URI, so
3187
+ * blocks never reach it: every runner reports blocks, and this function turns
3188
+ * them into the per-step findings the benchmark defines.
3189
+ */
3190
+ async function expandCodeTraceFailureBlocks(options) {
3191
+ const diagnostics = emptyCodeTraceBlockDiagnostics();
3192
+ diagnostics.reportedBlocks = options.blocks.length;
3193
+ if (options.blocks.length === 0) return {
3194
+ findings: [],
3195
+ diagnostics,
3196
+ stepBlocks: []
3197
+ };
3198
+ const blocks = acceptCodeTraceBlockShape(options.blocks, diagnostics);
3199
+ if (blocks.length === 0) return {
3200
+ findings: [],
3201
+ diagnostics,
3202
+ stepBlocks: []
3203
+ };
3204
+ const boundarySteps = blocks.flatMap((block) => [block.firstStep, block.lastStep]);
3205
+ const derivedSteps = blocks.flatMap((block) => [block.consequenceStep, ...interiorSteps(block)]);
3206
+ const evidenceByStep = await resolveAssistantStepEvidence({
3207
+ trajectoryId: options.trajectoryId,
3208
+ steps: boundarySteps,
3209
+ optionalSteps: derivedSteps,
3210
+ store: options.store,
3211
+ ...options.signal ? { signal: options.signal } : {}
3212
+ });
3213
+ const byStep = /* @__PURE__ */ new Map();
3214
+ for (const block of blocks) {
3215
+ if (!evidenceByStep.has(block.consequenceStep)) {
3216
+ diagnostics.blocksWithoutConsequenceEvidence.push(block);
3217
+ continue;
3218
+ }
3219
+ if (block.escapeStatus === "escaped") diagnostics.escapedBlocks += 1;
3220
+ for (let step = block.firstStep; step <= block.lastStep; step += 1) {
3221
+ if (!evidenceByStep.has(step)) {
3222
+ diagnostics.unresolvedBlockInteriorSteps.push(step);
3223
+ continue;
3224
+ }
3225
+ if (byStep.has(step)) {
3226
+ diagnostics.overlappingBlockSteps.push(step);
3227
+ continue;
3228
+ }
3229
+ byStep.set(step, block);
3230
+ }
3231
+ }
3232
+ const stepBlocks = [...byStep].sort(([left], [right]) => left - right).map(([step, block]) => ({
3233
+ step,
3234
+ block
3235
+ }));
3236
+ return {
3237
+ findings: stepBlocks.map(({ step, block }) => makeFinding({
3238
+ analyst_id: options.analystId,
3239
+ area: "incorrect",
3240
+ subject: `incorrect-step-${step}`,
3241
+ claim: `Step ${step} is incorrect. ${block.claim}`,
3242
+ rationale: block.rationale,
3243
+ severity: block.severity,
3244
+ confidence: block.confidence,
3245
+ evidence_refs: [evidenceByStep.get(step)],
3246
+ recommended_action: block.recommendedAction,
3247
+ metadata: {
3248
+ ...block.metadata,
3249
+ block_first_step: block.firstStep,
3250
+ block_last_step: block.lastStep,
3251
+ block_consequence_step: block.consequenceStep,
3252
+ escape_status: block.escapeStatus
3253
+ },
3254
+ ...options.producedAt === void 0 ? {} : { produced_at: options.producedAt },
3255
+ id_basis: `incorrect-step-${step}`
3256
+ })),
3257
+ diagnostics,
3258
+ stepBlocks
3259
+ };
3260
+ }
3261
+ /**
3262
+ * Enforce the protocol's per-block and per-case limits without voiding the
3263
+ * case: an offending block is dropped and named in `diagnostics.droppedBlocks`
3264
+ * while every valid sibling survives. A case whose blocks are ALL invalid ends
3265
+ * empty and carries the diagnostic for each drop. Shape is checked before the
3266
+ * count, so a malformed block never consumes one of the accepted slots.
3267
+ */
3268
+ function acceptCodeTraceBlockShape(blocks, diagnostics) {
3269
+ const accepted = [];
3270
+ for (const block of blocks) {
3271
+ const reason = codeTraceBlockShapeViolation(block) ?? (accepted.length >= 16 ? `model reported ${blocks.length} failure blocks; the maximum is 16` : void 0);
3272
+ if (reason) {
3273
+ diagnostics.droppedBlocks.push(`block ${block.firstStep}-${block.lastStep} (consequence ${block.consequenceStep}): ${reason}`);
3274
+ continue;
3275
+ }
3276
+ accepted.push(block);
3277
+ }
3278
+ return accepted;
3279
+ }
3280
+ function codeTraceBlockShapeViolation(block) {
3281
+ if (block.lastStep < block.firstStep) return `failure block last_step ${block.lastStep} precedes first_step ${block.firstStep}`;
3282
+ const length = block.lastStep - block.firstStep + 1;
3283
+ if (length > 12) return `failure block spans ${length} steps; the maximum is 12`;
3284
+ if (block.consequenceStep < block.firstStep) return `failure block consequence_step ${block.consequenceStep} precedes first_step ${block.firstStep}`;
3285
+ }
3286
+ function interiorSteps(block) {
3287
+ const steps = [];
3288
+ for (let step = block.firstStep + 1; step < block.lastStep; step += 1) steps.push(step);
3289
+ return steps;
3290
+ }
3291
+ function emptyCodeTraceBlockDiagnostics() {
3292
+ return {
3293
+ reportedBlocks: 0,
3294
+ escapedBlocks: 0,
3295
+ blocksWithoutConsequenceEvidence: [],
3296
+ unresolvedBlockInteriorSteps: [],
3297
+ overlappingBlockSteps: [],
3298
+ droppedBlocks: []
3299
+ };
3300
+ }
3301
+ function exactFindingSteps(trajectoryId, finding) {
3302
+ if (finding.evidence_refs.length === 0) throw new Error(`model finding '${finding.finding_id}' has no step evidence`);
3303
+ const steps = finding.evidence_refs.map((evidence) => {
3304
+ const parsed = codeTraceStepFromEvidence(evidence.uri);
3305
+ if (!parsed || parsed.traceId !== trajectoryId) throw new Error(`model finding '${finding.finding_id}' cites non-case evidence '${evidence.uri}'`);
3306
+ return parsed.step;
3307
+ });
3308
+ return [...new Set(steps)];
3309
+ }
3310
+ //#endregion
3311
+ //#region src/analyst/benchmark-public-errors.ts
3312
+ function publicBenchmarkError(error, secrets = []) {
3313
+ if (error instanceof LlmCallError) return {
3314
+ class: "LlmCallError",
3315
+ code: error.code,
3316
+ status: error.status,
3317
+ message: `Provider request failed with HTTP ${error.status}.`
3318
+ };
3319
+ if (error instanceof LlmResponseError) return {
3320
+ class: "LlmResponseError",
3321
+ code: error.code,
3322
+ message: "Provider response did not satisfy the structured output contract."
3323
+ };
3324
+ if (error instanceof z.ZodError) return {
3325
+ class: "ModelOutputValidationError",
3326
+ message: "Provider response did not match the benchmark output schema."
3327
+ };
3328
+ if (error instanceof SyntaxError) return {
3329
+ class: "ModelOutputParseError",
3330
+ message: "Provider response was not valid JSON."
3331
+ };
3332
+ if (error instanceof CostCeilingReachedError || error instanceof CostAccountingIncompleteError || error instanceof CostReservationExceededError) return {
3333
+ class: error.constructor.name,
3334
+ code: error.code,
3335
+ message: redactSensitiveText(error.message, secrets)
3336
+ };
3337
+ if (error instanceof Error && error.name === "AbortError") return {
3338
+ class: "ProviderTimeoutError",
3339
+ message: "Provider request timed out."
3340
+ };
3341
+ if (error instanceof Error && /(?:assistant steps?|finding evidence|selected missing|selected unavailable|no readable spans|requires a trace store)/i.test(error.message)) return {
3342
+ class: "BenchmarkEvidenceError",
3343
+ message: redactSensitiveText(error.message, secrets)
3344
+ };
3345
+ if (error instanceof AgentEvalError) return {
3346
+ class: error.constructor.name,
3347
+ code: error.code,
3348
+ message: redactSensitiveText(error.message, secrets)
3349
+ };
3350
+ if (error instanceof Error) return {
3351
+ class: error.constructor.name || "Error",
3352
+ message: redactSensitiveText(error.message, secrets)
3353
+ };
3354
+ return {
3355
+ class: "Error",
3356
+ message: "Benchmark analyst execution failed."
3357
+ };
3358
+ }
3359
+ function redactSensitiveText(value, secrets) {
3360
+ let redacted = value;
3361
+ for (const secret of secrets) if (secret) redacted = redacted.replaceAll(secret, "[REDACTED]");
3362
+ redacted = redacted.replace(/\bBearer\s+[^\s"',;]+/gi, "Bearer [REDACTED]").replace(/\b(api[_-]?key|access[_-]?token|refresh[_-]?token|password|secret)\b\s*[:=]\s*[^\s"',;]+/gi, "$1=[REDACTED]");
3363
+ if (redacted.length <= 500) return redacted;
3364
+ const head = redacted.slice(0, 180);
3365
+ const marker = `...[${redacted.length - 460} chars omitted]...`;
3366
+ return `${head}${marker}${redacted.slice(-(500 - head.length - marker.length))}`;
3367
+ }
3368
+ //#endregion
3369
+ //#region src/analyst/benchmark-public-types.ts
3370
+ function requiredString(value, field) {
3371
+ const trimmed = value.trim();
3372
+ if (!trimmed) throw new TypeError(`${field} must be a non-empty string`);
3373
+ return trimmed;
3374
+ }
3375
+ function positiveSafeInteger(value, field) {
3376
+ if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`);
3377
+ return value;
3378
+ }
3379
+ function safeInteger(value, field) {
3380
+ if (!Number.isSafeInteger(value)) throw new RangeError(`${field} must be a safe integer`);
3381
+ return value;
3382
+ }
3383
+ function isRecord(value) {
3384
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3385
+ }
3386
+ //#endregion
3387
+ //#region src/analyst/benchmark-response-cache.ts
3388
+ const SHA256 = /^[a-f0-9]{64}$/;
3389
+ const CostReceiptInputSchema = z.object({
3390
+ model: z.string().min(1),
3391
+ inputTokens: z.number().int().nonnegative(),
3392
+ outputTokens: z.number().int().nonnegative(),
3393
+ reasoningTokens: z.number().int().nonnegative().optional(),
3394
+ cachedTokens: z.number().int().nonnegative().optional(),
3395
+ cacheWriteTokens: z.number().int().nonnegative().optional(),
3396
+ customTokenPricing: z.object({
3397
+ inputUsdPerMillion: z.number().nonnegative(),
3398
+ cachedInputUsdPerMillion: z.number().nonnegative().optional(),
3399
+ cacheWriteUsdPerMillion: z.number().nonnegative().optional(),
3400
+ outputUsdPerMillion: z.number().nonnegative()
3401
+ }).strict().optional(),
3402
+ actualCostUsd: z.number().nonnegative().optional(),
3403
+ estimatedCostUsd: z.number().nonnegative().optional(),
3404
+ costUnknown: z.boolean().optional(),
3405
+ usageUnknown: z.boolean().optional()
3406
+ }).strict();
3407
+ const BenchmarkErrorSchema = z.object({
3408
+ class: z.string().min(1),
3409
+ message: z.string(),
3410
+ code: z.string().min(1).optional(),
3411
+ status: z.number().int().min(100).max(599).optional()
3412
+ }).strict();
3413
+ const ResponseMetadataSchema = z.object({
3414
+ providerModel: z.string().min(1),
3415
+ providerDurationMs: z.number().nonnegative(),
3416
+ finishReason: z.string().nullable(),
3417
+ producedAt: z.string().datetime()
3418
+ }).strict();
3419
+ const CacheIdentityShape = {
3420
+ kind: z.literal("agent-eval/public-benchmark-model-response"),
3421
+ callId: z.string().min(1),
3422
+ runIdentitySha256: z.string().regex(SHA256),
3423
+ caseId: z.string().min(1),
3424
+ repetition: z.number().int().nonnegative()
3425
+ };
3426
+ const SuccessCacheEntryWithoutDigestSchema = z.object({
3427
+ ...CacheIdentityShape,
3428
+ status: z.literal("succeeded"),
3429
+ response: z.json(),
3430
+ metadata: ResponseMetadataSchema,
3431
+ receipt: CostReceiptInputSchema
3432
+ }).strict();
3433
+ const FailureCacheEntryWithoutDigestSchema = z.object({
3434
+ ...CacheIdentityShape,
3435
+ status: z.literal("failed"),
3436
+ error: BenchmarkErrorSchema,
3437
+ receipt: CostReceiptInputSchema
3438
+ }).strict();
3439
+ const CacheEntryWithoutDigestSchema = z.discriminatedUnion("status", [SuccessCacheEntryWithoutDigestSchema, FailureCacheEntryWithoutDigestSchema]);
3440
+ const CacheEntrySchema = z.discriminatedUnion("status", [SuccessCacheEntryWithoutDigestSchema.extend({ entrySha256: z.string().regex(SHA256) }), FailureCacheEntryWithoutDigestSchema.extend({ entrySha256: z.string().regex(SHA256) })]);
3441
+ function publicBenchmarkCallId(identity) {
3442
+ assertCacheIdentity(identity);
3443
+ return `analyst-benchmark-${hashCanonical({
3444
+ runIdentitySha256: identity.runIdentitySha256,
3445
+ caseId: identity.caseId,
3446
+ repetition: identity.repetition
3447
+ }).slice(7)}`;
3448
+ }
3449
+ function readPublicBenchmarkResponseCache(cacheDirectory, identity) {
3450
+ const callId = publicBenchmarkCallId(identity);
3451
+ const path = responseCachePath(cacheDirectory, callId);
3452
+ if (!existsSync(path)) return void 0;
3453
+ const metadata = lstatSync(path);
3454
+ if (!metadata.isFile() || metadata.isSymbolicLink()) throw new ValidationError(`benchmark response cache must be a real file: ${path}`);
3455
+ let parsed;
3456
+ try {
3457
+ parsed = JSON.parse(readFileSync(path, "utf8"));
3458
+ } catch (error) {
3459
+ throw new ValidationError(`benchmark response cache contains invalid JSON: ${path}`, { cause: error });
3460
+ }
3461
+ const entry = parseCacheEntry(parsed, path);
3462
+ if (entry.callId !== callId || entry.runIdentitySha256 !== identity.runIdentitySha256 || entry.caseId !== identity.caseId || entry.repetition !== identity.repetition) throw new ValidationError(`benchmark response cache identity does not match: ${path}`);
3463
+ return entry;
3464
+ }
3465
+ function writePublicBenchmarkResponseCache(cacheDirectory, entry) {
3466
+ const expectedCallId = publicBenchmarkCallId(entry);
3467
+ if (entry.callId !== expectedCallId) throw new ValidationError("benchmark response cache callId does not match its identity");
3468
+ const validated = JSON.parse(JSON.stringify(CacheEntryWithoutDigestSchema.parse(entry)));
3469
+ const complete = {
3470
+ ...validated,
3471
+ entrySha256: hashCanonical(validated).slice(7)
3472
+ };
3473
+ const path = responseCachePath(cacheDirectory, complete.callId);
3474
+ const content = `${canonicalString(complete)}\n`;
3475
+ withLedgerFileLock(path, fileContext(), () => {
3476
+ if (existsSync(path)) {
3477
+ const existing = readPublicBenchmarkResponseCache(cacheDirectory, complete);
3478
+ if (!existing || canonicalString(existing) !== canonicalString(complete)) throw new ValidationError(`benchmark response cache conflicts with existing file: ${path}`);
3479
+ return;
3480
+ }
3481
+ writeLedgerFileAtomically(path, content, fileContext());
3482
+ });
3483
+ return complete;
3484
+ }
3485
+ function parseCacheEntry(value, path) {
3486
+ let parsed;
3487
+ try {
3488
+ parsed = CacheEntrySchema.parse(value);
3489
+ } catch (error) {
3490
+ throw new ValidationError(`benchmark response cache has an invalid shape: ${path}`, { cause: error });
3491
+ }
3492
+ const { entrySha256, ...withoutDigest } = parsed;
3493
+ if (entrySha256 !== hashCanonical(withoutDigest).slice(7)) throw new ValidationError(`benchmark response cache digest does not match: ${path}`);
3494
+ return parsed;
3495
+ }
3496
+ function responseCachePath(cacheDirectory, callId) {
3497
+ const directory = nodePath.resolve(cacheDirectory);
3498
+ const path = nodePath.resolve(directory, `${hashCanonical(callId).slice(7)}.json`);
3499
+ if (!isPathInsideDirectory(directory, path, nodePath)) throw new ValidationError("benchmark response cache path escapes its directory");
3500
+ return path;
3501
+ }
3502
+ function isPathInsideDirectory(directory, candidate, pathOperations = nodePath) {
3503
+ const relative = pathOperations.relative(directory, candidate);
3504
+ return relative !== "" && relative !== ".." && !relative.startsWith(`..${pathOperations.sep}`) && !pathOperations.isAbsolute(relative);
3505
+ }
3506
+ function assertCacheIdentity(identity) {
3507
+ if (!SHA256.test(identity.runIdentitySha256)) throw new ValidationError("benchmark response cache requires a SHA-256 run identity");
3508
+ if (!identity.caseId.trim()) throw new ValidationError("benchmark response cache requires a case id");
3509
+ if (!Number.isSafeInteger(identity.repetition) || identity.repetition < 0) throw new ValidationError("benchmark response cache repetition must be non-negative");
3510
+ }
3511
+ function fileContext() {
3512
+ return {
3513
+ subject: "benchmark response cache",
3514
+ integrityError: (message, options) => new ValidationError(message, options)
3515
+ };
3516
+ }
3517
+ //#endregion
3518
+ //#region src/analyst/benchmark-public-model.ts
3519
+ /** One-shot JSON baseline. This is not a recursive trace analyst. */
3520
+ function createPublicBenchmarkDirectRunner(dataset, config) {
3521
+ if (config.instructionsOverride) throw new Error("the direct runner executes only the stock protocol; an instructions override requires the dspy-rlm runner");
3522
+ const model = requiredString(config.model, "model");
3523
+ const baseUrl = requiredString(config.baseUrl, "baseUrl");
3524
+ const apiKey = requiredString(config.apiKey, "apiKey");
3525
+ const maxOutputTokens = positiveSafeInteger(config.maxOutputTokens, "maxOutputTokens");
3526
+ const timeoutMs = positiveSafeInteger(config.timeoutMs, "timeoutMs");
3527
+ const costLedger = config.costLedger ?? new CostLedger();
3528
+ const durability = config.durability ? {
3529
+ runIdentitySha256: requiredString(config.durability.runIdentitySha256, "durability.runIdentitySha256"),
3530
+ responseCacheDir: requiredString(config.durability.responseCacheDir, "durability.responseCacheDir")
3531
+ } : void 0;
3532
+ const actor = dataset === "agentrx" ? "agentrx-root-cause-localizer" : "codetracebench-step-localizer";
3533
+ const outputAdapter = dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block";
3534
+ const llmOptions = {
3535
+ baseUrl,
3536
+ apiKey,
3537
+ maximumAttempts: 1,
3538
+ jsonSchemaTransport: "json-object",
3539
+ jsonPayloadMode: "exact",
3540
+ thinking: "disabled",
3541
+ ...config.fetchImpl ? { fetch: config.fetchImpl } : {}
3542
+ };
3543
+ return {
3544
+ id: "direct",
3545
+ async analyze(input, context) {
3546
+ const trajectoryId = trajectoryIdFromCaseId$1(dataset, context.caseId);
3547
+ const costTags = {
3548
+ analystId: actor,
3549
+ benchmarkCaseId: context.caseId,
3550
+ benchmarkRepetition: String(context.repetition)
3551
+ };
3552
+ let rawPredictions = [];
3553
+ let rejectedBlocks = [];
3554
+ let modelFindings = [];
3555
+ let providerModel = model;
3006
3556
  let producedAt;
3007
3557
  let modelMetadata = {
3008
3558
  analysisMode: "direct-baseline",
@@ -3129,1176 +3679,1021 @@ function createPublicBenchmarkDirectRunner(dataset, config) {
3129
3679
  responseSource: "provider",
3130
3680
  report: response.report,
3131
3681
  providerModel: paid.value.result.model,
3132
- providerDurationMs: paid.value.result.durationMs,
3133
- finishReason: paid.value.result.finishReason ?? null,
3134
- cost: costReceiptMetadata(paid.receipt)
3135
- };
3136
- }
3137
- const converted = await publicBenchmarkPredictionsToFindings({
3138
- dataset,
3139
- trajectoryId,
3140
- predictions: rawPredictions,
3141
- store: input.traceStore,
3142
- analystId: "direct",
3143
- providerModel,
3144
- producedAt: requiredString(producedAt ?? "", "finding producedAt"),
3145
- ...context.signal ? { signal: context.signal } : {}
3146
- });
3147
- modelFindings = converted.findings;
3148
- if (converted.diagnostics) modelMetadata = {
3149
- ...modelMetadata,
3150
- blockDiagnostics: {
3151
- ...converted.diagnostics,
3152
- rejectedBlocks
3153
- }
3154
- };
3155
- if (dataset === "codetracebench") await validateCodeTraceFindingEvidence({
3156
- trajectoryId,
3157
- findings: modelFindings,
3158
- store: input.traceStore,
3159
- ...context.signal ? { signal: context.signal } : {}
3160
- });
3161
- return {
3162
- findings: modelFindings,
3163
- usage: usageReceiptFromCostLedger(costLedger, {
3164
- channel: "analyst",
3165
- tags: costTags
3166
- }),
3167
- metadata: modelMetadata
3168
- };
3169
- } catch (error) {
3170
- if (context.signal?.aborted) throw error;
3171
- if (isPaidCallControlError$1(error)) throw error;
3172
- return {
3173
- findings: [],
3174
- usage: usageReceiptFromCostLedger(costLedger, {
3175
- channel: "analyst",
3176
- tags: costTags
3177
- }),
3178
- error: publicBenchmarkError(error, [apiKey]),
3179
- metadata: {
3180
- ...modelMetadata,
3181
- rawPredictions,
3182
- acceptedFindings: modelFindings
3183
- }
3184
- };
3185
- }
3186
- }
3187
- };
3188
- }
3189
- function settleCachedResponse(costLedger, cached) {
3190
- const settled = costLedger.list().find((receipt) => receipt.callId === cached.callId);
3191
- const pending = costLedger.listPending?.().find((record) => record.callId === cached.callId);
3192
- if (settled && pending) throw new CostCallConflictError(`benchmark response '${cached.callId}' is both pending and settled`, { callId: cached.callId });
3193
- const receipt = pending ? costLedger.reconcile(cached.callId, cached.receipt, { ...cached.status === "failed" ? { failed: true } : {} }) : settled;
3194
- if (!receipt) throw new CostCallConflictError(`benchmark response cache '${cached.callId}' has no matching cost record`, { callId: cached.callId });
3195
- assertCacheReceiptMatches(cached, receipt);
3196
- return receipt;
3197
- }
3198
- function assertNoSettledResponseWithoutCache(costLedger, callId) {
3199
- if (!callId) return;
3200
- if (costLedger.list().some((receipt) => receipt.callId === callId)) throw new CostCallConflictError(`settled benchmark call '${callId}' has no durable response cache`, { callId });
3201
- }
3202
- function assertCacheReceiptMatches(cached, receipt) {
3203
- const expected = cached.receipt;
3204
- if (receipt.callId !== cached.callId || receipt.model !== expected.model || receipt.inputTokens !== expected.inputTokens || receipt.outputTokens !== expected.outputTokens || (receipt.reasoningTokens ?? 0) !== (expected.reasoningTokens ?? 0) || (receipt.cachedTokens ?? 0) !== (expected.cachedTokens ?? 0) || (receipt.cacheWriteTokens ?? 0) !== (expected.cacheWriteTokens ?? 0) || expected.actualCostUsd !== void 0 && receipt.actualCostUsd !== expected.actualCostUsd || expected.estimatedCostUsd !== void 0 && receipt.estimatedCostUsd !== expected.estimatedCostUsd || expected.costUnknown === true && !receipt.costUnknown || expected.usageUnknown === true && !receipt.usageUnknown || cached.status === "succeeded" && receipt.error !== void 0 || cached.status === "failed" && receipt.error === void 0) throw new CostCallConflictError(`benchmark response cache receipt does not match cost record '${cached.callId}'`, {
3205
- callId: cached.callId,
3206
- receipt
3207
- });
3208
- }
3209
- function isPaidCallControlError$1(error) {
3210
- return error instanceof CostAccountingIncompleteError || error instanceof CostCallConflictError || error instanceof CostCeilingReachedError || error instanceof CostLedgerPersistenceError || error instanceof CostReceiptCaptureError || error instanceof CostReservationExceededError;
3211
- }
3212
- function receiptForProviderFailure(error, completedResult, model) {
3213
- if (completedResult) return costReceiptFromLlm(completedResult);
3214
- if (error instanceof Error) {
3215
- const captured = costReceiptFromLlmError(error);
3216
- if (captured) return captured;
3217
- }
3218
- return {
3219
- model,
3220
- inputTokens: 0,
3221
- outputTokens: 0,
3222
- costUnknown: true,
3223
- usageUnknown: true
3224
- };
3225
- }
3226
- function costReceiptMetadata(receipt) {
3227
- if (receipt.actualCostUsd !== void 0) return {
3228
- source: "provider",
3229
- actualCostUsd: receipt.actualCostUsd
3230
- };
3231
- if (receipt.estimatedCostUsd !== void 0) return {
3232
- source: "external-estimate",
3233
- estimatedCostUsd: receipt.estimatedCostUsd
3234
- };
3235
- if (receipt.pricing) return {
3236
- source: "agent-eval-model-pricing",
3237
- estimatedCostUsd: receipt.costUsd,
3238
- ratesPerThousandTokens: receipt.pricing
3239
- };
3240
- return {
3241
- source: "unknown",
3242
- estimatedCostUsd: null
3243
- };
3244
- }
3245
- const ModelSeveritySchema = z.enum([
3246
- "critical",
3247
- "high",
3248
- "medium",
3249
- "low",
3250
- "info"
3251
- ]);
3252
- const AgentRxPredictionSchema = z.object({
3253
- step: z.number().int().positive(),
3254
- severity: ModelSeveritySchema,
3255
- claim: z.string().min(1),
3256
- confidence: z.number().min(0).max(1),
3257
- rationale: z.string().min(1).optional(),
3258
- recommended_action: z.string().min(1).optional()
3259
- }).strict();
3260
- const CodeTraceBlockPredictionSchema = z.object({
3261
- first_step: z.number().int().positive(),
3262
- last_step: z.number().int().positive(),
3263
- consequence_step: z.number().int().positive(),
3264
- escape_status: z.enum(["escaped", "unescaped"]),
3265
- severity: ModelSeveritySchema,
3266
- claim: z.string().min(1),
3267
- confidence: z.number().min(0).max(1),
3268
- rationale: z.string().min(1).optional(),
3269
- recommended_action: z.string().min(1).optional()
3270
- }).strict().superRefine((block, ctx) => {
3271
- if (block.last_step < block.first_step) {
3272
- ctx.addIssue({
3273
- code: z.ZodIssueCode.custom,
3274
- message: `failure block last_step ${block.last_step} precedes first_step ${block.first_step}`
3275
- });
3276
- return;
3277
- }
3278
- const length = block.last_step - block.first_step + 1;
3279
- if (length > 12) ctx.addIssue({
3280
- code: z.ZodIssueCode.custom,
3281
- message: `failure block spans ${length} steps; the maximum is 12`
3282
- });
3283
- if (block.consequence_step < block.first_step) ctx.addIssue({
3284
- code: z.ZodIssueCode.custom,
3285
- message: `failure block consequence_step ${block.consequence_step} precedes first_step ${block.first_step}`
3286
- });
3287
- });
3288
- const AgentRxCategorySchema = z.enum([
3289
- "instruction-plan-adherence-failure",
3290
- "invention-of-new-information",
3291
- "invalid-invocation",
3292
- "misinterpretation-of-tool-output-handoff-failure",
3293
- "intent-plan-misalignment",
3294
- "underspecified-user-intent",
3295
- "intent-not-supported",
3296
- "guardrails-triggered",
3297
- "system-failure",
3298
- "inconclusive"
3299
- ]);
3300
- const CodeTraceModelResponseEnvelopeSchema = z.object({
3301
- report: z.string().min(1).max(4e3),
3302
- findings: z.array(z.unknown()).max(16)
3303
- }).strict();
3304
- const AgentRxModelResponseSchema = z.object({
3305
- report: z.string().min(1).max(4e3),
3306
- findings: z.array(AgentRxPredictionSchema.extend({ category: AgentRxCategorySchema }).strict()).max(1)
3307
- }).strict();
3308
- function parsePublicBenchmarkModelResponse(dataset, value) {
3309
- if (dataset === "agentrx") return {
3310
- ...AgentRxModelResponseSchema.parse(value),
3311
- rejectedBlocks: []
3312
- };
3313
- const envelope = CodeTraceModelResponseEnvelopeSchema.parse(value);
3314
- const findings = [];
3315
- const rejectedBlocks = [];
3316
- for (const [index, block] of envelope.findings.entries()) {
3317
- const parsed = CodeTraceBlockPredictionSchema.safeParse(block);
3318
- if (parsed.success) {
3319
- findings.push(parsed.data);
3320
- continue;
3321
- }
3322
- rejectedBlocks.push(`block ${index}: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`);
3323
- }
3324
- if (findings.length === 0 && envelope.findings.length > 0) throw new ValidationError(`every reported failure block was malformed: ${rejectedBlocks.join(" | ")}`);
3325
- return {
3326
- report: envelope.report,
3327
- findings,
3328
- rejectedBlocks
3329
- };
3330
- }
3331
- async function publicBenchmarkPredictionsToFindings(options) {
3332
- if (options.predictions.length === 0 && options.dataset === "agentrx") return {
3333
- findings: [],
3334
- diagnostics: void 0
3335
- };
3336
- if (options.dataset === "agentrx") {
3337
- const prediction = options.predictions[0];
3338
- if (!("step" in prediction)) throw new Error("AgentRx model output must name a single root-cause step");
3339
- if (!prediction.category) throw new Error("AgentRx model output is missing its failure category");
3340
- const evidenceByStep = await resolveAssistantStepEvidence({
3341
- trajectoryId: options.trajectoryId,
3342
- steps: [prediction.step],
3343
- store: options.store,
3344
- ...options.signal ? { signal: options.signal } : {}
3345
- });
3346
- const [finding] = agentRxPredictionsToFindings(options.trajectoryId, [{
3347
- failure_case: prediction.category,
3348
- step_number: prediction.step,
3349
- description: prediction.rationale ?? prediction.claim
3350
- }], {
3351
- analystId: options.analystId,
3352
- producedAt: options.producedAt,
3353
- confidence: prediction.confidence
3354
- });
3355
- if (!finding) throw new Error("AgentRx output adapter produced no root-cause finding");
3356
- return {
3357
- findings: [{
3358
- ...finding,
3359
- evidence_refs: [evidenceByStep.get(prediction.step)],
3360
- metadata: {
3361
- ...finding.metadata,
3362
- model: options.providerModel
3682
+ providerDurationMs: paid.value.result.durationMs,
3683
+ finishReason: paid.value.result.finishReason ?? null,
3684
+ cost: costReceiptMetadata(paid.receipt)
3685
+ };
3363
3686
  }
3364
- }],
3365
- diagnostics: void 0
3366
- };
3367
- }
3368
- const blocks = options.predictions.map((prediction) => {
3369
- if (!("first_step" in prediction)) throw new Error("CodeTraceBench model output must report first_step/last_step failure blocks");
3370
- return {
3371
- firstStep: prediction.first_step,
3372
- lastStep: prediction.last_step,
3373
- consequenceStep: prediction.consequence_step,
3374
- escapeStatus: prediction.escape_status,
3375
- severity: prediction.severity,
3376
- claim: prediction.claim,
3377
- confidence: prediction.confidence,
3378
- ...prediction.rationale === void 0 ? {} : { rationale: prediction.rationale },
3379
- ...prediction.recommended_action === void 0 ? {} : { recommendedAction: prediction.recommended_action },
3380
- metadata: {
3381
- analysis_mode: "direct-baseline",
3382
- model: options.providerModel
3383
- }
3384
- };
3385
- });
3386
- return expandCodeTraceFailureBlocks({
3387
- trajectoryId: options.trajectoryId,
3388
- blocks,
3389
- store: options.store,
3390
- analystId: options.analystId,
3391
- producedAt: options.producedAt,
3392
- ...options.signal ? { signal: options.signal } : {}
3393
- });
3394
- }
3395
- async function prepareSingleTraceContext(store, context) {
3396
- const storeContext = context.signal ? { signal: context.signal } : void 0;
3397
- const overview = await store.getOverview(void 0, storeContext);
3398
- if (overview.total_traces !== 1 || overview.sample_trace_ids.length !== 1) throw new Error(`public model benchmark requires exactly one trace, received ${overview.total_traces}`);
3399
- const traceId = overview.sample_trace_ids[0];
3400
- for (const perAttributeByteCap of TRACE_PROJECTION_ATTRIBUTE_BYTE_CAPS) {
3401
- const viewed = await store.viewTrace({
3402
- trace_id: traceId,
3403
- per_attribute_byte_cap: perAttributeByteCap
3404
- }, storeContext);
3405
- if (!viewed.spans) continue;
3406
- return JSON.stringify({
3407
- trace_id: traceId,
3408
- per_attribute_byte_cap: perAttributeByteCap,
3409
- spans: viewed.spans
3410
- });
3411
- }
3412
- }
3413
- function trajectoryIdFromCaseId$1(dataset, caseId) {
3414
- const prefix = dataset === "agentrx" ? "agentrx:" : "codetrace:";
3415
- if (!caseId.startsWith(prefix) || caseId.length === prefix.length) throw new Error(`unexpected ${dataset} benchmark case id '${caseId}'`);
3416
- return caseId.slice(prefix.length);
3417
- }
3418
- //#endregion
3419
- //#region src/analyst/benchmark-public-rlm.ts
3420
- /** Public benchmark candidate that runs the actual recursive trace analyst. */
3421
- function createPublicBenchmarkRlmRunner(dataset, config) {
3422
- const costLedger = config.costLedger ?? new CostLedger();
3423
- const limits = {
3424
- maxIterations: config.dspyRlm?.maxIterations ?? 14,
3425
- maxLlmCalls: config.dspyRlm?.maxLlmCalls ?? 8,
3426
- maxToolCalls: config.dspyRlm?.maxToolCalls ?? 80,
3427
- maxOutputChars: config.dspyRlm?.maxOutputChars ?? 8e3
3428
- };
3429
- const pricing = config.pricing ?? pricingForModel(config.model);
3430
- const engine = createDspyRlmTraceEngine({
3431
- baseUrl: config.baseUrl,
3432
- apiKey: config.apiKey,
3433
- model: config.model,
3434
- maxOutputTokens: config.maxOutputTokens,
3435
- timeoutMs: config.timeoutMs,
3436
- maxCostUsd: config.maxCostUsdPerAnalysis ?? 1,
3437
- pricing,
3438
- ...config.dspyRlm?.runner ? { runner: config.dspyRlm.runner } : {}
3439
- });
3440
- const definition = publicBenchmarkDefinition(dataset, limits);
3441
- return {
3442
- id: "dspy-rlm",
3443
- async analyze(input, context) {
3444
- const trajectoryId = trajectoryIdFromCaseId(dataset, context.caseId);
3445
- const tags = {
3446
- benchmarkCaseId: context.caseId,
3447
- benchmarkRepetition: String(context.repetition)
3448
- };
3449
- let usage;
3450
- let rawFindings = [];
3451
- try {
3452
- if (!input.traceStore) throw new Error(`${dataset} DSPy RLM runner requires a trace store`);
3453
- const completed = await runTraceAnalyst({
3454
- definition,
3455
- engine,
3687
+ const converted = await publicBenchmarkPredictionsToFindings({
3688
+ dataset,
3689
+ trajectoryId,
3690
+ predictions: rawPredictions,
3456
3691
  store: input.traceStore,
3457
- context: {
3458
- runId: context.caseId,
3459
- correlationId: `${context.caseId}:${context.repetition}`,
3460
- costLedger,
3461
- costPhase: "analyst.public-benchmark.dspy-rlm",
3462
- tags,
3463
- recordUsage: (receipt) => {
3464
- usage = receipt;
3465
- },
3466
- signal: context.signal
3467
- }
3692
+ analystId: "direct",
3693
+ providerModel,
3694
+ producedAt: requiredString(producedAt ?? "", "finding producedAt"),
3695
+ ...context.signal ? { signal: context.signal } : {}
3468
3696
  });
3469
- const producedAt = (/* @__PURE__ */ new Date()).toISOString();
3470
- rawFindings = completed.findings.map((finding) => makeFinding({
3471
- analyst_id: "dspy-rlm",
3472
- area: dataset === "agentrx" ? "root-cause" : "incorrect",
3473
- subject: finding.subject,
3474
- claim: finding.claim,
3475
- rationale: finding.rationale,
3476
- severity: finding.severity,
3477
- confidence: finding.confidence,
3478
- evidence_refs: evidenceRefsFromRawFinding(finding),
3479
- recommended_action: finding.recommended_action,
3480
- metadata: {
3481
- analysis_mode: "recursive",
3482
- engine: "dspy-rlm",
3483
- model: config.model
3484
- },
3485
- produced_at: producedAt
3486
- }));
3487
- const adapted = await adaptPublicBenchmarkFindings({
3488
- dataset,
3697
+ modelFindings = converted.findings;
3698
+ if (converted.diagnostics) modelMetadata = {
3699
+ ...modelMetadata,
3700
+ blockDiagnostics: {
3701
+ ...converted.diagnostics,
3702
+ rejectedBlocks
3703
+ }
3704
+ };
3705
+ if (dataset === "codetracebench") await validateCodeTraceFindingEvidence({
3489
3706
  trajectoryId,
3490
- findings: rawFindings,
3491
- analystId: "dspy-rlm",
3707
+ findings: modelFindings,
3492
3708
  store: input.traceStore,
3493
3709
  ...context.signal ? { signal: context.signal } : {}
3494
3710
  });
3495
3711
  return {
3496
- findings: adapted.findings,
3497
- usage,
3498
- metadata: {
3499
- analysisMode: "recursive",
3500
- engine: "dspy-rlm",
3501
- protocolSha256: publicBenchmarkProtocolSha256(dataset),
3502
- ...adapted.diagnostics ? { blockDiagnostics: adapted.diagnostics } : {},
3503
- answer: completed.answer,
3504
- trajectory: completed.trajectory,
3505
- modelCalls: completed.modelCalls,
3506
- toolCalls: completed.toolCalls,
3507
- runtime: completed.runtime
3508
- }
3712
+ findings: modelFindings,
3713
+ usage: usageReceiptFromCostLedger(costLedger, {
3714
+ channel: "analyst",
3715
+ tags: costTags
3716
+ }),
3717
+ metadata: modelMetadata
3509
3718
  };
3510
3719
  } catch (error) {
3511
3720
  if (context.signal?.aborted) throw error;
3512
- if (isPaidCallControlError(error)) throw error;
3721
+ if (isPaidCallControlError$1(error)) throw error;
3513
3722
  return {
3514
3723
  findings: [],
3515
- usage,
3516
- error: publicBenchmarkError(error, [config.apiKey]),
3724
+ usage: usageReceiptFromCostLedger(costLedger, {
3725
+ channel: "analyst",
3726
+ tags: costTags
3727
+ }),
3728
+ error: publicBenchmarkError(error, [apiKey]),
3517
3729
  metadata: {
3518
- analysisMode: "recursive",
3519
- engine: "dspy-rlm",
3520
- rawFindings
3730
+ ...modelMetadata,
3731
+ rawPredictions,
3732
+ acceptedFindings: modelFindings
3521
3733
  }
3522
3734
  };
3523
3735
  }
3524
3736
  }
3525
3737
  };
3526
3738
  }
3527
- function publicBenchmarkDefinition(dataset, limits) {
3528
- return {
3529
- id: dataset === "agentrx" ? "agentrx-dspy-rlm" : "codetracebench-dspy-rlm",
3530
- description: dataset === "agentrx" ? "Localizes the first unrecoverable root-cause step." : "Localizes every incorrect state-changing assistant step.",
3531
- area: dataset === "agentrx" ? "root-cause" : "incorrect",
3532
- version: "1.0.0",
3533
- question: dataset === "agentrx" ? "What is the first unrecoverable root cause in this failed trajectory?" : "Which assistant steps are incorrect under the CodeTraceBench definition?",
3534
- instructions: publicBenchmarkRlmInstructions(dataset),
3535
- toolGroup: "singleTrace",
3536
- limits
3537
- };
3739
+ function settleCachedResponse(costLedger, cached) {
3740
+ const settled = costLedger.list().find((receipt) => receipt.callId === cached.callId);
3741
+ const pending = costLedger.listPending?.().find((record) => record.callId === cached.callId);
3742
+ if (settled && pending) throw new CostCallConflictError(`benchmark response '${cached.callId}' is both pending and settled`, { callId: cached.callId });
3743
+ const receipt = pending ? costLedger.reconcile(cached.callId, cached.receipt, { ...cached.status === "failed" ? { failed: true } : {} }) : settled;
3744
+ if (!receipt) throw new CostCallConflictError(`benchmark response cache '${cached.callId}' has no matching cost record`, { callId: cached.callId });
3745
+ assertCacheReceiptMatches(cached, receipt);
3746
+ return receipt;
3538
3747
  }
3539
- function pricingForModel(model) {
3540
- const pricing = resolveModelPricing(model);
3541
- if (!pricing) throw new Error(`no pricing is configured for '${model}'; provide PublicAnalystBenchmarkModelConfig.pricing`);
3542
- return {
3543
- inputUsdPerMillion: pricing.input * 1e3,
3544
- outputUsdPerMillion: pricing.output * 1e3
3545
- };
3748
+ function assertNoSettledResponseWithoutCache(costLedger, callId) {
3749
+ if (!callId) return;
3750
+ if (costLedger.list().some((receipt) => receipt.callId === callId)) throw new CostCallConflictError(`settled benchmark call '${callId}' has no durable response cache`, { callId });
3546
3751
  }
3547
- function trajectoryIdFromCaseId(dataset, caseId) {
3548
- const prefix = dataset === "agentrx" ? "agentrx:" : "codetrace:";
3549
- if (!caseId.startsWith(prefix) || caseId.length === prefix.length) throw new Error(`unexpected ${dataset} benchmark case id '${caseId}'`);
3550
- return caseId.slice(prefix.length);
3752
+ function assertCacheReceiptMatches(cached, receipt) {
3753
+ const expected = cached.receipt;
3754
+ if (receipt.callId !== cached.callId || receipt.model !== expected.model || receipt.inputTokens !== expected.inputTokens || receipt.outputTokens !== expected.outputTokens || (receipt.reasoningTokens ?? 0) !== (expected.reasoningTokens ?? 0) || (receipt.cachedTokens ?? 0) !== (expected.cachedTokens ?? 0) || (receipt.cacheWriteTokens ?? 0) !== (expected.cacheWriteTokens ?? 0) || expected.actualCostUsd !== void 0 && receipt.actualCostUsd !== expected.actualCostUsd || expected.estimatedCostUsd !== void 0 && receipt.estimatedCostUsd !== expected.estimatedCostUsd || expected.costUnknown === true && !receipt.costUnknown || expected.usageUnknown === true && !receipt.usageUnknown || cached.status === "succeeded" && receipt.error !== void 0 || cached.status === "failed" && receipt.error === void 0) throw new CostCallConflictError(`benchmark response cache receipt does not match cost record '${cached.callId}'`, {
3755
+ callId: cached.callId,
3756
+ receipt
3757
+ });
3551
3758
  }
3552
- function isPaidCallControlError(error) {
3759
+ function isPaidCallControlError$1(error) {
3553
3760
  return error instanceof CostAccountingIncompleteError || error instanceof CostCallConflictError || error instanceof CostCeilingReachedError || error instanceof CostLedgerPersistenceError || error instanceof CostReceiptCaptureError || error instanceof CostReservationExceededError;
3554
3761
  }
3555
- //#endregion
3556
- //#region src/analyst/benchmark-command-persistence.ts
3557
- const ANALYST_BENCHMARK_INITIALIZATION_COMPLETE_FILE = "initialization-complete.json";
3558
- async function openOutputDirectory(outDir, resume) {
3559
- const directory = resolve(outDir);
3560
- if (resume) {
3561
- let outputStat;
3562
- try {
3563
- outputStat = await lstat(directory);
3564
- } catch (error) {
3565
- if (isNodeError(error, "ENOENT")) throw new Error(`cannot resume missing benchmark output directory: ${directory}`);
3566
- throw error;
3567
- }
3568
- if (!outputStat.isDirectory() || outputStat.isSymbolicLink()) throw new Error(`benchmark output must be a real directory: ${directory}`);
3569
- } else {
3570
- await mkdir(dirname(directory), { recursive: true });
3571
- try {
3572
- await mkdir(directory);
3573
- } catch (error) {
3574
- if (isNodeError(error, "EEXIST")) throw new Error(`refusing to use existing benchmark output directory: ${directory}`);
3575
- throw error;
3576
- }
3577
- await syncDirectory(dirname(directory));
3578
- }
3579
- return {
3580
- directory,
3581
- initializationComplete: resolve(directory, ANALYST_BENCHMARK_INITIALIZATION_COMPLETE_FILE),
3582
- manifest: resolve(directory, ANALYST_BENCHMARK_MANIFEST_FILE),
3583
- observations: resolve(directory, ANALYST_BENCHMARK_OBSERVATIONS_FILE),
3584
- costLedger: resolve(directory, ANALYST_BENCHMARK_COST_LEDGER_FILE),
3585
- modelResponses: resolve(directory, "model-responses"),
3586
- localReceipt: resolve(directory, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE),
3587
- result: resolve(directory, "result.json"),
3588
- report: resolve(directory, "report.md")
3589
- };
3590
- }
3591
- async function prepareOutputLockPath(outDir) {
3592
- const directory = resolve(outDir);
3593
- await mkdir(dirname(directory), { recursive: true });
3594
- return `${directory}.lock`;
3595
- }
3596
- function createRunIdentity(config, prepared) {
3597
- const caseDefinitions = prepared.cases.map((testCase) => ({
3598
- id: testCase.id,
3599
- clusterId: testCase.clusterId,
3600
- labelState: testCase.labelState,
3601
- expectedIssues: testCase.expectedIssues,
3602
- labeledEvidence: testCase.labeledEvidence ?? [],
3603
- tags: testCase.tags ?? [],
3604
- metadata: testCase.metadata ?? {}
3605
- }));
3762
+ function receiptForProviderFailure(error, completedResult, model) {
3763
+ if (completedResult) return costReceiptFromLlm(completedResult);
3764
+ if (error instanceof Error) {
3765
+ const captured = costReceiptFromLlmError(error);
3766
+ if (captured) return captured;
3767
+ }
3606
3768
  return {
3607
- config: {
3608
- dataset: config.dataset,
3609
- datasetRevision: config.revision,
3610
- datasetSplit: config.split,
3611
- model: {
3612
- id: config.model.model,
3613
- maxOutputTokens: config.model.maxOutputTokens,
3614
- timeoutMs: config.model.timeoutMs
3615
- },
3616
- limit: config.limit,
3617
- seed: config.seed,
3618
- concurrency: config.concurrency,
3619
- repetitions: config.repetitions,
3620
- maxCostUsd: config.maxCostUsd,
3621
- maxArtifactBytes: config.maxArtifactBytes,
3622
- analystProtocolSha256: publicBenchmarkProtocolSha256(config.dataset),
3623
- implementationSha256: ANALYST_BENCHMARK_IMPLEMENTATION_SHA256,
3624
- dependencyLockSha256: ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256,
3625
- runnerIds: ["empty", config.analyst]
3626
- },
3627
- inputs: {
3628
- labelsSha256: prepared.labelsSha256,
3629
- sourceRowCount: prepared.sourceRowCount,
3630
- selectedCaseIds: [...prepared.selectedCaseIds],
3631
- traceFiles: prepared.traceFiles.map((traceFile) => ({ ...traceFile })),
3632
- verificationArtifactsSha256: digestCanonical(prepared.verificationArtifacts),
3633
- caseDefinitionsSha256: digestCanonical(caseDefinitions)
3634
- }
3769
+ model,
3770
+ inputTokens: 0,
3771
+ outputTokens: 0,
3772
+ costUnknown: true,
3773
+ usageUnknown: true
3635
3774
  };
3636
3775
  }
3637
- function createLocalRunReceipt(config, paths) {
3776
+ function costReceiptMetadata(receipt) {
3777
+ if (receipt.actualCostUsd !== void 0) return {
3778
+ source: "provider",
3779
+ actualCostUsd: receipt.actualCostUsd
3780
+ };
3781
+ if (receipt.estimatedCostUsd !== void 0) return {
3782
+ source: "external-estimate",
3783
+ estimatedCostUsd: receipt.estimatedCostUsd
3784
+ };
3785
+ if (receipt.pricing) return {
3786
+ source: "agent-eval-model-pricing",
3787
+ estimatedCostUsd: receipt.costUsd,
3788
+ ratesPerThousandTokens: receipt.pricing
3789
+ };
3638
3790
  return {
3639
- kind: "agent-eval/analyst-benchmark-local-run",
3640
- local: {
3641
- labelsPath: resolve(config.labelsPath),
3642
- traceDir: resolve(config.traceDir),
3643
- ...config.artifactDir ? { artifactDir: resolve(config.artifactDir) } : {},
3644
- outputDir: paths.directory,
3645
- baseUrl: config.model.baseUrl,
3646
- apiKeyEnvironment: config.apiKeyEnv
3647
- },
3648
- command: config.command,
3649
- environment: {
3650
- node: process.version,
3651
- platform: platform(),
3652
- arch: arch()
3653
- },
3654
- files: {
3655
- manifest: paths.manifest,
3656
- observations: paths.observations,
3657
- costLedger: paths.costLedger,
3658
- modelResponses: paths.modelResponses,
3659
- result: paths.result,
3660
- report: paths.report
3661
- }
3791
+ source: "unknown",
3792
+ estimatedCostUsd: null
3662
3793
  };
3663
3794
  }
3664
- async function initializeRunFiles(paths, identity, identitySha256, localIdentitySha256, localReceiptInput) {
3665
- const existingManifest = await readOptionalRegularFile(paths.manifest, "benchmark run manifest");
3666
- const manifest = existingManifest ? await readAndValidateManifestContent(paths.manifest, existingManifest, identity, identitySha256, localIdentitySha256) : {
3667
- kind: "agent-eval/analyst-benchmark-run",
3668
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3669
- identitySha256,
3670
- localIdentitySha256,
3671
- identity
3795
+ const ModelSeveritySchema = z.enum([
3796
+ "critical",
3797
+ "high",
3798
+ "medium",
3799
+ "low",
3800
+ "info"
3801
+ ]);
3802
+ const AgentRxPredictionSchema = z.object({
3803
+ step: z.number().int().positive(),
3804
+ severity: ModelSeveritySchema,
3805
+ claim: z.string().min(1),
3806
+ confidence: z.number().min(0).max(1),
3807
+ rationale: z.string().min(1).optional(),
3808
+ recommended_action: z.string().min(1).optional()
3809
+ }).strict();
3810
+ const CodeTraceBlockPredictionSchema = z.object({
3811
+ first_step: z.number().int().positive(),
3812
+ last_step: z.number().int().positive(),
3813
+ consequence_step: z.number().int().positive(),
3814
+ escape_status: z.enum(["escaped", "unescaped"]),
3815
+ severity: ModelSeveritySchema,
3816
+ claim: z.string().min(1),
3817
+ confidence: z.number().min(0).max(1),
3818
+ rationale: z.string().min(1).optional(),
3819
+ recommended_action: z.string().min(1).optional()
3820
+ }).strict().superRefine((block, ctx) => {
3821
+ if (block.last_step < block.first_step) {
3822
+ ctx.addIssue({
3823
+ code: z.ZodIssueCode.custom,
3824
+ message: `failure block last_step ${block.last_step} precedes first_step ${block.first_step}`
3825
+ });
3826
+ return;
3827
+ }
3828
+ const length = block.last_step - block.first_step + 1;
3829
+ if (length > 12) ctx.addIssue({
3830
+ code: z.ZodIssueCode.custom,
3831
+ message: `failure block spans ${length} steps; the maximum is 12`
3832
+ });
3833
+ if (block.consequence_step < block.first_step) ctx.addIssue({
3834
+ code: z.ZodIssueCode.custom,
3835
+ message: `failure block consequence_step ${block.consequence_step} precedes first_step ${block.first_step}`
3836
+ });
3837
+ });
3838
+ const AgentRxCategorySchema = z.enum([
3839
+ "instruction-plan-adherence-failure",
3840
+ "invention-of-new-information",
3841
+ "invalid-invocation",
3842
+ "misinterpretation-of-tool-output-handoff-failure",
3843
+ "intent-plan-misalignment",
3844
+ "underspecified-user-intent",
3845
+ "intent-not-supported",
3846
+ "guardrails-triggered",
3847
+ "system-failure",
3848
+ "inconclusive"
3849
+ ]);
3850
+ const CodeTraceModelResponseEnvelopeSchema = z.object({
3851
+ report: z.string().min(1).max(4e3),
3852
+ findings: z.array(z.unknown()).max(16)
3853
+ }).strict();
3854
+ const AgentRxModelResponseSchema = z.object({
3855
+ report: z.string().min(1).max(4e3),
3856
+ findings: z.array(AgentRxPredictionSchema.extend({ category: AgentRxCategorySchema }).strict()).max(1)
3857
+ }).strict();
3858
+ function parsePublicBenchmarkModelResponse(dataset, value) {
3859
+ if (dataset === "agentrx") return {
3860
+ ...AgentRxModelResponseSchema.parse(value),
3861
+ rejectedBlocks: []
3672
3862
  };
3673
- const localReceipt = {
3674
- ...localReceiptInput,
3675
- runIdentitySha256: identitySha256,
3676
- localIdentitySha256
3863
+ const envelope = CodeTraceModelResponseEnvelopeSchema.parse(value);
3864
+ const findings = [];
3865
+ const rejectedBlocks = [];
3866
+ for (const [index, block] of envelope.findings.entries()) {
3867
+ const parsed = CodeTraceBlockPredictionSchema.safeParse(block);
3868
+ if (parsed.success) {
3869
+ findings.push(parsed.data);
3870
+ continue;
3871
+ }
3872
+ rejectedBlocks.push(`block ${index}: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`);
3873
+ }
3874
+ if (findings.length === 0 && envelope.findings.length > 0) throw new ValidationError(`every reported failure block was malformed: ${rejectedBlocks.join(" | ")}`);
3875
+ return {
3876
+ report: envelope.report,
3877
+ findings,
3878
+ rejectedBlocks
3677
3879
  };
3678
- const manifestContent = `${JSON.stringify(manifest, null, 2)}\n`;
3679
- const localReceiptContent = `${JSON.stringify(localReceipt, null, 2)}\n`;
3680
- const initializationCompleteContent = renderInitializationComplete(manifest);
3681
- await assertAbsentOrExact(paths.observations, "", "benchmark observation log");
3682
- await assertAbsentOrExact(paths.localReceipt, localReceiptContent, "benchmark local run receipt");
3683
- await assertAbsentOrExact(paths.manifest, manifestContent, "benchmark run manifest");
3684
- for (const path of [
3685
- paths.costLedger,
3686
- paths.modelResponses,
3687
- paths.result,
3688
- paths.report
3689
- ]) if (await regularFileExists(path)) throw new Error(`benchmark initialization marker is missing but later run artifact exists: ${path}`);
3690
- if (await regularFileExists(paths.initializationComplete)) throw new Error(`benchmark initialization marker already exists during partial initialization: ${paths.initializationComplete}`);
3691
- await writeExclusiveOrVerify(paths.observations, "");
3692
- await writeExclusiveOrVerify(paths.localReceipt, localReceiptContent);
3693
- await writeExclusiveOrVerify(paths.manifest, manifestContent);
3694
- await writeExclusiveOrVerify(paths.initializationComplete, initializationCompleteContent);
3695
- return manifest;
3696
3880
  }
3697
- async function readAndValidateResumeFiles(paths, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256, localReceiptInput) {
3698
- if (!await regularFileExists(paths.initializationComplete)) return initializeRunFiles(paths, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256, localReceiptInput);
3699
- const manifest = await readAndValidateManifest(paths.manifest, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256);
3700
- const localReceiptContent = await readRegularFile(paths.localReceipt, "benchmark local run receipt");
3701
- const value = parseJson(localReceiptContent, paths.localReceipt);
3702
- if (!isRecord$1(value)) throw new TypeError(`benchmark local run receipt must be an object: ${paths.localReceipt}`);
3703
- assertExactKeys(value, [
3704
- "kind",
3705
- "runIdentitySha256",
3706
- "localIdentitySha256",
3707
- "local",
3708
- "command",
3709
- "environment",
3710
- "files"
3711
- ], "benchmark local run receipt");
3712
- if (value.kind !== "agent-eval/analyst-benchmark-local-run" || value.runIdentitySha256 !== currentIdentitySha256 || value.localIdentitySha256 !== currentLocalIdentitySha256 || !isRecord$1(value.local)) throw new Error("benchmark local run receipt does not match the requested resume");
3713
- const expectedLocalReceipt = {
3714
- ...localReceiptInput,
3715
- runIdentitySha256: currentIdentitySha256,
3716
- localIdentitySha256: currentLocalIdentitySha256
3717
- };
3718
- if (digestCanonical(value.local) !== currentLocalIdentitySha256 || canonicalJson(value.local) !== canonicalJson(localReceiptInput.local)) throw new Error("benchmark local paths or endpoint do not match the requested resume");
3719
- if (localReceiptContent !== `${JSON.stringify(expectedLocalReceipt, null, 2)}\n`) throw new Error(`benchmark local run receipt does not exactly match: ${paths.localReceipt}`);
3720
- if (await readRegularFile(paths.initializationComplete, "benchmark initialization marker") !== renderInitializationComplete(manifest)) throw new Error(`benchmark initialization marker does not match the run manifest: ${paths.initializationComplete}`);
3721
- return manifest;
3881
+ async function publicBenchmarkPredictionsToFindings(options) {
3882
+ if (options.predictions.length === 0 && options.dataset === "agentrx") return {
3883
+ findings: [],
3884
+ diagnostics: void 0
3885
+ };
3886
+ if (options.dataset === "agentrx") {
3887
+ const prediction = options.predictions[0];
3888
+ if (!("step" in prediction)) throw new Error("AgentRx model output must name a single root-cause step");
3889
+ if (!prediction.category) throw new Error("AgentRx model output is missing its failure category");
3890
+ const evidenceByStep = await resolveAssistantStepEvidence({
3891
+ trajectoryId: options.trajectoryId,
3892
+ steps: [prediction.step],
3893
+ store: options.store,
3894
+ ...options.signal ? { signal: options.signal } : {}
3895
+ });
3896
+ const [finding] = agentRxPredictionsToFindings(options.trajectoryId, [{
3897
+ failure_case: prediction.category,
3898
+ step_number: prediction.step,
3899
+ description: prediction.rationale ?? prediction.claim
3900
+ }], {
3901
+ analystId: options.analystId,
3902
+ producedAt: options.producedAt,
3903
+ confidence: prediction.confidence
3904
+ });
3905
+ if (!finding) throw new Error("AgentRx output adapter produced no root-cause finding");
3906
+ return {
3907
+ findings: [{
3908
+ ...finding,
3909
+ evidence_refs: [evidenceByStep.get(prediction.step)],
3910
+ metadata: {
3911
+ ...finding.metadata,
3912
+ model: options.providerModel
3913
+ }
3914
+ }],
3915
+ diagnostics: void 0
3916
+ };
3917
+ }
3918
+ const blocks = options.predictions.map((prediction) => {
3919
+ if (!("first_step" in prediction)) throw new Error("CodeTraceBench model output must report first_step/last_step failure blocks");
3920
+ return {
3921
+ firstStep: prediction.first_step,
3922
+ lastStep: prediction.last_step,
3923
+ consequenceStep: prediction.consequence_step,
3924
+ escapeStatus: prediction.escape_status,
3925
+ severity: prediction.severity,
3926
+ claim: prediction.claim,
3927
+ confidence: prediction.confidence,
3928
+ ...prediction.rationale === void 0 ? {} : { rationale: prediction.rationale },
3929
+ ...prediction.recommended_action === void 0 ? {} : { recommendedAction: prediction.recommended_action },
3930
+ metadata: {
3931
+ analysis_mode: "direct-baseline",
3932
+ model: options.providerModel
3933
+ }
3934
+ };
3935
+ });
3936
+ return expandCodeTraceFailureBlocks({
3937
+ trajectoryId: options.trajectoryId,
3938
+ blocks,
3939
+ store: options.store,
3940
+ analystId: options.analystId,
3941
+ producedAt: options.producedAt,
3942
+ ...options.signal ? { signal: options.signal } : {}
3943
+ });
3944
+ }
3945
+ async function prepareSingleTraceContext(store, context) {
3946
+ const storeContext = context.signal ? { signal: context.signal } : void 0;
3947
+ const overview = await store.getOverview(void 0, storeContext);
3948
+ if (overview.total_traces !== 1 || overview.sample_trace_ids.length !== 1) throw new Error(`public model benchmark requires exactly one trace, received ${overview.total_traces}`);
3949
+ const traceId = overview.sample_trace_ids[0];
3950
+ for (const perAttributeByteCap of TRACE_PROJECTION_ATTRIBUTE_BYTE_CAPS) {
3951
+ const viewed = await store.viewTrace({
3952
+ trace_id: traceId,
3953
+ per_attribute_byte_cap: perAttributeByteCap
3954
+ }, storeContext);
3955
+ if (!viewed.spans) continue;
3956
+ return JSON.stringify({
3957
+ trace_id: traceId,
3958
+ per_attribute_byte_cap: perAttributeByteCap,
3959
+ spans: viewed.spans
3960
+ });
3961
+ }
3722
3962
  }
3723
- async function readAndValidateManifest(path, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256) {
3724
- const content = await readRegularFile(path, "benchmark run manifest");
3725
- const manifest = await readAndValidateManifestContent(path, content, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256);
3726
- if (content !== `${JSON.stringify(manifest, null, 2)}\n`) throw new Error(`benchmark run manifest does not exactly match: ${path}`);
3727
- return manifest;
3963
+ function trajectoryIdFromCaseId$1(dataset, caseId) {
3964
+ const prefix = dataset === "agentrx" ? "agentrx:" : "codetrace:";
3965
+ if (!caseId.startsWith(prefix) || caseId.length === prefix.length) throw new Error(`unexpected ${dataset} benchmark case id '${caseId}'`);
3966
+ return caseId.slice(prefix.length);
3728
3967
  }
3729
- async function readAndValidateManifestContent(path, content, currentIdentity, currentIdentitySha256, currentLocalIdentitySha256) {
3730
- const value = parseJson(content, path);
3731
- if (!isRecord$1(value)) throw new TypeError(`benchmark run manifest must be an object: ${path}`);
3732
- assertExactKeys(value, [
3733
- "kind",
3734
- "createdAt",
3735
- "identitySha256",
3736
- "localIdentitySha256",
3737
- "identity"
3738
- ], "benchmark run manifest");
3739
- if (value.kind !== "agent-eval/analyst-benchmark-run") throw new TypeError(`unsupported benchmark run manifest: ${path}`);
3740
- if (typeof value.createdAt !== "string" || !Number.isFinite(Date.parse(value.createdAt))) throw new TypeError(`benchmark run manifest has an invalid createdAt: ${path}`);
3741
- if (!isSha256(value.identitySha256) || !isSha256(value.localIdentitySha256) || !isRecord$1(value.identity)) throw new TypeError(`benchmark run manifest has an invalid identity: ${path}`);
3742
- if (digestCanonical(value.identity) !== value.identitySha256) throw new Error(`benchmark run manifest identity digest does not match its contents: ${path}`);
3743
- if (currentIdentitySha256 !== value.identitySha256 || currentLocalIdentitySha256 !== value.localIdentitySha256 || canonicalJson(currentIdentity) !== canonicalJson(value.identity)) throw new Error(`benchmark resume configuration or inputs do not match ${ANALYST_BENCHMARK_MANIFEST_FILE}`);
3968
+ //#endregion
3969
+ //#region src/analyst/benchmark-public-consensus.ts
3970
+ /**
3971
+ * Step-level majority vote across independent analyst samples.
3972
+ *
3973
+ * Each sample's accepted, evidence-resolved steps count as one vote per step.
3974
+ * Steps present in at least ceil(k/2) samples survive; surviving steps are
3975
+ * reassembled into contiguous consensus blocks. Each consensus block borrows
3976
+ * its metadata (consequence step, escape status, claim, severity, rationale)
3977
+ * from the contributing sample block with the largest step overlap — ties go
3978
+ * to the higher-confidence block, then to the earlier sample — while its
3979
+ * confidence is the mean across every contributor. The returned blocks still
3980
+ * pass through the shared expansion, so width, count, and evidence rules are
3981
+ * enforced there, never assumed here.
3982
+ */
3983
+ function consensusCodeTraceBlocks(sampleAssignments) {
3984
+ const samples = sampleAssignments.length;
3985
+ if (samples < 2) throw new RangeError("step-level consensus requires at least two samples");
3986
+ const threshold = Math.ceil(samples / 2);
3987
+ const votesByStep = /* @__PURE__ */ new Map();
3988
+ sampleAssignments.forEach((assignments, sample) => {
3989
+ const seen = /* @__PURE__ */ new Set();
3990
+ for (const { step } of assignments) {
3991
+ if (!Number.isSafeInteger(step) || step < 0) throw new RangeError(`sample ${sample} assigned a non-step value: ${step}`);
3992
+ if (seen.has(step)) throw new Error(`sample ${sample} assigned step ${step} to more than one block`);
3993
+ seen.add(step);
3994
+ votesByStep.set(step, (votesByStep.get(step) ?? 0) + 1);
3995
+ }
3996
+ });
3997
+ const stepVotes = [...votesByStep].sort(([left], [right]) => left - right).map(([step, votes]) => ({
3998
+ step,
3999
+ votes,
4000
+ kept: votes >= threshold
4001
+ }));
4002
+ const keptSteps = stepVotes.filter((entry) => entry.kept).map((entry) => entry.step);
4003
+ const blocks = [];
4004
+ const blockDecisions = [];
4005
+ for (const segment of contiguousSegments(keptSteps)) {
4006
+ const contributors = segmentContributors(sampleAssignments, segment);
4007
+ const donor = contributors.reduce(betterDonor);
4008
+ const confidence = contributors.reduce((sum, contributor) => sum + contributor.block.confidence, 0) / contributors.length;
4009
+ blocks.push({
4010
+ firstStep: segment.firstStep,
4011
+ lastStep: segment.lastStep,
4012
+ consequenceStep: donor.block.consequenceStep,
4013
+ escapeStatus: donor.block.escapeStatus,
4014
+ severity: donor.block.severity,
4015
+ claim: donor.block.claim,
4016
+ confidence,
4017
+ ...donor.block.rationale === void 0 ? {} : { rationale: donor.block.rationale },
4018
+ ...donor.block.recommendedAction === void 0 ? {} : { recommendedAction: donor.block.recommendedAction },
4019
+ metadata: {
4020
+ ...donor.block.metadata,
4021
+ consensus_samples: samples,
4022
+ consensus_threshold: threshold,
4023
+ consensus_contributors: contributors.length,
4024
+ consensus_donor_sample: donor.sample
4025
+ }
4026
+ });
4027
+ blockDecisions.push({
4028
+ firstStep: segment.firstStep,
4029
+ lastStep: segment.lastStep,
4030
+ consequenceStep: donor.block.consequenceStep,
4031
+ escapeStatus: donor.block.escapeStatus,
4032
+ confidence,
4033
+ donor: publicContributor(donor),
4034
+ contributors: contributors.map(publicContributor)
4035
+ });
4036
+ }
3744
4037
  return {
3745
- kind: "agent-eval/analyst-benchmark-run",
3746
- createdAt: value.createdAt,
3747
- identitySha256: currentIdentitySha256,
3748
- localIdentitySha256: currentLocalIdentitySha256,
3749
- identity: currentIdentity
4038
+ blocks,
4039
+ decision: {
4040
+ samples,
4041
+ threshold,
4042
+ stepVotes,
4043
+ blocks: blockDecisions
4044
+ }
3750
4045
  };
3751
4046
  }
3752
- function renderInitializationComplete(manifest) {
3753
- return `${JSON.stringify({
3754
- kind: "agent-eval/analyst-benchmark-initialization-complete",
3755
- runIdentitySha256: manifest.identitySha256,
3756
- localIdentitySha256: manifest.localIdentitySha256,
3757
- createdAt: manifest.createdAt
3758
- }, null, 2)}\n`;
4047
+ /**
4048
+ * All (sample, block) pairs whose accepted steps intersect the segment,
4049
+ * ordered by sample then by first overlapping step — the deterministic
4050
+ * tie-break order for donor selection.
4051
+ */
4052
+ function segmentContributors(sampleAssignments, segment) {
4053
+ const contributors = [];
4054
+ sampleAssignments.forEach((assignments, sample) => {
4055
+ const overlapByBlock = /* @__PURE__ */ new Map();
4056
+ for (const { step, block } of assignments) {
4057
+ if (step < segment.firstStep || step > segment.lastStep) continue;
4058
+ overlapByBlock.set(block, (overlapByBlock.get(block) ?? 0) + 1);
4059
+ }
4060
+ for (const [block, overlapSteps] of overlapByBlock) contributors.push({
4061
+ sample,
4062
+ block,
4063
+ overlapSteps
4064
+ });
4065
+ });
4066
+ return contributors;
3759
4067
  }
3760
- async function assertAbsentOrExact(path, expected, label) {
3761
- const existing = await readOptionalRegularFile(path, label);
3762
- if (existing !== void 0 && existing !== expected) throw new Error(`${label} does not exactly match interrupted initialization: ${path}`);
4068
+ function betterDonor(left, right) {
4069
+ if (right.overlapSteps !== left.overlapSteps) return right.overlapSteps > left.overlapSteps ? right : left;
4070
+ if (right.block.confidence !== left.block.confidence) return right.block.confidence > left.block.confidence ? right : left;
4071
+ return left;
3763
4072
  }
3764
- async function readOptionalRegularFile(path, label) {
3765
- if (!await regularFileExists(path)) return void 0;
3766
- return readRegularFile(path, label);
4073
+ function publicContributor(contributor) {
4074
+ return {
4075
+ sample: contributor.sample,
4076
+ firstStep: contributor.block.firstStep,
4077
+ lastStep: contributor.block.lastStep,
4078
+ consequenceStep: contributor.block.consequenceStep,
4079
+ confidence: contributor.block.confidence,
4080
+ overlapSteps: contributor.overlapSteps
4081
+ };
3767
4082
  }
3768
- function createObservationAppender(path, runIdentitySha256, progress) {
3769
- let writes = Promise.resolve();
3770
- const seen = new Set(progress.observations.map(observationKey));
3771
- return (observation) => {
3772
- const write = writes.then(async () => {
3773
- assertAnalystBenchmarkObservation(observation, "benchmark observation");
3774
- const key = observationKey(observation);
3775
- if (seen.has(key)) throw new Error(`refusing duplicate benchmark observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}'`);
3776
- const rowWithoutDigest = {
3777
- sequence: progress.nextSequence,
3778
- runIdentitySha256,
3779
- previousRowSha256: progress.previousRowSha256,
3780
- observation
3781
- };
3782
- const row = {
3783
- ...rowWithoutDigest,
3784
- rowSha256: digestCanonical(rowWithoutDigest)
3785
- };
3786
- await appendDurable(path, `${JSON.stringify(row)}\n`);
3787
- progress.nextSequence += 1;
3788
- progress.previousRowSha256 = row.rowSha256;
3789
- progress.observations.push(observation);
3790
- seen.add(key);
4083
+ function contiguousSegments(sortedSteps) {
4084
+ const segments = [];
4085
+ for (const step of sortedSteps) {
4086
+ const current = segments[segments.length - 1];
4087
+ if (current && step === current.lastStep + 1) {
4088
+ current.lastStep = step;
4089
+ continue;
4090
+ }
4091
+ segments.push({
4092
+ firstStep: step,
4093
+ lastStep: step
3791
4094
  });
3792
- writes = write;
3793
- return write;
4095
+ }
4096
+ return segments;
4097
+ }
4098
+ //#endregion
4099
+ //#region src/analyst/benchmark-public-rlm.ts
4100
+ /** Public benchmark candidate that runs the actual recursive trace analyst. */
4101
+ function createPublicBenchmarkRlmRunner(dataset, config) {
4102
+ const costLedger = config.costLedger ?? new CostLedger();
4103
+ const samples = config.dspyRlm?.samples ?? 1;
4104
+ if (!Number.isSafeInteger(samples) || samples < 1) throw new RangeError("dspyRlm.samples must be a positive safe integer");
4105
+ if (samples > 1 && dataset !== "codetracebench") throw new Error("dspyRlm.samples > 1 requires the codetracebench dataset; step-level consensus is defined on its block grammar");
4106
+ const limits = {
4107
+ maxIterations: config.dspyRlm?.maxIterations ?? 14,
4108
+ maxLlmCalls: config.dspyRlm?.maxLlmCalls ?? 8,
4109
+ maxToolCalls: config.dspyRlm?.maxToolCalls ?? 80,
4110
+ maxOutputChars: config.dspyRlm?.maxOutputChars ?? 8e3
4111
+ };
4112
+ const pricing = config.pricing ?? pricingForModel(config.model);
4113
+ const engine = createDspyRlmTraceEngine({
4114
+ baseUrl: config.baseUrl,
4115
+ apiKey: config.apiKey,
4116
+ model: config.model,
4117
+ maxOutputTokens: config.maxOutputTokens,
4118
+ timeoutMs: config.timeoutMs,
4119
+ maxCostUsd: config.maxCostUsdPerAnalysis ?? 1,
4120
+ pricing,
4121
+ ...config.dspyRlm?.runner ? { runner: config.dspyRlm.runner } : {}
4122
+ });
4123
+ const instructions = config.instructionsOverride?.text ?? publicBenchmarkRlmInstructions(dataset);
4124
+ const protocolSha256 = effectiveAnalystProtocolSha256(dataset, config.instructionsOverride);
4125
+ const definition = publicBenchmarkDefinition(dataset, limits, instructions);
4126
+ const { instructionsOverride: _rlmOnlyOverride, ...directConfig } = config;
4127
+ const abstentionFallbackRunner = createPublicBenchmarkDirectRunner(dataset, {
4128
+ ...directConfig,
4129
+ costLedger
4130
+ });
4131
+ return {
4132
+ id: "dspy-rlm",
4133
+ async analyze(input, context) {
4134
+ const trajectoryId = trajectoryIdFromCaseId(dataset, context.caseId);
4135
+ const tags = {
4136
+ benchmarkCaseId: context.caseId,
4137
+ benchmarkRepetition: String(context.repetition)
4138
+ };
4139
+ let usage;
4140
+ let rawFindings = [];
4141
+ try {
4142
+ if (!input.traceStore) throw new Error(`${dataset} DSPy RLM runner requires a trace store`);
4143
+ if (samples > 1) {
4144
+ const store = input.traceStore;
4145
+ const caseUsageFilter = {
4146
+ channel: "analyst",
4147
+ tags
4148
+ };
4149
+ const sampleRuns = [];
4150
+ const sampleAssignments = [];
4151
+ let totalModelCalls = 0;
4152
+ let totalToolCalls = 0;
4153
+ for (let sample = 0; sample < samples; sample += 1) {
4154
+ let sampleUsage;
4155
+ const completed = await runTraceAnalyst({
4156
+ definition,
4157
+ engine,
4158
+ store,
4159
+ context: {
4160
+ runId: context.caseId,
4161
+ correlationId: `${context.caseId}:${context.repetition}:sample-${sample}`,
4162
+ costLedger,
4163
+ costPhase: "analyst.public-benchmark.dspy-rlm",
4164
+ tags,
4165
+ recordUsage: (receipt) => {
4166
+ sampleUsage = receipt;
4167
+ usage = usageReceiptFromCostLedger(costLedger, caseUsageFilter);
4168
+ },
4169
+ signal: context.signal
4170
+ }
4171
+ });
4172
+ const producedAt = (/* @__PURE__ */ new Date()).toISOString();
4173
+ const sampleFindings = completed.findings.map((finding) => makeFinding({
4174
+ analyst_id: "dspy-rlm",
4175
+ area: "incorrect",
4176
+ subject: finding.subject,
4177
+ claim: finding.claim,
4178
+ rationale: finding.rationale,
4179
+ severity: finding.severity,
4180
+ confidence: finding.confidence,
4181
+ evidence_refs: evidenceRefsFromRawFinding(finding),
4182
+ recommended_action: finding.recommended_action,
4183
+ metadata: {
4184
+ analysis_mode: "recursive",
4185
+ engine: "dspy-rlm",
4186
+ model: config.model,
4187
+ sample,
4188
+ ...codeTraceBlockMetadataFromSubject(finding.subject) ?? {}
4189
+ },
4190
+ produced_at: producedAt
4191
+ }));
4192
+ rawFindings = [...rawFindings, ...sampleFindings];
4193
+ const adapted = await adaptPublicBenchmarkFindings({
4194
+ dataset,
4195
+ trajectoryId,
4196
+ findings: sampleFindings,
4197
+ analystId: "dspy-rlm",
4198
+ store,
4199
+ ...context.signal ? { signal: context.signal } : {}
4200
+ });
4201
+ const assignments = adapted.stepBlocks ?? [];
4202
+ sampleAssignments.push(assignments);
4203
+ totalModelCalls += completed.modelCalls;
4204
+ totalToolCalls += completed.toolCalls;
4205
+ sampleRuns.push({
4206
+ sample,
4207
+ answer: completed.answer,
4208
+ trajectory: completed.trajectory,
4209
+ modelCalls: completed.modelCalls,
4210
+ toolCalls: completed.toolCalls,
4211
+ runtime: completed.runtime,
4212
+ blocks: sampleBlockRecords(assignments),
4213
+ steps: assignments.map((assignment) => assignment.step),
4214
+ ...adapted.diagnostics ? { blockDiagnostics: adapted.diagnostics } : {},
4215
+ ...sampleUsage ? { usage: sampleUsage } : {}
4216
+ });
4217
+ }
4218
+ const consensus = consensusCodeTraceBlocks(sampleAssignments);
4219
+ const expanded = await expandCodeTraceFailureBlocks({
4220
+ trajectoryId,
4221
+ blocks: consensus.blocks,
4222
+ store,
4223
+ analystId: "dspy-rlm",
4224
+ producedAt: (/* @__PURE__ */ new Date()).toISOString(),
4225
+ ...context.signal ? { signal: context.signal } : {}
4226
+ });
4227
+ let fallback;
4228
+ if (consensus.blocks.length === 0) fallback = await abstentionFallbackRunner.analyze(input, context);
4229
+ usage = usageReceiptFromCostLedger(costLedger, caseUsageFilter);
4230
+ return {
4231
+ findings: fallback && !fallback.error ? fallback.findings : expanded.findings,
4232
+ usage,
4233
+ metadata: {
4234
+ analysisMode: "recursive",
4235
+ engine: "dspy-rlm",
4236
+ protocolSha256,
4237
+ samples,
4238
+ sampleRuns,
4239
+ consensus: consensus.decision,
4240
+ blockDiagnostics: expanded.diagnostics,
4241
+ modelCalls: totalModelCalls,
4242
+ toolCalls: totalToolCalls,
4243
+ ...fallback ? {
4244
+ abstentionFallback: "direct",
4245
+ ...fallback.metadata ? { abstentionFallbackMetadata: fallback.metadata } : {},
4246
+ ...fallback.error ? { abstentionFallbackError: fallback.error } : {}
4247
+ } : {}
4248
+ }
4249
+ };
4250
+ }
4251
+ const completed = await runTraceAnalyst({
4252
+ definition,
4253
+ engine,
4254
+ store: input.traceStore,
4255
+ context: {
4256
+ runId: context.caseId,
4257
+ correlationId: `${context.caseId}:${context.repetition}`,
4258
+ costLedger,
4259
+ costPhase: "analyst.public-benchmark.dspy-rlm",
4260
+ tags,
4261
+ recordUsage: (receipt) => {
4262
+ usage = receipt;
4263
+ },
4264
+ signal: context.signal
4265
+ }
4266
+ });
4267
+ const producedAt = (/* @__PURE__ */ new Date()).toISOString();
4268
+ rawFindings = completed.findings.map((finding) => makeFinding({
4269
+ analyst_id: "dspy-rlm",
4270
+ area: dataset === "agentrx" ? "root-cause" : "incorrect",
4271
+ subject: finding.subject,
4272
+ claim: finding.claim,
4273
+ rationale: finding.rationale,
4274
+ severity: finding.severity,
4275
+ confidence: finding.confidence,
4276
+ evidence_refs: evidenceRefsFromRawFinding(finding),
4277
+ recommended_action: finding.recommended_action,
4278
+ metadata: {
4279
+ analysis_mode: "recursive",
4280
+ engine: "dspy-rlm",
4281
+ model: config.model,
4282
+ ...dataset === "codetracebench" ? codeTraceBlockMetadataFromSubject(finding.subject) : {}
4283
+ },
4284
+ produced_at: producedAt
4285
+ }));
4286
+ const adapted = await adaptPublicBenchmarkFindings({
4287
+ dataset,
4288
+ trajectoryId,
4289
+ findings: rawFindings,
4290
+ analystId: "dspy-rlm",
4291
+ store: input.traceStore,
4292
+ ...context.signal ? { signal: context.signal } : {}
4293
+ });
4294
+ let fallback;
4295
+ if (completed.findings.length === 0) {
4296
+ fallback = await abstentionFallbackRunner.analyze(input, context);
4297
+ usage = usageReceiptFromCostLedger(costLedger, {
4298
+ channel: "analyst",
4299
+ tags: {
4300
+ benchmarkCaseId: context.caseId,
4301
+ benchmarkRepetition: String(context.repetition)
4302
+ }
4303
+ });
4304
+ }
4305
+ return {
4306
+ findings: fallback && !fallback.error ? fallback.findings : adapted.findings,
4307
+ usage,
4308
+ metadata: {
4309
+ analysisMode: "recursive",
4310
+ engine: "dspy-rlm",
4311
+ protocolSha256,
4312
+ ...adapted.diagnostics ? { blockDiagnostics: adapted.diagnostics } : {},
4313
+ answer: completed.answer,
4314
+ trajectory: completed.trajectory,
4315
+ modelCalls: completed.modelCalls,
4316
+ toolCalls: completed.toolCalls,
4317
+ runtime: completed.runtime,
4318
+ ...fallback ? {
4319
+ abstentionFallback: "direct",
4320
+ ...fallback.metadata ? { abstentionFallbackMetadata: fallback.metadata } : {},
4321
+ ...fallback.error ? { abstentionFallbackError: fallback.error } : {}
4322
+ } : {}
4323
+ }
4324
+ };
4325
+ } catch (error) {
4326
+ if (context.signal?.aborted) throw error;
4327
+ if (isPaidCallControlError(error)) throw error;
4328
+ return {
4329
+ findings: [],
4330
+ usage,
4331
+ error: publicBenchmarkError(error, [config.apiKey]),
4332
+ metadata: {
4333
+ analysisMode: "recursive",
4334
+ engine: "dspy-rlm",
4335
+ ...samples > 1 ? { samples } : {},
4336
+ rawFindings
4337
+ }
4338
+ };
4339
+ }
4340
+ }
3794
4341
  };
3795
4342
  }
3796
- async function readProgress(path, runIdentitySha256, caseIds, repetitions, analystRunnerId) {
3797
- const rawLines = (await readRegularFile(path, "benchmark observation log")).split("\n");
3798
- if (rawLines.at(-1) === "") rawLines.pop();
3799
- const observations = [];
3800
- const seen = /* @__PURE__ */ new Set();
3801
- const executionIndexes = /* @__PURE__ */ new Set();
3802
- let previousRowSha256 = null;
3803
- const allowedCases = new Set(caseIds);
3804
- const plannedObservationCount = caseIds.length * 2 * repetitions;
3805
- for (const [index, line] of rawLines.entries()) {
3806
- if (!line.trim()) throw new Error(`benchmark observation log contains an empty row at line ${index + 1}`);
3807
- const parsed = parseJson(line, `${path}:${index + 1}`);
3808
- if (!isRecord$1(parsed)) throw new TypeError(`benchmark observation row ${index + 1} must be an object`);
3809
- assertExactKeys(parsed, [
3810
- "sequence",
3811
- "runIdentitySha256",
3812
- "previousRowSha256",
3813
- "observation",
3814
- "rowSha256"
3815
- ], `benchmark observation row ${index + 1}`);
3816
- assertAnalystBenchmarkObservation(parsed.observation, `benchmark observation row ${index + 1}.observation`);
3817
- const observation = parsed.observation;
3818
- const key = observationKey(observation);
3819
- if (seen.has(key)) throw new Error(`duplicate benchmark observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}' at line ${index + 1}`);
3820
- if (parsed.sequence !== index) throw new Error(`benchmark observation row ${index + 1} has sequence ${String(parsed.sequence)}; expected ${index}`);
3821
- if (parsed.runIdentitySha256 !== runIdentitySha256) throw new Error(`benchmark observation row ${index + 1} belongs to another run`);
3822
- if (parsed.previousRowSha256 !== previousRowSha256) throw new Error(`benchmark observation row ${index + 1} breaks the digest chain`);
3823
- if (!isSha256(parsed.rowSha256)) throw new TypeError(`benchmark observation row ${index + 1} has an invalid digest`);
3824
- if (digestCanonical({
3825
- sequence: parsed.sequence,
3826
- runIdentitySha256: parsed.runIdentitySha256,
3827
- previousRowSha256: parsed.previousRowSha256,
3828
- observation
3829
- }) !== parsed.rowSha256) throw new Error(`benchmark observation row ${index + 1} digest does not match its contents`);
3830
- if (!allowedCases.has(observation.caseId) || observation.runnerId !== "empty" && observation.runnerId !== analystRunnerId || observation.repetition >= repetitions || observation.executionIndex >= plannedObservationCount) throw new Error(`benchmark observation row ${index + 1} does not match a planned case, runner, and repetition`);
3831
- if (executionIndexes.has(observation.executionIndex)) throw new Error(`duplicate benchmark executionIndex ${observation.executionIndex} at line ${index + 1}`);
3832
- observations.push(observation);
3833
- seen.add(key);
3834
- executionIndexes.add(observation.executionIndex);
3835
- previousRowSha256 = parsed.rowSha256;
4343
+ /** Per-sample accepted blocks with the exact steps the expansion kept for each. */
4344
+ function sampleBlockRecords(assignments) {
4345
+ const stepsByBlock = /* @__PURE__ */ new Map();
4346
+ for (const { step, block } of assignments) {
4347
+ const steps = stepsByBlock.get(block);
4348
+ if (steps) steps.push(step);
4349
+ else stepsByBlock.set(block, [step]);
3836
4350
  }
4351
+ return [...stepsByBlock].map(([block, acceptedSteps]) => ({
4352
+ firstStep: block.firstStep,
4353
+ lastStep: block.lastStep,
4354
+ consequenceStep: block.consequenceStep,
4355
+ escapeStatus: block.escapeStatus,
4356
+ severity: block.severity,
4357
+ confidence: block.confidence,
4358
+ claim: block.claim,
4359
+ acceptedSteps
4360
+ }));
4361
+ }
4362
+ function publicBenchmarkDefinition(dataset, limits, instructions) {
3837
4363
  return {
3838
- observations,
3839
- nextSequence: observations.length,
3840
- previousRowSha256
4364
+ id: dataset === "agentrx" ? "agentrx-dspy-rlm" : "codetracebench-dspy-rlm",
4365
+ description: dataset === "agentrx" ? "Localizes the first unrecoverable root-cause step." : "Localizes every incorrect state-changing assistant step.",
4366
+ area: dataset === "agentrx" ? "root-cause" : "incorrect",
4367
+ version: "1.0.0",
4368
+ question: dataset === "agentrx" ? "What is the first unrecoverable root cause in this failed trajectory?" : "Which assistant steps are incorrect under the CodeTraceBench definition?",
4369
+ instructions,
4370
+ toolGroup: "singleTrace",
4371
+ limits
3841
4372
  };
3842
4373
  }
3843
- async function writeExclusiveOrVerify(path, content) {
3844
- try {
3845
- await writeExclusive(path, content);
3846
- } catch (error) {
3847
- if (!isNodeError(error, "EEXIST")) throw error;
3848
- if (await readRegularFile(path, "existing benchmark artifact") !== content) throw new Error(`refusing to replace existing benchmark artifact: ${path}`);
3849
- }
4374
+ function pricingForModel(model) {
4375
+ const pricing = resolveModelPricing(model);
4376
+ if (!pricing) throw new Error(`no pricing is configured for '${model}'; provide PublicAnalystBenchmarkModelConfig.pricing`);
4377
+ return {
4378
+ inputUsdPerMillion: pricing.input * 1e3,
4379
+ outputUsdPerMillion: pricing.output * 1e3
4380
+ };
3850
4381
  }
3851
- async function regularFileExists(path) {
3852
- try {
3853
- const fileStat = await lstat(path);
3854
- if (!fileStat.isFile() || fileStat.isSymbolicLink()) throw new Error(`benchmark artifact path must be a real file: ${path}`);
3855
- return true;
3856
- } catch (error) {
3857
- if (isNodeError(error, "ENOENT")) return false;
3858
- throw error;
3859
- }
4382
+ function trajectoryIdFromCaseId(dataset, caseId) {
4383
+ const prefix = dataset === "agentrx" ? "agentrx:" : "codetrace:";
4384
+ if (!caseId.startsWith(prefix) || caseId.length === prefix.length) throw new Error(`unexpected ${dataset} benchmark case id '${caseId}'`);
4385
+ return caseId.slice(prefix.length);
3860
4386
  }
3861
- async function appendDurable(path, content) {
3862
- const handle = await open(path, constants.O_APPEND | constants.O_WRONLY | constants.O_NOFOLLOW);
4387
+ function isPaidCallControlError(error) {
4388
+ return error instanceof CostAccountingIncompleteError || error instanceof CostCallConflictError || error instanceof CostCeilingReachedError || error instanceof CostLedgerPersistenceError || error instanceof CostReceiptCaptureError || error instanceof CostReservationExceededError;
4389
+ }
4390
+ //#endregion
4391
+ //#region src/analyst/benchmark-public-data.ts
4392
+ const DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES = 256 * 1024 * 1024;
4393
+ const INPUT_OPEN_FLAGS = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0);
4394
+ async function loadPublicBenchmarkRows(path) {
4395
+ return parsePublicBenchmarkRows((await readImmutableInputSnapshot(resolve(path), DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES)).text, path);
4396
+ }
4397
+ function parsePublicBenchmarkRows(text, path) {
4398
+ const trimmed = text.trim();
4399
+ if (!trimmed) throw new Error(`public analyst benchmark dataset is empty: ${path}`);
4400
+ let parsed;
3863
4401
  try {
3864
- await handle.writeFile(content, "utf8");
3865
- await handle.sync();
3866
- } finally {
3867
- await handle.close();
4402
+ parsed = JSON.parse(trimmed);
4403
+ } catch {
4404
+ return parseJsonl(trimmed, path);
3868
4405
  }
4406
+ if (Array.isArray(parsed)) return records(parsed, path);
4407
+ if (isRecord(parsed) && Array.isArray(parsed.data)) return records(parsed.data, `${path}.data`);
4408
+ if (isRecord(parsed) && Array.isArray(parsed.cases)) return records(parsed.cases, `${path}.cases`);
4409
+ if (isRecord(parsed)) return [parsed];
4410
+ throw new TypeError(`public analyst benchmark dataset must contain JSON objects: ${path}`);
3869
4411
  }
3870
- async function writeExclusive(path, content) {
3871
- const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
3872
- let handle;
3873
- try {
3874
- handle = await open(temporary, "wx");
3875
- await handle.writeFile(content, "utf8");
3876
- await handle.sync();
3877
- await handle.close();
3878
- handle = void 0;
3879
- await link(temporary, path);
3880
- await syncDirectory(dirname(path));
3881
- } finally {
3882
- await handle?.close().catch(() => void 0);
3883
- await unlink(temporary).catch(() => void 0);
4412
+ function selectPublicBenchmarkRows(dataset, rows, options) {
4413
+ positiveSafeInteger(options.limit, "limit");
4414
+ safeInteger(options.seed, "seed");
4415
+ if (rows.length === 0) throw new Error("public analyst benchmark dataset has no rows");
4416
+ const byId = /* @__PURE__ */ new Map();
4417
+ for (const row of rows) {
4418
+ const id = publicBenchmarkRowId(dataset, row);
4419
+ if (byId.has(id)) throw new Error(`public analyst benchmark dataset repeats trajectory id '${id}'`);
4420
+ byId.set(id, row);
3884
4421
  }
4422
+ return [...byId].sort(([left], [right]) => selectionKey(options.seed, left).localeCompare(selectionKey(options.seed, right)) || left.localeCompare(right)).slice(0, Math.min(options.limit, byId.size)).map(([, row]) => row);
3885
4423
  }
3886
- async function readRegularFile(path, label) {
3887
- let fileStat;
3888
- try {
3889
- fileStat = await lstat(path);
3890
- } catch (error) {
3891
- if (isNodeError(error, "ENOENT")) throw new Error(`${label} is missing: ${path}`);
3892
- throw error;
4424
+ function publicBenchmarkDistributions(dataset, rows) {
4425
+ const values = {
4426
+ class: [],
4427
+ agent: [],
4428
+ model: [],
4429
+ difficulty: [],
4430
+ solved: []
4431
+ };
4432
+ for (const row of rows) {
4433
+ const benchmarkCase = dataset === "agentrx" ? agentRxBenchmarkCase(row, void 0) : codeTraceBenchCase(row, void 0);
4434
+ values.class.push(dataset === "codetracebench" ? benchmarkCase.expectedIssues.length > 0 ? "positive" : row.solved === true ? "trusted-negative" : row.solved === false ? "unlabeled-failure" : "unlabeled-unknown" : benchmarkCase.expectedIssues[0]?.areas?.[0]);
4435
+ values.agent.push(scalarDistributionValue(row.agent) ?? (dataset === "agentrx" ? rootAgent(row) : void 0));
4436
+ values.model.push(scalarDistributionValue(row.model));
4437
+ values.difficulty.push(scalarDistributionValue(row.difficulty));
4438
+ values.solved.push(scalarDistributionValue(row.solved));
3893
4439
  }
3894
- if (!fileStat.isFile() || fileStat.isSymbolicLink()) throw new Error(`${label} must be a real file: ${path}`);
3895
- return readFile(path, "utf8");
4440
+ return {
4441
+ class: valueDistribution(values.class),
4442
+ agent: valueDistribution(values.agent),
4443
+ model: valueDistribution(values.model),
4444
+ difficulty: valueDistribution(values.difficulty),
4445
+ solved: valueDistribution(values.solved)
4446
+ };
3896
4447
  }
3897
- async function syncDirectory(path) {
3898
- const directory = await open(path, "r");
3899
- try {
3900
- await directory.sync();
3901
- } finally {
3902
- await directory.close();
4448
+ function publicBenchmarkSelectionReport(dataset, source, selected, seed) {
4449
+ const census = source.length === selected.length;
4450
+ return {
4451
+ method: census ? "census" : "deterministic-hash",
4452
+ seed,
4453
+ sourceCount: source.length,
4454
+ selectedCount: selected.length,
4455
+ stratified: false,
4456
+ representativeOfInput: census,
4457
+ source: publicBenchmarkDistributions(dataset, source),
4458
+ selected: publicBenchmarkDistributions(dataset, selected)
4459
+ };
4460
+ }
4461
+ async function preparePublicAnalystBenchmark(options) {
4462
+ const labelsPath = resolve(options.labelsPath);
4463
+ const traceRoot = resolve(options.traceDir);
4464
+ const artifactRoot = options.artifactDir ? resolve(options.artifactDir) : void 0;
4465
+ const labelSnapshot = await readImmutableInputSnapshot(labelsPath, DEFAULT_MAX_PUBLIC_BENCHMARK_LABEL_BYTES);
4466
+ const rows = parsePublicBenchmarkRows(labelSnapshot.text, labelsPath);
4467
+ const selected = selectPublicBenchmarkRows(options.dataset, rows, {
4468
+ limit: options.limit,
4469
+ seed: options.seed
4470
+ });
4471
+ const stores = await indexSelectedSingleTraceFiles(traceRoot, new Set(selected.map((row) => publicBenchmarkRowId(options.dataset, row))));
4472
+ const resolver = traceStoreEvidenceResolver((input) => {
4473
+ if (!input.traceStore) throw new Error("prepared benchmark case has no trace store");
4474
+ return input.traceStore;
4475
+ });
4476
+ const traceFiles = [];
4477
+ const verificationArtifacts = [];
4478
+ const cases = [];
4479
+ for (const row of selected) {
4480
+ const trajectoryId = publicBenchmarkRowId(options.dataset, row);
4481
+ const indexed = stores.get(trajectoryId);
4482
+ if (!indexed) throw new Error(`public analyst benchmark trace directory has no single-trace OTLP JSONL for '${trajectoryId}'`);
4483
+ let modelVisibleOtlp = indexed.text;
4484
+ let traceStore = indexed.store;
4485
+ let artifactDir;
4486
+ let verificationManifest;
4487
+ if (options.dataset === "codetracebench") {
4488
+ if (!options.artifactDir?.trim()) throw new Error("--artifact-dir is required for CodeTraceBench so final verification evidence is not omitted");
4489
+ const artifacts = await loadCodeTraceVerificationArtifacts({
4490
+ artifactDir: options.artifactDir,
4491
+ row,
4492
+ maxBytes: options.maxArtifactBytes ?? 8388608
4493
+ });
4494
+ for (const artifact of artifacts.files) assertNoBenchmarkLabelsInArtifact({
4495
+ traceId: trajectoryId,
4496
+ relativePath: artifact.relativePath,
4497
+ content: artifact.content
4498
+ });
4499
+ verificationManifest = shareableVerificationManifest(artifacts.manifest, artifactRoot ?? resolve(options.artifactDir));
4500
+ const collisions = await indexed.store.hasSpans({
4501
+ trace_id: trajectoryId,
4502
+ span_ids: [...artifacts.manifest.files.map((file) => file.spanId), artifacts.manifest.outcomeSpanId]
4503
+ });
4504
+ if (collisions.length > 0) throw new Error(`CodeTraceBench '${trajectoryId}' trace already contains benchmark verification span '${collisions[0]}'`);
4505
+ modelVisibleOtlp = appendVerificationArtifactsToOtlp(indexed.text, trajectoryId, artifacts, indexed.latestTimestamp);
4506
+ traceStore = otlpTextToTraceAnalysisStore(modelVisibleOtlp);
4507
+ artifactDir = artifacts.manifest.status === "present" ? artifacts.manifest.caseDirectory : void 0;
4508
+ verificationArtifacts.push(verificationManifest);
4509
+ }
4510
+ const labelLeakScan = assertNoBenchmarkLabelsInTrace({
4511
+ traceId: trajectoryId,
4512
+ otlpText: modelVisibleOtlp
4513
+ });
4514
+ const input = {
4515
+ traceStore,
4516
+ artifactDir
4517
+ };
4518
+ const benchmarkCase = options.dataset === "agentrx" ? agentRxBenchmarkCase(row, input, { stepCount: indexed.stepCount }) : codeTraceBenchCase(row, input);
4519
+ for (const evidence of benchmarkCase.labeledEvidence ?? []) if (!await resolver({
4520
+ caseId: benchmarkCase.id,
4521
+ caseInput: input,
4522
+ evidence: {
4523
+ kind: evidence.kind ?? "span",
4524
+ uri: evidence.uri
4525
+ }
4526
+ })) throw new Error(`${benchmarkCase.id}: missing labeled span ${spanIdFromEvidence(evidence.uri) ?? evidence.uri} in ${indexed.path}`);
4527
+ cases.push({
4528
+ ...benchmarkCase,
4529
+ metadata: {
4530
+ ...benchmarkCase.metadata,
4531
+ traceFileRelativePath: slashRelative(traceRoot, indexed.path),
4532
+ traceFileSha256: indexed.sha256,
4533
+ labelLeakScan,
4534
+ ...verificationManifest ? { verificationArtifacts: verificationManifest } : {}
4535
+ }
4536
+ });
4537
+ traceFiles.push({
4538
+ traceId: trajectoryId,
4539
+ relativePath: slashRelative(traceRoot, indexed.path),
4540
+ sha256: indexed.sha256
4541
+ });
3903
4542
  }
3904
- }
3905
- function isNodeError(error, code) {
3906
- return error instanceof Error && "code" in error && error.code === code;
3907
- }
3908
- //#endregion
3909
- //#region src/analyst/benchmark-comparison.ts
3910
- function compareAnalystRunners(result, options) {
3911
- const confidence = options.confidence ?? .95;
3912
- const resamples = options.resamples ?? 2e3;
3913
- assertComparisonControls(confidence, resamples);
3914
- const runnerIds = new Set(result.summaries.map((summary) => summary.runnerId));
3915
- if (!runnerIds.has(options.baselineRunnerId)) throw new TypeError(`unknown baseline analyst runner '${options.baselineRunnerId}'`);
3916
- if (!runnerIds.has(options.candidateRunnerId)) throw new TypeError(`unknown candidate analyst runner '${options.candidateRunnerId}'`);
3917
- if (options.baselineRunnerId === options.candidateRunnerId) throw new TypeError("baseline and candidate analyst runners must be different");
3918
- const baseline = observationsByCase(result.observations, options.baselineRunnerId);
3919
- const candidate = observationsByCase(result.observations, options.candidateRunnerId);
3920
- const populationRepresentativenessProven = result.provenance.metadata?.populationRepresentativenessProven === true;
3921
- const metrics = METRICS.map((metric) => compareMetric({
3922
- metric,
3923
- baseline,
3924
- candidate,
3925
- confidence,
3926
- resamples,
3927
- seed: options.seed,
3928
- populationRepresentativenessProven
3929
- }));
3930
4543
  return {
3931
- baselineRunnerId: options.baselineRunnerId,
3932
- candidateRunnerId: options.candidateRunnerId,
3933
- metrics
4544
+ cases,
4545
+ sourceRowCount: rows.length,
4546
+ selectedCaseIds: cases.map((testCase) => testCase.id),
4547
+ labelsSha256: labelSnapshot.sha256,
4548
+ traceFiles,
4549
+ verificationArtifacts,
4550
+ selection: publicBenchmarkSelectionReport(options.dataset, rows, selected, options.seed)
3934
4551
  };
3935
4552
  }
3936
- function compareMetric(options) {
3937
- const pairedCases = [];
3938
- let eligibleObservations = 0;
3939
- let pairedObservations = 0;
3940
- let baselineMissingObservations = 0;
3941
- let candidateMissingObservations = 0;
3942
- let asymmetricMissingObservations = 0;
3943
- const caseIds = /* @__PURE__ */ new Set([...options.baseline.keys(), ...options.candidate.keys()]);
3944
- for (const caseId of caseIds) {
3945
- const baselineByRepetition = new Map((options.baseline.get(caseId) ?? []).map((observation) => [observation.repetition, observation]));
3946
- const candidateByRepetition = new Map((options.candidate.get(caseId) ?? []).map((observation) => [observation.repetition, observation]));
3947
- const caseBefore = [];
3948
- const caseAfter = [];
3949
- let clusterId;
3950
- const repetitions = /* @__PURE__ */ new Set([...baselineByRepetition.keys(), ...candidateByRepetition.keys()]);
3951
- for (const repetition of repetitions) {
3952
- const baselineObservation = baselineByRepetition.get(repetition);
3953
- const candidateObservation = candidateByRepetition.get(repetition);
3954
- const identity = baselineObservation ?? candidateObservation;
3955
- if (!identity || !metricApplies(identity, options.metric)) continue;
3956
- if (baselineObservation && candidateObservation) assertSameCaseIdentity(baselineObservation, candidateObservation);
3957
- eligibleObservations += 1;
3958
- clusterId = identity.clusterId;
3959
- const baselineValue = baselineObservation ? metricValue(baselineObservation, options.metric) : null;
3960
- const candidateValue = candidateObservation ? metricValue(candidateObservation, options.metric) : null;
3961
- const baselineMissing = baselineValue === null;
3962
- const candidateMissing = candidateValue === null;
3963
- if (baselineMissing) baselineMissingObservations += 1;
3964
- if (candidateMissing) candidateMissingObservations += 1;
3965
- if (baselineMissing !== candidateMissing) asymmetricMissingObservations += 1;
3966
- if (baselineMissing || candidateMissing) continue;
3967
- caseBefore.push(baselineValue);
3968
- caseAfter.push(candidateValue);
3969
- pairedObservations += 1;
3970
- }
3971
- if (caseBefore.length === 0 || !clusterId) continue;
3972
- pairedCases.push({
3973
- clusterId,
3974
- baseline: mean$1(caseBefore),
3975
- candidate: mean$1(caseAfter)
4553
+ async function indexSelectedSingleTraceFiles(traceDir, selectedTraceIds) {
4554
+ if (selectedTraceIds.size === 0) throw new Error("public analyst benchmark selected no trace ids");
4555
+ const files = (await readdir(traceDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => resolve(traceDir, entry.name)).sort();
4556
+ if (files.length === 0) throw new Error(`public analyst benchmark trace directory has no JSONL files: ${traceDir}`);
4557
+ const indexed = /* @__PURE__ */ new Map();
4558
+ for (const path of files) {
4559
+ const snapshot = await readImmutableInputSnapshot(path, DEFAULT_MAX_TRACE_FILE_BYTES);
4560
+ const store = createOtlpBufferTraceStore(snapshot.bytes);
4561
+ const overview = await store.getOverview();
4562
+ if (overview.total_traces !== 1 || overview.sample_trace_ids.length !== 1) throw new Error(`public analyst benchmark trace file must contain exactly one trace: ${path} contains ${overview.total_traces}`);
4563
+ if (!overview.time_range) throw new Error(`public analyst benchmark trace file has no valid timestamps: ${path}`);
4564
+ const traceId = overview.sample_trace_ids[0];
4565
+ if (!selectedTraceIds.has(traceId)) continue;
4566
+ if (indexed.has(traceId)) throw new Error(`public analyst benchmark trace id '${traceId}' appears in multiple files`);
4567
+ indexed.set(traceId, {
4568
+ path,
4569
+ sha256: snapshot.sha256,
4570
+ store,
4571
+ latestTimestamp: overview.time_range.latest,
4572
+ text: snapshot.text,
4573
+ stepCount: traceStepCount(snapshot.text, path)
3976
4574
  });
3977
4575
  }
3978
- const byCluster = /* @__PURE__ */ new Map();
3979
- for (const pairedCase of pairedCases) {
3980
- const rows = byCluster.get(pairedCase.clusterId) ?? [];
3981
- rows.push(pairedCase);
3982
- byCluster.set(pairedCase.clusterId, rows);
3983
- }
3984
- const before = [...byCluster.values()].map((rows) => mean$1(rows.map((row) => row.baseline)));
3985
- const after = [...byCluster.values()].map((rows) => mean$1(rows.map((row) => row.candidate)));
3986
- const interval = before.length === 0 ? null : pairedBootstrap(before, after, {
3987
- confidence: options.confidence,
3988
- resamples: options.resamples,
3989
- statistic: "mean",
3990
- seed: options.seed
3991
- });
3992
- const survivorOnly = pairedObservations < eligibleObservations;
3993
- const limitations = [];
3994
- if (!interval?.gateEligible) limitations.push("fewer-than-20-independent-clusters");
3995
- if (!options.populationRepresentativenessProven) limitations.push("population-representativeness-not-proven");
3996
- if (survivorOnly) limitations.push("missing-observations");
3997
- const comparison = {
3998
- metric: options.metric,
3999
- direction: LOWER_IS_BETTER.has(options.metric) ? "lower" : "higher",
4000
- pairedCases: pairedCases.length,
4001
- pairedClusters: before.length,
4002
- eligibleObservations,
4003
- pairedObservations,
4004
- baselineMissingObservations,
4005
- candidateMissingObservations,
4006
- asymmetricMissingObservations,
4007
- survivorOnly,
4008
- baselineMean: before.length === 0 ? null : mean$1(before),
4009
- candidateMean: after.length === 0 ? null : mean$1(after),
4010
- meanDelta: interval?.mean ?? null,
4011
- intervalLow: interval?.low ?? null,
4012
- intervalHigh: interval?.high ?? null,
4013
- confidence: options.confidence,
4014
- resamples: options.resamples,
4015
- minimumSampleMet: interval?.gateEligible ?? false,
4016
- populationInferenceEligible: limitations.length === 0,
4017
- inferenceLimitations: limitations
4018
- };
4019
- assertValidComparison(comparison);
4020
- return comparison;
4576
+ return indexed;
4021
4577
  }
4022
- const METRICS = [
4023
- "completion",
4024
- "issueRecall",
4025
- "findingPrecision",
4026
- "f1",
4027
- "criticalStepAccuracy",
4028
- "citationCoverage",
4029
- "citationExcerptCoverage",
4030
- "citationLabelAgreement",
4031
- "citationResolution",
4032
- "trustedNegativeAccuracy",
4033
- "latencyMs",
4034
- "calls",
4035
- "inputTokens",
4036
- "outputTokens",
4037
- "reasoningTokens",
4038
- "cachedTokens",
4039
- "cacheWriteTokens",
4040
- "costUsd"
4041
- ];
4042
- const LOWER_IS_BETTER = /* @__PURE__ */ new Set([
4043
- "latencyMs",
4044
- "calls",
4045
- "inputTokens",
4046
- "outputTokens",
4047
- "reasoningTokens",
4048
- "cachedTokens",
4049
- "cacheWriteTokens",
4050
- "costUsd"
4051
- ]);
4052
- function observationsByCase(observations, runnerId) {
4053
- const byCase = /* @__PURE__ */ new Map();
4054
- for (const observation of observations) {
4055
- if (observation.runnerId !== runnerId) continue;
4056
- const rows = byCase.get(observation.caseId) ?? [];
4057
- rows.push(observation);
4058
- byCase.set(observation.caseId, rows);
4578
+ async function readImmutableInputSnapshot(path, maxBytes) {
4579
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new RangeError("benchmark input maxBytes must be a positive safe integer");
4580
+ const handle = await open(path, INPUT_OPEN_FLAGS);
4581
+ try {
4582
+ return await readImmutableInputHandle(handle, path, maxBytes);
4583
+ } finally {
4584
+ await handle.close();
4059
4585
  }
4060
- return byCase;
4061
- }
4062
- function assertSameCaseIdentity(baseline, candidate) {
4063
- if (baseline.clusterId !== candidate.clusterId || baseline.labelState !== candidate.labelState) throw new Error(`analyst comparison case identity differs for '${baseline.caseId}' repetition ${baseline.repetition}`);
4064
- }
4065
- function metricApplies(observation, metric) {
4066
- if (metric === "trustedNegativeAccuracy") return observation.labelState === "trusted-negative";
4067
- if (metric === "issueRecall" || metric === "findingPrecision" || metric === "f1") return observation.labelState === "positive";
4068
- if (metric === "criticalStepAccuracy") return observation.labelState === "positive" && observation.score.criticalStepAccuracy !== null;
4069
- return true;
4070
4586
  }
4071
- function metricValue(observation, metric) {
4072
- if (metric === "completion") return observation.error ? 0 : 1;
4073
- if (metric === "latencyMs") return observation.latencyMs;
4074
- if (metric === "trustedNegativeAccuracy") {
4075
- if (observation.error) return 0;
4076
- return observation.score.predictionOnLabelEmptyCase ? 0 : 1;
4587
+ async function readImmutableInputHandle(handle, path, maxBytes) {
4588
+ const before = await handle.stat({ bigint: true });
4589
+ if (!before.isFile()) throw new TypeError(`public analyst benchmark input must be a regular file: ${path}`);
4590
+ if (before.size > BigInt(maxBytes)) throw new RangeError(`public analyst benchmark input exceeds ${maxBytes} bytes: ${path} has ${before.size}`);
4591
+ const size = Number(before.size);
4592
+ const bytes = Buffer.allocUnsafe(size);
4593
+ let offset = 0;
4594
+ while (offset < size) {
4595
+ const result = await handle.read(bytes, offset, size - offset, offset);
4596
+ if (result.bytesRead === 0) throw new Error(`public analyst benchmark input changed while being read: ${path}`);
4597
+ offset += result.bytesRead;
4077
4598
  }
4078
- if (observation.error && (metric === "issueRecall" || metric === "findingPrecision" || metric === "f1" || metric === "criticalStepAccuracy")) return 0;
4079
- if (observation.error && (metric === "citationCoverage" || metric === "citationExcerptCoverage" || metric === "citationLabelAgreement" || metric === "citationResolution")) return null;
4080
- if (metric === "issueRecall") return observation.score.issueRecall;
4081
- if (metric === "findingPrecision") return observation.score.findingPrecision;
4082
- if (metric === "f1") return observation.score.f1;
4083
- if (metric === "criticalStepAccuracy") return observation.score.criticalStepAccuracy;
4084
- if (metric === "citationCoverage") return observation.score.citationCoverage;
4085
- if (metric === "citationExcerptCoverage") return observation.score.citationExcerptCoverage;
4086
- if (metric === "citationLabelAgreement") return observation.score.citationLabelAgreement;
4087
- if (metric === "citationResolution") return observation.evidenceResolution?.validity ?? null;
4088
- if (metric === "calls") return observation.usage?.calls ?? null;
4089
- if (metric === "inputTokens") return observation.usage?.tokens?.input ?? null;
4090
- if (metric === "outputTokens") return observation.usage?.tokens?.output ?? null;
4091
- if (metric === "reasoningTokens") return observation.usage?.tokens?.reasoning ?? null;
4092
- if (metric === "cachedTokens") return observation.usage?.tokens?.cached ?? null;
4093
- if (metric === "cacheWriteTokens") return observation.usage?.tokens?.cacheWrite ?? null;
4094
- if (observation.usage?.cost.kind === "uncaptured") return null;
4095
- return observation.usage?.cost.usd ?? null;
4096
- }
4097
- function mean$1(values) {
4098
- return values.reduce((sum, value) => sum + value, 0) / values.length;
4099
- }
4100
- function assertComparisonControls(confidence, resamples) {
4101
- if (!Number.isSafeInteger(resamples) || resamples <= 0 || resamples > 1e6) throw new Error(`compareAnalystRunners: resamples must be a positive safe integer no greater than 1000000, got ${String(resamples)}`);
4102
- if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) throw new Error(`compareAnalystRunners: confidence must be a finite number in (0,1), got ${String(confidence)}`);
4599
+ const overflow = Buffer.allocUnsafe(1);
4600
+ const extra = await handle.read(overflow, 0, 1, size);
4601
+ const after = await handle.stat({ bigint: true });
4602
+ if (extra.bytesRead !== 0 || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs) throw new Error(`public analyst benchmark input changed while being read: ${path}`);
4603
+ let text;
4604
+ try {
4605
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
4606
+ } catch (error) {
4607
+ throw new TypeError(`public analyst benchmark input is not valid UTF-8: ${path}: ${error instanceof Error ? error.message : String(error)}`);
4608
+ }
4609
+ return Object.freeze({
4610
+ bytes,
4611
+ sha256: sha256Digest(bytes),
4612
+ text
4613
+ });
4103
4614
  }
4104
- function assertValidComparison(comparison) {
4105
- if ([
4106
- "pairedCases",
4107
- "pairedClusters",
4108
- "eligibleObservations",
4109
- "pairedObservations",
4110
- "baselineMissingObservations",
4111
- "candidateMissingObservations",
4112
- "asymmetricMissingObservations",
4113
- "confidence",
4114
- "resamples"
4115
- ].some((field) => !Number.isFinite(comparison[field])) || [
4116
- "baselineMean",
4117
- "candidateMean",
4118
- "meanDelta",
4119
- "intervalLow",
4120
- "intervalHigh"
4121
- ].some((field) => comparison[field] !== null && !Number.isFinite(comparison[field]))) throw new Error(`compareAnalystRunners: ${comparison.metric} produced non-finite comparison output`);
4122
- if (comparison.intervalLow !== null && comparison.intervalHigh !== null && comparison.intervalLow > comparison.intervalHigh) throw new Error(`compareAnalystRunners: ${comparison.metric} produced an invalid confidence interval`);
4615
+ function traceStepCount(text, path) {
4616
+ const steps = parseJsonl(text, path).map((row) => row.span_id).filter((spanId) => typeof spanId === "string").map((spanId) => /^step-(\d+)$/.exec(spanId)?.[1]).filter((step) => step !== void 0).map(Number).filter((step) => Number.isSafeInteger(step) && step > 0);
4617
+ if (steps.length === 0) throw new Error(`public analyst benchmark trace has no step-<n> spans: ${path}`);
4618
+ return Math.max(...steps);
4123
4619
  }
4124
- //#endregion
4125
- //#region src/analyst/benchmark-public-calibration.ts
4126
- function summarizeCodeTraceCalibration(result) {
4620
+ function shareableVerificationManifest(manifest, artifactRoot) {
4127
4621
  return {
4128
- protocol: "labeled-positive-and-solved-negative",
4129
- rationale: "Uses rows with incorrect-step labels as positives and solved label-empty rows as trusted negatives. Failed label-empty rows remain in the published result but are not treated as clean controls.",
4130
- runners: result.provenance.runnerIds.map((runnerId) => summarizeRunner(runnerId, result.observations.filter((observation) => observation.runnerId === runnerId)))
4622
+ ...manifest,
4623
+ caseDirectory: slashRelative(artifactRoot, manifest.caseDirectory),
4624
+ caseDirectoriesSearched: manifest.caseDirectoriesSearched.map((path) => slashRelative(artifactRoot, path)),
4625
+ files: manifest.files.map((file) => ({
4626
+ ...file,
4627
+ path: slashRelative(artifactRoot, file.path)
4628
+ }))
4131
4629
  };
4132
4630
  }
4133
- function renderCodeTraceCalibrationMarkdown(summary) {
4134
- return [
4135
- "## CodeTraceBench Calibrated View",
4136
- "",
4137
- summary.rationale,
4138
- "",
4139
- "| Runner | Completed/selected | Failed | Positive runs | Trusted negative runs | Unlabeled runs | Failed label-empty | Unknown label-empty | Matched/expected steps | Predicted steps | Precision | Recall | F1 | Official all-row F1 | Official rows | Trusted-negative false positives | Trusted-negative failures | Unlabeled predictions | Unlabeled failures |",
4140
- "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |",
4141
- ...summary.runners.map((runner) => `| ${escapeCell$1(runner.runnerId)} | ${runner.completedRuns}/${runner.selectedRuns} | ${runner.failedRuns} | ${runner.positiveRuns} | ${runner.trustedNegativeRuns} | ${runner.unlabeledRuns} | ${runner.failedLabelEmptyRuns} | ${runner.unknownLabelEmptyRuns} | ${runner.matchedIncorrectSteps}/${runner.expectedIncorrectSteps} | ${runner.predictedIncorrectSteps} | ${rate$1(runner.precision)} | ${rate$1(runner.recall)} | ${rate$1(runner.f1)} | ${rate$1(runner.officialAllRowF1)} | ${runner.officialAllRowRuns} | ${rate$1(runner.trustedNegativeFalsePositiveRate)} | ${rate$1(runner.trustedNegativeFailureRate)} | ${rate$1(runner.unlabeledPredictionRate)} | ${rate$1(runner.unlabeledFailureRate)} |`)
4142
- ].join("\n");
4143
- }
4144
- function summarizeRunner(runnerId, observations) {
4145
- const positive = observations.filter((observation) => observation.labelState === "positive");
4146
- const trustedNegative = observations.filter((observation) => observation.labelState === "trusted-negative");
4147
- const excluded = observations.filter((observation) => observation.labelState === "unlabeled");
4148
- const selected = [...positive, ...trustedNegative];
4149
- const expected = sum(positive.map((observation) => observation.score.expectedIssueCount));
4150
- const predicted = sum(selected.map((observation) => observation.error ? 0 : observation.findings.length));
4151
- const matched = sum(positive.map((observation) => observation.score.matchedIssueIds.length));
4152
- const precision = predicted === 0 ? expected > 0 ? 0 : null : matched / predicted;
4153
- const recall = ratio(matched, expected);
4154
- const completedTrustedNegative = trustedNegative.filter((observation) => !observation.error);
4155
- const completedExcluded = excluded.filter((observation) => !observation.error);
4156
- const officialRows = observations.map(officialCodeTraceF1);
4157
- return {
4158
- runnerId,
4159
- selectedRuns: selected.length,
4160
- positiveRuns: positive.length,
4161
- trustedNegativeRuns: trustedNegative.length,
4162
- unlabeledRuns: excluded.length,
4163
- failedLabelEmptyRuns: excluded.filter((observation) => observation.caseMetadata?.solved === false).length,
4164
- unknownLabelEmptyRuns: excluded.filter((observation) => observation.caseMetadata?.solved !== false).length,
4165
- completedRuns: selected.filter((observation) => !observation.error).length,
4166
- failedRuns: selected.filter((observation) => observation.error).length,
4167
- expectedIncorrectSteps: expected,
4168
- predictedIncorrectSteps: predicted,
4169
- matchedIncorrectSteps: matched,
4170
- officialAllRowF1: mean(officialRows),
4171
- officialAllRowRuns: officialRows.length,
4172
- precision,
4173
- recall,
4174
- f1: harmonicMean(precision, recall),
4175
- trustedNegativeFalsePositiveRate: ratio(completedTrustedNegative.filter((observation) => observation.score.predictionOnLabelEmptyCase).length, completedTrustedNegative.length),
4176
- trustedNegativeFailureRate: ratio(trustedNegative.filter((observation) => observation.error).length, trustedNegative.length),
4177
- unlabeledPredictionRate: ratio(completedExcluded.filter((observation) => observation.findings.length > 0).length, completedExcluded.length),
4178
- unlabeledFailureRate: ratio(excluded.filter((observation) => Boolean(observation.error)).length, excluded.length)
4179
- };
4631
+ function slashRelative(root, path) {
4632
+ const value = relative(root, path);
4633
+ if (!value || value === ".." || value.startsWith(`..${sep}`)) {
4634
+ if (!value) return ".";
4635
+ throw new Error(`benchmark artifact path escapes its declared root: ${path}`);
4636
+ }
4637
+ return value.replaceAll("\\", "/");
4180
4638
  }
4181
- function officialCodeTraceF1(observation) {
4182
- const trajectoryId = observation.caseMetadata?.trajectoryId;
4183
- if (typeof trajectoryId !== "string" || !trajectoryId.trim()) throw new TypeError(`${observation.caseId}: CodeTraceBench trajectoryId metadata is missing`);
4184
- const expected = new Set([...observation.score.matchedIssueIds, ...observation.score.missedIssueIds].map((issueId) => {
4185
- const match = /^incorrect:(\d+)$/.exec(issueId);
4186
- if (!match) throw new TypeError(`${observation.caseId}: invalid incorrect-step label '${issueId}'`);
4187
- return Number(match[1]);
4188
- }));
4189
- const predicted = /* @__PURE__ */ new Set();
4190
- if (!observation.error) for (const finding of observation.findings) {
4191
- if (finding.area !== "incorrect") continue;
4192
- for (const evidence of finding.evidence_refs) {
4193
- const location = codeTraceStepFromEvidence(evidence.uri);
4194
- if (!location || location.traceId !== trajectoryId) throw new TypeError(`${observation.caseId}: invalid CodeTraceBench prediction evidence '${evidence.uri}'`);
4195
- predicted.add(location.step);
4639
+ function parseJsonl(text, path) {
4640
+ const rows = [];
4641
+ for (const [index, line] of text.split(/\r?\n/).entries()) {
4642
+ const trimmed = line.trim();
4643
+ if (!trimmed) continue;
4644
+ let parsed;
4645
+ try {
4646
+ parsed = JSON.parse(trimmed);
4647
+ } catch (error) {
4648
+ throw new Error(`${path}:${index + 1}: invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
4196
4649
  }
4650
+ if (!isRecord(parsed)) throw new TypeError(`${path}:${index + 1}: dataset row must be a JSON object`);
4651
+ rows.push(parsed);
4197
4652
  }
4198
- let matched = 0;
4199
- for (const step of predicted) if (expected.has(step)) matched += 1;
4200
- return harmonicMean(predicted.size === 0 ? 0 : matched / predicted.size, expected.size === 0 ? 0 : matched / expected.size) ?? 0;
4201
- }
4202
- function sum(values) {
4203
- return values.reduce((total, value) => total + value, 0);
4204
- }
4205
- function ratio(numerator, denominator) {
4206
- return denominator === 0 ? null : numerator / denominator;
4207
- }
4208
- function mean(values) {
4209
- return values.length === 0 ? null : sum(values) / values.length;
4653
+ if (rows.length === 0) throw new Error(`public analyst benchmark dataset is empty: ${path}`);
4654
+ return rows;
4210
4655
  }
4211
- function harmonicMean(left, right) {
4212
- if (left === null || right === null) return null;
4213
- return left + right === 0 ? 0 : 2 * left * right / (left + right);
4656
+ function records(values, path) {
4657
+ return values.map((value, index) => {
4658
+ if (!isRecord(value)) throw new TypeError(`${path}[${index}] must be a JSON object`);
4659
+ return value;
4660
+ });
4214
4661
  }
4215
- function rate$1(value) {
4216
- return value === null ? "n/a" : value.toFixed(3);
4662
+ function publicBenchmarkRowId(dataset, row) {
4663
+ const value = dataset === "agentrx" ? row.trajectory_id : row.traj_id;
4664
+ if (typeof value !== "string" && typeof value !== "number" || !String(value).trim()) throw new TypeError(`${dataset} dataset row requires a non-empty ${dataset === "agentrx" ? "trajectory_id" : "traj_id"}`);
4665
+ return String(value);
4217
4666
  }
4218
- function escapeCell$1(value) {
4219
- return value.replaceAll("|", "\\|").replaceAll("\n", " ");
4667
+ function spanIdFromEvidence(uri) {
4668
+ const match = /\/span\/([^/]+)$/.exec(uri);
4669
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
4220
4670
  }
4221
- //#endregion
4222
- //#region src/analyst/benchmark-command-result.ts
4223
- async function readAnalystBenchmarkArtifact(path) {
4224
- const value = parseJson(await readRegularFile(path, "analyst benchmark result"), path);
4225
- assertAnalystBenchmarkArtifact(value, "analyst benchmark result");
4226
- return value;
4671
+ function selectionKey(seed, id) {
4672
+ return sha256Digest(`${seed}\u0000${id}`);
4227
4673
  }
4228
- function assertCompletedArtifactMatchesRun(artifact, manifest, observations, prepared) {
4229
- if (artifact.runIdentitySha256 !== manifest.identitySha256) throw new Error("completed benchmark result belongs to another run");
4230
- assertSameObservations(artifact.result.observations, observations);
4231
- const expectedCount = manifest.identity.inputs.selectedCaseIds.length * manifest.identity.config.runnerIds.length * manifest.identity.config.repetitions;
4232
- if (observations.length !== expectedCount) throw new Error(`completed benchmark result has ${observations.length} observations; expected ${expectedCount}`);
4233
- const { config, inputs } = manifest.identity;
4234
- const verificationAvailability = {
4235
- cases: prepared.verificationArtifacts.length,
4236
- resultFilesPresent: prepared.verificationArtifacts.filter((artifact) => artifact.status === "present").length,
4237
- resultFilesMissing: prepared.verificationArtifacts.filter((artifact) => artifact.status === "missing").length,
4238
- outcomes: {
4239
- passed: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "passed").length,
4240
- failed: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "failed").length,
4241
- unavailable: prepared.verificationArtifacts.filter((artifact) => artifact.outcome.status === "unavailable").length
4242
- }
4243
- };
4244
- const expectedInputs = {
4245
- dataset: config.dataset,
4246
- datasetRevision: config.datasetRevision,
4247
- datasetSplit: config.datasetSplit,
4248
- labelsSha256: inputs.labelsSha256,
4249
- sourceRowCount: inputs.sourceRowCount,
4250
- traceFiles: inputs.traceFiles.map((traceFile) => ({ ...traceFile })),
4251
- verificationArtifacts: prepared.verificationArtifacts,
4252
- verificationAvailability,
4253
- selection: {
4254
- limit: config.limit,
4255
- seed: config.seed,
4256
- selectedCaseIds: [...inputs.selectedCaseIds],
4257
- report: prepared.selection
4258
- },
4259
- execution: {
4260
- repetitions: config.repetitions,
4261
- concurrency: config.concurrency,
4262
- model: config.model.id,
4263
- maxOutputTokens: config.model.maxOutputTokens,
4264
- timeoutMs: config.model.timeoutMs,
4265
- maxCostUsd: config.maxCostUsd,
4266
- maxArtifactBytes: config.maxArtifactBytes,
4267
- analystProtocolSha256: config.analystProtocolSha256,
4268
- implementationSha256: config.implementationSha256,
4269
- dependencyLockSha256: config.dependencyLockSha256
4674
+ function valueDistribution(values) {
4675
+ const counts = /* @__PURE__ */ new Map();
4676
+ let missing = 0;
4677
+ for (const value of values) {
4678
+ if (value === void 0) {
4679
+ missing += 1;
4680
+ continue;
4270
4681
  }
4682
+ counts.set(value, (counts.get(value) ?? 0) + 1);
4683
+ }
4684
+ return {
4685
+ total: values.length,
4686
+ missing,
4687
+ counts: Object.fromEntries([...counts].sort(([left], [right]) => left.localeCompare(right)))
4271
4688
  };
4272
- if (canonicalJson(artifact.inputs) !== canonicalJson(expectedInputs)) throw new Error("completed benchmark result inputs do not match the run manifest");
4273
- const provenance = artifact.result.provenance;
4274
- const expectedDatasetId = config.dataset === "agentrx" ? "microsoft/AgentRx" : "NJU-LINK/CodeTraceBench";
4275
- const expectedOutputAdapter = config.dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block";
4276
- if (provenance.id !== `${config.dataset}-real-model-analyst` || provenance.startedAt !== manifest.createdAt || !Number.isFinite(Date.parse(provenance.endedAt)) || Date.parse(provenance.endedAt) < Date.parse(provenance.startedAt) || canonicalJson(provenance.dataset) !== canonicalJson({
4277
- id: expectedDatasetId,
4278
- revision: config.datasetRevision,
4279
- split: config.datasetSplit
4280
- }) || provenance.caseCount !== inputs.selectedCaseIds.length || canonicalJson(provenance.runnerIds) !== canonicalJson(config.runnerIds) || provenance.repetitions !== config.repetitions || provenance.maxConcurrency !== Math.min(config.concurrency, expectedCount) || provenance.runnerOrderSeed !== config.seed || provenance.metadata?.model !== config.model.id || provenance.metadata?.outputAdapter !== expectedOutputAdapter || provenance.metadata?.caseSelection !== prepared.selection.method || provenance.metadata?.caseSelectionSeed !== config.seed || provenance.metadata?.selectionStratified !== prepared.selection.stratified || provenance.metadata?.protocolSha256 !== config.analystProtocolSha256 || provenance.metadata?.implementationSha256 !== config.implementationSha256 || provenance.metadata?.dependencyLockSha256 !== config.dependencyLockSha256 || provenance.metadata?.populationRepresentativenessProven !== false) throw new Error("completed benchmark result provenance does not match the run manifest");
4281
- const expectedSummaries = config.runnerIds.map((runnerId) => summarizeAnalystBenchmarkRunner(runnerId, observations.filter((observation) => observation.runnerId === runnerId)));
4282
- if (canonicalJson(artifact.result.summaries) !== canonicalJson(expectedSummaries)) throw new Error("completed benchmark summaries do not match durable observations");
4283
- const expectedComparisons = [compareAnalystRunners(artifact.result, {
4284
- baselineRunnerId: "empty",
4285
- candidateRunnerId: config.runnerIds[1],
4286
- seed: config.seed
4287
- })];
4288
- if (canonicalJson(artifact.comparisons) !== canonicalJson(expectedComparisons)) throw new Error("completed benchmark comparisons do not match durable observations");
4289
- if (config.dataset === "codetracebench") {
4290
- if (canonicalJson(artifact.codeTraceCalibration) !== canonicalJson(summarizeCodeTraceCalibration(artifact.result)) || artifact.agentRxCalibration !== void 0) throw new Error("completed CodeTraceBench calibration does not match durable observations");
4291
- } else if (canonicalJson(artifact.agentRxCalibration) !== canonicalJson(summarizeAgentRxCalibration(artifact.result, "f228165bfec60a801fd5fedd9d8ffe0f9de0c69d")) || artifact.codeTraceCalibration !== void 0) throw new Error("completed AgentRx calibration does not match durable observations");
4292
4689
  }
4293
- function assertSameObservations(expected, actual) {
4294
- if (expected.length !== actual.length) throw new Error(`benchmark result has ${expected.length} observations but the durable log has ${actual.length}`);
4295
- const expectedByKey = new Map(expected.map((observation) => [observationKey(observation), canonicalJson(observation)]));
4296
- for (const observation of actual) {
4297
- const key = observationKey(observation);
4298
- if (expectedByKey.get(key) !== canonicalJson(observation)) throw new Error(`benchmark result does not match durable observation '${observation.runnerId}/${observation.caseId}/${observation.repetition}'`);
4299
- expectedByKey.delete(key);
4300
- }
4301
- if (expectedByKey.size > 0) throw new Error("benchmark result is missing durable observations");
4690
+ function scalarDistributionValue(value) {
4691
+ if (typeof value === "string") return value.trim() || void 0;
4692
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
4693
+ }
4694
+ function rootAgent(row) {
4695
+ const rootCauseId = row.root_cause_failure_id ?? row.root_cause?.failure_id;
4696
+ return scalarDistributionValue(row.failures.find((failure) => String(failure.failure_id) === String(rootCauseId))?.failed_agent);
4302
4697
  }
4303
4698
  //#endregion
4304
4699
  //#region src/analyst/benchmark-report.ts
@@ -4474,11 +4869,12 @@ async function executeAnalystBenchmarkCommand(config, dependencies) {
4474
4869
  },
4475
4870
  metadata: {
4476
4871
  model: config.model.model,
4872
+ rlmSamples: config.rlmSamples,
4477
4873
  outputAdapter: config.dataset === "agentrx" ? "agentrx-taxonomy-and-root-step" : "codetracebench-incorrect-block",
4478
4874
  caseSelection: prepared.selection.method,
4479
4875
  caseSelectionSeed: config.seed,
4480
4876
  selectionStratified: prepared.selection.stratified,
4481
- protocolSha256: publicBenchmarkProtocolSha256(config.dataset),
4877
+ protocolSha256: effectiveAnalystProtocolSha256(config.dataset, config.model.instructionsOverride),
4482
4878
  implementationSha256: ANALYST_BENCHMARK_IMPLEMENTATION_SHA256,
4483
4879
  dependencyLockSha256: ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256,
4484
4880
  populationRepresentativenessProven: false
@@ -4522,12 +4918,14 @@ async function executeAnalystBenchmarkCommand(config, dependencies) {
4522
4918
  execution: {
4523
4919
  repetitions: config.repetitions,
4524
4920
  concurrency: config.concurrency,
4921
+ rlmSamples: config.rlmSamples,
4525
4922
  model: config.model.model,
4526
4923
  maxOutputTokens: config.model.maxOutputTokens,
4527
4924
  timeoutMs: config.model.timeoutMs,
4528
4925
  maxCostUsd: config.maxCostUsd,
4529
4926
  maxArtifactBytes: config.maxArtifactBytes,
4530
- analystProtocolSha256: publicBenchmarkProtocolSha256(config.dataset),
4927
+ analystProtocolSha256: effectiveAnalystProtocolSha256(config.dataset, config.model.instructionsOverride),
4928
+ ...config.model.instructionsOverride ? { instructionsOverrideSha256: config.model.instructionsOverride.sha256 } : {},
4531
4929
  implementationSha256: ANALYST_BENCHMARK_IMPLEMENTATION_SHA256,
4532
4930
  dependencyLockSha256: ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256
4533
4931
  }
@@ -4608,6 +5006,14 @@ Controls:
4608
5006
  --seed <integer> Case-selection and comparison seed. Default: 0
4609
5007
  --concurrency <positive integer> Parallel benchmark jobs. Default: 1
4610
5008
  --repetitions <positive integer> Runs per case and runner. Default: 1
5009
+ --rlm-samples <positive integer> Recursive-engine runs per case; above 1 the
5010
+ step-level majority consensus is scored
5011
+ (CodeTraceBench + dspy-rlm only). Default: 1
5012
+ --instructions-file <path> Replace the recursive analyst instructions
5013
+ with this file's text (dspy-rlm only). The
5014
+ recorded protocol digest binds the stock
5015
+ protocol to the override text, and
5016
+ result.json records instructionsOverrideSha256.
4611
5017
  --max-output-tokens <positive> Model output limit per call. Default: 16384
4612
5018
  --python <executable> Python with agent-eval-rpc[dspy]. Default: python
4613
5019
  --timeout-ms <positive> Model analyst deadline per case. Default: 300000
@@ -4636,6 +5042,12 @@ function parseCommandConfig(argv, env) {
4636
5042
  const python = flags.get("python")?.trim();
4637
5043
  const analyst = flags.get("analyst")?.trim() ?? "dspy-rlm";
4638
5044
  if (analyst !== "dspy-rlm" && analyst !== "direct") throw new Error("--analyst must be 'dspy-rlm' or 'direct'");
5045
+ const rlmSamples = positiveFlag(flags, "rlm-samples", 1);
5046
+ if (rlmSamples > 1 && analyst !== "dspy-rlm") throw new Error("--rlm-samples above 1 requires --analyst dspy-rlm");
5047
+ const instructionsFile = flags.get("instructions-file")?.trim();
5048
+ if (instructionsFile && analyst !== "dspy-rlm") throw new Error("--instructions-file requires --analyst dspy-rlm");
5049
+ const instructionsOverride = instructionsFile ? readAnalystInstructionsOverride(instructionsFile) : void 0;
5050
+ if (rlmSamples > 1 && dataset !== "codetracebench") throw new Error("--rlm-samples above 1 requires --dataset codetracebench; step-level consensus is defined on its block grammar");
4639
5051
  return {
4640
5052
  dataset,
4641
5053
  analyst,
@@ -4652,12 +5064,17 @@ function parseCommandConfig(argv, env) {
4652
5064
  maxOutputTokens: positiveFlag(flags, "max-output-tokens", 16384),
4653
5065
  timeoutMs: positiveFlag(flags, "timeout-ms", 3e5),
4654
5066
  maxCostUsdPerAnalysis: maxCostUsd,
4655
- ...python ? { dspyRlm: { runner: { command: python } } } : {}
5067
+ ...instructionsOverride ? { instructionsOverride } : {},
5068
+ dspyRlm: {
5069
+ ...python ? { runner: { command: python } } : {},
5070
+ samples: rlmSamples
5071
+ }
4656
5072
  },
4657
5073
  limit: positiveFlag(flags, "limit"),
4658
5074
  seed: integerFlag(flags, "seed", 0),
4659
5075
  concurrency: positiveFlag(flags, "concurrency", 1),
4660
5076
  repetitions: positiveFlag(flags, "repetitions", 1),
5077
+ rlmSamples,
4661
5078
  maxCostUsd,
4662
5079
  maxArtifactBytes: positiveFlag(flags, "max-artifact-bytes", DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES),
4663
5080
  apiKeyEnv,
@@ -4703,6 +5120,8 @@ const KNOWN_FLAGS = /* @__PURE__ */ new Set([
4703
5120
  "seed",
4704
5121
  "concurrency",
4705
5122
  "repetitions",
5123
+ "rlm-samples",
5124
+ "instructions-file",
4706
5125
  "max-output-tokens",
4707
5126
  "python",
4708
5127
  "timeout-ms",
@@ -4826,6 +5245,6 @@ function shellQuote(value) {
4826
5245
  return /^[a-zA-Z0-9_./:@%+=,-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
4827
5246
  }
4828
5247
  //#endregion
4829
- export { ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 as A, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE as B, publicBenchmarkSystemPrompt as C, parseVerificationOutcome as D, loadCodeTraceVerificationArtifacts as E, ANALYST_BENCHMARK_IMPLEMENTATION_FILES as F, summarizeAgentRxCalibration as G, ANALYST_BENCHMARK_OBSERVATIONS_FILE as H, ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 as I, agentRxBenchmarkCase as J, codeTraceBenchCase as K, analystBenchmarkDependencyLockDigest as L, ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256 as M, ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION as N, ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM as O, ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM as P, normalizeBenchmarkLabel as Q, analystBenchmarkImplementationDigest as R, publicBenchmarkRlmInstructions as S, appendVerificationArtifactsToOtlp as T, AGENT_RX_UPSTREAM_REVISION as U, ANALYST_BENCHMARK_MANIFEST_FILE as V, renderAgentRxCalibrationMarkdown as W, normalizeAgentRxCategory as X, agentRxPredictionsToFindings as Y, roundAgentRxStep as Z, expandCodeTraceFailureBlocks as _, renderCodeTraceCalibrationMarkdown as a, MAX_INCORRECT_BLOCK_STEPS as b, createPublicBenchmarkRlmRunner as c, preparePublicAnalystBenchmark as d, publicBenchmarkDistributions as f, emptyPublicBenchmarkRunner as g, adaptPublicBenchmarkFindings as h, readAnalystBenchmarkArtifact as i, ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256 as j, ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES as k, createPublicBenchmarkDirectRunner as l, selectPublicBenchmarkRows as m, runAnalystBenchmarkCommand as n, summarizeCodeTraceCalibration as o, publicBenchmarkSelectionReport as p, codeTracerPredictionsToFindings as q, renderAnalystBenchmarkMarkdown as r, compareAnalystRunners as s, ANALYST_BENCHMARK_HELP as t, loadPublicBenchmarkRows as u, CODE_TRACE_BENCH_ANALYST_PROMPT as v, DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES as w, publicBenchmarkProtocolSha256 as x, MAX_INCORRECT_BLOCKS as y, ANALYST_BENCHMARK_COST_LEDGER_FILE as z };
5248
+ export { normalizeAgentRxCategory as $, parseVerificationOutcome as A, analystBenchmarkDependencyLockDigest as B, MAX_INCORRECT_BLOCK_STEPS as C, DEFAULT_MAX_VERIFICATION_ARTIFACT_BYTES as D, publicBenchmarkSystemPrompt as E, ANALYST_BENCHMARK_EVIDENCE_IMPLEMENTATION_SHA256 as F, ANALYST_BENCHMARK_OBSERVATIONS_FILE as G, ANALYST_BENCHMARK_COST_LEDGER_FILE as H, ANALYST_BENCHMARK_EVIDENCE_PACKAGE_VERSION as I, summarizeAgentRxCalibration as J, AGENT_RX_UPSTREAM_REVISION as K, ANALYST_BENCHMARK_IMPLEMENTATION_DIGEST_ALGORITHM as L, ANALYST_BENCHMARK_DEPENDENCY_LOCK_FILES as M, ANALYST_BENCHMARK_DEPENDENCY_LOCK_SHA256 as N, appendVerificationArtifactsToOtlp as O, ANALYST_BENCHMARK_EVIDENCE_DEPENDENCY_LOCK_SHA256 as P, agentRxPredictionsToFindings as Q, ANALYST_BENCHMARK_IMPLEMENTATION_FILES as R, MAX_INCORRECT_BLOCKS as S, publicBenchmarkRlmInstructions as T, ANALYST_BENCHMARK_LOCAL_RECEIPT_FILE as U, analystBenchmarkImplementationDigest as V, ANALYST_BENCHMARK_MANIFEST_FILE as W, codeTracerPredictionsToFindings as X, codeTraceBenchCase as Y, agentRxBenchmarkCase as Z, compareAnalystRunners as _, preparePublicAnalystBenchmark as a, readAnalystInstructionsOverride as b, selectPublicBenchmarkRows as c, adaptPublicBenchmarkFindings as d, roundAgentRxStep as et, emptyPublicBenchmarkRunner as f, summarizeCodeTraceCalibration as g, renderCodeTraceCalibrationMarkdown as h, loadPublicBenchmarkRows as i, ANALYST_BENCHMARK_DEPENDENCY_LOCK_DIGEST_ALGORITHM as j, loadCodeTraceVerificationArtifacts as k, createPublicBenchmarkRlmRunner as l, readAnalystBenchmarkArtifact as m, runAnalystBenchmarkCommand as n, publicBenchmarkDistributions as o, expandCodeTraceFailureBlocks as p, renderAgentRxCalibrationMarkdown as q, renderAnalystBenchmarkMarkdown as r, publicBenchmarkSelectionReport as s, ANALYST_BENCHMARK_HELP as t, normalizeBenchmarkLabel as tt, createPublicBenchmarkDirectRunner as u, analystInstructionsOverrideFromText as v, publicBenchmarkProtocolSha256 as w, CODE_TRACE_BENCH_ANALYST_PROMPT as x, effectiveAnalystProtocolSha256 as y, ANALYST_BENCHMARK_IMPLEMENTATION_SHA256 as z };
4830
5249
 
4831
- //# sourceMappingURL=benchmark-command-Bo_hkhQf.js.map
5250
+ //# sourceMappingURL=benchmark-command-BG2PlMDp.js.map