@tangle-network/agent-eval 0.126.7 → 0.127.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 (129) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +2 -2
  3. package/dist/analyst/index.d.ts +51 -39
  4. package/dist/analyst/index.js +4 -4
  5. package/dist/belief-state/index.d.ts +34 -36
  6. package/dist/belief-state/index.js +2 -2
  7. package/dist/benchmarks/index.d.ts +30 -12
  8. package/dist/benchmarks/index.js +12 -10
  9. package/dist/builder-eval/index.js +1 -1
  10. package/dist/campaign/index.d.ts +432 -146
  11. package/dist/campaign/index.js +11 -9
  12. package/dist/{chunk-ARU2PZFM.js → chunk-424XHVKV.js} +43 -23
  13. package/dist/chunk-424XHVKV.js.map +1 -0
  14. package/dist/{chunk-NUKSVU3W.js → chunk-5DTSBUL2.js} +2 -2
  15. package/dist/{chunk-BTACVO2W.js → chunk-65QETEKG.js} +542 -258
  16. package/dist/chunk-65QETEKG.js.map +1 -0
  17. package/dist/{chunk-CGG5SLH3.js → chunk-ARCFIY7U.js} +2 -2
  18. package/dist/{chunk-P22LJ3Y2.js → chunk-CLELFRQG.js} +6 -4
  19. package/dist/chunk-CLELFRQG.js.map +1 -0
  20. package/dist/{chunk-LUNF2SEL.js → chunk-DJKY2TSY.js} +3 -3
  21. package/dist/chunk-DPUHNQLN.js +232 -0
  22. package/dist/chunk-DPUHNQLN.js.map +1 -0
  23. package/dist/{chunk-IPYXE555.js → chunk-EJGRPCO3.js} +36 -13
  24. package/dist/chunk-EJGRPCO3.js.map +1 -0
  25. package/dist/{chunk-K6IAZZ6L.js → chunk-FA3MFYNA.js} +132 -110
  26. package/dist/chunk-FA3MFYNA.js.map +1 -0
  27. package/dist/chunk-IG35YDN3.js +614 -0
  28. package/dist/chunk-IG35YDN3.js.map +1 -0
  29. package/dist/{chunk-DPZAEKA6.js → chunk-IMGJZBFG.js} +84 -56
  30. package/dist/chunk-IMGJZBFG.js.map +1 -0
  31. package/dist/{chunk-H5UD2323.js → chunk-IN455XKS.js} +53 -1
  32. package/dist/chunk-IN455XKS.js.map +1 -0
  33. package/dist/{chunk-PJQFMIOX.js → chunk-MHELPNRP.js} +31 -1
  34. package/dist/chunk-MHELPNRP.js.map +1 -0
  35. package/dist/{chunk-IILEIWGW.js → chunk-NL33OXEP.js} +41 -36
  36. package/dist/chunk-NL33OXEP.js.map +1 -0
  37. package/dist/{chunk-474LBSOX.js → chunk-OD5NQ2CS.js} +41 -16
  38. package/dist/chunk-OD5NQ2CS.js.map +1 -0
  39. package/dist/{chunk-QOTFXW5L.js → chunk-P5W7RQKK.js} +2 -2
  40. package/dist/{chunk-IR3KBHOY.js → chunk-P6FYH6K4.js} +39 -3
  41. package/dist/chunk-P6FYH6K4.js.map +1 -0
  42. package/dist/{chunk-J5SQWP6Y.js → chunk-PBE2LOSS.js} +18 -2
  43. package/dist/chunk-PBE2LOSS.js.map +1 -0
  44. package/dist/{chunk-E3IADPLG.js → chunk-PRB53E3J.js} +50 -224
  45. package/dist/chunk-PRB53E3J.js.map +1 -0
  46. package/dist/{chunk-X4UCIOTZ.js → chunk-S5YLIBFX.js} +2 -2
  47. package/dist/{chunk-7VYEGHWF.js → chunk-SZLVEKMJ.js} +41 -20
  48. package/dist/chunk-SZLVEKMJ.js.map +1 -0
  49. package/dist/{chunk-LKKT3IVV.js → chunk-TSN7JT6D.js} +6 -4
  50. package/dist/{chunk-LKKT3IVV.js.map → chunk-TSN7JT6D.js.map} +1 -1
  51. package/dist/{chunk-M7AH34KV.js → chunk-UTA2TGC4.js} +32 -16
  52. package/dist/chunk-UTA2TGC4.js.map +1 -0
  53. package/dist/{chunk-MAX3TN3C.js → chunk-UWZZKKU7.js} +7 -19
  54. package/dist/chunk-UWZZKKU7.js.map +1 -0
  55. package/dist/{chunk-ZVCHKKOP.js → chunk-WED5KLZQ.js} +39 -15
  56. package/dist/chunk-WED5KLZQ.js.map +1 -0
  57. package/dist/{chunk-OCFJACJU.js → chunk-X6VOPMLD.js} +74 -14
  58. package/dist/chunk-X6VOPMLD.js.map +1 -0
  59. package/dist/{chunk-MOXWMGPC.js → chunk-Y5CYOL42.js} +159 -70
  60. package/dist/chunk-Y5CYOL42.js.map +1 -0
  61. package/dist/{chunk-FO7HEH76.js → chunk-YJBNWCAA.js} +2 -2
  62. package/dist/chunk-ZPUEEM5U.js +179 -0
  63. package/dist/chunk-ZPUEEM5U.js.map +1 -0
  64. package/dist/{chunk-KE2VWPZX.js → chunk-ZUUWPZCV.js} +3 -3
  65. package/dist/cli.js +4 -4
  66. package/dist/contract/index.d.ts +421 -124
  67. package/dist/contract/index.js +242 -115
  68. package/dist/contract/index.js.map +1 -1
  69. package/dist/control.d.ts +34 -32
  70. package/dist/control.js +2 -2
  71. package/dist/hosted/index.d.ts +142 -41
  72. package/dist/hosted/index.js +23 -1
  73. package/dist/index.d.ts +364 -255
  74. package/dist/index.js +315 -226
  75. package/dist/index.js.map +1 -1
  76. package/dist/meta-eval/index.d.ts +32 -32
  77. package/dist/meta-eval/index.js +2 -2
  78. package/dist/multishot/index.d.ts +1 -0
  79. package/dist/openapi.json +1 -1
  80. package/dist/pipelines/index.js +2 -2
  81. package/dist/reporting.d.ts +97 -74
  82. package/dist/reporting.js +5 -4
  83. package/dist/rl.d.ts +177 -131
  84. package/dist/rl.js +232 -126
  85. package/dist/rl.js.map +1 -1
  86. package/dist/rollout/index.d.ts +53 -63
  87. package/dist/rollout/index.js +7 -5
  88. package/dist/{run-campaign-FFRM3RH5.js → run-campaign-3A2EBYBE.js} +4 -3
  89. package/dist/supervisor-run/index.d.ts +7 -15
  90. package/dist/supervisor-run/index.js +2 -2
  91. package/dist/traces.d.ts +66 -41
  92. package/dist/traces.js +9 -5
  93. package/dist/wire/index.d.ts +1 -0
  94. package/dist/wire/index.js +2 -2
  95. package/docs/concepts.md +18 -1
  96. package/docs/hosted-ingest-spec.md +37 -40
  97. package/docs/insight-report.md +57 -7
  98. package/docs/research-report-methodology.md +20 -21
  99. package/docs/rollout.md +13 -8
  100. package/package.json +4 -3
  101. package/dist/chunk-474LBSOX.js.map +0 -1
  102. package/dist/chunk-7VYEGHWF.js.map +0 -1
  103. package/dist/chunk-ARU2PZFM.js.map +0 -1
  104. package/dist/chunk-BTACVO2W.js.map +0 -1
  105. package/dist/chunk-DPZAEKA6.js.map +0 -1
  106. package/dist/chunk-E3IADPLG.js.map +0 -1
  107. package/dist/chunk-H5UD2323.js.map +0 -1
  108. package/dist/chunk-IILEIWGW.js.map +0 -1
  109. package/dist/chunk-IPYXE555.js.map +0 -1
  110. package/dist/chunk-IR3KBHOY.js.map +0 -1
  111. package/dist/chunk-J5SQWP6Y.js.map +0 -1
  112. package/dist/chunk-K6IAZZ6L.js.map +0 -1
  113. package/dist/chunk-M7AH34KV.js.map +0 -1
  114. package/dist/chunk-MAX3TN3C.js.map +0 -1
  115. package/dist/chunk-MOXWMGPC.js.map +0 -1
  116. package/dist/chunk-OCFJACJU.js.map +0 -1
  117. package/dist/chunk-P22LJ3Y2.js.map +0 -1
  118. package/dist/chunk-PJQFMIOX.js.map +0 -1
  119. package/dist/chunk-ZVCHKKOP.js.map +0 -1
  120. package/dist/chunk-ZZUXHH3R.js +0 -99
  121. package/dist/chunk-ZZUXHH3R.js.map +0 -1
  122. /package/dist/{chunk-NUKSVU3W.js.map → chunk-5DTSBUL2.js.map} +0 -0
  123. /package/dist/{chunk-CGG5SLH3.js.map → chunk-ARCFIY7U.js.map} +0 -0
  124. /package/dist/{chunk-LUNF2SEL.js.map → chunk-DJKY2TSY.js.map} +0 -0
  125. /package/dist/{chunk-QOTFXW5L.js.map → chunk-P5W7RQKK.js.map} +0 -0
  126. /package/dist/{chunk-X4UCIOTZ.js.map → chunk-S5YLIBFX.js.map} +0 -0
  127. /package/dist/{chunk-FO7HEH76.js.map → chunk-YJBNWCAA.js.map} +0 -0
  128. /package/dist/{chunk-KE2VWPZX.js.map → chunk-ZUUWPZCV.js.map} +0 -0
  129. /package/dist/{run-campaign-FFRM3RH5.js.map → run-campaign-3A2EBYBE.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/trace-analyst/hook.ts","../src/trace-analyst/insights.ts","../src/trace-analyst/otlp-flatten.ts","../src/trace-analyst/otlp-to-run-records.ts","../src/trace/store.ts","../src/trace/capture-fetch.ts","../src/trace/otel.ts","../src/trace/otel-bridge.ts","../src/trace/otel-export.ts","../src/trace/store-to-otlp.ts","../src/replay.ts"],"sourcesContent":["/**\n * Trace-analyst auto-execution hook.\n *\n * Wires `analyzeTraces` into a `TraceEmitter`'s `onRunComplete` so a\n * direct matrix run produces an analysis artifact without an out-of-band\n * step. Designed for the case where the consumer reports \"the analyst\n * never ran\" — the cause is almost always orchestration, not the analyst.\n *\n * Usage:\n *\n * const emitter = new TraceEmitter(store, {\n * onRunComplete: [traceAnalystOnRunComplete({ analyze: opts, save })],\n * })\n *\n * Hooks are best-effort by default — they never crash the underlying run.\n * The caller decides whether to gate the run on the analysis result via\n * the `gateOn` callback.\n */\n\nimport type { RunCompleteHook, RunCompleteHookContext } from '../trace/emitter'\nimport { type AnalyzeTracesOptions, type AnalyzeTracesResult, analyzeTraces } from './analyst'\n\nexport interface TraceAnalystHookOptions {\n /**\n * Options forwarded to `analyzeTraces`. The hook supplies the question\n * if you don't pass one — defaulting to a launch-grade prompt that asks\n * for failure modes, surprising findings, and a recommendation.\n */\n analyze: Omit<AnalyzeTracesOptions, 'source'> & { source?: AnalyzeTracesOptions['source'] }\n /**\n * Override the question. The default is intentionally generic:\n * \"Summarise what happened in this run, surface any failure modes,\n * surprising findings, or evidence the verdict is wrong.\"\n */\n question?: string\n /**\n * Persist the result. The hook calls this with the analysis output and\n * the run context. Common implementations write to a TraceAnalysisStore\n * or append to a per-run JSONL.\n */\n save?: (result: AnalyzeTracesResult, ctx: RunCompleteHookContext) => Promise<void>\n /**\n * Predicate gating execution per run. Default: every completed run.\n * Use to skip aborted runs, debug runs, or runs without LLM activity.\n */\n shouldRun?: (ctx: RunCompleteHookContext) => boolean\n /**\n * Optional gate: if set and returns false, the hook records the failure\n * as a log event on the run instead of staying quiet. The caller can\n * then trigger downstream alerts off `analyst_gate_failed` log events.\n */\n gateOn?: (result: AnalyzeTracesResult, ctx: RunCompleteHookContext) => boolean\n}\n\nconst DEFAULT_QUESTION =\n \"Summarise what happened in this run. Surface any failure modes, surprising findings, or evidence that the run's verdict is wrong.\"\n\nexport function traceAnalystOnRunComplete(opts: TraceAnalystHookOptions): RunCompleteHook {\n return async (ctx: RunCompleteHookContext) => {\n if (opts.shouldRun && !opts.shouldRun(ctx)) return\n const source = opts.analyze.source\n if (source === undefined) {\n // The analyst needs a source. If the caller didn't supply one we don't\n // run — but we do leave a breadcrumb so the absence is visible.\n await ctx.store.appendEvent({\n eventId: `analyst-skip-${ctx.runId}`,\n runId: ctx.runId,\n kind: 'log',\n timestamp: Date.now(),\n payload: { source: 'trace_analyst_hook', reason: 'no source configured' },\n })\n return\n }\n const result = await analyzeTraces({ question: opts.question ?? DEFAULT_QUESTION }, {\n ...opts.analyze,\n source,\n } as AnalyzeTracesOptions)\n if (opts.save) await opts.save(result, ctx)\n if (opts.gateOn && !opts.gateOn(result, ctx)) {\n await ctx.store.appendEvent({\n eventId: `analyst-gate-${ctx.runId}`,\n runId: ctx.runId,\n kind: 'log',\n timestamp: Date.now(),\n payload: {\n source: 'trace_analyst_hook',\n reason: 'analyst_gate_failed',\n findings: result.findings,\n },\n })\n }\n }\n}\n","export interface TraceInsightTask {\n id: string\n name: string\n prompt?: string\n difficulty?: string\n tags?: string[]\n outcome?: string\n score?: number\n gaps?: string[]\n}\n\nexport interface TraceInsightSuite {\n name: string\n collectionId?: string\n tasks: TraceInsightTask[]\n}\n\nexport interface TraceInsightFinding {\n kind: string\n severity?: string\n taskIds: string[]\n evidence?: string\n proposedFixClass?: string\n}\n\nexport interface TraceInsightQuestion {\n id: string\n question: string\n why: string\n}\n\nexport interface TraceInsightPanelRole {\n id: string\n name: string\n responsibility: string\n}\n\nexport interface TraceInsightPromptInput {\n suite: TraceInsightSuite\n findings?: TraceInsightFinding[]\n agent?: Record<string, unknown>\n totals?: Record<string, unknown>\n maxRepresentativeTraces?: number\n}\n\nexport interface TraceInsightContext {\n suite: TraceInsightSuite\n scope: string\n keywords: string[]\n questions: TraceInsightQuestion[]\n panel: TraceInsightPanelRole[]\n findings: TraceInsightFinding[]\n agent: Record<string, unknown> | null\n totals: Record<string, unknown> | null\n}\n\nexport interface TraceInsightQualityGate {\n id: string\n label: string\n passed: boolean\n severity: 'critical' | 'high' | 'medium' | 'low'\n detail: string\n}\n\nexport interface TraceInsightReadiness {\n score: number\n grade: 'external-ready' | 'internal-review' | 'raw-analysis'\n gates: TraceInsightQualityGate[]\n}\n\nconst DOMAIN_STOP_WORDS = new Set([\n 'and',\n 'advanced',\n 'app',\n 'build',\n 'create',\n 'easy',\n 'expert',\n 'extreme',\n 'for',\n 'from',\n 'hard',\n 'implementation',\n 'integrate',\n 'medium',\n 'project',\n 'task',\n 'the',\n 'this',\n 'with',\n 'workflow',\n])\n\nexport function tokenizeDomainWords(value: string): string[] {\n return [...value.matchAll(/[A-Za-z][A-Za-z0-9.+#-]{2,}/g)]\n .map((match) => match[0].toLowerCase())\n .filter((word) => !DOMAIN_STOP_WORDS.has(word))\n}\n\nexport function inferDomainKeywords(suite: TraceInsightSuite): string[] {\n const suiteWords = new Set(tokenizeDomainWords(`${suite.name} ${suite.collectionId ?? ''}`))\n const source = [\n suite.name,\n suite.collectionId ?? '',\n ...suite.tasks.flatMap((task) => [\n task.id,\n task.name,\n task.prompt ?? '',\n task.difficulty ?? '',\n ...(task.tags ?? []),\n ...(task.gaps ?? []),\n ]),\n ].join(' ')\n const counts = new Map<string, number>()\n for (const word of tokenizeDomainWords(source)) counts.set(word, (counts.get(word) ?? 0) + 1)\n return [...counts.entries()]\n .filter(([word, count]) => count >= 2 || suiteWords.has(word))\n .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n .map(([word]) => word)\n .slice(0, 18)\n}\n\nexport function domainEvidencePattern(keywords: string[]): RegExp {\n const escaped = keywords\n .filter((keyword) => keyword.length >= 3)\n .map((keyword) => keyword.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n return escaped.length > 0\n ? new RegExp(`(?<![A-Za-z0-9])(?:${escaped.join('|')})(?![A-Za-z0-9])`, 'i')\n : /(?<![A-Za-z0-9])(?:sdk|api|css|dns|xml|provider|client|service|integration|webhook|transaction|auth|oauth|graphql|rest)(?![A-Za-z0-9])/i\n}\n\nexport function describeTraceInsightScope(suite: TraceInsightSuite): string {\n const taskLabel =\n suite.tasks.length === 1\n ? '1 implementation task'\n : `${suite.tasks.length} implementation tasks`\n const tags = new Map<string, number>()\n for (const task of suite.tasks) {\n for (const tag of task.tags ?? []) tags.set(tag, (tags.get(tag) ?? 0) + 1)\n }\n const topTags = [...tags.entries()]\n .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n .slice(0, 8)\n .map(([tag]) => tag)\n if (topTags.length > 0) return `${taskLabel} across ${topTags.join(', ')}.`\n const difficulties = [\n ...new Set(\n suite.tasks.map((task) => task.difficulty).filter((value): value is string => Boolean(value)),\n ),\n ].join(', ')\n return `${taskLabel} across ${difficulties || 'the selected benchmark scope'}.`\n}\n\nexport function planTraceInsightQuestions(input: TraceInsightPromptInput): TraceInsightQuestion[] {\n const hasFailures = input.suite.tasks.some((task) => task.outcome && task.outcome !== 'satisfied')\n const hasMultipleShots = input.suite.tasks.some((task) =>\n (task.gaps ?? []).some((gap) => /shot|review|retry|continue/i.test(gap)),\n )\n const questions: TraceInsightQuestion[] = [\n {\n id: 'execution-path',\n question: 'What did the worker actually do before the first meaningful implementation edit?',\n why: 'Separates grounded execution from polished but shallow output.',\n },\n {\n id: 'research-grounding',\n question:\n 'Did the worker inspect docs, source, examples, or package references before committing to an implementation path?',\n why: 'Identifies whether failures came from weak retrieval, weak examples, or premature coding.',\n },\n {\n id: 'domain-proof',\n question:\n 'Which tasks produced executable domain proof versus UI copy, placeholders, or inferred behavior?',\n why: 'Keeps product-quality claims tied to concrete evidence.',\n },\n {\n id: 'root-cause',\n question:\n 'For each major failure cluster, is the likely root cause prompt/scaffold, docs/examples, SDK/API ergonomics, evaluator, runtime, or model behavior?',\n why: 'Turns trace observations into actionable ownership.',\n },\n {\n id: 'evidence-quality',\n question:\n 'Which external-facing claims are directly supported by trace ids, span ids, verifier findings, reviewer notes, or generated code?',\n why: 'Prevents unsupported customer-report conclusions.',\n },\n ]\n if (hasMultipleShots) {\n questions.push({\n id: 'reviewer-lift',\n question: 'Where did reviewer feedback improve score, stall, or regress across shots?',\n why: 'Shows whether the driver loop is learning or merely repeating work.',\n })\n }\n if (hasFailures) {\n questions.push({\n id: 'optimization-targets',\n question:\n 'Which prompt, evaluator, scaffold, or workflow changes should feed the next GEPA/autoresearch optimization run?',\n why: 'Connects benchmark evidence to the optimization loop.',\n })\n }\n return questions\n}\n\nexport function buildTraceInsightContext(input: TraceInsightPromptInput): TraceInsightContext {\n return {\n suite: input.suite,\n scope: describeTraceInsightScope(input.suite),\n keywords: inferDomainKeywords(input.suite),\n questions: planTraceInsightQuestions(input),\n panel: defaultTraceInsightPanel(),\n findings: input.findings ?? [],\n agent: input.agent ?? null,\n totals: input.totals ?? null,\n }\n}\n\nexport function scoreTraceInsightReadiness(context: TraceInsightContext): TraceInsightReadiness {\n const failedTasks = context.suite.tasks.filter(\n (task) => task.outcome && task.outcome !== 'satisfied',\n )\n const findingTaskIds = new Set(context.findings.flatMap((finding) => finding.taskIds))\n const failedTasksWithFindings = failedTasks.filter((task) => findingTaskIds.has(task.id))\n const tasksWithGaps = context.suite.tasks.filter((task) => (task.gaps ?? []).length > 0)\n const gates: TraceInsightQualityGate[] = [\n {\n id: 'domain-context',\n label: 'Domain context inferred',\n passed: context.keywords.length > 0,\n severity: 'high',\n detail:\n context.keywords.length > 0\n ? `${context.keywords.length} domain terms inferred: ${context.keywords.slice(0, 8).join(', ')}`\n : 'No domain terms were inferred from suite, tasks, prompts, tags, or gaps.',\n },\n {\n id: 'panel-coverage',\n label: 'Analyst panel planned',\n passed: context.panel.length >= 4 && context.questions.length >= 5,\n severity: 'high',\n detail: `${context.panel.length} panel roles and ${context.questions.length} investigation questions planned.`,\n },\n {\n id: 'failure-coverage',\n label: 'Failures mapped to findings',\n passed:\n failedTasks.length === 0 || failedTasksWithFindings.length / failedTasks.length >= 0.5,\n severity: 'critical',\n detail:\n failedTasks.length === 0\n ? 'No failed tasks in suite.'\n : `${failedTasksWithFindings.length}/${failedTasks.length} failed tasks appear in finding clusters.`,\n },\n {\n id: 'gap-evidence',\n label: 'Task gaps captured',\n passed: failedTasks.length === 0 || tasksWithGaps.length / failedTasks.length >= 0.5,\n severity: 'medium',\n detail: `${tasksWithGaps.length} tasks include explicit evaluator or analyst gaps.`,\n },\n ]\n const penalty = gates.reduce((sum, gate) => {\n if (gate.passed) return sum\n if (gate.severity === 'critical') return sum + 35\n if (gate.severity === 'high') return sum + 20\n if (gate.severity === 'medium') return sum + 10\n return sum + 5\n }, 0)\n const score = Math.max(0, Math.min(1, 1 - penalty / 100))\n return {\n score,\n grade: score >= 0.9 ? 'external-ready' : score >= 0.7 ? 'internal-review' : 'raw-analysis',\n gates,\n }\n}\n\nexport function defaultTraceInsightPanel(): TraceInsightPanelRole[] {\n return [\n {\n id: 'trace-forensics',\n name: 'Trace Forensics',\n responsibility:\n 'Reconstruct what the worker did in order, including research, edits, reviewer interventions, verifier feedback, and stop reason.',\n },\n {\n id: 'root-cause',\n name: 'Root Cause',\n responsibility:\n 'Map failures to prompt/scaffold, docs/examples, SDK/API/product ergonomics, evaluator, runtime, or model behavior.',\n },\n {\n id: 'optimization',\n name: 'Optimization',\n responsibility:\n 'Identify prompt, reviewer, evaluator, scaffold, and GEPA/autoresearch changes that should be tested next.',\n },\n {\n id: 'external-evidence',\n name: 'External Evidence',\n responsibility:\n 'Separate customer-safe claims from internal harness findings and reject conclusions without task, trace, span, code, reviewer, or verifier evidence.',\n },\n ]\n}\n\nexport function buildTraceInsightPrompt(input: TraceInsightPromptInput): string {\n const context = buildTraceInsightContext(input)\n const maxRepresentativeTraces = input.maxRepresentativeTraces ?? 6\n return `Analyze this benchmark run and produce evidence-backed trace intelligence.\n\nAudience:\n- internal AI/product leadership\n- possible customer-facing report for ${input.suite.name}\n\nInvestigation plan:\n${context.questions.map((item, index) => `${index + 1}. ${item.question} (${item.why})`).join('\\n')}\n\nAnalyst panel:\n${context.panel.map((role) => `- ${role.name}: ${role.responsibility}`).join('\\n')}\n\nIf the task branches are independent, use subagents for the panel roles above and aggregate their findings. Do not run a panel role unless its answer will change the final report.\n\nRequired output:\n1. Executive verdict: what this run proves and does not prove.\n2. The investigation questions you answered and the evidence used.\n3. Failure taxonomy: agent prompting, evaluator/harness, docs/examples, SDK/API/product integration, infra.\n4. Evidence-backed examples with trace ids/task ids and concrete verifier findings.\n5. Highest-ROI fixes for the benchmark harness, prompt/GEPA optimization, and customer-facing product/docs surface.\n6. What is safe for an external report versus what must stay internal.\n7. One rerun plan that would validate lift after optimization.\n\nBudget:\n- Inspect the dataset overview, the failure summary, and at most ${maxRepresentativeTraces} representative traces.\n- Prefer traces named in the failure summary over broad exploration.\n- Do not do exhaustive trace sweeps.\n- Return the final report as soon as the taxonomy and examples are supported.\n\nRun summary:\n${JSON.stringify(\n {\n suite: input.suite.name,\n scope: context.scope,\n inferredKeywords: context.keywords,\n agent: context.agent,\n totals: context.totals,\n findings: context.findings.map((finding) => ({\n kind: finding.kind,\n severity: finding.severity,\n taskCount: finding.taskIds.length,\n proposedFixClass: finding.proposedFixClass,\n })),\n failures: input.suite.tasks\n .filter((task) => task.outcome && task.outcome !== 'satisfied')\n .map((task) => ({\n task: task.id,\n difficulty: task.difficulty,\n outcome: task.outcome,\n score: task.score,\n gaps: task.gaps ?? [],\n })),\n },\n null,\n 2,\n)}\n\nUse the trace tools. Do not invent facts. Cite task ids. Separate customer-facing claims from internal harness/model findings.`\n}\n","/**\n * `flattenOtlpExportToNdjson` — flatten an `OtlpExport` (the shape\n * `exportRunAsOtlp` produces) into the per-line JSON the analyst's\n * `OtlpFileTraceStore` index reads. Replaces three per-consumer OTLP\n * flatteners with one canonical projection.\n *\n * Pure function, no I/O — the caller does `.map(JSON.stringify).join('\\n')`\n * and writes the file (consumers want control over rotation + naming).\n */\n\nimport type { OtlpExport, OtlpSpan } from '../trace/otel'\nimport {\n LLM_INPUT_TOKENS,\n LLM_MODEL_NAME,\n LLM_OUTPUT_TOKENS,\n OPENINFERENCE_SPAN_KIND,\n TOOL_NAME,\n} from '../trace/otlp-attributes'\n\nexport interface OtlpFlatLine {\n trace_id: string\n span_id: string\n parent_span_id: string | null\n name: string\n kind: string\n start_time: string\n end_time: string\n status: {\n code: 'STATUS_CODE_OK' | 'STATUS_CODE_ERROR' | 'STATUS_CODE_UNSET'\n message?: string\n }\n resource: { attributes: Record<string, string | number | boolean> }\n attributes: Record<string, string | number | boolean>\n events?: Array<{ name: string; timeUnixNano?: string; attributes?: Record<string, unknown> }>\n}\n\nexport interface FlattenOtlpOptions {\n /** `'openinference'` (default) mirrors legacy per-span attributes into the\n * canonical OpenInference vocabulary the analyst readers consume. `'none'`\n * passes attributes through untouched. */\n attributeVocabulary?: 'openinference' | 'none'\n /** Override the numeric-kind → otlp-string mapping. */\n kindMap?: Partial<Record<number, string>>\n}\n\nconst DEFAULT_KIND_MAP: Record<number, string> = {\n 0: 'SPAN_KIND_UNSPECIFIED',\n 1: 'SPAN_KIND_INTERNAL',\n 2: 'SPAN_KIND_SERVER',\n 3: 'SPAN_KIND_CLIENT',\n 4: 'SPAN_KIND_PRODUCER',\n 5: 'SPAN_KIND_CONSUMER',\n}\n\nconst STATUS_MAP: Record<number, OtlpFlatLine['status']['code']> = {\n 0: 'STATUS_CODE_UNSET',\n 1: 'STATUS_CODE_OK',\n 2: 'STATUS_CODE_ERROR',\n}\n\n/** Unwrap an OTLP attribute-value union to a scalar. */\nfunction attrValue(v: OtlpSpan['attributes'][number]['value']): string | number | boolean {\n if (v.stringValue !== undefined) return v.stringValue\n if (v.intValue !== undefined) return Number(v.intValue)\n if (v.doubleValue !== undefined) return v.doubleValue\n if (v.boolValue !== undefined) return v.boolValue\n return ''\n}\n\nfunction attrsToRecord(attrs: OtlpSpan['attributes']): Record<string, string | number | boolean> {\n const out: Record<string, string | number | boolean> = {}\n for (const a of attrs) out[a.key] = attrValue(a.value)\n return out\n}\n\nfunction nanoToIso(nano: string): string {\n const ms = Number(nano) / 1_000_000\n return Number.isFinite(ms) ? new Date(ms).toISOString() : new Date(0).toISOString()\n}\n\n/** Mirror selected attributes into the OpenInference vocabulary in place. */\nfunction applyOpenInference(attrs: Record<string, string | number | boolean>): void {\n if ('llm.model' in attrs && !(LLM_MODEL_NAME in attrs)) {\n attrs[LLM_MODEL_NAME] = attrs['llm.model']!\n }\n if ('llm.input_tokens' in attrs && !(LLM_INPUT_TOKENS in attrs)) {\n attrs[LLM_INPUT_TOKENS] = attrs['llm.input_tokens']!\n }\n if ('inference.llm.input_tokens' in attrs && !(LLM_INPUT_TOKENS in attrs)) {\n attrs[LLM_INPUT_TOKENS] = attrs['inference.llm.input_tokens']!\n }\n if ('llm.output_tokens' in attrs && !(LLM_OUTPUT_TOKENS in attrs)) {\n attrs[LLM_OUTPUT_TOKENS] = attrs['llm.output_tokens']!\n }\n if ('inference.llm.output_tokens' in attrs && !(LLM_OUTPUT_TOKENS in attrs)) {\n attrs[LLM_OUTPUT_TOKENS] = attrs['inference.llm.output_tokens']!\n }\n if (TOOL_NAME in attrs && !('inference.tool.name' in attrs)) {\n attrs['inference.tool.name'] = attrs[TOOL_NAME]!\n }\n if ('span.kind' in attrs && !(OPENINFERENCE_SPAN_KIND in attrs)) {\n attrs[OPENINFERENCE_SPAN_KIND] = String(attrs['span.kind']).toUpperCase()\n }\n}\n\nexport function flattenOtlpExportToNdjson(\n otlpExport: OtlpExport,\n opts: FlattenOtlpOptions = {},\n): OtlpFlatLine[] {\n const vocab = opts.attributeVocabulary ?? 'openinference'\n const kindMap = { ...DEFAULT_KIND_MAP, ...opts.kindMap }\n const lines: OtlpFlatLine[] = []\n\n for (const rs of otlpExport.resourceSpans ?? []) {\n const resource = { attributes: attrsToRecord(rs.resource?.attributes ?? []) }\n for (const scope of rs.scopeSpans ?? []) {\n for (const span of scope.spans ?? []) {\n const attributes = attrsToRecord(span.attributes ?? [])\n if (vocab === 'openinference') applyOpenInference(attributes)\n const line: OtlpFlatLine = {\n trace_id: span.traceId,\n span_id: span.spanId,\n parent_span_id: span.parentSpanId ?? null,\n name: span.name,\n kind: kindMap[span.kind] ?? 'SPAN_KIND_UNSPECIFIED',\n start_time: nanoToIso(span.startTimeUnixNano),\n end_time: nanoToIso(span.endTimeUnixNano),\n status: {\n code: STATUS_MAP[span.status?.code ?? 0] ?? 'STATUS_CODE_UNSET',\n ...(span.status?.message ? { message: span.status.message } : {}),\n },\n resource,\n attributes,\n }\n if (span.events && span.events.length > 0) {\n line.events = span.events.map((e) => ({\n name: e.name,\n timeUnixNano: e.timeUnixNano,\n ...(e.attributes ? { attributes: attrsToRecord(e.attributes) } : {}),\n }))\n }\n lines.push(line)\n }\n }\n }\n\n return lines\n}\n","/**\n * `otlpToRunRecords` — fold an OTLP traces.jsonl (one OTLP span per line;\n * the form AppWorld / HALO emit via their OpenInference OTLP exporter, the\n * same shape `flattenOtlpExportToNdjson` produces) into validated\n * `RunRecord[]` — one record per `trace_id` by default, or per caller-defined\n * logical run when one task is fragmented across multiple OTLP traces.\n *\n * This is the offline ingestion primitive the AppWorld proposer bench and the\n * hosted Intelligence product both stand on: traces in, paper-grade rows\n * out, ready for `compareOptimizationMethods` / `analyzeRuns` / the promotion gate.\n *\n * Aggregation per trace:\n * - tokenUsage: reconcile input, output, cache-read, and cache-write across\n * nested model-call wrappers without double-counting parent aggregates.\n * - costUsd: reconcile complete observed model-call cost when present; else priced via\n * `opts.priceUsdPerToken` from the aggregated tokens; else 0 with a\n * loud `raw.cost_unpriced = 1` marker so a missing price is visible, not\n * a silent zero folded into a gate.\n * - failureMode: the first `STATUS_CODE_ERROR` span's normalized status\n * message (carries the real failure signature, not a generic class).\n * - model: the dominant LLM model in the trace (snapshot-padded to satisfy\n * `validateRunRecord` when the trace's model is a bare alias).\n * - outcome score: `opts.scoreForTrace` (AppWorld `world.evaluate()` →\n * TGC/SGC) when supplied; else 1 when the trace had no error span, 0\n * when it did — a defensible default the caller can override.\n * - prompt / completion: carried into `raw` as token-count signals and,\n * when the first/last LLM span exposes `input.value` / `output.value`,\n * the verbatim text is preserved on the optional `promptText` /\n * `completionText` of the returned `OtlpTraceRunRecord`.\n *\n * Fail-loud: an OTLP file with zero valid spans throws. A trace with no\n * spans is impossible (a trace exists only because a span referenced it).\n * `validateRunRecord` runs on every row — a malformed projection throws\n * rather than silently producing a half-record.\n */\n\nimport {\n type RunCostProvenance,\n type RunRecord,\n type RunSplitTag,\n type RunTokenUsage,\n validateRunRecord,\n} from '../run-record'\nimport {\n type MeasurementCoverage,\n recordAggregateMeasurements,\n summarizeExecutionMeasurements,\n} from '../trace/execution-measurements'\nimport { LLM_MODEL_ATTR_KEYS } from '../trace/otlp-attributes'\nimport {\n compareSpanTime,\n firstStringAttr,\n type ProjectedOtlpSpan,\n projectOtlpFlatLine,\n spanEpochMillis,\n} from './otlp-span'\n\nexport interface OtlpToRunRecordsOptions {\n /** Logical experiment grouping for every produced record. */\n experimentId: string\n /** Candidate (variant) id — the surface these traces exercised. The\n * bench passes the proposer label here so `compareOptimizationMethods` can pair rows. */\n candidateId: string\n /** Split assignment for every produced record. Default `'holdout'` —\n * ingested traces are evidence, not the optimizer's training pool. */\n splitTag?: RunSplitTag\n /** Git SHA the traces were produced from. Default `'unknown'`. */\n commitSha?: string\n /** sha256 of the effective prompt surface. Default `'unknown'`. */\n promptHash?: string\n /** sha256 of the effective config. Default `'unknown'`. */\n configHash?: string\n /** RNG seed recorded on every row. Default 0. */\n seed?: number\n /**\n * Fallback model snapshot when the trace exposes no LLM model attribute\n * OR exposes a bare alias `validateRunRecord` would reject. The trace's\n * own model wins when it already carries a snapshot. Default\n * `'unknown@otlp'` (opaque-snapshot form the validator accepts).\n */\n fallbackModel?: string\n /**\n * USD per total token (input+output) used to price a trace when no\n * per-span cost attribute is present. When unset, an unpriced trace\n * records `costUsd: 0` AND `raw.cost_unpriced = 1` — the zero is flagged,\n * never silent.\n */\n priceUsdPerToken?: number\n /**\n * Map each OTLP `trace_id` to the logical run it belongs to. Use this when a\n * provider emits several traces for one task attempt. All mapped traces are\n * aggregated into one record; duplicate span ids remain isolated by their\n * source trace. The callback must return a non-empty id for every trace.\n *\n * When omitted, every `trace_id` remains an independent run.\n */\n logicalRunIdForTrace?: (traceId: string) => string\n /**\n * Score for a produced run's outcome (AppWorld `world.evaluate()` →\n * TGC/SGC, or\n * any [0,1] task-success signal). Keyed by the logical run id when\n * `logicalRunIdForTrace` is supplied, otherwise by `trace_id`; falls through to\n * the error-derived default (1 = no error span, 0 = had one) when the map\n * has no entry or the function returns undefined.\n */\n scoreForTrace?: (runId: string, span: TraceAggregate) => number | undefined\n /**\n * Per-record judge metadata when an external judge produced the score.\n * Keyed by the logical run id when supplied, otherwise by `trace_id`.\n */\n judgeMetadataForTrace?: (runId: string) => RunRecord['judgeMetadata'] | undefined\n}\n\n/** A `RunRecord` plus the verbatim prompt/completion text when the trace's\n * LLM spans exposed it. The text is NOT on the validated `RunRecord`\n * (`outcome.raw` is numeric-only) but consumers ingesting full traces want\n * it — so it rides alongside. */\nexport interface OtlpTraceRunRecord {\n record: RunRecord\n /** Verbatim first-LLM-span `input.value`, when present. */\n promptText?: string\n /** Verbatim last-LLM-span `output.value`, when present. */\n completionText?: string\n}\n\n/** Per-trace rollup the score callback can inspect. */\nexport interface TraceAggregate {\n traceId: string\n /** Number of source OTLP traces folded into this run. */\n sourceTraceCount: number\n /** Source OTLP trace ids folded into this run, sorted for deterministic audit output. */\n sourceTraceIds: readonly string[]\n spanCount: number\n llmSpanCount: number\n toolSpanCount: number\n agentSpanCount: number\n errorSpanCount: number\n tokenUsage: RunTokenUsage\n /** First error span's normalized status message, if any. */\n firstErrorMessage?: string\n model: string\n startTime: string\n endTime: string\n wallMs: number\n}\n\ninterface AggregatedTrace extends TraceAggregate {\n callSpanIds: string[]\n costMeasurement: MeasurementCoverage\n aggregateMeasurement?: ReturnType<typeof summarizeExecutionMeasurements>['aggregate']\n}\n\n/**\n * Parse + aggregate an OTLP traces.jsonl string into validated\n * `RunRecord[]` (one per trace). Use {@link otlpToTraceRunRecords} when you\n * also want the verbatim prompt/completion text alongside each record.\n */\nexport function otlpToRunRecords(otlpJsonl: string, opts: OtlpToRunRecordsOptions): RunRecord[] {\n return otlpToTraceRunRecords(otlpJsonl, opts).map((r) => r.record)\n}\n\n/**\n * Aggregate already-parsed OTLP flat rows without serializing them back to\n * JSONL. This is the in-memory counterpart to {@link otlpToRunRecords}; both\n * paths share projection, reconciliation, validation, and ordering.\n */\nexport function otlpRowsToRunRecords(\n rows: Iterable<object>,\n opts: OtlpToRunRecordsOptions,\n): RunRecord[] {\n return otlpRowsToTraceRunRecords(rows, opts).map((row) => row.record)\n}\n\n/** As {@link otlpToRunRecords} but returns the prompt/completion text too. */\nexport function otlpToTraceRunRecords(\n otlpJsonl: string,\n opts: OtlpToRunRecordsOptions,\n): OtlpTraceRunRecord[] {\n return traceRunRecordsFromSpans(\n groupSpansByLogicalRun(groupJsonlSpansByTrace(otlpJsonl), opts.logicalRunIdForTrace),\n opts,\n )\n}\n\n/** Parsed-row counterpart to {@link otlpToTraceRunRecords}. */\nexport function otlpRowsToTraceRunRecords(\n rows: Iterable<object>,\n opts: OtlpToRunRecordsOptions,\n): OtlpTraceRunRecord[] {\n return traceRunRecordsFromSpans(\n groupSpansByLogicalRun(groupRowsByTrace(rows), opts.logicalRunIdForTrace),\n opts,\n )\n}\n\nfunction traceRunRecordsFromSpans(\n byTrace: Map<string, ProjectedOtlpSpan[]>,\n opts: OtlpToRunRecordsOptions,\n): OtlpTraceRunRecord[] {\n const splitTag = opts.splitTag ?? 'holdout'\n const commitSha = opts.commitSha ?? 'unknown'\n const promptHash = opts.promptHash ?? 'unknown'\n const configHash = opts.configHash ?? 'unknown'\n const seed = opts.seed ?? 0\n const fallbackModel = opts.fallbackModel ?? 'unknown@otlp'\n\n if (byTrace.size === 0) {\n throw new Error(\n 'otlpToRunRecords: OTLP input produced zero valid spans — every row was empty, malformed, or missing trace_id/span_id',\n )\n }\n\n // Stable trace order (insertion order of first appearance is preserved by\n // Map; sort by trace_id for determinism across producers).\n const traceIds = [...byTrace.keys()].sort()\n const out: OtlpTraceRunRecord[] = []\n\n for (const traceId of traceIds) {\n const spans = byTrace.get(traceId)!\n const agg = aggregateTrace(traceId, spans, fallbackModel)\n\n const score = resolveScore(opts, traceId, agg)\n const { costUsd, costProvenance } = resolveCost(opts, agg)\n\n const raw: Record<string, number> = {\n source_trace_count: agg.sourceTraceCount,\n span_count: agg.spanCount,\n llm_span_count: agg.llmSpanCount,\n tool_span_count: agg.toolSpanCount,\n agent_span_count: agg.agentSpanCount,\n error_span_count: agg.errorSpanCount,\n prompt_tokens: agg.tokenUsage.input,\n completion_tokens: agg.tokenUsage.output,\n }\n if (agg.tokenUsage.reasoning !== undefined) raw.reasoning_tokens = agg.tokenUsage.reasoning\n if (agg.tokenUsage.cached !== undefined) raw.cached_tokens = agg.tokenUsage.cached\n if (agg.tokenUsage.cacheWrite !== undefined) {\n raw.cache_write_tokens = agg.tokenUsage.cacheWrite\n }\n if (agg.costMeasurement.value !== undefined && !agg.costMeasurement.complete) {\n raw.partial_observed_cost_usd = agg.costMeasurement.value\n }\n recordAggregateMeasurements(raw, agg.aggregateMeasurement)\n if (costProvenance.kind === 'uncaptured') raw.cost_unpriced = 1\n\n const outcome =\n splitTag === 'holdout' ? { holdoutScore: score, raw } : { searchScore: score, raw }\n\n const { promptText, completionText } = extractPromptCompletion(spans, agg.callSpanIds)\n const judgeMetadata = opts.judgeMetadataForTrace?.(traceId)\n\n const record = validateRunRecord({\n runId: `otlp:${opts.experimentId}:${opts.candidateId}:${traceId}`,\n experimentId: opts.experimentId,\n candidateId: opts.candidateId,\n seed,\n model: ensureSnapshot(agg.model, fallbackModel),\n promptHash,\n configHash,\n commitSha,\n wallMs: agg.wallMs,\n costUsd,\n costProvenance,\n tokenUsage: agg.tokenUsage,\n ...(judgeMetadata ? { judgeMetadata } : {}),\n outcome,\n ...(agg.firstErrorMessage ? { failureMode: agg.firstErrorMessage } : {}),\n splitTag,\n scenarioId: traceId,\n })\n\n out.push({\n record,\n ...(promptText !== undefined ? { promptText } : {}),\n ...(completionText !== undefined ? { completionText } : {}),\n })\n }\n\n return out\n}\n\n// ── Internals ──────────────────────────────────────────────────────────\n\nfunction* yieldJsonlRows(otlpJsonl: string): Iterable<Record<string, unknown>> {\n for (const line of otlpJsonl.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.length === 0) continue\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed)\n } catch {\n // Tolerate a stray malformed line — mirrors the store's index, which\n // skips unparseable lines rather than nuking a whole dataset. A file\n // that is ENTIRELY malformed still throws (zero valid spans).\n continue\n }\n if (parsed && typeof parsed === 'object') yield parsed as Record<string, unknown>\n }\n}\n\nfunction groupJsonlSpansByTrace(otlpJsonl: string): Map<string, ProjectedOtlpSpan[]> {\n return groupRowsByTrace(yieldJsonlRows(otlpJsonl))\n}\n\nfunction groupRowsByTrace(rows: Iterable<object>): Map<string, ProjectedOtlpSpan[]> {\n const byTrace = new Map<string, ProjectedOtlpSpan[]>()\n for (const row of rows) {\n if (!row || typeof row !== 'object') continue\n const span = projectOtlpFlatLine(row as Record<string, unknown>)\n if (!span) continue\n const arr = byTrace.get(span.trace_id)\n if (arr) arr.push(span)\n else byTrace.set(span.trace_id, [span])\n }\n return byTrace\n}\n\nfunction groupSpansByLogicalRun(\n byTrace: Map<string, ProjectedOtlpSpan[]>,\n logicalRunIdForTrace: OtlpToRunRecordsOptions['logicalRunIdForTrace'],\n): Map<string, ProjectedOtlpSpan[]> {\n if (!logicalRunIdForTrace) return byTrace\n\n const byRun = new Map<string, ProjectedOtlpSpan[]>()\n for (const [traceId, spans] of byTrace) {\n const suppliedRunId = logicalRunIdForTrace(traceId)\n if (typeof suppliedRunId !== 'string' || suppliedRunId.trim().length === 0) {\n throw new Error(\n `otlpToRunRecords: logicalRunIdForTrace('${traceId}') returned an empty run id`,\n )\n }\n const runId = suppliedRunId.trim()\n const target = byRun.get(runId) ?? []\n for (const span of spans) {\n target.push({\n ...span,\n span_id: qualifySpanId(traceId, span.span_id),\n parent_span_id: span.parent_span_id ? qualifySpanId(traceId, span.parent_span_id) : null,\n })\n }\n byRun.set(runId, target)\n }\n return byRun\n}\n\nfunction qualifySpanId(traceId: string, spanId: string): string {\n const prefix = `${traceId}:`\n return spanId.startsWith(prefix) ? spanId : `${prefix}${spanId}`\n}\n\nfunction aggregateTrace(\n traceId: string,\n spans: ProjectedOtlpSpan[],\n fallbackModel: string,\n): AggregatedTrace {\n // Span order within a trace is by start time (epoch-aware across ISO/epoch\n // dialects), then a stable tiebreak.\n const ordered = [...spans].sort(\n (a, b) => compareSpanTime(a.start_time, b.start_time) || a.span_id.localeCompare(b.span_id),\n )\n\n const measurements = summarizeExecutionMeasurements(\n ordered.map((span) => ({\n id: span.span_id,\n ...(span.parent_span_id ? { parentId: span.parent_span_id } : {}),\n attributes: span.attributes,\n modelCall:\n span.kind === 'LLM' ||\n (span.kind === 'UNKNOWN' &&\n (span.model_name !== null ||\n typeof span.attributes['gen_ai.operation.name'] === 'string')),\n aggregate: span.kind !== 'LLM' && span.kind !== 'UNKNOWN',\n })),\n )\n let toolSpanCount = 0\n let agentSpanCount = 0\n let errorSpanCount = 0\n let firstErrorMessage: string | undefined\n const modelVotes = new Map<string, number>()\n let earliest = ordered[0]?.start_time ?? ''\n let latest = ordered[0]?.end_time ?? ''\n\n for (const s of ordered) {\n if (s.start_time && (!earliest || compareSpanTime(s.start_time, earliest) < 0))\n earliest = s.start_time\n if (s.end_time && (!latest || compareSpanTime(s.end_time, latest) > 0)) latest = s.end_time\n\n if (s.kind === 'TOOL') {\n toolSpanCount += 1\n } else if (s.kind === 'AGENT') {\n agentSpanCount += 1\n }\n\n if (s.status === 'ERROR') {\n errorSpanCount += 1\n if (firstErrorMessage === undefined) {\n firstErrorMessage = (s.status_message ?? `${s.name} — STATUS_CODE_ERROR`).slice(0, 500)\n }\n }\n }\n\n const callSpanIds = new Set(measurements.callSpanIds)\n for (const span of ordered) {\n if (!callSpanIds.has(span.span_id)) continue\n const model = firstStringAttr(span.attributes, LLM_MODEL_ATTR_KEYS) ?? span.model_name\n if (model) modelVotes.set(model, (modelVotes.get(model) ?? 0) + 1)\n }\n\n // Dominant model across LLM spans; falls back to any model attribute on a\n // non-LLM span, then the supplied fallback snapshot.\n const model = topVote(modelVotes) ?? firstModelAttr(ordered) ?? fallbackModel\n\n let wallMs = 0\n // epoch-aware: Date.parse returns NaN for a bare epoch-millis string, which\n // silently zeroed wallMs for traces emitted with epoch timestamps.\n const a = spanEpochMillis(earliest)\n const b = spanEpochMillis(latest)\n if (a !== null && b !== null) wallMs = Math.max(0, b - a)\n\n const sourceTraceIds = [...new Set(spans.map((span) => span.trace_id))].sort()\n\n return {\n traceId,\n sourceTraceCount: sourceTraceIds.length,\n sourceTraceIds,\n spanCount: spans.length,\n llmSpanCount: measurements.modelCallCount,\n toolSpanCount,\n agentSpanCount,\n errorSpanCount,\n tokenUsage: measurements.tokenUsage,\n firstErrorMessage,\n model,\n startTime: earliest,\n endTime: latest,\n wallMs,\n callSpanIds: measurements.callSpanIds,\n costMeasurement: measurements.cost,\n ...(measurements.aggregate ? { aggregateMeasurement: measurements.aggregate } : {}),\n }\n}\n\nfunction resolveScore(opts: OtlpToRunRecordsOptions, traceId: string, agg: TraceAggregate): number {\n const supplied = opts.scoreForTrace?.(traceId, agg)\n if (supplied !== undefined) {\n if (!Number.isFinite(supplied)) {\n throw new Error(\n `otlpToRunRecords: scoreForTrace('${traceId}') returned non-finite ${supplied}`,\n )\n }\n return supplied\n }\n // Default: error-derived. A trace with any error span scores 0; otherwise 1.\n return agg.errorSpanCount > 0 ? 0 : 1\n}\n\nfunction resolveCost(\n opts: OtlpToRunRecordsOptions,\n agg: AggregatedTrace,\n): { costUsd: number; costProvenance: RunCostProvenance } {\n const observedCost = agg.costMeasurement\n if (observedCost.complete && observedCost.value !== undefined) {\n return {\n costUsd: observedCost.value,\n costProvenance: { kind: 'observed', usd: observedCost.value },\n }\n }\n if (agg.aggregateMeasurement?.costUsd !== undefined) {\n return {\n costUsd: agg.aggregateMeasurement.costUsd,\n costProvenance: { kind: 'observed', usd: agg.aggregateMeasurement.costUsd },\n }\n }\n\n if (opts.priceUsdPerToken !== undefined) {\n const totalTokens = agg.tokenUsage.input + agg.tokenUsage.output\n const costUsd = totalTokens * opts.priceUsdPerToken\n return { costUsd, costProvenance: { kind: 'estimated', usd: costUsd } }\n }\n\n // No per-span cost, no price table — record 0 but flag it loudly so a\n // missing price never silently flatters a cost axis.\n return { costUsd: 0, costProvenance: { kind: 'uncaptured', usd: null } }\n}\n\nfunction extractPromptCompletion(\n spans: ProjectedOtlpSpan[],\n callSpanIds: string[],\n): {\n promptText?: string\n completionText?: string\n} {\n const callIds = new Set(callSpanIds)\n const measuredCalls = spans.filter((span) => callIds.has(span.span_id))\n const llm = (\n measuredCalls.length > 0 ? measuredCalls : spans.filter((s) => s.kind === 'LLM')\n ).sort(\n (a, b) => compareSpanTime(a.start_time, b.start_time) || a.span_id.localeCompare(b.span_id),\n )\n if (llm.length === 0) return {}\n const promptText =\n firstStringAttr(llm[0]!.attributes, ['input.value', 'llm.input_messages', 'gen_ai.prompt']) ??\n undefined\n const last = llm[llm.length - 1]!\n const completionText =\n firstStringAttr(last.attributes, [\n 'output.value',\n 'llm.output_messages',\n 'gen_ai.completion',\n ]) ?? undefined\n return {\n ...(promptText !== undefined ? { promptText } : {}),\n ...(completionText !== undefined ? { completionText } : {}),\n }\n}\n\nfunction topVote(votes: Map<string, number>): string | null {\n let best: string | null = null\n let bestN = 0\n for (const [k, n] of votes) {\n // Strict > keeps the higher count; lexicographic tie-break makes the winner\n // independent of Map insertion order (reproducible across producers).\n if (n > bestN || (n === bestN && best !== null && k < best)) {\n best = k\n bestN = n\n }\n }\n return best\n}\n\nfunction firstModelAttr(spans: ProjectedOtlpSpan[]): string | null {\n for (const s of spans) {\n const m = firstStringAttr(s.attributes, LLM_MODEL_ATTR_KEYS) ?? s.model_name\n if (m) return m\n }\n return null\n}\n\n/**\n * `validateRunRecord` rejects bare model aliases (`gpt-4o`) that remap\n * silently. AppWorld/HALO traces frequently carry such bare ids (or a null\n * model). When the model already encodes a snapshot we keep it; otherwise we\n * append the fallback snapshot token so the row is admissible without lying\n * about the model — the bare base name is preserved verbatim before `@`.\n */\nfunction ensureSnapshot(model: string, fallbackModel: string): string {\n if (modelHasSnapshot(model)) return model\n const fallbackTag = fallbackModel.includes('@')\n ? fallbackModel.slice(fallbackModel.indexOf('@'))\n : '@otlp'\n return `${model}${fallbackTag}`\n}\n\nfunction modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n","/**\n * TraceStore — persistence + query over the TraceSchema v1 corpus.\n *\n * Two implementations ship in the core:\n * - InMemoryTraceStore: dev + tests, fully in-process\n * - FileSystemTraceStore: NDJSON append-only files per entity, suitable\n * for long-running CI jobs; rolled over at 32MB\n *\n * Downstream adapters (DuckDB, Langfuse, R2 parquet) implement this same\n * interface — the rest of the framework is storage-agnostic.\n */\n\nimport type {\n Artifact,\n BudgetLedgerEntry,\n EventKind,\n Run,\n RunStatus,\n Span,\n SpanKind,\n TraceEvent,\n} from './schema'\n\nexport interface RunFilter {\n scenarioId?: string\n variantId?: string\n status?: RunStatus\n since?: number\n until?: number\n tag?: { key: string; value: string }\n parentRunId?: string\n projectId?: string\n chatId?: string\n layer?: import('./schema').RunLayer\n}\n\nexport interface SpanFilter {\n runId?: string\n parentSpanId?: string\n kind?: SpanKind\n name?: string\n toolName?: string\n judgeId?: string\n since?: number\n until?: number\n}\n\nexport interface EventFilter {\n runId?: string\n spanId?: string\n kind?: EventKind\n since?: number\n until?: number\n}\n\nexport interface TraceStore {\n appendRun(run: Run): Promise<void>\n updateRun(runId: string, patch: Partial<Run>): Promise<void>\n appendSpan(span: Span): Promise<void>\n updateSpan(spanId: string, patch: Partial<Span>): Promise<void>\n appendEvent(event: TraceEvent): Promise<void>\n appendArtifact(artifact: Artifact): Promise<void>\n appendBudgetEntry(entry: BudgetLedgerEntry): Promise<void>\n\n getRun(runId: string): Promise<Run | undefined>\n listRuns(filter?: RunFilter): Promise<Run[]>\n spans(filter?: SpanFilter): Promise<Span[]>\n events(filter?: EventFilter): Promise<TraceEvent[]>\n budget(runId: string): Promise<BudgetLedgerEntry[]>\n artifacts(runId: string): Promise<Artifact[]>\n}\n\n// ── In-memory ────────────────────────────────────────────────────────\n\nexport class InMemoryTraceStore implements TraceStore {\n private runs = new Map<string, Run>()\n private allSpans: Span[] = []\n private allEvents: TraceEvent[] = []\n private allArtifacts: Artifact[] = []\n private allBudget: BudgetLedgerEntry[] = []\n\n async appendRun(run: Run): Promise<void> {\n if (this.runs.has(run.runId)) throw new Error(`run ${run.runId} already exists`)\n this.runs.set(run.runId, { ...run })\n }\n\n async updateRun(runId: string, patch: Partial<Run>): Promise<void> {\n const existing = this.runs.get(runId)\n if (!existing) throw new Error(`run ${runId} not found`)\n this.runs.set(runId, { ...existing, ...patch })\n }\n\n async appendSpan(span: Span): Promise<void> {\n this.allSpans.push({ ...span })\n }\n\n async updateSpan(spanId: string, patch: Partial<Span>): Promise<void> {\n const idx = this.allSpans.findIndex((s) => s.spanId === spanId)\n if (idx < 0) throw new Error(`span ${spanId} not found`)\n this.allSpans[idx] = { ...this.allSpans[idx], ...patch } as Span\n }\n\n async appendEvent(event: TraceEvent): Promise<void> {\n this.allEvents.push({ ...event })\n }\n\n async appendArtifact(artifact: Artifact): Promise<void> {\n this.allArtifacts.push({ ...artifact })\n }\n\n async appendBudgetEntry(entry: BudgetLedgerEntry): Promise<void> {\n this.allBudget.push({ ...entry })\n }\n\n async getRun(runId: string): Promise<Run | undefined> {\n const r = this.runs.get(runId)\n return r ? { ...r } : undefined\n }\n\n async listRuns(filter: RunFilter = {}): Promise<Run[]> {\n return [...this.runs.values()].filter((r) => matchesRun(r, filter))\n }\n\n async spans(filter: SpanFilter = {}): Promise<Span[]> {\n return this.allSpans.filter((s) => matchesSpan(s, filter)).map((s) => ({ ...s }))\n }\n\n async events(filter: EventFilter = {}): Promise<TraceEvent[]> {\n return this.allEvents.filter((e) => matchesEvent(e, filter)).map((e) => ({ ...e }))\n }\n\n async budget(runId: string): Promise<BudgetLedgerEntry[]> {\n return this.allBudget.filter((b) => b.runId === runId).map((b) => ({ ...b }))\n }\n\n async artifacts(runId: string): Promise<Artifact[]> {\n return this.allArtifacts.filter((a) => a.runId === runId).map((a) => ({ ...a }))\n }\n}\n\nfunction matchesRun(r: Run, f: RunFilter): boolean {\n if (f.scenarioId && r.scenarioId !== f.scenarioId) return false\n if (f.variantId && r.variantId !== f.variantId) return false\n if (f.status && r.status !== f.status) return false\n if (f.since !== undefined && r.startedAt < f.since) return false\n if (f.until !== undefined && r.startedAt > f.until) return false\n if (f.tag && r.tags?.[f.tag.key] !== f.tag.value) return false\n if (f.parentRunId && r.parentRunId !== f.parentRunId) return false\n if (f.projectId && r.projectId !== f.projectId) return false\n if (f.chatId && r.chatId !== f.chatId) return false\n if (f.layer && r.layer !== f.layer) return false\n return true\n}\n\nfunction matchesSpan(s: Span, f: SpanFilter): boolean {\n if (f.runId && s.runId !== f.runId) return false\n if (f.parentSpanId && s.parentSpanId !== f.parentSpanId) return false\n if (f.kind && s.kind !== f.kind) return false\n if (f.name && s.name !== f.name) return false\n if (f.toolName && (s.kind !== 'tool' || s.toolName !== f.toolName)) return false\n if (f.judgeId && (s.kind !== 'judge' || s.judgeId !== f.judgeId)) return false\n if (f.since !== undefined && s.startedAt < f.since) return false\n if (f.until !== undefined && s.startedAt > f.until) return false\n return true\n}\n\nfunction matchesEvent(e: TraceEvent, f: EventFilter): boolean {\n if (f.runId && e.runId !== f.runId) return false\n if (f.spanId && e.spanId !== f.spanId) return false\n if (f.kind && e.kind !== f.kind) return false\n if (f.since !== undefined && e.timestamp < f.since) return false\n if (f.until !== undefined && e.timestamp > f.until) return false\n return true\n}\n\n// ── Filesystem (NDJSON append-only, one file per entity) ─────────────\n\nexport interface FileSystemTraceStoreOptions {\n dir: string\n /** Roll over NDJSON files when they exceed this size in bytes. Default 32 MB. */\n maxBytes?: number\n}\n\nexport class FileSystemTraceStore implements TraceStore {\n private dir: string\n private maxBytes: number\n /** Lazy in-memory index for queries — populated on first read. */\n private index?: InMemoryTraceStore\n /** Memoized index build — concurrent first reads share one build, and an\n * append racing an in-flight load awaits this so its row isn't lost. */\n private indexPromise?: Promise<InMemoryTraceStore>\n /** Strictly-increasing rollover stamp. Date.now() alone collides when two\n * rollovers land in the same millisecond, overwriting a rolled file. */\n private lastRolloverStamp = 0\n /**\n * Per-file append serialization. stat → conditional-rename → appendFile is a\n * read-modify-write on the active file; without a lock two concurrent appends\n * to the same `name` can both pass the size check (exceeding maxBytes) or one\n * can append to a file the other just renamed away. Each entry chains the\n * next append behind the prior one for that file.\n */\n private appendLocks = new Map<string, Promise<void>>()\n\n constructor(options: FileSystemTraceStoreOptions) {\n this.dir = options.dir\n this.maxBytes = options.maxBytes ?? 32 * 1024 * 1024\n }\n\n private async ensureDir(): Promise<void> {\n const fs = await import('node:fs/promises')\n await fs.mkdir(this.dir, { recursive: true })\n }\n\n private async append(name: string, record: unknown): Promise<void> {\n // If an index load is in flight, wait for it. The row must hit disk AFTER\n // the load finished reading, so it lands in the completed index via the\n // mirror below — never lost in the gap before `this.index` is assigned.\n if (this.indexPromise) await this.indexPromise\n // Chain this append behind any in-flight append for the same file. The tail\n // promise never rejects (errors are isolated to each caller's `result`), so\n // one failed append can't break the lock chain for the next one.\n const prior = this.appendLocks.get(name) ?? Promise.resolve()\n const result = prior.then(() => this.appendLocked(name, record))\n const tail = result.then(\n () => {},\n () => {},\n )\n this.appendLocks.set(name, tail)\n try {\n await result\n } finally {\n // Drop the slot once this append is the current tail, so the map doesn't\n // grow without bound across many appends to the same file.\n if (this.appendLocks.get(name) === tail) this.appendLocks.delete(name)\n }\n }\n\n private async appendLocked(name: string, record: unknown): Promise<void> {\n await this.ensureDir()\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const active = path.join(this.dir, `${name}.ndjson`)\n try {\n const stat = await fs.stat(active)\n if (stat.size >= this.maxBytes) {\n // Strictly-increasing, collision-free even within one millisecond — a\n // bare Date.now() would let two same-ms rollovers overwrite each other.\n const stamp = Math.max(Date.now(), this.lastRolloverStamp + 1)\n this.lastRolloverStamp = stamp\n const rolled = path.join(this.dir, `${name}.${stamp}.ndjson`)\n await fs.rename(active, rolled)\n }\n } catch {\n /* file doesn't exist yet */\n }\n await fs.appendFile(active, `${JSON.stringify(record)}\\n`, 'utf8')\n // Mirror genuinely-new rows into the lazy index. Update rows (marked\n // with `_update: true` by updateRun/updateSpan) are applied by those\n // methods directly via the index's update* APIs — re-inserting them\n // here triggers a duplicate-id error once the first read populates\n // the index. Await the mirror: a fire-and-forget would let an index\n // rejection go unhandled and let disk + index diverge silently.\n if (this.index && !(record as { _update?: boolean })?._update) {\n await this.insertInto(name, record)\n }\n }\n\n private async insertInto(name: string, record: unknown): Promise<void> {\n if (!this.index) return\n switch (name) {\n case 'runs':\n await this.index.appendRun(record as Run)\n break\n case 'spans':\n await this.index.appendSpan(record as Span)\n break\n case 'events':\n await this.index.appendEvent(record as TraceEvent)\n break\n case 'artifacts':\n await this.index.appendArtifact(record as Artifact)\n break\n case 'budget':\n await this.index.appendBudgetEntry(record as BudgetLedgerEntry)\n break\n }\n }\n\n private load(): Promise<InMemoryTraceStore> {\n // Memoize: concurrent first reads share one build, and an append racing an\n // in-flight load awaits this same promise (see append()).\n this.indexPromise ??= this.buildIndex()\n return this.indexPromise\n }\n\n private async buildIndex(): Promise<InMemoryTraceStore> {\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const store = new InMemoryTraceStore()\n let entries: string[]\n try {\n entries = await fs.readdir(this.dir)\n } catch {\n // No dir yet (first run / empty corpus). Anything past this point — parse\n // errors, missing patch bases — is real corruption and must fail loud.\n this.index = store\n return store\n }\n // Replay files in write order. For one entity, rolled files\n // (`name.<ts>.ndjson`) are older than the active bare file (`name.ndjson`),\n // and readdir order is not chronological — so without this sort a patch in\n // an older rolled file could be applied AFTER (overwrite) a newer patch in\n // the active file, silently restoring a stale field. Sort: per entity,\n // rolled ascending by timestamp, then the bare active file last.\n entries.sort((a, b) => {\n // Group by the same entity base the loop uses (`split('.')[0]`); within an\n // entity, real rollover files (`<base>.<ms>.ndjson`) sort by timestamp\n // ascending and the bare active file (no numeric segment) sorts last.\n // Non-rollover names tie (Infinity) and a stable sort preserves their\n // readdir order.\n const baseA = a.split('.')[0]!\n const baseB = b.split('.')[0]!\n if (baseA !== baseB) return baseA < baseB ? -1 : 1\n const ta = a.match(/^[^.]+\\.(\\d+)\\.ndjson$/)\n const tb = b.match(/^[^.]+\\.(\\d+)\\.ndjson$/)\n const tsA = ta ? Number(ta[1]) : Number.POSITIVE_INFINITY\n const tsB = tb ? Number(tb[1]) : Number.POSITIVE_INFINITY\n return tsA - tsB\n })\n {\n // Two-pass load. Pass 1 indexes all full (base) rows; pass 2 replays the\n // `_update` patch rows that updateRun/updateSpan append. readdir order is\n // not deterministic and rollover splits a stream across files, so a patch\n // can be read before its base. Applying patches in a separate pass — after\n // every base row is indexed — means a patch always finds its target.\n // Doing it in one pass let a patch hit the catch and append a runId-less\n // fragment, corrupting span/run counts cross-instance.\n const runUpdates: Array<Record<string, unknown>> = []\n const spanUpdates: Array<Record<string, unknown>> = []\n for (const file of entries) {\n if (!file.endsWith('.ndjson')) continue\n const full = path.join(this.dir, file)\n const content = await fs.readFile(full, 'utf8')\n const base = file.split('.')[0]\n const lines = content.split('\\n')\n for (let ln = 0; ln < lines.length; ln++) {\n const line = lines[ln]!\n if (!line.trim()) continue\n let record: ReturnType<typeof JSON.parse>\n try {\n record = JSON.parse(line)\n } catch (err) {\n // Fail loud WITH context — a bare SyntaxError loses which file/line\n // is corrupt and which valid rows surround it.\n throw new Error(\n `FileSystemTraceStore: corrupt NDJSON in ${file} line ${ln + 1}: ${\n err instanceof Error ? err.message : String(err)\n } — ${line.slice(0, 120)}`,\n )\n }\n if (base === 'runs') {\n if (record?._update) {\n runUpdates.push(record)\n continue\n }\n // A duplicate full row (same dir loaded twice into one stream) is\n // collapsed last-write-wins rather than thrown.\n try {\n await store.appendRun(record)\n } catch {\n await store.updateRun(record.runId, record)\n }\n } else if (base === 'spans') {\n // `updateSpan` appends an `_update: true` patch row instead of\n // rewriting the original span. Deferred to pass 2 so it collapses\n // onto the original span — otherwise a fresh FileSystemTraceStore\n // reading the same dir reports duplicate spans (one full, one\n // fragment with no runId/kind/name), which breaks any downstream\n // consumer that re-opens the store cross-process (e.g. the OTLP\n // converter).\n if (record?._update) {\n spanUpdates.push(record)\n continue\n }\n await store.appendSpan(record)\n } else if (base === 'events') {\n await store.appendEvent(record)\n } else if (base === 'artifacts') {\n await store.appendArtifact(record)\n } else if (base === 'budget') {\n await store.appendBudgetEntry(record)\n }\n }\n }\n // Pass 2: every base row is now indexed. A patch whose base is genuinely\n // absent (truncated/partial corpus) throws inside update* — we let it\n // propagate rather than silently appending a fragment, so a corrupt\n // corpus fails loud instead of polluting counts.\n for (const record of runUpdates) {\n await store.updateRun(record.runId as string, record as Partial<Run>)\n }\n for (const record of spanUpdates) {\n await store.updateSpan(record.spanId as string, record as Partial<Span>)\n }\n }\n this.index = store\n return store\n }\n\n async appendRun(run: Run): Promise<void> {\n await this.append('runs', run)\n }\n async updateRun(runId: string, patch: Partial<Run>): Promise<void> {\n // NDJSON is append-only; record updates as new rows with the same runId —\n // readers collapse by last-write-wins on load.\n await this.append('runs', { runId, ...patch, _update: true })\n if (this.index) await this.index.updateRun(runId, patch)\n }\n async appendSpan(span: Span): Promise<void> {\n await this.append('spans', span)\n }\n async updateSpan(spanId: string, patch: Partial<Span>): Promise<void> {\n await this.append('spans', { spanId, ...patch, _update: true })\n if (this.index) await this.index.updateSpan(spanId, patch)\n }\n async appendEvent(event: TraceEvent): Promise<void> {\n await this.append('events', event)\n }\n async appendArtifact(artifact: Artifact): Promise<void> {\n await this.append('artifacts', artifact)\n }\n async appendBudgetEntry(entry: BudgetLedgerEntry): Promise<void> {\n await this.append('budget', entry)\n }\n\n async getRun(runId: string): Promise<Run | undefined> {\n return (await this.load()).getRun(runId)\n }\n async listRuns(filter?: RunFilter): Promise<Run[]> {\n return (await this.load()).listRuns(filter)\n }\n async spans(filter?: SpanFilter): Promise<Span[]> {\n return (await this.load()).spans(filter)\n }\n async events(filter?: EventFilter): Promise<TraceEvent[]> {\n return (await this.load()).events(filter)\n }\n async budget(runId: string): Promise<BudgetLedgerEntry[]> {\n return (await this.load()).budget(runId)\n }\n async artifacts(runId: string): Promise<Artifact[]> {\n return (await this.load()).artifacts(runId)\n }\n}\n","/**\n * Wrap a provider `fetch` and record request, response, and error events.\n *\n * The returned value is a plain `typeof fetch`. Capture is best-effort by\n * default; set `failClosed` when telemetry loss must stop the provider call.\n */\n\nimport {\n type ExtractedUsage,\n extractUsage,\n extractUsageFromSse,\n type SseUsageMode,\n} from './extract-usage'\nimport {\n defaultProviderRedactor,\n type ProviderRedactor,\n providerFromBaseUrl,\n type RawProviderDirection,\n type RawProviderEvent,\n type RawProviderSink,\n} from './raw-provider-sink'\n\nexport interface CaptureFetchContext {\n /** Logical run id stamped on every captured event. Required — without it\n * the raw events can't be paired with their parent `Run`. */\n runId: string\n /** Optional logical span id (enables span-level sink filtering). */\n spanId?: string\n /** Resolved base URL (normalised, no trailing slash). Used for the event's\n * `baseUrl` and for endpoint-path extraction. */\n baseUrl: string\n /** Model id the caller intends to invoke. Stamped on every event. */\n model: string\n /** Provider override. When omitted, `providerFromBaseUrl(baseUrl)`. */\n provider?: string\n}\n\nexport interface CaptureFetchOptions {\n /** Override the capture-time redactor. Default `defaultProviderRedactor`. */\n redactor?: ProviderRedactor\n /** Cap on captured response-body bytes; beyond it the body is truncated and\n * `body_truncated` is added to `redactedFields`. Default 2 MiB. */\n responseBodyByteCap?: number\n /** When true, a sink-write failure propagates to the caller. Default false\n * — capture is best-effort so a sink failure never kills the LLM call. */\n failClosed?: boolean\n /**\n * Invoked with the token usage parsed off each successful response (JSON or\n * SSE), keyed by the captured context. Lets a caller fold usage → cost without\n * re-cloning the response themselves. Not called when the response carries no\n * usage. Best-effort: a throw here is swallowed (it never kills the LLM call)\n * unless `failClosed` is set.\n */\n onUsage?: (usage: ExtractedUsage, ctx: CaptureFetchContext) => void\n /** How repeated SSE usage events should be reconciled. Default `cumulative`. */\n sseUsageMode?: SseUsageMode\n}\n\nconst DEFAULT_BODY_CAP = 2 * 1024 * 1024\n\nfunction headersToRecord(headers: Headers | undefined): Record<string, string> | undefined {\n if (!headers) return undefined\n const out: Record<string, string> = {}\n headers.forEach((value, key) => {\n out[key.toLowerCase()] = value\n })\n return Object.keys(out).length > 0 ? out : undefined\n}\n\nfunction parseMaybeJson(text: string): unknown {\n if (text.length === 0) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\n/** Best-effort request-body read across the `fetch` input forms. */\nasync function readRequestBody(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n): Promise<unknown> {\n if (typeof init?.body === 'string') return parseMaybeJson(init.body)\n if (init?.body != null) return undefined // streams / FormData / Blob — not captured\n if (input instanceof Request) {\n try {\n return parseMaybeJson(await input.clone().text())\n } catch {\n return undefined\n }\n }\n return undefined\n}\n\nfunction endpointFromUrl(url: string, baseUrl: string): string {\n const normalisedBase = baseUrl.replace(/\\/+$/, '')\n if (url.startsWith(normalisedBase)) return url.slice(normalisedBase.length) || '/'\n try {\n return new URL(url).pathname\n } catch {\n return url\n }\n}\n\nexport function captureFetchToRawSink(\n fetch: typeof globalThis.fetch,\n sink: RawProviderSink,\n ctx: CaptureFetchContext,\n opts: CaptureFetchOptions = {},\n): typeof globalThis.fetch {\n const provider = ctx.provider ?? providerFromBaseUrl(ctx.baseUrl)\n const redactor = opts.redactor ?? defaultProviderRedactor\n const bodyCap = opts.responseBodyByteCap ?? DEFAULT_BODY_CAP\n let warned = false\n\n const baseEvent = (direction: RawProviderDirection, endpoint: string): RawProviderEvent => ({\n eventId: crypto.randomUUID(),\n runId: ctx.runId,\n spanId: ctx.spanId,\n provider,\n model: ctx.model,\n endpoint,\n baseUrl: ctx.baseUrl,\n attemptIndex: 0, // retries are re-invocations one layer up; documented in 0.x\n direction,\n timestamp: Date.now(),\n redactedFields: [],\n })\n\n const record = async (event: RawProviderEvent): Promise<void> => {\n try {\n await sink.record(redactor(event))\n } catch (err) {\n if (opts.failClosed) throw err\n if (!warned) {\n warned = true\n console.warn(\n `captureFetchToRawSink: sink.record failed (capture is best-effort) — ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n }\n }\n }\n\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url =\n typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n const endpoint = endpointFromUrl(url, ctx.baseUrl)\n\n const reqHeaders = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n await record({\n ...baseEvent('request', endpoint),\n requestHeaders: { ...headersToRecord(reqHeaders), 'x-http-method': method },\n requestBody: await readRequestBody(input, init),\n })\n\n const start = Date.now()\n let response: Response\n try {\n response = await fetch(input, init)\n } catch (err) {\n await record({\n ...baseEvent('error', endpoint),\n durationMs: Date.now() - start,\n errorMessage: err instanceof Error ? err.message : String(err),\n })\n throw err\n }\n\n // Read the body off a clone so the caller still consumes the original.\n let responseBody: unknown\n let rawText: string | undefined\n const redactedFields: string[] = []\n try {\n rawText = await response.clone().text()\n if (rawText.length > bodyCap) {\n responseBody = rawText.slice(0, bodyCap)\n redactedFields.push('body_truncated')\n } else {\n responseBody = parseMaybeJson(rawText)\n }\n } catch {\n responseBody = undefined\n }\n\n if (opts.onUsage && rawText !== undefined) {\n // Reuse the body already read for capture; no extra clone. JSON first,\n // then SSE accumulation. A throw in the consumer's callback is swallowed\n // (best-effort) unless failClosed is set — the LLM call must not die here.\n try {\n const parsedForUsage = parseMaybeJson(rawText)\n const usage =\n extractUsage(parsedForUsage) ??\n (typeof parsedForUsage === 'string'\n ? extractUsageFromSse(rawText, { mode: opts.sseUsageMode })\n : null)\n if (usage) opts.onUsage(usage, ctx)\n } catch (err) {\n if (opts.failClosed) throw err\n }\n }\n\n await record({\n ...baseEvent('response', endpoint),\n durationMs: Date.now() - start,\n statusCode: response.status,\n responseHeaders: headersToRecord(response.headers),\n responseBody,\n redactedFields,\n })\n\n return response\n }\n}\n","/**\n * OpenTelemetry JSON export — maps TraceSchema v1 to OTLP/JSON so\n * traces render natively in Jaeger / Honeycomb / Langfuse / Grafana.\n *\n * Wire format only. We do NOT depend on the @opentelemetry SDK — that\n * would drag in polyfills incompatible with Workers/Edge. Consumers\n * push the JSON to their collector of choice via HTTP.\n *\n * Reference: OTLP 1.3.2 (ResourceSpans / ScopeSpans / Span).\n */\n\nimport {\n applyLlmSpanOtlpAttributes,\n applyToolSpanOtlpAttributes,\n OPENINFERENCE_SPAN_KIND,\n traceSpanKindToOpenInferenceKind,\n} from './otlp-attributes'\nimport type { Run, Span, TraceEvent } from './schema'\nimport type { TraceStore } from './store'\n\nexport const OTEL_AGENT_EVAL_SCOPE = { name: '@tangle-network/agent-eval', version: '0.3.0' }\n\nexport interface OtlpSpan {\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n attributes: Array<{\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n }>\n events?: Array<{ timeUnixNano: string; name: string; attributes?: OtlpSpan['attributes'] }>\n status?: { code: number; message?: string }\n}\n\nexport interface OtlpResourceSpans {\n resource: { attributes: OtlpSpan['attributes'] }\n scopeSpans: Array<{ scope: typeof OTEL_AGENT_EVAL_SCOPE; spans: OtlpSpan[] }>\n}\n\nexport interface OtlpExport {\n resourceSpans: OtlpResourceSpans[]\n}\n\n/** Export a single run's spans + events in OTLP/JSON. */\nexport async function exportRunAsOtlp(\n store: TraceStore,\n runId: string,\n resourceAttrs: Record<string, string | number | boolean> = {},\n): Promise<OtlpExport> {\n const run = await store.getRun(runId)\n if (!run) throw new Error(`run ${runId} not found`)\n const spans = await store.spans({ runId })\n const events = await store.events({ runId })\n const eventsBySpan = new Map<string, TraceEvent[]>()\n for (const e of events) {\n if (!e.spanId) continue\n const arr = eventsBySpan.get(e.spanId) ?? []\n arr.push(e)\n eventsBySpan.set(e.spanId, arr)\n }\n const traceId = runToTraceId(run)\n const otlpSpans: OtlpSpan[] = spans.map((s) =>\n spanToOtlp(s, traceId, eventsBySpan.get(s.spanId) ?? []),\n )\n return {\n resourceSpans: [\n {\n resource: {\n attributes: toAttributes({\n 'service.name': 'agent-eval',\n 'run.id': run.runId,\n 'run.scenario_id': run.scenarioId,\n 'run.variant_id': run.variantId ?? '',\n 'run.dataset_version': run.datasetVersion ?? '',\n 'run.code_sha': run.codeSha ?? '',\n 'run.model_fingerprint': run.modelFingerprint ?? '',\n ...resourceAttrs,\n }),\n },\n scopeSpans: [{ scope: OTEL_AGENT_EVAL_SCOPE, spans: otlpSpans }],\n },\n ],\n }\n}\n\nfunction spanToOtlp(span: Span, traceId: string, events: TraceEvent[]): OtlpSpan {\n const endedAt = span.endedAt ?? span.startedAt\n return {\n traceId,\n spanId: padSpanId(span.spanId),\n parentSpanId: span.parentSpanId ? padSpanId(span.parentSpanId) : undefined,\n name: span.name,\n kind: 1, // SPAN_KIND_INTERNAL\n startTimeUnixNano: msToNs(span.startedAt),\n endTimeUnixNano: msToNs(endedAt),\n attributes: toAttributes(flattenSpanAttributes(span)),\n events: events.map((e) => ({\n timeUnixNano: msToNs(e.timestamp),\n name: e.kind,\n attributes: toAttributes(flattenPayload(e.payload)),\n })),\n status: span.status === 'error' ? { code: 2, message: span.error } : { code: 1 },\n }\n}\n\nfunction flattenSpanAttributes(span: Span): Record<string, string | number | boolean> {\n const base: Record<string, string | number | boolean> = {}\n if (span.attributes) {\n for (const [k, v] of Object.entries(span.attributes)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') base[k] = v\n }\n }\n base[OPENINFERENCE_SPAN_KIND] = traceSpanKindToOpenInferenceKind(span.kind)\n if (span.kind === 'llm') {\n applyLlmSpanOtlpAttributes(base, span)\n } else if (span.kind === 'tool') {\n applyToolSpanOtlpAttributes(base, span)\n } else if (span.kind === 'retrieval') {\n base['retrieval.query'] = span.query\n base['retrieval.hits'] = span.hits.length\n } else if (span.kind === 'judge') {\n base['judge.id'] = span.judgeId\n base['judge.dimension'] = span.dimension\n base['judge.score'] = span.score\n base['judge.target_span_id'] = span.targetSpanId\n } else if (span.kind === 'sandbox') {\n if (span.image) base['sandbox.image'] = span.image\n if (span.exitCode !== undefined) base['sandbox.exit_code'] = span.exitCode\n if (span.testsPassed !== undefined) base['sandbox.tests_passed'] = span.testsPassed\n if (span.testsTotal !== undefined) base['sandbox.tests_total'] = span.testsTotal\n }\n return base\n}\n\nfunction flattenPayload(\n payload: Record<string, unknown>,\n): Record<string, string | number | boolean> {\n const out: Record<string, string | number | boolean> = {}\n for (const [k, v] of Object.entries(payload)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') out[k] = v\n else out[k] = JSON.stringify(v)\n }\n return out\n}\n\nfunction toAttributes(record: Record<string, string | number | boolean>): OtlpSpan['attributes'] {\n return Object.entries(record).map(([key, value]) => ({\n key,\n value:\n typeof value === 'number'\n ? Number.isInteger(value)\n ? { intValue: value.toString() }\n : { doubleValue: value }\n : typeof value === 'boolean'\n ? { boolValue: value }\n : { stringValue: value },\n }))\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n\nfunction padSpanId(id: string): string {\n // OTLP wants 16-hex spanIds. UUIDs are 32-hex; strip dashes and take first 16.\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 16).padEnd(16, '0')\n}\n\nfunction runToTraceId(run: Run): string {\n // OTLP wants 32-hex traceIds. Use runId directly when it's 32-hex already,\n // else SHA-ish truncate.\n const cleaned = run.runId.replace(/-/g, '')\n return cleaned.slice(0, 32).padEnd(32, '0')\n}\n","/**\n * OTEL bridge — connects TraceEmitter span lifecycle to the OtelExporter.\n *\n * When an OtelExporter is active, every span that closes through the\n * TraceEmitter is also pushed to the exporter for real-time streaming to\n * the user's OTEL collector.\n *\n * The bridge is opt-in: attach via `otelRunCompleteHook(exporter)` as a\n * RunCompleteHook, or wrap the store with `createOtelTracingStore` for\n * real-time per-span export.\n */\n\nimport type { RunCompleteHook } from './emitter'\nimport type { ExportableSpan, OtelExporter } from './otel-export'\nimport type { LlmSpan, Span, ToolSpan } from './schema'\nimport type { TraceStore } from './store'\n\n/**\n * Create a RunCompleteHook that exports all spans from the completed run\n * to the OTEL exporter, then flushes.\n */\nexport function otelRunCompleteHook(exporter: OtelExporter): RunCompleteHook {\n return async (ctx) => {\n const spans = await ctx.store.spans({ runId: ctx.runId })\n for (const span of spans) {\n if (span.endedAt) {\n exporter.exportSpan(storeSpanToExportable(span, ctx.runId))\n }\n }\n await exporter.flush()\n }\n}\n\n/**\n * Create an auto-exporting TraceStore wrapper that intercepts updateSpan\n * calls. When a span gets an endedAt, it's exported immediately. This\n * gives real-time streaming instead of batch-at-end.\n *\n * This is the preferred integration path: wrap the store before\n * constructing the TraceEmitter.\n */\nexport function createOtelTracingStore(\n inner: TraceStore,\n exporter: OtelExporter,\n traceId: string,\n): TraceStore {\n return {\n async appendRun(run) {\n return inner.appendRun(run)\n },\n async updateRun(runId, patch) {\n return inner.updateRun(runId, patch)\n },\n async appendSpan(span) {\n if (span.endedAt) {\n exporter.exportSpan(storeSpanToExportable(span, traceId))\n }\n return inner.appendSpan(span)\n },\n async updateSpan(spanId, patch) {\n await inner.updateSpan(spanId, patch)\n if (patch.endedAt) {\n const spans = await inner.spans({ runId: traceId })\n const found = spans.find((s) => s.spanId === spanId)\n if (found) {\n exporter.exportSpan(storeSpanToExportable(found, traceId))\n }\n }\n },\n async appendEvent(event) {\n return inner.appendEvent(event)\n },\n async appendBudgetEntry(entry) {\n return inner.appendBudgetEntry(entry)\n },\n async appendArtifact(artifact) {\n return inner.appendArtifact(artifact)\n },\n getRun: inner.getRun.bind(inner),\n listRuns: inner.listRuns.bind(inner),\n spans: inner.spans.bind(inner),\n events: inner.events.bind(inner),\n budget: inner.budget.bind(inner),\n artifacts: inner.artifacts.bind(inner),\n }\n}\n\nfunction storeSpanToExportable(span: Span, traceId: string): ExportableSpan {\n const llm = span.kind === 'llm' ? (span as LlmSpan) : undefined\n const tool = span.kind === 'tool' ? (span as ToolSpan) : undefined\n return {\n traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startedAt: span.startedAt,\n endedAt: span.endedAt,\n status: span.status,\n error: span.error,\n model: llm?.model,\n inputTokens: llm?.inputTokens,\n outputTokens: llm?.outputTokens,\n reasoningTokens: llm?.reasoningTokens,\n cachedTokens: llm?.cachedTokens,\n cacheWriteTokens: llm?.cacheWriteTokens,\n costUsd: llm?.costUsd,\n tool: tool\n ? {\n toolName: tool.toolName,\n args: tool.args,\n argsCaptured: tool.argsCaptured,\n result: tool.result,\n latencyMs: tool.latencyMs,\n }\n : undefined,\n attributes: span.attributes as Record<string, unknown> | undefined,\n }\n}\n","/**\n * OTEL span exporter — streams spans to an OTLP/HTTP collector.\n *\n * Reads OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_EXPORTER_OTLP_HEADERS from env\n * when no explicit config is given. Batches spans and flushes periodically\n * or when the batch fills. No @opentelemetry SDK dependency — minimal\n * OTLP/JSON serializer (~120 LOC) using the existing otel.ts helpers.\n */\n\nimport { OTEL_AGENT_EVAL_SCOPE, type OtlpExport, type OtlpSpan } from './otel'\nimport {\n applyLlmSpanOtlpAttributes,\n applyToolSpanOtlpAttributes,\n OPENINFERENCE_SPAN_KIND,\n type ToolSpanOtlpInput,\n traceSpanKindToOpenInferenceKind,\n} from './otlp-attributes'\n\nexport interface OtelExportConfig {\n /** OTLP endpoint. Reads OTEL_EXPORTER_OTLP_ENDPOINT env by default. */\n endpoint?: string\n /** OTLP headers. Reads OTEL_EXPORTER_OTLP_HEADERS env by default. */\n headers?: Record<string, string>\n /** Batch size before flush. Default 64. */\n batchSize?: number\n /** Flush interval ms. Default 5000. */\n flushIntervalMs?: number\n /** Resource attributes stamped on every export. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Service name. Default 'agent-eval'. */\n serviceName?: string\n}\n\nexport interface OtelExporter {\n /** Called by the TraceEmitter on every span close. */\n exportSpan(span: ExportableSpan): void\n /** Force flush pending spans. */\n flush(): Promise<void>\n /** Shutdown cleanly — flushes remaining spans and stops the timer. */\n shutdown(): Promise<void>\n}\n\nexport interface ExportableSpan {\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind: string\n startedAt: number\n endedAt?: number\n status?: string\n error?: string\n model?: string\n inputTokens?: number\n outputTokens?: number\n reasoningTokens?: number\n cachedTokens?: number\n cacheWriteTokens?: number\n costUsd?: number\n tool?: ToolSpanOtlpInput\n attributes?: Record<string, unknown>\n}\n\n/**\n * Create an OTEL exporter. Returns undefined when no endpoint is configured\n * (neither via config nor env) — callers should check before attaching.\n */\nexport function createOtelExporter(config?: OtelExportConfig): OtelExporter | undefined {\n const resolvedEndpoint =\n config?.endpoint ??\n (typeof process !== 'undefined' ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : undefined)\n if (!resolvedEndpoint) return undefined\n const endpoint: string = resolvedEndpoint\n\n const headers = config?.headers ?? parseHeadersFromEnv()\n const batchSize = config?.batchSize ?? 64\n const flushIntervalMs = config?.flushIntervalMs ?? 5000\n const serviceName = config?.serviceName ?? 'agent-eval'\n const resourceAttrs = config?.resourceAttributes ?? {}\n\n const pending: OtlpSpan[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n let stopped = false\n\n const exporter: OtelExporter = {\n exportSpan(span: ExportableSpan): void {\n if (stopped) return\n pending.push(toOtlpSpan(span))\n if (pending.length >= batchSize) {\n void doFlush()\n }\n },\n\n async flush(): Promise<void> {\n await doFlush()\n },\n\n async shutdown(): Promise<void> {\n stopped = true\n if (timer !== undefined) {\n clearInterval(timer)\n timer = undefined\n }\n await doFlush()\n },\n }\n\n timer = setInterval(() => {\n if (pending.length > 0) void doFlush()\n }, flushIntervalMs)\n // Unref so the timer doesn't keep the process alive.\n if (typeof timer === 'object' && 'unref' in timer) {\n ;(timer as NodeJS.Timeout).unref()\n }\n\n async function doFlush(): Promise<void> {\n if (pending.length === 0) return\n const batch = pending.splice(0)\n const body: OtlpExport = {\n resourceSpans: [\n {\n resource: {\n attributes: toAttributes({\n 'service.name': serviceName,\n ...resourceAttrs,\n }),\n },\n scopeSpans: [{ scope: OTEL_AGENT_EVAL_SCOPE, spans: batch }],\n },\n ],\n }\n const url = `${endpoint.replace(/\\/+$/, '')}/v1/traces`\n try {\n await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...headers,\n },\n body: JSON.stringify(body),\n })\n } catch {\n // Best-effort — telemetry export must not crash the pipeline.\n }\n }\n\n return exporter\n}\n\nfunction parseHeadersFromEnv(): Record<string, string> {\n if (typeof process === 'undefined') return {}\n const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS\n if (!raw) return {}\n const out: Record<string, string> = {}\n for (const pair of raw.split(',')) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const key = pair.slice(0, eq).trim()\n const value = pair.slice(eq + 1).trim()\n if (key) out[key] = value\n }\n return out\n}\n\nfunction toOtlpSpan(span: ExportableSpan): OtlpSpan {\n const endedAt = span.endedAt ?? span.startedAt\n const attrs: Record<string, string | number | boolean> = {}\n if (span.attributes) {\n for (const [k, v] of Object.entries(span.attributes)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') attrs[k] = v\n }\n }\n attrs[OPENINFERENCE_SPAN_KIND] = traceSpanKindToOpenInferenceKind(span.kind)\n applyLlmSpanOtlpAttributes(attrs, span)\n if (span.tool) applyToolSpanOtlpAttributes(attrs, span.tool)\n return {\n traceId: padTraceId(span.traceId),\n spanId: padSpanId(span.spanId),\n parentSpanId: span.parentSpanId ? padSpanId(span.parentSpanId) : undefined,\n name: span.name,\n kind: 1, // SPAN_KIND_INTERNAL\n startTimeUnixNano: msToNs(span.startedAt),\n endTimeUnixNano: msToNs(endedAt),\n attributes: toAttributes(attrs),\n status: span.status === 'error' ? { code: 2, message: span.error } : { code: 1 },\n }\n}\n\nfunction toAttributes(record: Record<string, string | number | boolean>): OtlpSpan['attributes'] {\n return Object.entries(record).map(([key, value]) => ({\n key,\n value:\n typeof value === 'number'\n ? Number.isInteger(value)\n ? { intValue: value.toString() }\n : { doubleValue: value }\n : typeof value === 'boolean'\n ? { boolValue: value }\n : { stringValue: value },\n }))\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n\nfunction padSpanId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 16).padEnd(16, '0')\n}\n\nfunction padTraceId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 32).padEnd(32, '0')\n}\n","/**\n * Convert agent-eval's internal trace shape (`FileSystemTraceStore` → `Run`,\n * `Span`, `TraceEvent`) into the OTLP-flat JSONL the trace analyst\n * (`analyzeTraces` + `OtlpFileTraceStore`) reads.\n *\n * Eval harnesses shard a `FileSystemTraceStore` per cell (persona / variant)\n * under a run directory. The analyst consumes a single OTLP-NDJSON file keyed\n * on `trace_id` + `span_id` with `start_time`/`end_time` in ISO-8601 and\n * resource + `attributes` rolled up per-span. This module walks every shard,\n * projects each `Span` (plus events pinned to it) into the flat OTLP shape,\n * and emits one NDJSON file.\n *\n * Generic OTLP/OpenInference fields are always emitted (`service.name`,\n * `agent.name`, `run.id`/`run.status`, `openinference.span.kind`,\n * `llm.model_name`, …). Domain attributes (`legal.*`, `tax.*`, …) are injected\n * per-run via {@link TraceStoreToOtlpOptions.resourceAttributes} /\n * {@link TraceStoreToOtlpOptions.runAttributes} so consumers don't re-roll the\n * walker.\n */\n\nimport { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n applyLlmSpanOtlpAttributes,\n applyToolSpanOtlpAttributes,\n OPENINFERENCE_SPAN_KIND,\n traceSpanKindToOpenInferenceKind,\n} from './otlp-attributes'\nimport type { Run, Span, TraceEvent } from './schema'\n\n/** Marker `FileSystemTraceStore` stamps on partial-update NDJSON rows. */\ninterface MaybeUpdate {\n _update?: boolean\n}\n\ninterface OtlpFlatSpan {\n trace_id: string\n span_id: string\n parent_span_id: string\n name: string\n kind: string\n start_time: string\n end_time: string\n status: { code: 'STATUS_CODE_OK' | 'STATUS_CODE_ERROR'; message: string }\n resource: { attributes: Record<string, unknown> }\n attributes: Record<string, unknown>\n}\n\nexport interface TracesToOtlpResult {\n /** Total spans emitted across every cell. */\n spanCount: number\n /** Total run-anchor spans (one per Run) appended for analyst visibility. */\n runCount: number\n /** Cells whose shards parsed cleanly. */\n cellCount: number\n /** Cells that errored mid-conversion — surfaced so a partial conversion\n * isn't silently masked. */\n cellErrorCount: number\n}\n\n/**\n * A trace source the analyst should ingest. Two layouts are supported:\n *\n * - `celled` (default): the root holds one cell subdirectory per\n * persona/variant, each a `FileSystemTraceStore` (`runs.ndjson`,\n * `spans.ndjson`, `events.ndjson`).\n * - `flat`: the root is itself a single `FileSystemTraceStore` (e.g. a\n * production-ingestion sidecar that appends one ndjson set directly under\n * the chosen directory).\n */\nexport interface TraceStoreSource {\n /** Absolute path to the trace store root. */\n root: string\n /** Layout — `celled` (default) or `flat`. */\n layout?: 'celled' | 'flat'\n /** OTLP `service.name` for this source. Overrides the options default. */\n serviceName?: string\n}\n\n/** Domain hooks. The walker is generic; consumers inject the namespaced\n * attributes that ride along on every run + span for analyst discovery. */\nexport interface TraceStoreToOtlpOptions {\n /** Default OTLP `service.name` when a source doesn't set its own.\n * Default `agent-eval`. */\n serviceName?: string\n /** Extra resource attributes per run, e.g.\n * `(run) => ({ 'legal.persona_id': run.tags?.personaId ?? '' })`. */\n resourceAttributes?: (run: Run) => Record<string, unknown>\n /** Extra attributes on the per-run anchor span, e.g. domain outcome fields. */\n runAttributes?: (run: Run) => Record<string, unknown>\n}\n\n/**\n * Read every per-cell shard under each source root and write a flat OTLP-JSONL\n * view of the corpus to `outPath`. Each cell directory is a\n * `FileSystemTraceStore` — NDJSON append-only with size-based rotation;\n * `updateRun`/`updateSpan` append `{ id, ...patch, _update: true }` rows\n * rather than rewriting, so readers must merge those patches in (done here).\n *\n * A `string` source is treated as a celled root.\n */\nexport function convertTraceStoresToOtlp(\n source: string | TraceStoreSource | readonly TraceStoreSource[],\n outPath: string,\n opts: TraceStoreToOtlpOptions = {},\n): TracesToOtlpResult {\n const sources: TraceStoreSource[] = Array.isArray(source)\n ? [...source]\n : typeof source === 'string'\n ? [{ root: source, layout: 'celled' }]\n : [source as TraceStoreSource]\n\n const defaultServiceName = opts.serviceName ?? 'agent-eval'\n const resourceAttributes = opts.resourceAttributes ?? (() => ({}))\n const runAttributes = opts.runAttributes ?? (() => ({}))\n\n const lines: string[] = []\n let spanCount = 0\n let runCount = 0\n let cellCount = 0\n let cellErrorCount = 0\n\n for (const src of sources) {\n const serviceName = src.serviceName ?? defaultServiceName\n const cellDirs: Array<{ label: string; dir: string }> =\n src.layout === 'flat'\n ? [{ label: '<root>', dir: src.root }]\n : listCells(src.root).map((name) => ({ label: name, dir: join(src.root, name) }))\n\n for (const cell of cellDirs) {\n try {\n const result = projectCell({\n cellDir: cell.dir,\n serviceName,\n resourceAttributes,\n runAttributes,\n })\n for (const line of result.lines) lines.push(line)\n spanCount += result.spanCount\n runCount += result.runCount\n cellCount += 1\n } catch (err) {\n console.warn(\n `[traces-to-otlp] cell ${cell.label} (${cell.dir}) skipped: ${err instanceof Error ? err.message : String(err)}`,\n )\n cellErrorCount += 1\n }\n }\n }\n\n writeFileSync(outPath, lines.join('\\n') + (lines.length > 0 ? '\\n' : ''))\n return { spanCount, runCount, cellCount, cellErrorCount }\n}\n\ninterface ProjectCellResult {\n lines: string[]\n runCount: number\n spanCount: number\n}\n\nfunction projectCell(args: {\n cellDir: string\n serviceName: string\n resourceAttributes: (run: Run) => Record<string, unknown>\n runAttributes: (run: Run) => Record<string, unknown>\n}): ProjectCellResult {\n const { cellDir, serviceName, resourceAttributes, runAttributes } = args\n const lines: string[] = []\n let runCount = 0\n let spanCount = 0\n\n const runs = readMergedShards<Run & MaybeUpdate>(cellDir, 'runs', 'runId')\n const spans = readMergedShards<Span & MaybeUpdate>(cellDir, 'spans', 'spanId')\n const events = readShards<TraceEvent>(cellDir, 'events')\n\n const runByRunId = new Map<string, Run>()\n for (const r of runs) runByRunId.set(r.runId, r)\n const spanBySpanId = new Map<string, Span>()\n for (const s of spans) spanBySpanId.set(s.spanId, s)\n const eventsBySpanId = new Map<string, TraceEvent[]>()\n\n // An HTTP-backed trace store can only POST `TraceEvent`s through the wire;\n // run/span lifecycle is projected into `state_mutation` events with\n // `payload.entity ∈ { run, run.update, span, span.update }`. Fold those back\n // so the analyst sees a complete Run + Span tree.\n for (const e of events) {\n if (e.kind === 'state_mutation' && e.payload && typeof e.payload === 'object') {\n const entity = (e.payload as Record<string, unknown>).entity\n if (entity === 'run') {\n const run = (e.payload as { run?: Run }).run\n if (run?.runId) runByRunId.set(run.runId, run)\n continue\n }\n if (entity === 'run.update') {\n const patch = (e.payload as { patch?: Partial<Run> }).patch\n if (patch && e.runId) {\n const prior = runByRunId.get(e.runId)\n if (prior) runByRunId.set(e.runId, { ...prior, ...patch })\n }\n continue\n }\n if (entity === 'span') {\n const span = (e.payload as { span?: Span }).span\n if (span?.spanId) spanBySpanId.set(span.spanId, span)\n continue\n }\n if (entity === 'span.update') {\n const spanId = (e.payload as { spanId?: string }).spanId\n const patch = (e.payload as { patch?: Partial<Span> }).patch\n if (spanId && patch) {\n const prior = spanBySpanId.get(spanId)\n if (prior) spanBySpanId.set(spanId, { ...prior, ...patch } as Span)\n }\n continue\n }\n }\n if (!e.spanId) continue\n const arr = eventsBySpanId.get(e.spanId) ?? []\n arr.push(e)\n eventsBySpanId.set(e.spanId, arr)\n }\n\n for (const run of runByRunId.values()) {\n const traceId = padTraceId(run.runId)\n const agentName = run.variantId ?? run.scenarioId\n const sharedResource = {\n attributes: {\n 'service.name': serviceName,\n 'agent.name': agentName,\n 'run.id': run.runId,\n 'run.status': run.status,\n ...resourceAttributes(run),\n },\n }\n\n const runSpanId = padSpanId(`run-${run.runId}`)\n const runStart = msToIso(run.startedAt)\n const runEnd = msToIso(run.endedAt ?? run.startedAt)\n const runStatus =\n run.outcome?.failureClass && run.outcome.failureClass !== 'success'\n ? 'STATUS_CODE_ERROR'\n : 'STATUS_CODE_OK'\n const runAttrs: Record<string, unknown> = {\n [OPENINFERENCE_SPAN_KIND]: 'AGENT',\n 'agent.name': agentName,\n 'agent.workflow.name': serviceName,\n ...runAttributes(run),\n }\n lines.push(\n JSON.stringify(\n toLine({\n traceId,\n spanId: runSpanId,\n parentSpanId: '',\n name: `run.${agentName}`,\n kind: 'SPAN_KIND_INTERNAL',\n startTime: runStart,\n endTime: runEnd,\n statusCode: runStatus,\n statusMessage: run.outcome?.notes ?? '',\n resource: sharedResource,\n attributes: runAttrs,\n }),\n ),\n )\n runCount += 1\n\n for (const span of spanBySpanId.values()) {\n if (span.runId !== run.runId) continue\n const spanAttrs = spanToAttributes(span, eventsBySpanId.get(span.spanId) ?? [])\n const statusCode = span.status === 'error' ? 'STATUS_CODE_ERROR' : 'STATUS_CODE_OK'\n lines.push(\n JSON.stringify(\n toLine({\n traceId,\n spanId: padSpanId(span.spanId),\n parentSpanId: span.parentSpanId ? padSpanId(span.parentSpanId) : runSpanId,\n name: span.name,\n kind: spanKindToOtlpKind(span.kind),\n startTime: msToIso(span.startedAt),\n endTime: msToIso(span.endedAt ?? span.startedAt),\n statusCode,\n statusMessage: span.error ?? '',\n resource: sharedResource,\n attributes: spanAttrs,\n }),\n ),\n )\n spanCount += 1\n }\n }\n\n return { lines, runCount, spanCount }\n}\n\nfunction listCells(root: string): string[] {\n try {\n return readdirSync(root, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name)\n .sort()\n } catch {\n return []\n }\n}\n\n/**\n * Read every NDJSON shard for `name` under `cellDir`, ordered by mtime so\n * rotated files apply before the active one. Yields raw rows including any\n * `_update: true` patches.\n */\nfunction readShards<T>(cellDir: string, name: string): T[] {\n let entries: string[]\n try {\n entries = readdirSync(cellDir)\n } catch {\n return []\n }\n const shards = entries\n .filter((f) => (f === `${name}.ndjson` || f.startsWith(`${name}.`)) && f.endsWith('.ndjson'))\n .map((f) => ({ file: f, path: join(cellDir, f) }))\n .map((s) => {\n let mtime = 0\n try {\n mtime = statSync(s.path).mtimeMs\n } catch {\n /* skip stat errors */\n }\n return { ...s, mtime }\n })\n .sort((a, b) => a.mtime - b.mtime || a.file.localeCompare(b.file))\n\n const rows: T[] = []\n for (const shard of shards) {\n let text: string\n try {\n text = readFileSync(shard.path, 'utf-8')\n } catch {\n continue\n }\n for (const line of text.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n rows.push(JSON.parse(trimmed) as T)\n } catch {\n /* skip partial line */\n }\n }\n }\n return rows\n}\n\n/**\n * Read NDJSON shards and merge `{ ...patch, _update: true }` rows into the\n * prior record keyed on `idKey` — mirrors the in-memory merge\n * `FileSystemTraceStore` keeps but doesn't replay on cross-process load.\n */\nfunction readMergedShards<T extends { _update?: boolean }>(\n cellDir: string,\n name: string,\n idKey: keyof T,\n): T[] {\n const rows = readShards<T>(cellDir, name)\n const byId = new Map<string, T>()\n for (const row of rows) {\n const id = row[idKey] as unknown as string\n if (!id) continue\n const prior = byId.get(id)\n if (prior && row._update) {\n byId.set(id, { ...prior, ...row, _update: undefined } as T)\n } else {\n byId.set(id, row)\n }\n }\n return [...byId.values()]\n}\n\nfunction spanToAttributes(span: Span, events: TraceEvent[]): Record<string, unknown> {\n const attrs: Record<string, unknown> = {\n [OPENINFERENCE_SPAN_KIND]: traceSpanKindToOpenInferenceKind(span.kind),\n }\n if (span.kind === 'llm') {\n applyLlmSpanOtlpAttributes(attrs, span)\n if (Array.isArray(span.messages)) {\n attrs['llm.input_messages'] = JSON.stringify(span.messages.slice(-6))\n }\n if (typeof span.output === 'string') {\n attrs['llm.output_messages'] = JSON.stringify([{ role: 'assistant', content: span.output }])\n }\n } else if (span.kind === 'tool') {\n applyToolSpanOtlpAttributes(attrs, span)\n } else if (span.kind === 'judge') {\n attrs['judge.id'] = span.judgeId\n attrs['judge.dimension'] = span.dimension\n attrs['judge.score'] = span.score\n attrs['judge.target_span_id'] = span.targetSpanId\n }\n if (span.attributes) {\n for (const [k, v] of Object.entries(span.attributes)) {\n attrs[`agent_eval.${k}`] = v\n }\n }\n if (events.length > 0) {\n attrs['agent_eval.event_count'] = events.length\n attrs['agent_eval.event_kinds'] = JSON.stringify(events.map((e) => e.kind))\n }\n return attrs\n}\n\nfunction spanKindToOtlpKind(kind: Span['kind']): string {\n switch (kind) {\n case 'llm':\n return 'SPAN_KIND_CLIENT'\n case 'retrieval':\n return 'SPAN_KIND_CLIENT'\n default:\n return 'SPAN_KIND_INTERNAL'\n }\n}\n\ninterface ToLineArgs {\n traceId: string\n spanId: string\n parentSpanId: string\n name: string\n kind: string\n startTime: string\n endTime: string\n statusCode: 'STATUS_CODE_OK' | 'STATUS_CODE_ERROR'\n statusMessage: string\n resource: { attributes: Record<string, unknown> }\n attributes: Record<string, unknown>\n}\n\nfunction toLine(args: ToLineArgs): OtlpFlatSpan {\n return {\n trace_id: args.traceId,\n span_id: args.spanId,\n parent_span_id: args.parentSpanId,\n name: args.name,\n kind: args.kind,\n start_time: args.startTime,\n end_time: args.endTime,\n status: { code: args.statusCode, message: args.statusMessage },\n resource: args.resource,\n attributes: args.attributes,\n }\n}\n\nfunction msToIso(ms: number): string {\n if (!Number.isFinite(ms) || ms <= 0) return new Date(0).toISOString()\n return new Date(ms).toISOString()\n}\n\n/** OTLP wants 16-hex span ids; eval traces use UUID-ish strings. Hex-strip +\n * take 16, else deterministic FNV fold. */\nfunction padSpanId(id: string): string {\n const cleaned = id.replace(/[^a-f0-9]/gi, '').toLowerCase()\n if (cleaned.length >= 16) return cleaned.slice(0, 16)\n return foldTo16Hex(id)\n}\n\n/** OTLP wants 32-hex trace ids; fold deterministically when too short. */\nfunction padTraceId(id: string): string {\n const cleaned = id.replace(/[^a-f0-9]/gi, '').toLowerCase()\n if (cleaned.length >= 32) return cleaned.slice(0, 32)\n return foldTo32Hex(id)\n}\n\nfunction foldTo16Hex(s: string): string {\n let h1 = 0x811c9dc5\n for (const ch of s) {\n h1 ^= ch.charCodeAt(0)\n h1 = Math.imul(h1, 0x01000193) >>> 0\n }\n const part = h1.toString(16).padStart(8, '0')\n return (part + part).slice(0, 16)\n}\n\nfunction foldTo32Hex(s: string): string {\n return foldTo16Hex(s) + foldTo16Hex(`${s}::trace`).slice(0, 16)\n}\n","/**\n * Replay-from-raw-events — turn every captured campaign run into a\n * re-runnable artifact.\n *\n * `RawProviderSink` captures every provider HTTP envelope; `runEvalCampaign`\n * makes that capture the default. Together they make every past run a\n * complete fingerprint of what happened on the wire — enough to replay\n * the run without burning new LLM cost.\n *\n * Three use cases this primitive enables:\n *\n * 1. **Post-hoc judging** — apply a new judge / rubric / scoring callback\n * to last week's runs without re-calling any LLM. The cost of trying\n * a new rubric drops from \"another full sweep\" to a CPU-bound replay.\n * 2. **Determinism audits** — replay the same campaign and verify the\n * raw responses match byte-for-byte. Any drift is a non-determinism\n * bug (in the harness, the prompt builder, the sandbox, …).\n * 3. **Free judge calibration** — run two judges on identical responses\n * and measure inter-judge agreement without doubling LLM spend.\n *\n * The interface is deliberately fetch-shaped. Inject `createReplayFetch`\n * into `LlmClientOptions.fetch` and every `callLlm` transparently reads\n * from the cache instead of calling the network. No new code path through\n * the LLM client is needed; the cache hit is invisible to the runner.\n */\n\nimport { ReplayError } from './errors'\nimport { canonicalize, hashJson } from './pre-registration'\nimport type { RawProviderEvent, RawProviderSink } from './trace/raw-provider-sink'\n\nexport class ReplayCacheMissError extends ReplayError {\n constructor(\n public readonly url: string,\n public readonly requestKey: string,\n message?: string,\n ) {\n super(message ?? `replay cache miss for ${url} (key=${requestKey})`)\n }\n}\n\nexport interface ReplayCacheEntry {\n request: RawProviderEvent\n response: RawProviderEvent\n}\n\nexport interface ReplayCacheStats {\n total: number\n byProvider: Record<string, number>\n byModel: Record<string, number>\n /** Spans for which we have a request but no response (run aborted mid-call). */\n orphanRequests: number\n}\n\n/**\n * In-memory deterministic cache of (request → response) keyed on a stable\n * hash of the request body. Built from a `RawProviderSink` containing\n * paired `request` and `response` events from a previous run.\n *\n * The cache is the source of truth for replay; `createReplayFetch` is a\n * thin wrapper that reads from it.\n */\nexport class ReplayCache {\n private byKey = new Map<string, ReplayCacheEntry>()\n private orphans = 0\n private byProvider: Record<string, number> = {}\n private byModel: Record<string, number> = {}\n\n /**\n * Build a cache from a sink's events. The sink must implement `list()`.\n * Filter by `runId` / `spanId` to scope to a specific replay.\n */\n static async fromSink(\n sink: RawProviderSink,\n filter: { runId?: string; spanId?: string } = {},\n ): Promise<ReplayCache> {\n if (!sink.list) {\n throw new ReplayError('ReplayCache.fromSink: sink must implement list() to be replayable.')\n }\n const events = await sink.list(filter)\n return ReplayCache.fromEvents(events)\n }\n\n /** Build a cache from an in-memory event list. */\n static async fromEvents(events: RawProviderEvent[]): Promise<ReplayCache> {\n const cache = new ReplayCache()\n // Group by (runId, spanId, attemptIndex) so request/response/error pairs are matched.\n // A cell can have many spans; each retry attempt within a span is a separate group.\n type GroupKey = string\n const groups = new Map<GroupKey, { req?: RawProviderEvent; res?: RawProviderEvent }>()\n for (const e of events) {\n const k = `${e.runId ?? ''}::${e.spanId ?? ''}::${e.attemptIndex}`\n const g = groups.get(k) ?? {}\n if (e.direction === 'request') g.req = e\n else g.res = e\n groups.set(k, g)\n }\n for (const g of groups.values()) {\n if (!g.req) continue\n if (!g.res) {\n cache.orphans += 1\n continue\n }\n const key = await requestKey(g.req)\n cache.byKey.set(key, { request: g.req, response: g.res })\n cache.byProvider[g.req.provider] = (cache.byProvider[g.req.provider] ?? 0) + 1\n cache.byModel[g.req.model] = (cache.byModel[g.req.model] ?? 0) + 1\n }\n return cache\n }\n\n /** Number of cacheable (request, response) pairs in the cache. */\n size(): number {\n return this.byKey.size\n }\n\n stats(): ReplayCacheStats {\n return {\n total: this.byKey.size,\n byProvider: { ...this.byProvider },\n byModel: { ...this.byModel },\n orphanRequests: this.orphans,\n }\n }\n\n /** Iterate every cached `(request, response)` pair in insertion order. */\n *entries(): IterableIterator<ReplayCacheEntry> {\n for (const entry of this.byKey.values()) yield entry\n }\n\n /**\n * Look up a cached response by hashing the (model, messages, temperature,\n * maxTokens, response_format) shape. Returns `undefined` on miss; the\n * caller decides whether to throw, fall back to the network, or skip.\n */\n async lookup(requestBody: unknown): Promise<ReplayCacheEntry | undefined> {\n const key = await keyFromBody(requestBody)\n return this.byKey.get(key)\n }\n}\n\nexport interface ReplayFetchOptions {\n /**\n * Behaviour on cache miss. Default `'throw'`. `'fallback'` calls the\n * `fallbackFetch` (typically `globalThis.fetch`) so a partial replay can\n * still complete; `'fail-closed'` returns a synthetic 599 response so the\n * call site sees a non-retriable failure.\n */\n onMiss?: 'throw' | 'fallback' | 'fail-closed'\n fallbackFetch?: typeof fetch\n /** Optional callback fired once per replayed call (for telemetry / counters). */\n onHit?: (info: { url: string; provider: string; model: string }) => void\n /** Optional callback fired on cache miss before the `onMiss` policy applies. */\n onMissNotify?: (info: { url: string; requestBody: unknown }) => void\n}\n\n/**\n * Build a `fetch`-shaped function that serves cached responses out of a\n * `ReplayCache` for any URL ending in `/chat/completions`. Pass through\n * `LlmClientOptions.fetch` and `callLlm` becomes free.\n *\n * Non-`/chat/completions` URLs are passed straight to the fallback fetch\n * (default: `globalThis.fetch`). This matters because non-LLM HTTP work\n * (judge HTTP servers, sandbox callbacks) sometimes flows through the same\n * `fetch` and shouldn't be intercepted.\n */\nexport function createReplayFetch(cache: ReplayCache, opts: ReplayFetchOptions = {}): typeof fetch {\n const onMiss = opts.onMiss ?? 'throw'\n const fallback = opts.fallbackFetch ?? globalThis.fetch?.bind(globalThis)\n\n return (async (input: RequestInfo | URL, init?: RequestInit) => {\n const url =\n typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n if (!/\\/chat\\/completions(?:[?#].*)?$/.test(url)) {\n if (!fallback)\n throw new ReplayError(\n `replay fetch: non-completions URL ${url} but no fallbackFetch configured`,\n )\n return fallback(input as RequestInfo, init)\n }\n let bodyParsed: unknown\n if (init?.body && typeof init.body === 'string') {\n try {\n bodyParsed = JSON.parse(init.body)\n } catch {\n /* raw body, not JSON */\n }\n }\n const hit = bodyParsed === undefined ? undefined : await cache.lookup(bodyParsed)\n if (hit) {\n opts.onHit?.({ url, provider: hit.request.provider, model: hit.request.model })\n const status = hit.response.statusCode ?? 200\n const headers = new Headers(\n Object.entries(hit.response.responseHeaders ?? { 'Content-Type': 'application/json' }),\n )\n const bodyText =\n typeof hit.response.responseBody === 'string'\n ? hit.response.responseBody\n : JSON.stringify(hit.response.responseBody ?? {})\n return new Response(bodyText, { status, headers })\n }\n opts.onMissNotify?.({ url, requestBody: bodyParsed })\n if (onMiss === 'throw') {\n const key = bodyParsed === undefined ? '<unparseable>' : await keyFromBody(bodyParsed)\n throw new ReplayCacheMissError(url, key)\n }\n if (onMiss === 'fail-closed') {\n return new Response(JSON.stringify({ error: 'replay_cache_miss' }), { status: 599 })\n }\n if (!fallback)\n throw new ReplayError('replay fetch: onMiss=fallback but no fallbackFetch configured')\n return fallback(input as RequestInfo, init)\n }) as typeof fetch\n}\n\n/**\n * Convenience iterator over `(request, response)` pairs in a sink — for\n * post-hoc scoring that doesn't need a `fetch` shim. The judge or scorer\n * runs purely in-process over cached LLM outputs.\n */\nexport async function* iterateRawCalls(\n sink: RawProviderSink,\n filter: { runId?: string; spanId?: string } = {},\n): AsyncGenerator<ReplayCacheEntry> {\n if (!sink.list) {\n throw new ReplayError('iterateRawCalls: sink must implement list().')\n }\n const events = await sink.list(filter)\n const cache = await ReplayCache.fromEvents(events)\n for (const entry of cache.entries()) yield entry\n}\n\n// ── Hashing ──────────────────────────────────────────────────────────────\n\n/**\n * Canonical request key.\n *\n * `model + messages + temperature + max_tokens|max_completion_tokens +\n * response_format` are the dimensions that affect the response shape.\n * Other fields (timestamp headers, provider-specific metadata) are\n * intentionally excluded so a request hashes the same across re-runs.\n */\nasync function requestKey(event: RawProviderEvent): Promise<string> {\n return keyFromBody(event.requestBody)\n}\n\nasync function keyFromBody(body: unknown): Promise<string> {\n if (body == null || typeof body !== 'object') return hashJson({ raw: String(body) })\n const b = body as Record<string, unknown>\n const reduced = canonicalize({\n model: b.model ?? null,\n messages: b.messages ?? null,\n temperature: b.temperature ?? null,\n max_tokens: b.max_tokens ?? null,\n max_completion_tokens: b.max_completion_tokens ?? null,\n response_format: b.response_format ?? null,\n })\n return hashJson(reduced)\n}\n"],"mappings":"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","names":["a","b","model","fetch","toAttributes","padSpanId","msToNs","padTraceId","padSpanId","requestKey"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/eval-campaign.ts"],"sourcesContent":["/**\n * EvalCampaign — opinionated matrix runner that wires the four\n * capture-integrity directives by construction.\n *\n * The canonical benchmark shape — matrix runner → for each\n * (variant, scenario, seed) → start a TraceEmitter → call LLMs → end the\n * run → analyze — has a bug class at the integration boundary: raw\n * events not captured, route silently wrong, integrity not asserted,\n * analyst never run. The directives in `SKILL.md § Capture integrity`\n * are the mitigations.\n *\n * `EvalCampaign` is the structural fix — consumers don't wire the\n * integrity surface themselves; the campaign owns it. Specifically:\n *\n * - calls `assertLlmRoute` once at preflight before any work runs\n * - constructs a per-run `TraceStore` and `RawProviderSink` via factories\n * - constructs the `TraceEmitter` with `onRunComplete: [analyst hook]`\n * - hands the runner an `LlmClientOptions` pre-wired with the sink and\n * trace context — the runner can't accidentally call an LLM without\n * capturing the raw HTTP envelope\n * - calls `assertRunCaptured` after every `endRun` and routes failures\n * through a configurable policy (`throw` / `mark_failed` / `log`)\n * - assembles per-run `RunRecord`s and runs `researchReport` at the end\n * so the campaign artifact is launch-decision-grade by default\n * - embeds the campaign fingerprint (a SHA-256 over the canonicalised\n * run set) and optional `preregistrationHash` in the report\n *\n * The runner contract is intentionally narrow: produce a `CampaignRunOutcome`\n * given a fully-wired `CampaignRunContext`. Everything orchestration-shaped\n * lives in the campaign. This is the inversion-of-control point — consumers\n * stop writing matrix runners and start writing scenario-runners.\n *\n * Out of scope for v1 (tracked in `docs/research-report-methodology.md`):\n *\n * - Distributed/cluster execution (concurrency is local async)\n * - Adaptive sampling / sequential interim looks\n * - Resume from partial state across crashes\n * - LLM-call retry beyond what `LlmClient` already does\n */\n\nimport {\n type AgentProfileCell,\n type AgentProfileCellInput,\n buildAgentProfileCell,\n verifyAgentProfileCell,\n} from './agent-profile-cell'\nimport { assertLlmRoute, type LlmClientOptions, type LlmRouteRequirements } from './llm-client'\nimport { canonicalize, hashJson } from './pre-registration'\nimport type {\n JudgeScoresRecord,\n RunJudgeMetadata,\n RunOutcome,\n RunRecord,\n RunSplitTag,\n RunTokenUsage,\n} from './run-record'\nimport { validateRunRecord } from './run-record'\nimport { type ResearchReport, type ResearchReportOptions, researchReport } from './summary-report'\nimport type { RunCompleteHook } from './trace/emitter'\nimport { TraceEmitter } from './trace/emitter'\nimport {\n assertRunCaptured,\n RunIntegrityError,\n type RunIntegrityExpectations,\n type RunIntegrityReport,\n} from './trace/integrity'\nimport { FileSystemRawProviderSink, type RawProviderSink } from './trace/raw-provider-sink'\nimport type { FailureClass } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\n// ── Public types ─────────────────────────────────────────────────────────\n\nexport interface CampaignVariant<V> {\n id: string\n payload: V\n}\n\nexport interface CampaignScenario {\n scenarioId: string\n /** Free-form metadata propagated to runs and reports. */\n tags?: Record<string, string>\n}\n\nexport interface CampaignRunContext<V> {\n /** Stable run id. The campaign generates this; the runner does not. */\n runId: string\n /** Logical experiment id (campaignId by default; overridable per-run via opts). */\n experimentId: string\n variant: V\n variantId: string\n scenarioId: string\n scenarioTags: Record<string, string>\n seed: number\n splitTag: RunSplitTag\n /**\n * The TraceEmitter for this run, with `onRunComplete` hooks pre-wired\n * (analyst auto-execution if configured, plus integrity check). The\n * runner MUST call `emitter.startRun` before doing any work and either\n * `emitter.endRun` or `emitter.abortRun` before returning.\n */\n emitter: TraceEmitter\n store: TraceStore\n rawSink: RawProviderSink\n /**\n * Pre-wired LLM client options — `rawSink` and `traceContext` are populated\n * so any `callLlm(req, ctx.llmOpts)` automatically captures raw HTTP. The\n * runner can spread additional fields if needed.\n */\n llmOpts: LlmClientOptions\n}\n\nexport interface CampaignRunOutcome {\n /** Did the run pass? Mirrors `RunOutcome.pass` semantics. */\n pass: boolean\n /** Score for the run on its split. Maps to `searchScore` or `holdoutScore`. */\n score: number\n /** Mandatory cost in USD. Use 0 + raw.cost_unknown=1 only if truly unknown. */\n costUsd: number\n tokenUsage: RunTokenUsage\n /** Snapshot model id (e.g. `claude-sonnet-4-6@2025-04-15`). */\n model: string\n /** sha256 of the effective prompt sent to the model. */\n promptHash: string\n /** sha256 of the effective config (model, temperature, tools, judges, splits). */\n configHash: string\n /** Optional extra numeric metrics to land in `outcome.raw`. */\n raw?: Record<string, number>\n /** Canonical cross-agent failure class from the shared `FAILURE_CLASSES`\n * taxonomy. Propagated to `RunRecord.failureClass` so campaign runs\n * aggregate failures in the same vocabulary as every other producer. */\n failureClass?: FailureClass\n /** Optional free-form failure detail, scoped under `failureClass`. */\n failureMode?: string\n /** Optional judge metadata when a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /**\n * Optional per-judge / per-dim breakdown for ensemble-judged runs.\n * Propagated to `outcome.judgeScores` on the resulting `RunRecord`.\n * Single-judge or scalar-only runs leave this unset.\n */\n judgeScores?: JudgeScoresRecord\n /**\n * Agent profile cell observed by the runner. When supplied, it overrides\n * `EvalCampaignOptions.agentProfile` for this run and must match the\n * outcome's `model` and `promptHash`.\n */\n agentProfile?: AgentProfileCell | AgentProfileCellInput\n}\n\nexport type CampaignRunner<V> = (ctx: CampaignRunContext<V>) => Promise<CampaignRunOutcome>\n\nexport type CampaignIntegrityPolicy = 'throw' | 'mark_failed' | 'log'\n\nexport interface EvalCampaignOptions<V> {\n /**\n * Stable id for the campaign. Used as the default `experimentId` on\n * every run, and folded into the campaign fingerprint.\n */\n campaignId: string\n variants: CampaignVariant<V>[]\n scenarios: CampaignScenario[]\n /** Default `[0, 1, 2]`. */\n seeds?: number[]\n /** Default `'holdout'` — the split that anchors a launch decision. */\n splitTag?: RunSplitTag\n /** Git SHA the campaign is run against. Mandatory; `RunRecord` rejects unset. */\n commitSha: string\n /**\n * LLM client config. Augmented per-run with `rawSink` and `traceContext`\n * before being passed to the runner. The campaign asserts this config\n * matches `routeRequirements` once at preflight.\n */\n llmOpts: LlmClientOptions\n /**\n * Default `{ requireExplicitBaseUrl: true, requireAuth: true }` — fail\n * loud if the campaign would silently fall back to the public router or\n * run unauthenticated. Override with an empty object to disable.\n */\n routeRequirements?: LlmRouteRequirements\n /**\n * Per-run TraceStore factory. Common shape: a fresh store per run keyed\n * on `runId`. Implementations that share a store across the campaign\n * are valid — the campaign only writes through `emitter`.\n */\n storeFactory: (params: CampaignFactoryParams) => TraceStore\n /**\n * Per-run RawProviderSink factory. Defaults to `FileSystemRawProviderSink`\n * rooted at `${workDir}/raw-events/${runId}` if `workDir` is supplied;\n * otherwise required. Forensic capture is non-negotiable in a campaign\n * run — pass `NoopRawProviderSink` explicitly if you want to opt out.\n */\n rawSinkFactory?: (params: CampaignFactoryParams) => RawProviderSink\n /**\n * Filesystem root for default `rawSinkFactory`. Ignored if\n * `rawSinkFactory` is supplied.\n */\n workDir?: string\n /**\n * Extra `onRunComplete` hooks the campaign appends (after its own\n * integrity-check hook). Pass `traceAnalystOnRunComplete(...)` here.\n */\n onRunComplete?: RunCompleteHook[]\n /**\n * Per-run integrity expectations. Defaults to:\n * `{ llmSpansMin: 1, requireRawCoverageOfLlmSpans: true, requireOutcome: true }`.\n * Override (e.g. `{ llmSpansMin: 0 }`) for runs that don't call LLMs.\n */\n integrity?: RunIntegrityExpectations\n /** Behaviour when integrity fails. Default `'mark_failed'`. */\n onIntegrityFailure?: CampaignIntegrityPolicy\n /**\n * Per-run runner. Receives a fully-wired context; produces an outcome\n * the campaign converts into a `RunRecord`.\n */\n runner: CampaignRunner<V>\n /**\n * If set, the campaign computes `researchReport` at the end. `comparator`\n * is a `variantId`. Other fields are forwarded verbatim.\n */\n report?: { comparator?: string } & Omit<\n ResearchReportOptions,\n 'comparator' | 'preregistrationHash' | 'generatedAt'\n >\n /**\n * Hash of a signed `HypothesisManifest` (see `pre-registration.ts`).\n * Embedded in the campaign fingerprint and the research report.\n */\n preregistrationHash?: string\n /** Local concurrency. Default `1` (sequential). */\n concurrency?: number\n /**\n * Override the time source. Tests pass a mock to make wallMs deterministic.\n */\n now?: () => number\n /** Override the runId generator. Tests pin this. */\n runId?: (params: CampaignFactoryParams) => string\n /**\n * Agent profile cell for campaign runs. Static profiles can pass an object;\n * routers or variant-specific harnesses can pass a factory. The campaign\n * stamps the built cell onto every `RunRecord` and rejects profile/model or\n * profile/prompt contradictions.\n */\n agentProfile?:\n | AgentProfileCell\n | AgentProfileCellInput\n | ((\n params: CampaignFactoryParams & {\n variant: V\n scenarioTags: Record<string, string>\n },\n ) =>\n | AgentProfileCell\n | AgentProfileCellInput\n | Promise<AgentProfileCell | AgentProfileCellInput>)\n}\n\nexport interface CampaignFactoryParams {\n campaignId: string\n runId: string\n variantId: string\n scenarioId: string\n seed: number\n}\n\nexport interface FailedRun {\n runId: string\n variantId: string\n scenarioId: string\n seed: number\n reason: string\n error?: string\n}\n\nexport interface EvalCampaignResult {\n campaignId: string\n /** SHA-256 over canonicalised `(variantIds, scenarioIds, seeds, comparator, splitTag, baseUrl, provider, preregistrationHash)`. */\n campaignFingerprint: string\n preregistrationHash: string | null\n /** Successful runs only. Failed runs land in `failedRuns`. */\n runs: RunRecord[]\n /** Integrity reports for every successful run. */\n integrityReports: RunIntegrityReport[]\n failedRuns: FailedRun[]\n /** Computed when `report` is set on options. */\n report?: ResearchReport\n startedAt: string\n endedAt: string\n}\n\n// ── Implementation ───────────────────────────────────────────────────────\n\nconst DEFAULT_INTEGRITY: RunIntegrityExpectations = {\n llmSpansMin: 1,\n requireRawCoverageOfLlmSpans: true,\n requireOutcome: true,\n}\n\nconst DEFAULT_ROUTE: LlmRouteRequirements = {\n requireExplicitBaseUrl: true,\n requireAuth: true,\n}\n\nexport async function runEvalCampaign<V>(\n opts: EvalCampaignOptions<V>,\n): Promise<EvalCampaignResult> {\n // ── Preflight ──────────────────────────────────────────────────────\n assertLlmRoute(opts.llmOpts, opts.routeRequirements ?? DEFAULT_ROUTE)\n\n if (opts.variants.length === 0) {\n throw new Error('runEvalCampaign: variants must be non-empty.')\n }\n if (opts.scenarios.length === 0) {\n throw new Error('runEvalCampaign: scenarios must be non-empty.')\n }\n const variantIds = new Set<string>()\n for (const v of opts.variants) {\n if (variantIds.has(v.id)) {\n throw new Error(`runEvalCampaign: duplicate variant id \"${v.id}\".`)\n }\n variantIds.add(v.id)\n }\n const scenarioIds = new Set<string>()\n for (const s of opts.scenarios) {\n if (scenarioIds.has(s.scenarioId)) {\n throw new Error(`runEvalCampaign: duplicate scenarioId \"${s.scenarioId}\".`)\n }\n scenarioIds.add(s.scenarioId)\n }\n if (opts.report?.comparator && !variantIds.has(opts.report.comparator)) {\n throw new Error(\n `runEvalCampaign: report.comparator \"${opts.report.comparator}\" is not a configured variantId.`,\n )\n }\n if (!opts.commitSha) {\n throw new Error('runEvalCampaign: commitSha is required (every RunRecord needs it).')\n }\n\n const seeds = opts.seeds ?? [0, 1, 2]\n const splitTag: RunSplitTag = opts.splitTag ?? 'holdout'\n const concurrency = Math.max(1, opts.concurrency ?? 1)\n const integrity = { ...DEFAULT_INTEGRITY, ...(opts.integrity ?? {}) }\n const onIntegrityFailure: CampaignIntegrityPolicy = opts.onIntegrityFailure ?? 'mark_failed'\n const now = opts.now ?? (() => Date.now())\n const baseUrl = (opts.llmOpts.baseUrl ?? '').replace(/\\/+$/, '')\n const provider = opts.llmOpts.provider ?? null\n const preregistrationHash = opts.preregistrationHash ?? null\n\n const rawSinkFactory = opts.rawSinkFactory ?? defaultRawSinkFactory(opts.workDir)\n\n // ── Fingerprint ────────────────────────────────────────────────────\n const campaignFingerprint = await hashJson(\n canonicalize({\n campaignId: opts.campaignId,\n variants: opts.variants.map((v) => v.id).sort(),\n scenarios: opts.scenarios.map((s) => s.scenarioId).sort(),\n seeds: [...seeds].sort((a, b) => a - b),\n splitTag,\n comparator: opts.report?.comparator ?? null,\n baseUrl,\n provider,\n preregistrationHash,\n }),\n )\n\n // ── Plan the matrix ────────────────────────────────────────────────\n type Cell = { variant: CampaignVariant<V>; scenario: CampaignScenario; seed: number }\n const cells: Cell[] = []\n for (const variant of opts.variants) {\n for (const scenario of opts.scenarios) {\n for (const seed of seeds) {\n cells.push({ variant, scenario, seed })\n }\n }\n }\n\n const startedAt = new Date(now()).toISOString()\n const runs: RunRecord[] = []\n const integrityReports: RunIntegrityReport[] = []\n const failedRuns: FailedRun[] = []\n\n // ── Execute (bounded-concurrency worker pool) ──────────────────────\n // A genuine (non-CellExecutionError) error from any worker is a bug, not a\n // run-level failure. We must NOT let `Promise.all` reject mid-flight and\n // orphan the other workers' in-progress runs (emitters never finalized,\n // sinks/handles leak, partial work silently discarded). Instead: capture the\n // first genuine error, stop dispatching new cells so in-flight workers wind\n // down, finalize every still-open run, then re-throw the aggregated error.\n let cursor = 0\n let aborting = false\n const genuineErrors: unknown[] = []\n // Emitters for runs that are currently mid-flight, keyed by runId. A worker\n // registers its emitter before invoking the runner and removes it once the\n // run is finalized (via endRun/abortRun, success or failure). Anything left\n // here after the pool settles is an orphan we must abort.\n const openRuns = new Map<string, TraceEmitter>()\n\n async function worker(): Promise<void> {\n while (!aborting) {\n const i = cursor++\n if (i >= cells.length) return\n const cell = cells[i]!\n try {\n const result = await runOneCell(cell)\n runs.push(result.record)\n integrityReports.push(result.integrity)\n } catch (err) {\n if (err instanceof CellExecutionError) {\n failedRuns.push(err.failed)\n if (err.integrity) integrityReports.push(err.integrity)\n } else {\n // Genuine bug — not a runner failure, not an integrity failure.\n // Capture it and stop dispatching so peers wind down gracefully;\n // re-thrown after the pool settles. Do not surface here — that would\n // reject Promise.all and orphan the other workers' runs.\n genuineErrors.push(err)\n aborting = true\n return\n }\n }\n }\n }\n\n async function runOneCell(\n cell: Cell,\n ): Promise<{ record: RunRecord; integrity: RunIntegrityReport }> {\n const runId = (opts.runId ?? defaultRunId)({\n campaignId: opts.campaignId,\n runId: '', // unused by default generator\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n })\n const factoryParams: CampaignFactoryParams = {\n campaignId: opts.campaignId,\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n }\n const store = opts.storeFactory(factoryParams)\n const rawSink = rawSinkFactory(factoryParams)\n\n const emitter = new TraceEmitter(store, {\n runId,\n now: opts.now,\n onRunComplete: opts.onRunComplete,\n })\n // Track this run as open so a genuine error elsewhere in the pool can\n // finalize it instead of orphaning it. Removed in the finally below.\n openRuns.set(runId, emitter)\n\n const llmOpts: LlmClientOptions = {\n ...opts.llmOpts,\n rawSink,\n traceContext: { runId },\n }\n\n const ctx: CampaignRunContext<V> = {\n runId,\n experimentId: opts.campaignId,\n variant: cell.variant.payload,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n scenarioTags: cell.scenario.tags ?? {},\n seed: cell.seed,\n splitTag,\n emitter,\n store,\n rawSink,\n llmOpts,\n }\n\n try {\n const wallStart = now()\n let outcome: CampaignRunOutcome\n try {\n outcome = await opts.runner(ctx)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n // The runner threw mid-execution. Abort the run so the emitter\n // finalizes. The only benign abortRun failure is \"the runner never\n // started the run\" (nothing to finalize). A store-write failure (disk\n // full, FS error) is a genuine diagnostic — surface it rather than\n // masking it as a plain runner failure.\n await finalizeAbort(emitter, runId, message)\n throw new CellExecutionError({\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n reason: 'runner_threw',\n error: message,\n })\n }\n const wallMs = now() - wallStart\n\n const integrityReport = await assertRunCaptured(store, runId, { ...integrity, rawSink })\n if (!integrityReport.ok) {\n switch (onIntegrityFailure) {\n case 'throw':\n throw new RunIntegrityError(integrityReport)\n case 'mark_failed':\n throw new CellExecutionError(\n {\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n reason: 'integrity_failed',\n error: integrityReport.issues.map((i) => i.code).join(', '),\n },\n integrityReport,\n )\n case 'log':\n // Caller wants the run admitted with a flagged report; fall through.\n break\n }\n }\n\n const recordOutcome: RunOutcome = {\n raw: outcome.raw ?? {},\n }\n if (splitTag === 'holdout') recordOutcome.holdoutScore = outcome.score\n else recordOutcome.searchScore = outcome.score\n if (outcome.judgeScores !== undefined) recordOutcome.judgeScores = outcome.judgeScores\n\n const record: RunRecord = {\n runId,\n experimentId: opts.campaignId,\n candidateId: cell.variant.id,\n seed: cell.seed,\n model: outcome.model,\n promptHash: outcome.promptHash,\n configHash: outcome.configHash,\n commitSha: opts.commitSha,\n wallMs,\n costUsd: outcome.costUsd,\n tokenUsage: outcome.tokenUsage,\n judgeMetadata: outcome.judgeMetadata,\n outcome: recordOutcome,\n ...(outcome.failureClass ? { failureClass: outcome.failureClass } : {}),\n failureMode: outcome.failureMode,\n splitTag,\n scenarioId: cell.scenario.scenarioId,\n }\n const profileSource =\n outcome.agentProfile ??\n (typeof opts.agentProfile === 'function'\n ? await opts.agentProfile({\n campaignId: opts.campaignId,\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n variant: cell.variant.payload,\n scenarioTags: cell.scenario.tags ?? {},\n })\n : opts.agentProfile)\n if (profileSource !== undefined) {\n const agentProfile = await resolveAgentProfileCell(profileSource)\n assertAgentProfileMatchesRun(agentProfile, outcome.model, outcome.promptHash)\n record.agentProfile = agentProfile\n }\n return { record: validateRunRecord(record), integrity: integrityReport }\n } finally {\n // This run's worker has finished with it (success, run-level failure, or\n // genuine error). It is no longer the pool's job to finalize — drop it so\n // the post-settle sweep doesn't double-abort a finalized run.\n openRuns.delete(runId)\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, cells.length) }, () => worker())\n // allSettled (not all): a genuine error in one worker must not reject the\n // pool mid-flight and orphan the others. Each worker captures its own\n // genuine error into `genuineErrors` and returns; we re-throw below.\n await Promise.allSettled(workers)\n\n // Finalize any run still open after the pool wound down. With the\n // stop-dispatch flag these are the runs that were mid-flight in peer workers\n // when the first genuine error fired — abort them so their emitters finalize\n // (hooks fire, store records a terminal status) instead of leaking.\n for (const [runId, emitter] of openRuns) {\n await finalizeAbort(emitter, runId, 'campaign aborted: genuine error in a sibling run')\n }\n openRuns.clear()\n\n if (genuineErrors.length > 0) {\n throw genuineErrors.length === 1\n ? genuineErrors[0]\n : new AggregateError(\n genuineErrors,\n `runEvalCampaign: ${genuineErrors.length} runs failed with genuine (non-run-level) errors`,\n )\n }\n\n // ── Optional research report ───────────────────────────────────────\n let report: ResearchReport | undefined\n if (opts.report) {\n const reportOpts: ResearchReportOptions = {\n ...opts.report,\n comparator: opts.report.comparator,\n split: splitTag === 'dev' ? 'search' : splitTag,\n generatedAt: new Date(now()).toISOString(),\n preregistrationHash: preregistrationHash ?? undefined,\n }\n report = await researchReport(runs, reportOpts)\n }\n\n const endedAt = new Date(now()).toISOString()\n\n return {\n campaignId: opts.campaignId,\n campaignFingerprint,\n preregistrationHash,\n runs,\n integrityReports,\n failedRuns,\n report,\n startedAt,\n endedAt,\n }\n}\n\n// ── Internal ─────────────────────────────────────────────────────────────\n\nclass CellExecutionError extends Error {\n readonly failed: FailedRun\n readonly integrity?: RunIntegrityReport\n constructor(failed: FailedRun, integrity?: RunIntegrityReport) {\n super(`cell ${failed.variantId}/${failed.scenarioId}@${failed.seed} failed: ${failed.reason}`)\n this.failed = failed\n this.integrity = integrity\n }\n}\n\n/**\n * Abort a run whose owning work threw or was orphaned by a sibling's genuine\n * error, finalizing the emitter so hooks fire and the store records a terminal\n * status. Safe to call unconditionally: it only aborts runs that are still\n * `running`. Two no-op cases are intentional and benign:\n *\n * - the run was never started (absent from the store) — nothing to finalize\n * - the run is already terminal (`completed` / `failed` / `aborted`) —\n * finalizing again would overwrite the real outcome (e.g. flip a passed run\n * to `aborted` with `{ pass: false, notes: reason }`), so we leave it alone\n *\n * Any OTHER failure of the store read or the abort write (disk full, FS fault,\n * backend down) is a genuine diagnostic and propagates rather than being\n * swallowed.\n */\nexport async function finalizeAbort(\n emitter: TraceEmitter,\n runId: string,\n reason: string,\n): Promise<void> {\n const existing = await emitter.traceStore.getRun(runId)\n if (existing === undefined) return // run never started; nothing to abort\n if (existing.status !== 'running') return // already finalized; never overwrite a real outcome\n await emitter.abortRun(reason)\n}\n\nfunction defaultRawSinkFactory(workDir: string | undefined) {\n return (params: CampaignFactoryParams): RawProviderSink => {\n if (!workDir) {\n throw new Error(\n 'runEvalCampaign: rawSinkFactory not supplied and workDir not set. Pass either to enable raw provider capture, or pass `new NoopRawProviderSink()` via rawSinkFactory to opt out explicitly.',\n )\n }\n return new FileSystemRawProviderSink({\n dir: `${workDir}/raw-events/${params.runId}`,\n })\n }\n}\n\nasync function resolveAgentProfileCell(\n input: AgentProfileCell | AgentProfileCellInput,\n): Promise<AgentProfileCell> {\n if (isAgentProfileCell(input)) {\n if (!(await verifyAgentProfileCell(input))) {\n throw new Error(`runEvalCampaign: agentProfile.cellId does not match its content`)\n }\n return input\n }\n return buildAgentProfileCell(input)\n}\n\nfunction isAgentProfileCell(\n input: AgentProfileCell | AgentProfileCellInput,\n): input is AgentProfileCell {\n return 'schemaVersion' in input && 'cellId' in input\n}\n\nfunction assertAgentProfileMatchesRun(\n profile: AgentProfileCell,\n model: string,\n promptHash: string,\n): void {\n if (profile.model !== undefined && profile.model !== model) {\n throw new Error(\n `runEvalCampaign: agentProfile.model \"${profile.model}\" does not match outcome.model \"${model}\"`,\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== promptHash) {\n throw new Error(\n `runEvalCampaign: agentProfile.promptHash \"${profile.promptHash}\" does not match outcome.promptHash \"${promptHash}\"`,\n )\n }\n}\n\nfunction defaultRunId(params: CampaignFactoryParams): string {\n // Stable across re-runs: fingerprint of (campaignId, variantId, scenarioId, seed).\n // Caller can override via opts.runId for non-deterministic IDs.\n const base = `${params.campaignId}::${params.variantId}::${params.scenarioId}::${params.seed}`\n // Lightweight hex: we don't need crypto-grade here, just stability + uniqueness.\n let h1 = 0x811c9dc5\n let h2 = 0x12345678\n for (let i = 0; i < base.length; i++) {\n const c = base.charCodeAt(i)\n h1 = Math.imul(h1 ^ c, 0x01000193) >>> 0\n h2 = Math.imul(h2 ^ c, 0x9e3779b1) >>> 0\n }\n return `run-${h1.toString(16).padStart(8, '0')}${h2.toString(16).padStart(8, '0')}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAmSA,IAAM,oBAA8C;AAAA,EAClD,aAAa;AAAA,EACb,8BAA8B;AAAA,EAC9B,gBAAgB;AAClB;AAEA,IAAM,gBAAsC;AAAA,EAC1C,wBAAwB;AAAA,EACxB,aAAa;AACf;AAEA,eAAsB,gBACpB,MAC6B;AAE7B,iBAAe,KAAK,SAAS,KAAK,qBAAqB,aAAa;AAEpE,MAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,MAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,KAAK,KAAK,UAAU;AAC7B,QAAI,WAAW,IAAI,EAAE,EAAE,GAAG;AACxB,YAAM,IAAI,MAAM,0CAA0C,EAAE,EAAE,IAAI;AAAA,IACpE;AACA,eAAW,IAAI,EAAE,EAAE;AAAA,EACrB;AACA,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,KAAK,WAAW;AAC9B,QAAI,YAAY,IAAI,EAAE,UAAU,GAAG;AACjC,YAAM,IAAI,MAAM,0CAA0C,EAAE,UAAU,IAAI;AAAA,IAC5E;AACA,gBAAY,IAAI,EAAE,UAAU;AAAA,EAC9B;AACA,MAAI,KAAK,QAAQ,cAAc,CAAC,WAAW,IAAI,KAAK,OAAO,UAAU,GAAG;AACtE,UAAM,IAAI;AAAA,MACR,uCAAuC,KAAK,OAAO,UAAU;AAAA,IAC/D;AAAA,EACF;AACA,MAAI,CAAC,KAAK,WAAW;AACnB,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,QAAM,QAAQ,KAAK,SAAS,CAAC,GAAG,GAAG,CAAC;AACpC,QAAM,WAAwB,KAAK,YAAY;AAC/C,QAAM,cAAc,KAAK,IAAI,GAAG,KAAK,eAAe,CAAC;AACrD,QAAM,YAAY,EAAE,GAAG,mBAAmB,GAAI,KAAK,aAAa,CAAC,EAAG;AACpE,QAAM,qBAA8C,KAAK,sBAAsB;AAC/E,QAAM,MAAM,KAAK,QAAQ,MAAM,KAAK,IAAI;AACxC,QAAM,WAAW,KAAK,QAAQ,WAAW,IAAI,QAAQ,QAAQ,EAAE;AAC/D,QAAM,WAAW,KAAK,QAAQ,YAAY;AAC1C,QAAM,sBAAsB,KAAK,uBAAuB;AAExD,QAAM,iBAAiB,KAAK,kBAAkB,sBAAsB,KAAK,OAAO;AAGhF,QAAM,sBAAsB,MAAM;AAAA,IAChC,aAAa;AAAA,MACX,YAAY,KAAK;AAAA,MACjB,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK;AAAA,MAC9C,WAAW,KAAK,UAAU,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK;AAAA,MACxD,OAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,MACtC;AAAA,MACA,YAAY,KAAK,QAAQ,cAAc;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAIA,QAAM,QAAgB,CAAC;AACvB,aAAW,WAAW,KAAK,UAAU;AACnC,eAAW,YAAY,KAAK,WAAW;AACrC,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,EAAE,SAAS,UAAU,KAAK,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,IAAI,KAAK,IAAI,CAAC,EAAE,YAAY;AAC9C,QAAM,OAAoB,CAAC;AAC3B,QAAM,mBAAyC,CAAC;AAChD,QAAM,aAA0B,CAAC;AASjC,MAAI,SAAS;AACb,MAAI,WAAW;AACf,QAAM,gBAA2B,CAAC;AAKlC,QAAM,WAAW,oBAAI,IAA0B;AAE/C,iBAAe,SAAwB;AACrC,WAAO,CAAC,UAAU;AAChB,YAAM,IAAI;AACV,UAAI,KAAK,MAAM,OAAQ;AACvB,YAAM,OAAO,MAAM,CAAC;AACpB,UAAI;AACF,cAAM,SAAS,MAAM,WAAW,IAAI;AACpC,aAAK,KAAK,OAAO,MAAM;AACvB,yBAAiB,KAAK,OAAO,SAAS;AAAA,MACxC,SAAS,KAAK;AACZ,YAAI,eAAe,oBAAoB;AACrC,qBAAW,KAAK,IAAI,MAAM;AAC1B,cAAI,IAAI,UAAW,kBAAiB,KAAK,IAAI,SAAS;AAAA,QACxD,OAAO;AAKL,wBAAc,KAAK,GAAG;AACtB,qBAAW;AACX;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,WACb,MAC+D;AAC/D,UAAM,SAAS,KAAK,SAAS,cAAc;AAAA,MACzC,YAAY,KAAK;AAAA,MACjB,OAAO;AAAA;AAAA,MACP,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,KAAK,SAAS;AAAA,MAC1B,MAAM,KAAK;AAAA,IACb,CAAC;AACD,UAAM,gBAAuC;AAAA,MAC3C,YAAY,KAAK;AAAA,MACjB;AAAA,MACA,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,KAAK,SAAS;AAAA,MAC1B,MAAM,KAAK;AAAA,IACb;AACA,UAAM,QAAQ,KAAK,aAAa,aAAa;AAC7C,UAAM,UAAU,eAAe,aAAa;AAE5C,UAAM,UAAU,IAAI,aAAa,OAAO;AAAA,MACtC;AAAA,MACA,KAAK,KAAK;AAAA,MACV,eAAe,KAAK;AAAA,IACtB,CAAC;AAGD,aAAS,IAAI,OAAO,OAAO;AAE3B,UAAM,UAA4B;AAAA,MAChC,GAAG,KAAK;AAAA,MACR;AAAA,MACA,cAAc,EAAE,MAAM;AAAA,IACxB;AAEA,UAAM,MAA6B;AAAA,MACjC;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK,QAAQ;AAAA,MACtB,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,KAAK,SAAS;AAAA,MAC1B,cAAc,KAAK,SAAS,QAAQ,CAAC;AAAA,MACrC,MAAM,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,YAAY,IAAI;AACtB,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,KAAK,OAAO,GAAG;AAAA,MACjC,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAM/D,cAAM,cAAc,SAAS,OAAO,OAAO;AAC3C,cAAM,IAAI,mBAAmB;AAAA,UAC3B;AAAA,UACA,WAAW,KAAK,QAAQ;AAAA,UACxB,YAAY,KAAK,SAAS;AAAA,UAC1B,MAAM,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM,SAAS,IAAI,IAAI;AAEvB,YAAM,kBAAkB,MAAM,kBAAkB,OAAO,OAAO,EAAE,GAAG,WAAW,QAAQ,CAAC;AACvF,UAAI,CAAC,gBAAgB,IAAI;AACvB,gBAAQ,oBAAoB;AAAA,UAC1B,KAAK;AACH,kBAAM,IAAI,kBAAkB,eAAe;AAAA,UAC7C,KAAK;AACH,kBAAM,IAAI;AAAA,cACR;AAAA,gBACE;AAAA,gBACA,WAAW,KAAK,QAAQ;AAAA,gBACxB,YAAY,KAAK,SAAS;AAAA,gBAC1B,MAAM,KAAK;AAAA,gBACX,QAAQ;AAAA,gBACR,OAAO,gBAAgB,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,cAC5D;AAAA,cACA;AAAA,YACF;AAAA,UACF,KAAK;AAEH;AAAA,QACJ;AAAA,MACF;AAEA,YAAM,gBAA4B;AAAA,QAChC,KAAK,QAAQ,OAAO,CAAC;AAAA,MACvB;AACA,UAAI,aAAa,UAAW,eAAc,eAAe,QAAQ;AAAA,UAC5D,eAAc,cAAc,QAAQ;AACzC,UAAI,QAAQ,gBAAgB,OAAW,eAAc,cAAc,QAAQ;AAE3E,YAAM,SAAoB;AAAA,QACxB;AAAA,QACA,cAAc,KAAK;AAAA,QACnB,aAAa,KAAK,QAAQ;AAAA,QAC1B,MAAM,KAAK;AAAA,QACX,OAAO,QAAQ;AAAA,QACf,YAAY,QAAQ;AAAA,QACpB,YAAY,QAAQ;AAAA,QACpB,WAAW,KAAK;AAAA,QAChB;AAAA,QACA,SAAS,QAAQ;AAAA,QACjB,YAAY,QAAQ;AAAA,QACpB,eAAe,QAAQ;AAAA,QACvB,SAAS;AAAA,QACT,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,QACrE,aAAa,QAAQ;AAAA,QACrB;AAAA,QACA,YAAY,KAAK,SAAS;AAAA,MAC5B;AACA,YAAM,gBACJ,QAAQ,iBACP,OAAO,KAAK,iBAAiB,aAC1B,MAAM,KAAK,aAAa;AAAA,QACtB,YAAY,KAAK;AAAA,QACjB;AAAA,QACA,WAAW,KAAK,QAAQ;AAAA,QACxB,YAAY,KAAK,SAAS;AAAA,QAC1B,MAAM,KAAK;AAAA,QACX,SAAS,KAAK,QAAQ;AAAA,QACtB,cAAc,KAAK,SAAS,QAAQ,CAAC;AAAA,MACvC,CAAC,IACD,KAAK;AACX,UAAI,kBAAkB,QAAW;AAC/B,cAAM,eAAe,MAAM,wBAAwB,aAAa;AAChE,qCAA6B,cAAc,QAAQ,OAAO,QAAQ,UAAU;AAC5E,eAAO,eAAe;AAAA,MACxB;AACA,aAAO,EAAE,QAAQ,kBAAkB,MAAM,GAAG,WAAW,gBAAgB;AAAA,IACzE,UAAE;AAIA,eAAS,OAAO,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,aAAa,MAAM,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC;AAI1F,QAAM,QAAQ,WAAW,OAAO;AAMhC,aAAW,CAAC,OAAO,OAAO,KAAK,UAAU;AACvC,UAAM,cAAc,SAAS,OAAO,kDAAkD;AAAA,EACxF;AACA,WAAS,MAAM;AAEf,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,cAAc,WAAW,IAC3B,cAAc,CAAC,IACf,IAAI;AAAA,MACF;AAAA,MACA,oBAAoB,cAAc,MAAM;AAAA,IAC1C;AAAA,EACN;AAGA,MAAI;AACJ,MAAI,KAAK,QAAQ;AACf,UAAM,aAAoC;AAAA,MACxC,GAAG,KAAK;AAAA,MACR,YAAY,KAAK,OAAO;AAAA,MACxB,OAAO,aAAa,QAAQ,WAAW;AAAA,MACvC,aAAa,IAAI,KAAK,IAAI,CAAC,EAAE,YAAY;AAAA,MACzC,qBAAqB,uBAAuB;AAAA,IAC9C;AACA,aAAS,MAAM,eAAe,MAAM,UAAU;AAAA,EAChD;AAEA,QAAM,UAAU,IAAI,KAAK,IAAI,CAAC,EAAE,YAAY;AAE5C,SAAO;AAAA,IACL,YAAY,KAAK;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAIA,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EACT,YAAY,QAAmB,WAAgC;AAC7D,UAAM,QAAQ,OAAO,SAAS,IAAI,OAAO,UAAU,IAAI,OAAO,IAAI,YAAY,OAAO,MAAM,EAAE;AAC7F,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AACF;AAiBA,eAAsB,cACpB,SACA,OACA,QACe;AACf,QAAM,WAAW,MAAM,QAAQ,WAAW,OAAO,KAAK;AACtD,MAAI,aAAa,OAAW;AAC5B,MAAI,SAAS,WAAW,UAAW;AACnC,QAAM,QAAQ,SAAS,MAAM;AAC/B;AAEA,SAAS,sBAAsB,SAA6B;AAC1D,SAAO,CAAC,WAAmD;AACzD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,0BAA0B;AAAA,MACnC,KAAK,GAAG,OAAO,eAAe,OAAO,KAAK;AAAA,IAC5C,CAAC;AAAA,EACH;AACF;AAEA,eAAe,wBACb,OAC2B;AAC3B,MAAI,mBAAmB,KAAK,GAAG;AAC7B,QAAI,CAAE,MAAM,uBAAuB,KAAK,GAAI;AAC1C,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACnF;AACA,WAAO;AAAA,EACT;AACA,SAAO,sBAAsB,KAAK;AACpC;AAEA,SAAS,mBACP,OAC2B;AAC3B,SAAO,mBAAmB,SAAS,YAAY;AACjD;AAEA,SAAS,6BACP,SACA,OACA,YACM;AACN,MAAI,QAAQ,UAAU,UAAa,QAAQ,UAAU,OAAO;AAC1D,UAAM,IAAI;AAAA,MACR,wCAAwC,QAAQ,KAAK,mCAAmC,KAAK;AAAA,IAC/F;AAAA,EACF;AACA,MAAI,QAAQ,eAAe,UAAa,QAAQ,eAAe,YAAY;AACzE,UAAM,IAAI;AAAA,MACR,6CAA6C,QAAQ,UAAU,wCAAwC,UAAU;AAAA,IACnH;AAAA,EACF;AACF;AAEA,SAAS,aAAa,QAAuC;AAG3D,QAAM,OAAO,GAAG,OAAO,UAAU,KAAK,OAAO,SAAS,KAAK,OAAO,UAAU,KAAK,OAAO,IAAI;AAE5F,MAAI,KAAK;AACT,MAAI,KAAK;AACT,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,WAAW,CAAC;AAC3B,SAAK,KAAK,KAAK,KAAK,GAAG,QAAU,MAAM;AACvC,SAAK,KAAK,KAAK,KAAK,GAAG,UAAU,MAAM;AAAA,EACzC;AACA,SAAO,OAAO,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACnF;","names":[]}