@tangle-network/agent-eval 0.183.0 → 0.185.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 (248) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/adapters/http.d.ts +2 -2
  3. package/dist/{agent-profile-cell-s__adRnK.d.ts → agent-profile-cell-BHcB-mZX.d.ts} +8 -9
  4. package/dist/{agent-profile-cell-s__adRnK.d.ts.map → agent-profile-cell-BHcB-mZX.d.ts.map} +1 -1
  5. package/dist/{agent-profile-cell-Cv6UA-W_.js → agent-profile-cell-DcFW4vOc.js} +16 -15
  6. package/dist/agent-profile-cell-DcFW4vOc.js.map +1 -0
  7. package/dist/{agent-profile-CivaSsSy.d.ts → agent-profile-uAIQK3Nr.d.ts} +3 -3
  8. package/dist/{agent-profile-CivaSsSy.d.ts.map → agent-profile-uAIQK3Nr.d.ts.map} +1 -1
  9. package/dist/analyst/index.d.ts +11 -336
  10. package/dist/analyst/index.d.ts.map +1 -1
  11. package/dist/analyst/index.js +10 -8
  12. package/dist/analyst/index.js.map +1 -1
  13. package/dist/analyze-runs-CrYhqXop.d.ts +75 -0
  14. package/dist/analyze-runs-CrYhqXop.d.ts.map +1 -0
  15. package/dist/{define-agent-eval-CneiWyuA.js → analyze-runs-sTygaDyD.js} +6 -813
  16. package/dist/analyze-runs-sTygaDyD.js.map +1 -0
  17. package/dist/{benchmark-DQKzykkO.js → benchmark-BeQJyrRC.js} +3 -3
  18. package/dist/{benchmark-DQKzykkO.js.map → benchmark-BeQJyrRC.js.map} +1 -1
  19. package/dist/{benchmark-command-NBrqNwgy.js → benchmark-command-kvq7yFY4.js} +17 -54
  20. package/dist/benchmark-command-kvq7yFY4.js.map +1 -0
  21. package/dist/benchmarks/index.d.ts +4 -4
  22. package/dist/benchmarks/index.js +3 -3
  23. package/dist/builder-eval/index.js +1 -1
  24. package/dist/campaign/index.d.ts +6 -5
  25. package/dist/campaign/index.js +10 -9
  26. package/dist/{campaign-BwcEBC91.js → campaign-eJgtRs-W.js} +16 -15
  27. package/dist/{campaign-BwcEBC91.js.map → campaign-eJgtRs-W.js.map} +1 -1
  28. package/dist/{campaign-evidence-PYPUftRy.js → campaign-evidence-BsrCmBSE.js} +7 -258
  29. package/dist/campaign-evidence-BsrCmBSE.js.map +1 -0
  30. package/dist/{canonical-DPyQ_rpt.js → canonical-BsZVgBhW.js} +2 -4
  31. package/dist/canonical-BsZVgBhW.js.map +1 -0
  32. package/dist/cli.js +2 -2
  33. package/dist/{client-kh2jOjTK.d.ts → client-Bc8LANCG.d.ts} +4 -4
  34. package/dist/{client-kh2jOjTK.d.ts.map → client-Bc8LANCG.d.ts.map} +1 -1
  35. package/dist/contract/index.d.ts +10 -10
  36. package/dist/contract/index.js +15 -284
  37. package/dist/contract/index.js.map +1 -1
  38. package/dist/{default-registry-BwDSWVzg.d.ts → default-registry-CXv9kHMt.d.ts} +6 -6
  39. package/dist/{default-registry-BwDSWVzg.d.ts.map → default-registry-CXv9kHMt.d.ts.map} +1 -1
  40. package/dist/{default-registry-C0-N4PkG.js → default-registry-xiHrldW8.js} +6 -4
  41. package/dist/{default-registry-C0-N4PkG.js.map → default-registry-xiHrldW8.js.map} +1 -1
  42. package/dist/define-agent-eval-D4uumjl3.js +813 -0
  43. package/dist/define-agent-eval-D4uumjl3.js.map +1 -0
  44. package/dist/{define-agent-eval-CwOWWQt_.d.ts → define-agent-eval-DE67ECH1.d.ts} +7 -7
  45. package/dist/{define-agent-eval-CwOWWQt_.d.ts.map → define-agent-eval-DE67ECH1.d.ts.map} +1 -1
  46. package/dist/diagnosis/index.d.ts +319 -0
  47. package/dist/diagnosis/index.d.ts.map +1 -0
  48. package/dist/diagnosis/index.js +1328 -0
  49. package/dist/diagnosis/index.js.map +1 -0
  50. package/dist/{dspy-rlm-engine-8pgBSiy7.js → dspy-rlm-engine-BE9lCzzL.js} +3 -3
  51. package/dist/{dspy-rlm-engine-8pgBSiy7.js.map → dspy-rlm-engine-BE9lCzzL.js.map} +1 -1
  52. package/dist/{engine-DS1cysJy.d.ts → engine-cXUK-WHS.d.ts} +5 -77
  53. package/dist/engine-cXUK-WHS.d.ts.map +1 -0
  54. package/dist/equal-terms-Blx9Zk5I.js +25 -0
  55. package/dist/equal-terms-Blx9Zk5I.js.map +1 -0
  56. package/dist/{eval-campaign-CCEkwzoH.js → eval-campaign-XFHEpN86.js} +4 -4
  57. package/dist/{eval-campaign-CCEkwzoH.js.map → eval-campaign-XFHEpN86.js.map} +1 -1
  58. package/dist/evaluation.d.ts +75 -0
  59. package/dist/evaluation.d.ts.map +1 -0
  60. package/dist/evaluation.js +137 -0
  61. package/dist/evaluation.js.map +1 -0
  62. package/dist/{exact-types-BZDe0W2D.d.ts → exact-types-BEHN7tnq.d.ts} +2 -2
  63. package/dist/{exact-types-BZDe0W2D.d.ts.map → exact-types-BEHN7tnq.d.ts.map} +1 -1
  64. package/dist/experiment/index.d.ts +2 -2
  65. package/dist/experiment/index.js +6 -5
  66. package/dist/experiment/index.js.map +1 -1
  67. package/dist/{experiment-tracker-C7PfnF4b.d.ts → experiment-tracker-URRGP9ek.d.ts} +2 -2
  68. package/dist/{experiment-tracker-C7PfnF4b.d.ts.map → experiment-tracker-URRGP9ek.d.ts.map} +1 -1
  69. package/dist/{external-optimizer-process-DIB4YWEe.js → external-optimizer-process-BbhvXTFx.js} +4 -4
  70. package/dist/{external-optimizer-process-DIB4YWEe.js.map → external-optimizer-process-BbhvXTFx.js.map} +1 -1
  71. package/dist/{external-optimizer-subprocess-CjguXN2e.js → external-optimizer-subprocess-DMgmqTB6.js} +3 -3
  72. package/dist/{external-optimizer-subprocess-CjguXN2e.js.map → external-optimizer-subprocess-DMgmqTB6.js.map} +1 -1
  73. package/dist/{feedback-trajectory-CXmtITBo.d.ts → feedback-trajectory-CytTR7u4.d.ts} +3 -3
  74. package/dist/{feedback-trajectory-CXmtITBo.d.ts.map → feedback-trajectory-CytTR7u4.d.ts.map} +1 -1
  75. package/dist/hosted/index.d.ts +2 -2
  76. package/dist/{index-DoykkxW0.d.ts → index-BQWfAFeH.d.ts} +11 -11
  77. package/dist/{index-DoykkxW0.d.ts.map → index-BQWfAFeH.d.ts.map} +1 -1
  78. package/dist/{index-DbG8QbH9.d.ts → index-C8_iU8KL.d.ts} +6 -6
  79. package/dist/{index-DbG8QbH9.d.ts.map → index-C8_iU8KL.d.ts.map} +1 -1
  80. package/dist/{index--_8_Nlpn.d.ts → index-CKZa_rnt.d.ts} +4 -121
  81. package/dist/index-CKZa_rnt.d.ts.map +1 -0
  82. package/dist/{index-Bp_6sj3x.d.ts → index-ww8736Am.d.ts} +20 -315
  83. package/dist/index-ww8736Am.d.ts.map +1 -0
  84. package/dist/index.d.ts +24 -22
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +25 -24
  87. package/dist/index.js.map +1 -1
  88. package/dist/{insight-report-D1qa0HWs.d.ts → insight-report-C3Bfl762.d.ts} +3 -3
  89. package/dist/{insight-report-D1qa0HWs.d.ts.map → insight-report-C3Bfl762.d.ts.map} +1 -1
  90. package/dist/jev-protocol.d.ts +74 -0
  91. package/dist/jev-protocol.d.ts.map +1 -0
  92. package/dist/jev-protocol.js +91 -0
  93. package/dist/jev-protocol.js.map +1 -0
  94. package/dist/jev.d.ts +131 -0
  95. package/dist/jev.d.ts.map +1 -0
  96. package/dist/jev.js +312 -0
  97. package/dist/jev.js.map +1 -0
  98. package/dist/{journal-Cs9f7385.js → journal-BuRLm6ho.js} +2 -2
  99. package/dist/{journal-Cs9f7385.js.map → journal-BuRLm6ho.js.map} +1 -1
  100. package/dist/{kind-factory-DxTzg32u.js → kind-factory-V79Hw0AU.js} +7 -84
  101. package/dist/kind-factory-V79Hw0AU.js.map +1 -0
  102. package/dist/ledger-core/index.js +2 -2
  103. package/dist/{llm-judge-FfaRgz9X.js → llm-judge-FWWhEb31.js} +11 -9
  104. package/dist/{llm-judge-FfaRgz9X.js.map → llm-judge-FWWhEb31.js.map} +1 -1
  105. package/dist/{matrix-CyhW-vgJ.d.ts → matrix-CPKsRY8Y.d.ts} +2 -2
  106. package/dist/{matrix-CyhW-vgJ.d.ts.map → matrix-CPKsRY8Y.d.ts.map} +1 -1
  107. package/dist/meta-eval/index.d.ts +54 -2
  108. package/dist/meta-eval/index.d.ts.map +1 -1
  109. package/dist/meta-eval/index.js +52 -3
  110. package/dist/meta-eval/index.js.map +1 -1
  111. package/dist/{mint-ySIIkKlV.js → mint-B4zgSAJW.js} +63 -14
  112. package/dist/mint-B4zgSAJW.js.map +1 -0
  113. package/dist/mint-BI14xehJ.d.ts +285 -0
  114. package/dist/mint-BI14xehJ.d.ts.map +1 -0
  115. package/dist/multishot/golden/index.d.ts +1 -1
  116. package/dist/multishot/index.d.ts +2 -2
  117. package/dist/openapi.json +1 -1
  118. package/dist/otel-spans-CQY1pNiN.js +275 -0
  119. package/dist/otel-spans-CQY1pNiN.js.map +1 -0
  120. package/dist/otlp-attributes-BpC_blLF.js +83 -0
  121. package/dist/otlp-attributes-BpC_blLF.js.map +1 -0
  122. package/dist/{run-record-DPa2PeHx.js → paired-promotion-decision-ClJh_9nK.js} +2 -215
  123. package/dist/paired-promotion-decision-ClJh_9nK.js.map +1 -0
  124. package/dist/pipelines/index.js +2 -2
  125. package/dist/prime-bridge-transport-Z3cpKGoV.js +43 -0
  126. package/dist/prime-bridge-transport-Z3cpKGoV.js.map +1 -0
  127. package/dist/prime-protocol-CDBcL9NM.d.ts +331 -0
  128. package/dist/prime-protocol-CDBcL9NM.d.ts.map +1 -0
  129. package/dist/{prime-protocol-6tZTVsWm.js → prime-protocol-DcAK9pC8.js} +2 -23
  130. package/dist/prime-protocol-DcAK9pC8.js.map +1 -0
  131. package/dist/{produced-state-CGoVInrl.js → produced-state-CmB02tr2.js} +23 -19
  132. package/dist/{produced-state-CGoVInrl.js.map → produced-state-CmB02tr2.js.map} +1 -1
  133. package/dist/profile-cell.d.ts +1 -1
  134. package/dist/profile-cell.js +1 -1
  135. package/dist/{promotion-policy-BKFrl7CC.js → promotion-policy-DdrYWHDh.js} +3 -3
  136. package/dist/{promotion-policy-BKFrl7CC.js.map → promotion-policy-DdrYWHDh.js.map} +1 -1
  137. package/dist/{query-D1nLIKt7.js → query-DlV0pdx4.js} +2 -2
  138. package/dist/{query-D1nLIKt7.js.map → query-DlV0pdx4.js.map} +1 -1
  139. package/dist/{registry-BRbB6Y0v.d.ts → registry-D5Ly3GRV.d.ts} +3 -3
  140. package/dist/{registry-BRbB6Y0v.d.ts.map → registry-D5Ly3GRV.d.ts.map} +1 -1
  141. package/dist/{release-confidence-BcqeQTHW.d.ts → release-confidence-DsETiO4f.d.ts} +3 -3
  142. package/dist/{release-confidence-BcqeQTHW.d.ts.map → release-confidence-DsETiO4f.d.ts.map} +1 -1
  143. package/dist/{release-confidence-DMg8n18l.js → release-confidence-RanRUXRW.js} +2 -2
  144. package/dist/{release-confidence-DMg8n18l.js.map → release-confidence-RanRUXRW.js.map} +1 -1
  145. package/dist/reporting.d.ts +3 -3
  146. package/dist/reporting.js +2 -2
  147. package/dist/{researcher-64T49THL.d.ts → researcher-CJkH-6Ty.d.ts} +4 -4
  148. package/dist/{researcher-64T49THL.d.ts.map → researcher-CJkH-6Ty.d.ts.map} +1 -1
  149. package/dist/{reward-hacking-uzO_ihep.d.ts → reward-hacking-BIQ2BWLG.d.ts} +2 -2
  150. package/dist/{reward-hacking-uzO_ihep.d.ts.map → reward-hacking-BIQ2BWLG.d.ts.map} +1 -1
  151. package/dist/rl.d.ts +10 -6
  152. package/dist/rl.d.ts.map +1 -1
  153. package/dist/rl.js +22 -7
  154. package/dist/rl.js.map +1 -1
  155. package/dist/rollout/index.d.ts +2 -2
  156. package/dist/rollout/index.js +2 -2
  157. package/dist/{rollout-D_54FZVu.js → rollout-C0Ifk3vK.js} +2 -2
  158. package/dist/{rollout-D_54FZVu.js.map → rollout-C0Ifk3vK.js.map} +1 -1
  159. package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts → rubric-predictive-validity-CTU8y8Cv.d.ts} +2 -2
  160. package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts.map → rubric-predictive-validity-CTU8y8Cv.d.ts.map} +1 -1
  161. package/dist/run-record-CNNzWGpB.js +216 -0
  162. package/dist/run-record-CNNzWGpB.js.map +1 -0
  163. package/dist/{run-record-BiTWauyO.d.ts → run-record-D9wS35fK.d.ts} +2 -2
  164. package/dist/{run-record-BiTWauyO.d.ts.map → run-record-D9wS35fK.d.ts.map} +1 -1
  165. package/dist/{run-record-DualPTn2.js → run-record-tg_5H2IK.js} +2 -2
  166. package/dist/{run-record-DualPTn2.js.map → run-record-tg_5H2IK.js.map} +1 -1
  167. package/dist/search-ledger-types-D7KDVg-o.d.ts +302 -0
  168. package/dist/search-ledger-types-D7KDVg-o.d.ts.map +1 -0
  169. package/dist/{semantic-concept-judge-_3Fp6Q_3.js → semantic-concept-judge-Cnt0TWp0.js} +4 -4
  170. package/dist/{semantic-concept-judge-_3Fp6Q_3.js.map → semantic-concept-judge-Cnt0TWp0.js.map} +1 -1
  171. package/dist/{sequential-D_xHrBZe.js → sequential-PgLEqcTJ.js} +3 -3
  172. package/dist/{sequential-D_xHrBZe.js.map → sequential-PgLEqcTJ.js.map} +1 -1
  173. package/dist/{server-BZQR1f0C.js → server-DmpcFiVK.js} +2 -2
  174. package/dist/{server-BZQR1f0C.js.map → server-DmpcFiVK.js.map} +1 -1
  175. package/dist/{skillopt-optimization-method-DY1aQ-aL.js → skillopt-optimization-method-FSk8b5FQ.js} +8 -7
  176. package/dist/{skillopt-optimization-method-DY1aQ-aL.js.map → skillopt-optimization-method-FSk8b5FQ.js.map} +1 -1
  177. package/dist/{statistical-heldout-CpVd6FmY.d.ts → statistical-heldout-Bu4oNOJh.d.ts} +3 -3
  178. package/dist/{statistical-heldout-CpVd6FmY.d.ts.map → statistical-heldout-Bu4oNOJh.d.ts.map} +1 -1
  179. package/dist/statistical-heldout-CeWT_W7y.js +256 -0
  180. package/dist/statistical-heldout-CeWT_W7y.js.map +1 -0
  181. package/dist/{store-otlp-DAaEbMLf.js → store-otlp-2gYCy-v0.js} +2 -2
  182. package/dist/{store-otlp-DAaEbMLf.js.map → store-otlp-2gYCy-v0.js.map} +1 -1
  183. package/dist/{store-tool-spans-BZ8MPKFe.js → store-tool-spans-B1e6Auc2.js} +69 -6
  184. package/dist/store-tool-spans-B1e6Auc2.js.map +1 -0
  185. package/dist/{store-tool-spans-Dt-YdAuE.d.ts → store-tool-spans-BrdfPaVh.d.ts} +54 -6
  186. package/dist/store-tool-spans-BrdfPaVh.d.ts.map +1 -0
  187. package/dist/{summary-report-IGAOtgPd.js → summary-report-BMvou2oZ.js} +2 -2
  188. package/dist/{summary-report-IGAOtgPd.js.map → summary-report-BMvou2oZ.js.map} +1 -1
  189. package/dist/{summary-report-D1h4dlrK.d.ts → summary-report-BzFS5UhZ.d.ts} +2 -2
  190. package/dist/{summary-report-D1h4dlrK.d.ts.map → summary-report-BzFS5UhZ.d.ts.map} +1 -1
  191. package/dist/{task-failure-attributes-B_JjrOVo.js → task-failure-attributes-B34TiMBe.js} +2 -2
  192. package/dist/{task-failure-attributes-B_JjrOVo.js.map → task-failure-attributes-B34TiMBe.js.map} +1 -1
  193. package/dist/{tool-groups-B2bSNaJB.d.ts → tool-groups-eOOgYGaM.d.ts} +3 -3
  194. package/dist/tool-groups-eOOgYGaM.d.ts.map +1 -0
  195. package/dist/{tool-waste-C7MU9u1e.js → tool-waste-nbHPAxei.js} +2 -2
  196. package/dist/{tool-waste-C7MU9u1e.js.map → tool-waste-nbHPAxei.js.map} +1 -1
  197. package/dist/trace-repair/index.d.ts +2 -2
  198. package/dist/trace-repair/index.js +5 -4
  199. package/dist/trace-repair/index.js.map +1 -1
  200. package/dist/traces.d.ts +5 -5
  201. package/dist/traces.js +8 -7
  202. package/dist/traces.js.map +1 -1
  203. package/dist/trajectory-replay/index.js +1 -1
  204. package/dist/{types-CS0qk_Yp.d.ts → types-BTRcIqFr.d.ts} +3 -3
  205. package/dist/{types-CS0qk_Yp.d.ts.map → types-BTRcIqFr.d.ts.map} +1 -1
  206. package/dist/{types-D7gEdPoQ.d.ts → types-BjB2wZM9.d.ts} +2 -2
  207. package/dist/{types-D7gEdPoQ.d.ts.map → types-BjB2wZM9.d.ts.map} +1 -1
  208. package/dist/types-C8VBbiw6.js +91 -0
  209. package/dist/types-C8VBbiw6.js.map +1 -0
  210. package/dist/{types-BvZoPTGa.d.ts → types-c3ZRTbw9.d.ts} +3 -3
  211. package/dist/{types-BvZoPTGa.d.ts.map → types-c3ZRTbw9.d.ts.map} +1 -1
  212. package/dist/{types-DQ0e2E7y.js → usage-receipt-Cx3xNeyB.js} +2 -89
  213. package/dist/usage-receipt-Cx3xNeyB.js.map +1 -0
  214. package/dist/{verdict-BQ3pCFf8.js → verdict-DhPoXApk.js} +2 -2
  215. package/dist/{verdict-BQ3pCFf8.js.map → verdict-DhPoXApk.js.map} +1 -1
  216. package/dist/{verdict-cache-B3eCVQtY.js → verdict-cache-BQEsVy9n.js} +2 -2
  217. package/dist/{verdict-cache-B3eCVQtY.js.map → verdict-cache-BQEsVy9n.js.map} +1 -1
  218. package/dist/wire/index.d.ts +1 -1
  219. package/dist/wire/index.js +1 -1
  220. package/docs/changes/evaluation-definition-identity.md +27 -0
  221. package/docs/changes/jev-evidence-review.md +18 -0
  222. package/docs/changes/jev-product-adoption.md +18 -0
  223. package/docs/changes/probability-policy-audit.md +81 -0
  224. package/docs/diagnosis.md +42 -0
  225. package/docs/jev-behavior-review.md +174 -0
  226. package/docs/jev-integrations.md +50 -0
  227. package/docs/jev.md +140 -0
  228. package/docs/produced-state.md +13 -0
  229. package/docs/profile-json-identity.md +33 -0
  230. package/package.json +22 -1
  231. package/dist/agent-profile-cell-Cv6UA-W_.js.map +0 -1
  232. package/dist/benchmark-command-NBrqNwgy.js.map +0 -1
  233. package/dist/campaign-evidence-PYPUftRy.js.map +0 -1
  234. package/dist/canonical-DPyQ_rpt.js.map +0 -1
  235. package/dist/define-agent-eval-CneiWyuA.js.map +0 -1
  236. package/dist/engine-DS1cysJy.d.ts.map +0 -1
  237. package/dist/exporters-D98GPi1n.d.ts +0 -161
  238. package/dist/exporters-D98GPi1n.d.ts.map +0 -1
  239. package/dist/index--_8_Nlpn.d.ts.map +0 -1
  240. package/dist/index-Bp_6sj3x.d.ts.map +0 -1
  241. package/dist/kind-factory-DxTzg32u.js.map +0 -1
  242. package/dist/mint-ySIIkKlV.js.map +0 -1
  243. package/dist/prime-protocol-6tZTVsWm.js.map +0 -1
  244. package/dist/run-record-DPa2PeHx.js.map +0 -1
  245. package/dist/store-tool-spans-BZ8MPKFe.js.map +0 -1
  246. package/dist/store-tool-spans-Dt-YdAuE.d.ts.map +0 -1
  247. package/dist/tool-groups-B2bSNaJB.d.ts.map +0 -1
  248. package/dist/types-DQ0e2E7y.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"prime-protocol-6tZTVsWm.js","names":[],"sources":["../src/analyst/equal-terms.ts","../src/analyst/reply-contract.ts","../src/analyst/prime-protocol.ts"],"sourcesContent":["import { ValidationError } from '../errors'\n\n/**\n * The terms every declarative-arm comparison must hold equal before any\n * per-kind check runs. Arm kinds (analyst definitions, repair arms) extend\n * the comparison with their own fields; the refusals here are the floor.\n */\nexport interface DeclarativeArmTerms {\n readonly id: string\n /** Bounded repair turns the arm earns on a malformed reply. */\n readonly repairTurns: number\n}\n\nexport interface EqualDeclarativeTerms {\n readonly ids: readonly string[]\n readonly repairTurns: number\n}\n\n/**\n * Refuses a comparison whose arms are not on equal terms: an empty set, a\n * duplicated id, or unequal repair turns — a retry is a second sample the\n * other arms never got. `noun` names the arm kind in every message so a\n * refusal reads in the caller's vocabulary.\n */\nexport function assertEqualDeclarativeTerms(\n noun: string,\n terms: ReadonlyArray<DeclarativeArmTerms>,\n): EqualDeclarativeTerms {\n if (terms.length === 0) {\n throw new ValidationError(`a ${noun} comparison needs at least one ${noun}`)\n }\n const ids = terms.map((term) => term.id)\n const duplicate = ids.find((id, index) => ids.indexOf(id) !== index)\n if (duplicate !== undefined) {\n throw new ValidationError(`${noun} '${duplicate}' is declared twice`)\n }\n const repairTurns = terms[0]!.repairTurns\n const unequal = terms.find((term) => term.repairTurns !== repairTurns)\n if (unequal) {\n throw new ValidationError(\n `${noun} '${unequal.id}' gets ${unequal.repairTurns} bounded repair turns and ` +\n `${noun} '${terms[0]!.id}' gets ${repairTurns}; a retry is a second sample ` +\n 'the other arms never got',\n )\n }\n return { ids, repairTurns }\n}\n","/**\n * The reply grammar an analyst arm holds a model to, independent of transport.\n *\n * One contract serves every arm shape: the inline bridge protocol\n * (`runPrimeExchange`) reads the base fields, and one-shot JSON arms\n * additionally use the strict-envelope and all-rejected knobs. `PrimeReplyContract`\n * in ./prime-protocol is a type alias of this contract, so a consumer written\n * against the prime protocol names the same grammar object.\n */\n\nimport { ValidationError } from '../errors'\n\n/** Verdict of decoding one raw reply row. */\nexport type ReplyRowDecoded<TRow> = { ok: true; row: TRow } | { ok: false; reason: string }\n\n/** A strictly parsed reply envelope: the row array plus retained extras. */\nexport interface ReplyEnvelope {\n rows: readonly unknown[]\n /** Envelope fields beside the rows the arm retains (e.g. a `report` string). */\n extras: Record<string, unknown>\n}\n\nexport interface ReplyContract<TRow> {\n /** Name of the reply's row array, e.g. `blocks` or `findings`. */\n rowsField: string\n /** Row-grammar lines spliced into the first-turn prompt. */\n contractLines: readonly string[]\n /**\n * The same grammar restated for the repair turn, which never carries the\n * evidence. Empty when the arm declares zero repair turns.\n */\n repairContractLines: readonly string[]\n /**\n * Validate and convert one raw row in a single pass. One function rather than\n * a separate validator and constructor, so the two can never disagree about\n * what a valid row is.\n */\n decodeRow(row: unknown, index: number): ReplyRowDecoded<TRow>\n /**\n * Cap on ACCEPTED rows. The cap is applied after decoding, so malformed rows\n * never consume an accepted slot; the surplus is reported as `overflow`.\n * Omit when the consumer's own expansion owns the cap and records the drop.\n */\n maxRows?: number\n /**\n * Strict envelope parse for one-shot JSON arms. Throws on an envelope defect\n * (missing report, unknown key, over-cap row count). When absent, rows are\n * read from `rowsField` on the parsed reply object.\n */\n parseEnvelope?(value: unknown): ReplyEnvelope\n /**\n * What a reply whose EVERY reported row was rejected means. `fail` throws a\n * validation error carrying each rejection; `accept-empty` (the default)\n * keeps the honest empty result beside the recorded rejections.\n */\n whenAllRowsRejected?: 'fail' | 'accept-empty'\n /**\n * Message prefix for the `fail` case, in the contract's own row vocabulary\n * (e.g. \"every reported failure block was malformed\").\n */\n allRejectedMessage?: string\n}\n\n/** One rejected row, indexed as the model reported it. */\nexport interface ReplyRowRejection {\n index: number\n reason: string\n}\n\nexport interface DecodedReply<TRow> {\n rows: TRow[]\n /** Envelope fields beside the rows (empty when the contract has no envelope). */\n extras: Record<string, unknown>\n rejected: ReplyRowRejection[]\n /** Rows the model reported, before decoding or the count cap. */\n reportedRows: number\n /** Valid rows dropped by `maxRows`. */\n overflow: number\n}\n\n/**\n * The per-row half of a decode: validate each raw row under the contract's\n * grammar and cap ACCEPTED rows. Shape before count — a malformed row never\n * consumes an accepted slot. Shared by every consumer of a `ReplyContract`\n * row array, whatever envelope handling surrounds it.\n */\nexport function decodeContractRows<TRow>(\n contract: Pick<ReplyContract<TRow>, 'decodeRow' | 'maxRows'>,\n rawRows: readonly unknown[],\n): { rows: TRow[]; rejected: ReplyRowRejection[]; overflow: number } {\n const rows: TRow[] = []\n const rejected: ReplyRowRejection[] = []\n let overflow = 0\n rawRows.forEach((row, index) => {\n const decoded = contract.decodeRow(row, index)\n if (!decoded.ok) {\n rejected.push({ index, reason: decoded.reason })\n return\n }\n if (contract.maxRows !== undefined && rows.length >= contract.maxRows) {\n overflow += 1\n return\n }\n rows.push(decoded.row)\n })\n return { rows, rejected, overflow }\n}\n\n/**\n * Decode a parsed reply value under a contract: strict envelope when declared,\n * then per-row decoding, then the all-rejected policy.\n */\nexport function decodeReplyRows<TRow>(\n contract: ReplyContract<TRow>,\n value: unknown,\n): DecodedReply<TRow> {\n let rawRows: readonly unknown[]\n let extras: Record<string, unknown> = {}\n if (contract.parseEnvelope) {\n const envelope = contract.parseEnvelope(value)\n rawRows = envelope.rows\n extras = envelope.extras\n } else {\n const record =\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n const field = record?.[contract.rowsField]\n if (!Array.isArray(field)) {\n throw new ValidationError(`reply has no \"${contract.rowsField}\" array`)\n }\n rawRows = field\n }\n const { rows, rejected, overflow } = decodeContractRows(contract, rawRows)\n if (rows.length === 0 && rawRows.length > 0 && contract.whenAllRowsRejected === 'fail') {\n throw new ValidationError(\n `${contract.allRejectedMessage ?? 'every reported row was malformed'}: ${rejected\n .map((entry) => entry.reason)\n .join(' | ')}`,\n )\n }\n return { rows, extras, rejected, reportedRows: rawRows.length, overflow }\n}\n","import { createHash } from 'node:crypto'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport type { PrimeBridgeTransport, PrimeBridgeTransportResult } from './prime-bridge-transport'\nimport { decodeContractRows, type ReplyContract, type ReplyRowDecoded } from './reply-contract'\nimport type { AnalystUsageReceipt } from './types'\n\n/**\n * The prime analyst protocol: a one-shot RLM reached through an\n * OpenAI-compatible bridge, given the whole trajectory inline because it has no\n * REPL and no trace tools, answering in one fenced JSON block of short strings.\n *\n * This module owns every part of that protocol that does not depend on what the\n * rows MEAN: prompt and contract composition, the bounded repair turn, reply\n * extraction, row decoding order, the render-measure-fall-back-fail-loud\n * projection ladder, usage normalization, and the protocol identity digest.\n *\n * The cut: the core speaks RAW ROWS and never names a finding type. It knows a\n * prime reply carries an `answer` string plus an array of rows under a named\n * field, and that each row is decoded by a caller-supplied function. Consumers\n * — the CodeTraceBench benchmark runner here, a span-grounded trace analyzer\n * elsewhere — map decoded rows into their own finding shape on the way out. So\n * nothing in this file may import a block type, a finding type, or a trace\n * store, and no consumer needs another copy of the protocol.\n */\n\n// ── Reply contract ───────────────────────────────────────────────────\n\n/**\n * The prime reply grammar is the general analyst reply contract: these aliases\n * keep every prime-protocol consumer compiling against the shared type in\n * ./reply-contract. The exchange below reads the base fields (`rowsField`,\n * contract lines, `decodeRow`, `maxRows`); the strict-envelope knobs serve\n * one-shot JSON arms and are inert here.\n */\nexport type PrimeRowDecoded<TRow> = ReplyRowDecoded<TRow>\n\nexport type PrimeReplyContract<TRow> = ReplyContract<TRow>\n\n// ── Prompt composition ───────────────────────────────────────────────\n\nexport interface PrimePromptSpec {\n question: string\n /** Task definition spliced under a `TASK DEFINITION:` heading. Omit when the question is the whole task. */\n taskDefinition?: string\n contractLines: readonly string[]\n /** Line introducing the trajectory, e.g. `TRAJECTORY (trace_id X; 12 assistant step spans; ...):`. */\n trajectoryHeader: string\n renderedTrajectory: string\n /** Material appended after the trajectory, e.g. the final-verification spans. */\n trailer?: string\n}\n\nexport function buildPrimePrompt(spec: PrimePromptSpec): string {\n return [\n `QUESTION: ${spec.question}`,\n '',\n ...(spec.taskDefinition === undefined ? [] : ['TASK DEFINITION:', spec.taskDefinition, '']),\n ...spec.contractLines,\n '',\n spec.trajectoryHeader,\n spec.renderedTrajectory,\n ...(spec.trailer === undefined ? [] : ['', spec.trailer]),\n ].join('\\n')\n}\n\nexport interface PrimeRepairPromptSpec {\n defect: string\n previousReply: string\n repairContractLines: readonly string[]\n}\n\n/** Carries the malformed reply and the contract — never the trajectory. */\nexport function buildPrimeRepairPrompt(spec: PrimeRepairPromptSpec): string {\n return [\n 'Your previous reply to a trace-analysis task was structurally malformed and could not be parsed',\n `(${spec.defect}). Below is your previous reply verbatim. Re-emit ONLY the corrected JSON — one`,\n 'fenced ```json block, no other text, no tools. The JSON object has exactly two fields:',\n ...spec.repairContractLines,\n '',\n 'PREVIOUS REPLY:',\n spec.previousReply,\n ].join('\\n')\n}\n\n// ── Reply extraction ─────────────────────────────────────────────────\n\n/**\n * Recover the reply's JSON object.\n *\n * Distinct from `extractJsonPayload` in ../llm-client, which serves a response\n * that DECLARES a JSON root and therefore must not scan onward. A prime reply\n * is prose plus a fenced block, and when the model emits several fences the\n * last one is its answer — so fences are scanned in reverse, and only then is a\n * brace-to-brace slice tried.\n */\nexport function extractPrimeJsonObject(text: string): Record<string, unknown> | null {\n const direct = parsePrimeJsonObject(text)\n if (direct) return direct\n const fenced = [...text.matchAll(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/g)]\n for (let index = fenced.length - 1; index >= 0; index -= 1) {\n const candidate = parsePrimeJsonObject(fenced[index]![1]!)\n if (candidate) return candidate\n }\n const start = text.indexOf('{')\n const end = text.lastIndexOf('}')\n if (start >= 0 && end > start) {\n const candidate = parsePrimeJsonObject(text.slice(start, end + 1))\n if (candidate) return candidate\n }\n return null\n}\n\n/** Why the reply cannot be read as a prime answer, or null when it can. */\nexport function primeReplyDefect(\n parsed: Record<string, unknown> | null,\n rowsField: string,\n): string | null {\n if (parsed === null) return 'no parseable JSON object'\n if (!Array.isArray(parsed[rowsField])) return `JSON has no \"${rowsField}\" array`\n return null\n}\n\nfunction parsePrimeJsonObject(text: string): Record<string, unknown> | null {\n try {\n const value: unknown = JSON.parse(text.trim())\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null\n } catch {\n return null\n }\n}\n\n// ── Usage ────────────────────────────────────────────────────────────\n\n/**\n * Token accounting exactly as the bridge reported it. Lossless on purpose: a\n * side the bridge did not report stays null rather than becoming a zero, and a\n * side it DID report survives even when its partner is missing.\n */\nexport interface PrimeRawUsage {\n /**\n * Model-usage records the bridge observed. NOT a count of bridge round trips:\n * one prime turn routes several internal model calls, so a single turn\n * typically reports 3-5.\n */\n calls: number | null\n /** Prompt tokens the bridge reported; null when it reported none. */\n inputTokens: number | null\n /** Completion tokens the bridge reported; null when it reported none. */\n outputTokens: number | null\n /**\n * True when the bridge DERIVED the counts (from character lengths) because\n * the backend reported no usage of its own. Pricing derived counts produces a\n * guess about a guess, which a reader must be able to tell apart from a\n * rate-estimated cost over exact tokens.\n */\n bridgeEstimated: boolean\n}\n\nexport function emptyPrimeRawUsage(): PrimeRawUsage {\n return { calls: null, inputTokens: null, outputTokens: null, bridgeEstimated: false }\n}\n\n/** Read the bridge's OpenAI-shaped `usage` object. */\nexport function normalizePrimeUsage(raw: unknown): PrimeRawUsage {\n if (typeof raw !== 'object' || raw === null) return emptyPrimeRawUsage()\n const record = raw as Record<string, unknown>\n return {\n calls: tokenCountOrNull(record.model_requests),\n inputTokens: tokenCountOrNull(record.prompt_tokens),\n outputTokens: tokenCountOrNull(record.completion_tokens),\n bridgeEstimated: record.estimated === true,\n }\n}\n\n/**\n * Sum two turns. Each side poisons independently: two turns that both report\n * input and neither report output yield a real input total beside a null\n * output, because discarding a measured count is as wrong as inventing one.\n */\nexport function mergePrimeRawUsage(a: PrimeRawUsage, b: PrimeRawUsage): PrimeRawUsage {\n return {\n calls: sumOrNull(a.calls, b.calls),\n inputTokens: sumOrNull(a.inputTokens, b.inputTokens),\n outputTokens: sumOrNull(a.outputTokens, b.outputTokens),\n bridgeEstimated: a.bridgeEstimated || b.bridgeEstimated,\n }\n}\n\nfunction sumOrNull(a: number | null, b: number | null): number | null {\n return a !== null && b !== null ? a + b : null\n}\n\nfunction tokenCountOrNull(value: unknown): number | null {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null\n}\n\n/**\n * Bind raw prime usage to agent-eval's typed receipt.\n *\n * `RunTokenUsage.input` and `.output` are non-nullable, so a one-sided count\n * cannot round-trip through `tokens` without writing a zero nobody measured.\n * The complete-accounting field therefore stays null, the reported side is\n * carried verbatim in `partialTokens`, and its price becomes the receipt's\n * `knownCostUsd` lower bound.\n *\n * Only agent-eval calls this; consumers with no pricing table read\n * `PrimeRawUsage` directly.\n */\nexport function analystUsageReceiptFromPrimeUsage(\n usage: PrimeRawUsage,\n pricing: CustomTokenPricing,\n): AnalystUsageReceipt {\n const { calls, inputTokens, outputTokens, bridgeEstimated } = usage\n const estimatedTokens = bridgeEstimated ? { tokensEstimated: true } : {}\n if (inputTokens !== null && outputTokens !== null) {\n return {\n calls,\n tokens: { input: inputTokens, output: outputTokens },\n cost: { kind: 'estimated', usd: priceTokens(inputTokens, outputTokens, pricing) },\n ...estimatedTokens,\n }\n }\n if (inputTokens === null && outputTokens === null) {\n return { calls, tokens: null, cost: { kind: 'uncaptured', usd: null }, ...estimatedTokens }\n }\n return {\n calls,\n tokens: null,\n partialTokens: { input: inputTokens, output: outputTokens },\n cost: { kind: 'uncaptured', usd: null },\n knownCostUsd: priceTokens(inputTokens ?? 0, outputTokens ?? 0, pricing),\n ...estimatedTokens,\n }\n}\n\nfunction priceTokens(input: number, output: number, pricing: CustomTokenPricing): number {\n return (input * pricing.inputUsdPerMillion + output * pricing.outputUsdPerMillion) / 1_000_000\n}\n\n// ── Two-turn exchange ────────────────────────────────────────────────\n\n/**\n * Why an exchange ended without a readable reply. `deadline` and `aborted` are\n * separate members from `transport` on purpose: a model that ran past its\n * deadline, a caller who cancelled, and a bridge that refused the connection\n * demand three different responses, and a record that conflates them cannot be\n * acted on.\n */\nexport type PrimeFailure =\n | {\n kind: 'transport' | 'unparseable-json' | 'no-content' | 'deadline' | 'malformed-reply'\n message: string\n }\n | { kind: 'http-status'; message: string; status: number; bodySnippet: string }\n | { kind: 'aborted'; message: string; cause: unknown }\n\nexport interface PrimeRepairState {\n attempted: boolean\n /** Null when no repair turn ran, or when the repair turn never returned a reply. */\n succeeded: boolean | null\n}\n\n/** One completed bridge turn. A turn that failed produces no record. */\nexport interface PrimeTurnRecord {\n turn: 'first' | 'repair'\n usage: PrimeRawUsage\n /** The reply's `usage` object verbatim; null when the bridge sent none. */\n rawUsage: unknown\n}\n\nexport interface PrimeRejectedRow {\n index: number\n reason: string\n}\n\nexport type PrimeExchangeOutcome<TRow> =\n | {\n ok: true\n /** The reply's `answer` field; null when absent or not a string. */\n answer: string | null\n rows: TRow[]\n rejected: PrimeRejectedRow[]\n /** Rows the model reported, before decoding or the count cap. */\n reportedRows: number\n /** Valid rows dropped by `contract.maxRows`. */\n overflow: number\n usage: PrimeRawUsage\n turns: PrimeTurnRecord[]\n repair: PrimeRepairState\n reply: string\n }\n | {\n ok: false\n failure: PrimeFailure\n usage: PrimeRawUsage\n turns: PrimeTurnRecord[]\n repair: PrimeRepairState\n /** The last reply received, when one arrived — the diagnostic artifact for a malformed case. */\n reply?: string\n }\n\nexport interface PrimeExchangeOptions<TRow> {\n contract: PrimeReplyContract<TRow>\n prompt: string\n transport: PrimeBridgeTransport\n /** Full endpoint, e.g. `http://localhost:4181/v1/chat/completions`. */\n url: string\n model: string\n /** Deadline for ONE turn. Prime analyses routinely exceed five minutes. */\n timeoutMs: number\n /** Whether a structurally malformed reply gets one bounded repair turn. */\n repair: boolean\n signal?: AbortSignal\n}\n\n/**\n * Run the protocol: one call, one bounded repair turn on a structurally\n * malformed reply, then decode. Zero valid rows from a well-formed reply is an\n * honest null, not a failure.\n */\nexport async function runPrimeExchange<TRow>(\n options: PrimeExchangeOptions<TRow>,\n): Promise<PrimeExchangeOutcome<TRow>> {\n const { contract } = options\n const turns: PrimeTurnRecord[] = []\n const repair: PrimeRepairState = { attempted: false, succeeded: null }\n\n const first = await callPrimeTurn(options, options.prompt)\n if (!first.ok) {\n return { ok: false, failure: first.failure, usage: mergeTurns(turns), turns, repair }\n }\n turns.push({ turn: 'first', usage: first.usage, rawUsage: first.rawUsage })\n\n let reply = first.content\n let parsed = extractPrimeJsonObject(reply)\n let defect = primeReplyDefect(parsed, contract.rowsField)\n\n if (defect !== null && options.repair) {\n repair.attempted = true\n const second = await callPrimeTurn(\n options,\n buildPrimeRepairPrompt({\n defect,\n previousReply: reply,\n repairContractLines: contract.repairContractLines,\n }),\n )\n if (!second.ok) {\n return { ok: false, failure: second.failure, usage: mergeTurns(turns), turns, repair, reply }\n }\n turns.push({ turn: 'repair', usage: second.usage, rawUsage: second.rawUsage })\n reply = second.content\n parsed = extractPrimeJsonObject(reply)\n defect = primeReplyDefect(parsed, contract.rowsField)\n repair.succeeded = defect === null\n }\n\n const usage = mergeTurns(turns)\n if (defect !== null) {\n return {\n ok: false,\n failure: {\n kind: 'malformed-reply',\n message: `${defect} in prime reply${repair.attempted ? ' even after the bounded repair turn' : ''}`,\n },\n usage,\n turns,\n repair,\n reply,\n }\n }\n\n const rawRows = parsed![contract.rowsField] as unknown[]\n const { rows, rejected, overflow } = decodeContractRows(contract, rawRows)\n const answer = parsed!.answer\n return {\n ok: true,\n answer: typeof answer === 'string' ? answer : null,\n rows,\n rejected,\n reportedRows: rawRows.length,\n overflow,\n usage,\n turns,\n repair,\n reply,\n }\n}\n\ntype PrimeTurnOutcome =\n | { ok: true; content: string; usage: PrimeRawUsage; rawUsage: unknown }\n | { ok: false; failure: PrimeFailure }\n\nasync function callPrimeTurn<TRow>(\n options: PrimeExchangeOptions<TRow>,\n content: string,\n): Promise<PrimeTurnOutcome> {\n const { transport, url, model, timeoutMs, signal } = options\n const controller = new AbortController()\n const forwardAbort = () => controller.abort(signal?.reason)\n if (signal?.aborted) controller.abort(signal.reason)\n else signal?.addEventListener('abort', forwardAbort, { once: true })\n const deadline = setTimeout(() => controller.abort(), timeoutMs)\n let result: PrimeBridgeTransportResult\n try {\n result = await transport({\n url,\n body: { model, messages: [{ role: 'user', content }] },\n signal: controller.signal,\n })\n } catch (error) {\n if (signal?.aborted) {\n return {\n ok: false,\n failure: {\n kind: 'aborted',\n message: 'prime exchange cancelled by the caller',\n cause: error,\n },\n }\n }\n if (controller.signal.aborted) {\n return {\n ok: false,\n failure: { kind: 'deadline', message: `bridge call exceeded ${timeoutMs}ms` },\n }\n }\n return {\n ok: false,\n failure: {\n kind: 'transport',\n message: `bridge transport failure: ${error instanceof Error ? error.message : String(error)}`,\n },\n }\n } finally {\n clearTimeout(deadline)\n signal?.removeEventListener('abort', forwardAbort)\n }\n\n if (result.status !== 200) {\n const bodySnippet = result.text.slice(0, 500)\n return {\n ok: false,\n failure: {\n kind: 'http-status',\n message: `bridge HTTP ${result.status}: ${bodySnippet}`,\n status: result.status,\n bodySnippet,\n },\n }\n }\n let response: unknown\n try {\n response = JSON.parse(result.text)\n } catch {\n return {\n ok: false,\n failure: {\n kind: 'unparseable-json',\n message: `bridge returned unparseable JSON (${result.text.length} bytes)`,\n },\n }\n }\n const replyContent = primeReplyContent(response)\n if (replyContent === null) {\n return {\n ok: false,\n failure: { kind: 'no-content', message: 'bridge reply carries no message content' },\n }\n }\n const rawUsage = primeReplyUsage(response)\n return { ok: true, content: replyContent, usage: normalizePrimeUsage(rawUsage), rawUsage }\n}\n\n/**\n * Fold from the FIRST turn, never from an empty receipt: an all-null identity\n * would poison every side it merged with and erase counts the bridge reported.\n */\nfunction mergeTurns(turns: readonly PrimeTurnRecord[]): PrimeRawUsage {\n if (turns.length === 0) return emptyPrimeRawUsage()\n return turns\n .slice(1)\n .reduce<PrimeRawUsage>((total, turn) => mergePrimeRawUsage(total, turn.usage), turns[0]!.usage)\n}\n\nfunction primeReplyContent(response: unknown): string | null {\n if (typeof response !== 'object' || response === null) return null\n const choices = (response as { choices?: unknown }).choices\n if (!Array.isArray(choices) || choices.length === 0) return null\n const message = (choices[0] as { message?: unknown })?.message\n if (typeof message !== 'object' || message === null) return null\n const content = (message as { content?: unknown }).content\n return typeof content === 'string' && content.length > 0 ? content : null\n}\n\nfunction primeReplyUsage(response: unknown): unknown {\n if (typeof response !== 'object' || response === null) return null\n return (response as { usage?: unknown }).usage ?? null\n}\n\n// ── Trajectory projection ────────────────────────────────────────────\n\n/**\n * Where the inlined trajectory comes from. The protocol needs only two moves —\n * fetch it all, or fetch a reduced version — so no store, artifact path, or\n * span type enters the shared signature.\n */\nexport interface PrimeProjectionSource<TItem> {\n /** The full projection, or null when the source declares itself oversized. */\n full(): Promise<readonly TItem[] | null>\n /** A reduced projection of the same material. */\n capped(): Promise<readonly TItem[]>\n /** How `capped` reduces, named for the failure message, e.g. `per-attribute cap 1200`. */\n cappedDescription: string\n}\n\nexport interface PrimeProjectionDelivery {\n mode: 'inline-json'\n fetch: 'full' | 'capped'\n renderedChars: number\n}\n\nexport type PrimeProjectionOutcome<TItem> =\n | {\n ok: true\n items: readonly TItem[]\n rendered: string\n delivery: PrimeProjectionDelivery\n }\n | { ok: false; reason: string; renderedChars: number }\n\n/**\n * Render, measure, fall back to the capped projection, re-measure, fail loud.\n *\n * Inline is the only delivery prime has, so an oversized trajectory is a\n * refusal rather than a silent truncation: dropping spans would understate the\n * trajectory and the analyst would answer a question about a different run.\n */\nexport async function projectPrimeTrajectory<TItem>(\n source: PrimeProjectionSource<TItem>,\n limits: { maxInlineChars: number },\n): Promise<PrimeProjectionOutcome<TItem>> {\n let fetch: PrimeProjectionDelivery['fetch'] = 'full'\n let items = await source.full()\n if (items === null) {\n fetch = 'capped'\n items = await source.capped()\n }\n let rendered = JSON.stringify(items)\n if (rendered.length > limits.maxInlineChars && fetch === 'full') {\n fetch = 'capped'\n items = await source.capped()\n rendered = JSON.stringify(items)\n }\n if (rendered.length > limits.maxInlineChars) {\n return {\n ok: false,\n reason: `trajectory renders to ${rendered.length} chars even at ${source.cappedDescription}; inline delivery impossible`,\n renderedChars: rendered.length,\n }\n }\n return {\n ok: true,\n items,\n rendered,\n delivery: { mode: 'inline-json', fetch, renderedChars: rendered.length },\n }\n}\n\n// ── Protocol identity ────────────────────────────────────────────────\n\nexport interface PrimeProtocolIdentity {\n question: string\n taskDefinition?: string\n contractLines: readonly string[]\n repairContractLines: readonly string[]\n /** Numeric limits the contract states, e.g. row and width caps. */\n limits: Readonly<Record<string, number>>\n}\n\n/**\n * Digest of everything a consumer can send to the bridge under the prime\n * protocol, recorded per observation so a prime result names the exact contract\n * that produced it.\n *\n * Computed over the ACTUALLY composed contract, so two consumers that both\n * stamp `analyst_id: 'prime'` while asking materially different questions get\n * different digests by construction. That is what makes 'prime' a reproducible\n * claim rather than a label.\n */\nexport function primeProtocolSha256(identity: PrimeProtocolIdentity): string {\n return createHash('sha256')\n .update(\n JSON.stringify({\n kind: 'prime-analyst-protocol',\n question: identity.question,\n taskPrompt: identity.taskDefinition ?? null,\n outputContract: identity.contractLines,\n repairContract: buildPrimeRepairPrompt({\n defect: '<defect>',\n previousReply: '<previous-reply>',\n repairContractLines: identity.repairContractLines,\n }),\n limits: identity.limits,\n }),\n )\n .digest('hex')\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-record-DPa2PeHx.js","names":[],"sources":["../src/paired-delta-test.ts","../src/paired-promotion-decision.ts","../src/campaign/run-record.ts"],"sourcesContent":["import {\n type PairedBootstrapOptions,\n type PairedBootstrapResult,\n pairedBootstrap,\n pairedSignTest,\n} from './statistics'\n\nexport interface PairedDeltaTestOptions extends PairedBootstrapOptions {\n /** Smallest candidate-minus-baseline delta that counts as improvement. Default 0. */\n threshold?: number\n /** Caller-required paired observations. The exact test may impose a higher minimum. */\n minPairs?: number\n}\n\nexport interface PairedDeltaTestResult {\n bootstrap: PairedBootstrapResult\n method: 'bootstrap-ci' | 'exact-sign'\n /** Exact one-sided p-value below the bootstrap minimum; otherwise null. */\n pValue: number | null\n /** Effective observation minimum after accounting for confidence. */\n minimumPairs: number\n sufficient: boolean\n /**\n * The bootstrap interval has zero width (or is non-finite), so it carries no\n * information about how far the estimate could be wrong and cannot support a\n * decision in either direction. See {@link pairedDeltaTest}.\n */\n indeterminate: boolean\n significant: boolean\n}\n\n/** Smallest all-positive sample that can clear a one-sided exact sign test. */\nexport function minimumPairsForPairedDeltaTest(confidence = 0.95): number {\n if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {\n throw new Error(\n `minimumPairsForPairedDeltaTest: confidence must be in (0,1), got ${confidence}`,\n )\n }\n const oneSidedAlpha = (1 - confidence) / 2\n return Math.ceil(Math.log2(1 / oneSidedAlpha))\n}\n\n/**\n * Tests whether a paired candidate-minus-baseline delta clears a threshold.\n *\n * At 20 or more pairs, the percentile bootstrap lower bound carries the\n * decision. Below that point the interval is descriptive only, so the function\n * switches to a pre-registered one-sided exact sign test. The exact path is\n * deliberately conservative: it requires both a point estimate above the\n * threshold and enough consistently positive paired differences.\n *\n * ## A zero-width interval is never significant\n *\n * When every paired delta is identical the resample distribution is a point\n * mass and the interval collapses: `[0, 0]` when all pairs tie, `[g, g]` on n\n * identical deltas of g. Neither says the effect is certain — both say the\n * sample carries no information about how far the estimate could be wrong, and\n * `low > threshold` then answers on the point estimate alone. It fails in both\n * directions: `[0, 0]` clears every NEGATIVE threshold, which is how a\n * tie-dominated pass/fail comparison laundered a regression into a\n * noninferiority pass, and `[g, g]` clears every threshold below g with no\n * spread behind it. Under a bounded asymmetric null whose true mean paired\n * delta is exactly 0 — 2 % of pairs dropping by 1.0, the rest gaining 0.0204 —\n * every sample that misses the drop is exactly that shape, and deciding on\n * `low > 0` promoted 65.65 % of samples at n = 20 against a nominal 5 %.\n *\n * So `indeterminate` is reported and `significant` is false whenever the\n * interval has zero width, on BOTH paths: at small n the exact sign test is a\n * test of the MEDIAN and a zero-spread sample is precisely where it stops\n * saying anything about the mean the caller is thresholding.\n *\n * `threshold` may be negative — that is a noninferiority margin, and it is the\n * regime the zero-width hole is worst in. For a two-point (pass/fail) outcome\n * the percentile bootstrap is not a valid interval at a nonzero margin at all;\n * use {@link decidePairedPromotion}, which routes those to Tango's score\n * interval, rather than thresholding this function's bootstrap directly.\n */\nexport function pairedDeltaTest(\n before: number[],\n after: number[],\n options: PairedDeltaTestOptions = {},\n): PairedDeltaTestResult {\n const threshold = options.threshold ?? 0\n if (!Number.isFinite(threshold)) {\n throw new Error(`pairedDeltaTest: threshold must be finite, got ${threshold}`)\n }\n const confidence = options.confidence ?? 0.95\n const exactMinimum = minimumPairsForPairedDeltaTest(confidence)\n const requestedMinimum = options.minPairs ?? exactMinimum\n if (!Number.isInteger(requestedMinimum) || requestedMinimum < 1) {\n throw new Error(`pairedDeltaTest: minPairs must be a positive integer, got ${requestedMinimum}`)\n }\n const minimumPairs = Math.max(requestedMinimum, exactMinimum)\n const bootstrap = pairedBootstrap(before, after, options)\n const sufficient = bootstrap.n >= minimumPairs\n // A point-mass resample distribution is an absence of evidence, not a\n // certainty, and it is the shape that clears every negative threshold. Both\n // paths refuse it: see the \"zero-width\" section of this function's docs.\n const indeterminate =\n bootstrap.n > 0 &&\n (!Number.isFinite(bootstrap.low) ||\n !Number.isFinite(bootstrap.high) ||\n bootstrap.low === bootstrap.high)\n\n if (bootstrap.gateEligible) {\n return {\n bootstrap,\n method: 'bootstrap-ci',\n pValue: null,\n minimumPairs,\n sufficient,\n indeterminate,\n significant: sufficient && !indeterminate && bootstrap.low > threshold,\n }\n }\n\n const differences = before.map((value, index) => after[index]! - value - threshold)\n const exact = pairedSignTest(differences, 'greater')\n const estimate = options.statistic === 'mean' ? bootstrap.mean : bootstrap.median\n return {\n bootstrap,\n method: 'exact-sign',\n pValue: exact.pValue,\n minimumPairs,\n sufficient,\n indeterminate,\n significant:\n sufficient &&\n !indeterminate &&\n estimate > threshold &&\n exact.pValue <= (1 - bootstrap.confidence) / 2,\n }\n}\n","/**\n * @module\n * ONE rule for \"does this paired interval clear a promotion threshold\".\n *\n * The rule below was derived on `HeldOutGate` (#479) after the same estimator\n * bug shipped twice. It then turned out that a SECOND gate — the composable\n * `heldOutGate`, plus everything else routed through `heldoutSignificance` —\n * still carried the original defect, because the rule had been written into one\n * gate's method body rather than into a shared function. Two copies of a\n * statistical rule is how a defect survives in one of them, so there is now\n * exactly one copy and both gates call it.\n *\n * Three things the rule does that a bare `pairedBootstrap(...).low > threshold`\n * does not:\n *\n * 1. **Two-point (pass/fail) outcomes decide on Tango's SCORE interval.** On a\n * pass/fail eval the paired delta vector is dominated by ties, so the\n * bootstrap of the mean is a resample of a lattice with three atoms and its\n * percentile interval is not valid at a nonzero margin. The score interval\n * (`pairedRiskDifferenceScore`) re-estimates the nuisance loss rate under\n * each hypothesised margin instead of fixing it at the observed value, which\n * is the only construction that stays a confidence interval as the margin\n * moves off zero — the regime every noninferiority threshold lives in.\n * Measured on the composable gate before this change, at a true risk\n * difference sitting exactly on the production caller's -0.05 margin and a\n * nominal 5 %: 14.60 % false promotion at n = 40 and 10.10 % at n = 76.\n * 2. **McNemar's exact test holds a VETO at every non-negative threshold.**\n * Redundant with the interval by construction and kept anyway, so that\n * swapping the estimator for one without that duality cannot silently\n * reintroduce \"promotes what the exact test refuses\". Witness: n = 6, b = 5,\n * c = 0 — no exact argument reaches alpha = 0.05 with 5 discordant pairs\n * (two-sided floor 2/2^5 = 0.0625), whatever an interval says. A NEGATIVE\n * threshold is a noninferiority question, which McNemar's test of \"no\n * difference\" is not the right test for, so the veto does not apply there.\n * 3. **A ZERO-WIDTH interval is refused, wherever it sits.** At [0, 0] it\n * cannot tell a gain from a regression and clears every negative threshold.\n * Away from zero it fails the opposite way: n identical positive deltas give\n * [g, g], which clears threshold 0 on no spread at all. Both are an absence\n * of evidence. Measured on the composable gate before this change, under a\n * bounded asymmetric null whose true mean paired delta is exactly 0: 88.50 %\n * false promotion at n = 6 and 65.65 % at n = 20 against a nominal 5 %.\n *\n * Eligibility follows the requested target. A continuous mean needs the\n * bootstrap minimum; binary outcomes and explicit median targets use the\n * exact-test minimum. A small-sample sign diagnostic cannot certify a mean\n * effect. These floors establish estimator eligibility, not adequate power.\n */\n\nimport { minimumPairsForPairedDeltaTest, pairedDeltaTest } from './paired-delta-test'\nimport {\n BOOTSTRAP_GATE_MIN_N,\n type PairedBootstrapResult,\n pairedBinaryScale,\n pairedDeltaTieFraction,\n pairedRiskDifferenceExact,\n pairedRiskDifferenceScore,\n} from './statistics'\n\n/** Which paired estimator produced the deciding interval. */\nexport type PairedDecisionStatistic =\n | 'paired_risk_difference'\n | 'mean_bootstrap'\n | 'median_bootstrap'\n\n/** Which test carried the decision, given the estimator and the sample size. */\nexport type PairedDecisionMethod = 'score-interval' | 'bootstrap-ci' | 'exact-sign'\n\n/** McNemar's exact paired-binary evidence, on the two-point path only. */\nexport interface PairedMcNemarEvidence {\n /** Discordant pairs the treatment won. */\n b: number\n /** Discordant pairs the control won. */\n c: number\n /** b + c — the only pairs carrying information. */\n nDiscordant: number\n /** Two-sided exact p-value. */\n pValue: number\n}\n\nexport interface PairedPromotionDecisionOptions {\n /** Smallest candidate-minus-baseline delta that counts as improvement, in the\n * caller's native units. May be negative (a noninferiority margin). Default 0. */\n threshold?: number\n /** Confidence level. Default 0.95. */\n confidence?: number\n /** Bootstrap resamples, on the paths where a bootstrap decides. Default 2000. */\n resamples?: number\n /** Deterministic bootstrap seed. Omitted ⇒ derived from the deltas. */\n seed?: number\n /** Caller-required paired observations. The test also imposes its own\n * minimum: bootstrap eligibility for a continuous mean, or the exact-test\n * minimum for binary and explicit median targets. This is not a power guarantee. */\n minPairs?: number\n /**\n * `'mean'` (default) routes by SHAPE: a two-point (pass/fail) outcome on any\n * encoding decides on the score interval, everything else on the mean\n * bootstrap. `'median'` forces the median bootstrap on every input, including\n * shapes where it is structurally blind — kept for callers who want outlier\n * robustness on genuinely continuous outcomes and accept that cost.\n */\n statistic?: 'mean' | 'median'\n /** Declared binary support {0, binaryScale}, including when all observations\n * are zero. Must be finite and positive; every observation must use that\n * support. Uses the risk-difference mean, so cannot accompany 'median'.\n * Omitted: infer binary support from observed positive values. */\n binaryScale?: number\n}\n\nexport interface PairedPromotionDecision {\n /** Paired observations supplied. */\n n: number\n /** Threshold the interval was judged against, native units. */\n threshold: number\n confidence: number\n statistic: PairedDecisionStatistic\n method: PairedDecisionMethod\n /** Declared or inferred positive level ({0,1} ⇒ 1, {0,100} ⇒ 100),\n * or null when the outcome is not two-point. Non-null is exactly the\n * condition for the `paired_risk_difference` path, and it is the factor\n * `delta` / `low` / `high` were rescaled by. */\n binaryScale: number | null\n /** Exact-tie fraction over the paired deltas; null when there are no pairs. */\n tieFraction: number | null\n /** Point estimate of the DECIDING statistic, in the caller's native units. */\n delta: number\n /** Lower bound of the DECIDING interval, native units. */\n low: number\n /** Upper bound of the DECIDING interval, native units. */\n high: number\n /** The bootstrap that decided, or null when the score interval did. Callers\n * that need a bootstrap as a diagnostic on the two-point path compute their\n * own — it is not computed here, so the binary path costs no resamples. */\n bootstrap: PairedBootstrapResult | null\n /** McNemar's exact evidence, or null off the two-point path. */\n mcnemar: PairedMcNemarEvidence | null\n /** Exact one-sided sign-test p-value on the small-sample bootstrap path;\n * null otherwise. */\n pValue: number | null\n /** Effective observation minimum for the target, confidence, and caller floor. */\n minimumPairs: number\n /** n >= minimumPairs. */\n sufficient: boolean\n /** The deciding interval is zero-width at numeric precision or non-finite — no evidence in either\n * direction, so it cannot clear any threshold on evidence. */\n indeterminate: boolean\n /** McNemar's exact test refuses at a non-negative threshold. */\n exactTestVetoes: boolean\n /** The deciding interval clears the threshold, ignoring the other two guards. */\n clearsThreshold: boolean\n /** `sufficient && !indeterminate && clearsThreshold && !exactTestVetoes` —\n * the whole rule. */\n promote: boolean\n /** What `delta` measures, for a reason string. */\n label: 'success-rate' | 'mean' | 'median'\n /** Why a zero-width interval is zero-width; empty when it is not. */\n indeterminateCause: string\n /** Sentence naming the test when the exact sign test decided; else empty. */\n methodDetail: string\n}\n\n/** The shape facts that pick the estimator, without computing an interval. */\nexport interface PairedDecisionShape {\n statistic: PairedDecisionStatistic\n /** Declared or inferred positive binary level; null off the binary path. */\n binaryScale: number | null\n /** Exact-tie fraction over the paired deltas; null when there are no pairs. */\n tieFraction: number | null\n}\n\n/**\n * Which estimator {@link decidePairedPromotion} would use on this data, and the\n * shape facts behind it — for callers that must report the shape on a path\n * where no interval is computed at all (an early rejection, or zero pairs).\n * Cheap: no bootstrap, no interval.\n */\nexport function pairedDecisionShape(\n before: number[],\n after: number[],\n statistic: 'mean' | 'median' = 'mean',\n declaredBinaryScale?: number,\n): PairedDecisionShape {\n if (declaredBinaryScale !== undefined) {\n if (!Number.isFinite(declaredBinaryScale) || declaredBinaryScale <= 0) {\n throw new Error('pairedDecisionShape: binaryScale must be finite and positive')\n }\n if (statistic === 'median') {\n throw new Error('pairedDecisionShape: binaryScale requires the mean statistic, not median')\n }\n for (const [name, arm] of [\n ['before', before],\n ['after', after],\n ] as const) {\n for (let i = 0; i < arm.length; i++) {\n const value = arm[i]!\n if (value !== 0 && value !== declaredBinaryScale) {\n throw new Error(\n `pairedDecisionShape: ${name}[${i}] must be 0 or binaryScale (${declaredBinaryScale}); got ${value}`,\n )\n }\n }\n }\n }\n const tieFraction = before.length === 0 ? null : pairedDeltaTieFraction(before, after)\n if (statistic === 'median') {\n return { statistic: 'median_bootstrap', binaryScale: null, tieFraction }\n }\n const binaryScale = declaredBinaryScale ?? pairedBinaryScale(before, after)\n if (binaryScale !== null) {\n return { statistic: 'paired_risk_difference', binaryScale, tieFraction }\n }\n return { statistic: 'mean_bootstrap', binaryScale: null, tieFraction }\n}\n\n/**\n * Decide whether a paired candidate-minus-baseline delta clears a promotion\n * threshold. `before` is the baseline arm, `after` the candidate arm, paired by\n * position. Throws on unequal lengths.\n */\nexport function decidePairedPromotion(\n before: number[],\n after: number[],\n options: PairedPromotionDecisionOptions = {},\n): PairedPromotionDecision {\n if (before.length !== after.length) {\n throw new Error(\n `decidePairedPromotion: unequal sample sizes (${before.length} vs ${after.length})`,\n )\n }\n const threshold = options.threshold ?? 0\n if (!Number.isFinite(threshold)) {\n throw new Error(`decidePairedPromotion: threshold must be finite, got ${threshold}`)\n }\n const confidence = options.confidence ?? 0.95\n const exactMinimum = minimumPairsForPairedDeltaTest(confidence)\n const requestedMinimum = options.minPairs ?? exactMinimum\n if (!Number.isInteger(requestedMinimum) || requestedMinimum < 1) {\n throw new Error(\n `decidePairedPromotion: minPairs must be a positive integer, got ${requestedMinimum}`,\n )\n }\n const { binaryScale, tieFraction } = pairedDecisionShape(\n before,\n after,\n options.statistic,\n options.binaryScale,\n )\n const estimatorMinimum =\n binaryScale === null && options.statistic !== 'median' ? BOOTSTRAP_GATE_MIN_N : exactMinimum\n const minimumPairs = Math.max(requestedMinimum, exactMinimum, estimatorMinimum)\n const n = before.length\n const sufficient = n >= minimumPairs\n\n let core: {\n statistic: PairedDecisionStatistic\n method: PairedDecisionMethod\n delta: number\n low: number\n high: number\n bootstrap: PairedBootstrapResult | null\n mcnemar: PairedMcNemarEvidence | null\n pValue: number | null\n clearsThreshold: boolean\n label: PairedPromotionDecision['label']\n methodDetail: string\n }\n\n if (binaryScale !== null) {\n // Normalise the two-point encoding to {0,1} so the estimators see the\n // pass/fail structure, then rescale the answer back into the caller's\n // native units — the threshold is read in the units of the scores, so a\n // 0-100 pass/fail dimension must be gated in points, not in a rate.\n const unitControl = before.map((v) => v / binaryScale)\n const unitTreatment = after.map((v) => v / binaryScale)\n // TWO estimators with different jobs, because no single one does both.\n // `exact` is the authority on RD = 0 and supplies the veto; its\n // Clopper-Pearson interval conditions on the discordant count and is\n // therefore NOT a confidence interval at a nonzero margin. `score` is\n // Tango's, which is.\n const exact = pairedRiskDifferenceExact(unitControl, unitTreatment, confidence)\n const score = pairedRiskDifferenceScore(unitControl, unitTreatment, confidence)\n const low = score.lower * binaryScale\n core = {\n statistic: 'paired_risk_difference',\n method: 'score-interval',\n delta: score.riskDifference * binaryScale,\n low,\n high: score.upper * binaryScale,\n bootstrap: null,\n mcnemar: {\n b: exact.b,\n c: exact.c,\n nDiscordant: exact.nDiscordant,\n pValue: exact.pValue,\n },\n pValue: null,\n clearsThreshold: low > threshold,\n label: 'success-rate',\n methodDetail: '',\n }\n } else {\n const bootstrapStatistic = options.statistic === 'median' ? 'median' : 'mean'\n const test = pairedDeltaTest(before, after, {\n confidence,\n resamples: options.resamples,\n statistic: bootstrapStatistic,\n seed: options.seed,\n threshold,\n minPairs: minimumPairs,\n })\n const ci = test.bootstrap\n core = {\n statistic: bootstrapStatistic === 'mean' ? 'mean_bootstrap' : 'median_bootstrap',\n method: test.method,\n delta: bootstrapStatistic === 'mean' ? ci.mean : ci.median,\n low: ci.low,\n high: ci.high,\n bootstrap: ci,\n mcnemar: null,\n pValue: test.pValue,\n clearsThreshold: test.significant,\n label: bootstrapStatistic,\n methodDetail:\n test.method === 'exact-sign'\n ? bootstrapStatistic === 'mean'\n ? ` The mean requires ${minimumPairs} pairs for bootstrap eligibility;` +\n ` the exact sign-test p=${fmt(test.pValue ?? 1)} does not establish a mean effect.`\n : ` Below ${BOOTSTRAP_GATE_MIN_N} pairs the interval is descriptive only;` +\n ` the median decision uses the exact one-sided sign test, p=${fmt(test.pValue ?? 1)}.`\n : '',\n }\n }\n\n // Equivalent deltas can differ by rounding after subtraction and averaging.\n // Use the interval's own scale so tiny score units retain the same decision\n // as a rescaled copy of the evidence.\n const intervalScale = Math.max(Math.abs(core.low), Math.abs(core.high))\n const intervalTolerance = intervalScale * Number.EPSILON * 8\n const indeterminate =\n !Number.isFinite(core.low) ||\n !Number.isFinite(core.high) ||\n core.high - core.low <= intervalTolerance\n const indeterminateCause = !indeterminate\n ? ''\n : tieFraction === 1\n ? 'every paired delta is an exact tie'\n : core.mcnemar !== null && core.mcnemar.nDiscordant === 0\n ? 'every pair is concordant (0 discordant pairs)'\n : `the ${core.label} CI collapsed to a point at ${fmt(core.low)}`\n // Only at a non-negative threshold: a negative threshold asks a\n // noninferiority question, which McNemar's test of \"no difference\" does not\n // answer.\n const exactTestVetoes =\n core.mcnemar !== null && threshold >= 0 && !(core.mcnemar.pValue < 1 - confidence)\n\n return {\n n,\n threshold,\n confidence,\n binaryScale,\n tieFraction,\n minimumPairs,\n sufficient,\n indeterminate,\n indeterminateCause,\n exactTestVetoes,\n promote: sufficient && !indeterminate && core.clearsThreshold && !exactTestVetoes,\n ...core,\n }\n}\n\nfunction fmt(x: number): string {\n return x.toFixed(4)\n}\n","import type { AgentProfileCell } from '../agent-profile-cell'\nimport type { CostProvenance } from '../cost-ledger'\nimport type {\n JudgeScoresRecord,\n RunOutcome,\n RunRecord,\n RunSplitTag,\n RunTerminalOutcome,\n} from '../run-record'\nimport { validateRunRecord } from '../run-record'\nimport type { CampaignCellResult, JudgeScore } from './types'\n\nexport interface CampaignCellRunRecordOptions {\n runId: string\n experimentId: string\n candidateId: string\n model: string\n promptHash: string\n configHash: string\n commitSha: string\n splitTag: RunSplitTag\n seed?: number\n scenarioId?: string\n defaultCostUsd?: number\n agentProfile?: AgentProfileCell\n raw?: Record<string, number>\n}\n\nexport interface CampaignCellQualityProjection {\n score?: number\n judgeScores?: JudgeScoresRecord\n successfulJudgeScores: Record<string, JudgeScore>\n failedJudges: string[]\n raw: Record<string, number>\n}\n\n/**\n * A campaign cell carried a judge score without a `dimensions` record.\n *\n * Two exported types share the name `JudgeScore`: the campaign verdict\n * (`{ dimensions, composite, notes }` from `@tangle-network/agent-eval/campaign`)\n * and the root export's flat per-dimension row (`{ judgeName, dimension, score }`\n * from `@tangle-network/agent-eval`). Campaign aggregation accepts only the\n * campaign shape; the flat shape previously crashed here with an opaque\n * TypeError deep inside aggregation.\n */\nexport class CampaignJudgeScoreShapeError extends TypeError {\n constructor(judgeName: string) {\n super(\n `campaign cell judge '${judgeName}' carries a score without a 'dimensions' record. ` +\n `Use the campaign JudgeScore ({ dimensions, composite, notes }) from ` +\n `'@tangle-network/agent-eval/campaign'; the root export's JudgeScore ` +\n `({ judgeName, dimension, score }) is a different type with the same name.`,\n )\n this.name = 'CampaignJudgeScoreShapeError'\n }\n}\n\nexport interface CampaignCellExecutionEvidence {\n terminalOutcome: RunTerminalOutcome\n executionErrorCount?: number\n judgeErrorCount?: number\n unclassifiedErrorCount?: number\n terminalFailureReason?: string\n}\n\n/**\n * Project one campaign cell into the canonical run format.\n *\n * A dispatch error establishes terminal execution failure. A judge error only\n * establishes that quality measurement failed after dispatch completed.\n * Failures without a stage remain unknown. No failure becomes a zero-quality\n * label.\n */\nexport function campaignCellToRunRecord<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n options: CampaignCellRunRecordOptions,\n): RunRecord {\n const quality = projectCampaignCellQuality(cell)\n const execution = campaignCellExecutionEvidence(cell)\n const judgeErrorCount = Math.max(\n quality.raw.judge_error_count ?? 0,\n execution.judgeErrorCount ?? 0,\n )\n const cellCostProvenance = campaignCellCostProvenance(cell)\n const costProvenance: CostProvenance =\n cellCostProvenance.kind === 'uncaptured' && options.defaultCostUsd !== undefined\n ? { kind: 'estimated', usd: options.defaultCostUsd }\n : cellCostProvenance\n const costUsd = costProvenance.kind === 'uncaptured' ? null : costProvenance.usd\n const raw: Record<string, number> = {\n ...finiteMetrics(options.raw),\n ...quality.raw,\n rep: cell.rep,\n duration_ms: cell.durationMs,\n ...(costUsd === null ? {} : { cost_usd: costUsd }),\n // Retain the observed subtotal even when the caller supplies an estimated total.\n ...(cellCostProvenance.kind === 'uncaptured' ? { cost_known_subtotal_usd: cell.costUsd } : {}),\n cost_observed: costProvenance.kind === 'observed' ? 1 : 0,\n cost_estimated: costProvenance.kind === 'estimated' ? 1 : 0,\n cost_uncaptured: costProvenance.kind === 'uncaptured' ? 1 : 0,\n tokens_input: cell.tokenUsage.input,\n tokens_output: cell.tokenUsage.output,\n tokens_known: cell.tokenUsage.tokensKnown === false ? 0 : 1,\n latency_ms: cell.durationMs,\n ...(execution.executionErrorCount === undefined\n ? {}\n : { execution_error_count: execution.executionErrorCount }),\n ...(judgeErrorCount > 0 ? { judge_error_count: judgeErrorCount } : {}),\n ...(execution.unclassifiedErrorCount === undefined\n ? {}\n : { unclassified_error_count: execution.unclassifiedErrorCount }),\n }\n if (typeof cell.generation === 'number') raw.generation = cell.generation\n if (cell.tokenUsage.reasoning !== undefined) {\n raw.tokens_reasoning = cell.tokenUsage.reasoning\n }\n if (cell.tokenUsage.cached !== undefined) raw.tokens_cached = cell.tokenUsage.cached\n if (cell.tokenUsage.cacheWrite !== undefined) {\n raw.tokens_cache_write = cell.tokenUsage.cacheWrite\n }\n if (cell.tokenUsage.tokensKnown !== false && costUsd !== null && costUsd > 0) {\n raw.tokens_per_dollar = (cell.tokenUsage.input + cell.tokenUsage.output) / costUsd\n }\n if (costUsd !== null && quality.score !== undefined && quality.score > 0.01) {\n raw.cost_per_quality = costUsd / quality.score\n }\n\n const outcome: RunOutcome = {\n raw,\n ...(quality.judgeScores ? { judgeScores: quality.judgeScores } : {}),\n }\n if (quality.score !== undefined) {\n if (options.splitTag === 'holdout') outcome.holdoutScore = quality.score\n else outcome.searchScore = quality.score\n }\n\n return validateRunRecord({\n runId: options.runId,\n experimentId: options.experimentId,\n candidateId: options.candidateId,\n seed: options.seed ?? cell.seed,\n model: options.model,\n promptHash: options.promptHash,\n configHash: options.configHash,\n commitSha: options.commitSha,\n wallMs: cell.durationMs,\n costUsd,\n costProvenance,\n tokenUsage: { ...cell.tokenUsage },\n terminalOutcome: execution.terminalOutcome,\n ...(execution.terminalFailureReason\n ? { terminalFailureReason: execution.terminalFailureReason }\n : {}),\n outcome,\n splitTag: options.splitTag,\n scenarioId: options.scenarioId ?? cell.scenarioId,\n ...(options.agentProfile ? { agentProfile: options.agentProfile } : {}),\n })\n}\n\n/**\n * Validate the cost fields that cross campaign cache and RunRecord boundaries.\n * `costUsd` is a known subtotal for uncaptured cells, but it must equal the\n * authoritative total whenever that total is observed or estimated.\n */\nexport function campaignCellCostProvenance<TArtifact>(\n cell: Pick<CampaignCellResult<TArtifact>, 'cellId' | 'costUsd' | 'costProvenance'>,\n): CostProvenance {\n if (!Number.isFinite(cell.costUsd) || cell.costUsd < 0) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costUsd`)\n }\n const provenance = cell.costProvenance\n if (!provenance || typeof provenance !== 'object') {\n throw new Error(`campaign cell '${cell.cellId}' has no costProvenance`)\n }\n if (provenance.kind === 'uncaptured') {\n if (provenance.usd !== null) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid uncaptured costProvenance`)\n }\n return { kind: 'uncaptured', usd: null }\n }\n if (\n (provenance.kind !== 'observed' && provenance.kind !== 'estimated') ||\n !Number.isFinite(provenance.usd) ||\n provenance.usd < 0\n ) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costProvenance`)\n }\n if (provenance.usd !== cell.costUsd) {\n throw new Error(`campaign cell '${cell.cellId}' has costUsd inconsistent with costProvenance`)\n }\n return { kind: provenance.kind, usd: provenance.usd }\n}\n\nexport function campaignCellExecutionEvidence<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellExecutionEvidence {\n if (cell.errorStage === 'dispatch') {\n return {\n terminalOutcome: 'failed',\n executionErrorCount: 1,\n ...(cell.error ? { terminalFailureReason: cell.error } : {}),\n }\n }\n if (cell.errorStage === 'judge') {\n return {\n terminalOutcome: 'succeeded',\n executionErrorCount: 0,\n judgeErrorCount: 1,\n }\n }\n if (!cell.error) {\n return { terminalOutcome: 'succeeded', executionErrorCount: 0 }\n }\n return {\n terminalOutcome: 'unknown',\n unclassifiedErrorCount: 1,\n }\n}\n\n/**\n * Produce the only task-quality view used by campaign aggregates and exports.\n *\n * Successful judge results remain available for diagnosis after another judge\n * fails, but a task score exists only for an error-free cell whose reported\n * judge values are all finite.\n */\nexport function projectCampaignCellQuality<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellQualityProjection {\n if (cell.errorStage === 'dispatch') {\n return { successfulJudgeScores: {}, failedJudges: [], raw: {} }\n }\n\n const perJudge: Record<string, Record<string, number>> = {}\n const successfulJudgeScores: Record<string, JudgeScore> = {}\n const dimensionValues = new Map<string, number[]>()\n const composites: number[] = []\n const notes: string[] = []\n const failedJudges = new Set<string>(\n cell.errorStage === 'judge' ? [cell.errorJudge ?? 'unknown-judge'] : [],\n )\n const raw: Record<string, number> = {}\n\n for (const [judgeName, score] of Object.entries(cell.judgeScores)) {\n const dimensionsShape = (score as { dimensions?: unknown }).dimensions\n if (\n typeof dimensionsShape !== 'object' ||\n dimensionsShape === null ||\n Array.isArray(dimensionsShape)\n ) {\n throw new CampaignJudgeScoreShapeError(judgeName)\n }\n const finiteDimensions = Object.values(score.dimensions).every(Number.isFinite)\n if (score.failed || !Number.isFinite(score.composite) || !finiteDimensions) {\n failedJudges.add(judgeName)\n continue\n }\n\n composites.push(score.composite)\n successfulJudgeScores[judgeName] = score\n const dimensions = { ...score.dimensions }\n perJudge[judgeName] = dimensions\n for (const [dimension, value] of Object.entries(dimensions)) {\n raw[`${judgeName}.${dimension}`] = value\n const values = dimensionValues.get(dimension) ?? []\n values.push(value)\n dimensionValues.set(dimension, values)\n }\n if (score.notes) notes.push(`${judgeName}: ${score.notes}`)\n for (const failedJudge of score.failedJudges ?? []) {\n failedJudges.add(`${judgeName}/${failedJudge}`)\n }\n }\n\n if (failedJudges.size > 0) raw.judge_error_count = failedJudges.size\n const sortedFailedJudges = [...failedJudges].sort()\n if (composites.length === 0) {\n return {\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n raw,\n }\n }\n\n const composite = mean(composites)\n const perDimMean = Object.fromEntries(\n [...dimensionValues.entries()].map(([dimension, values]) => [dimension, mean(values)]),\n )\n const complete =\n cell.error === undefined && cell.errorStage === undefined && failedJudges.size === 0\n if (complete) raw.composite = composite\n\n return {\n ...(complete ? { score: composite } : {}),\n raw,\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n judgeScores: {\n perJudge,\n perDimMean,\n composite,\n ...(sortedFailedJudges.length > 0 ? { failedJudges: sortedFailedJudges } : {}),\n ...(notes.length > 0 ? { notes: notes.join(' | ') } : {}),\n },\n }\n}\n\n/** Read the canonical task score without recomputing cell quality. */\nexport function campaignCellTaskScore<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): number | undefined {\n return projectCampaignCellQuality(cell).score\n}\n\n/** Read canonical successful judge dimensions without recomputing cell quality. */\nexport function campaignCellJudgeDimensions<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): Record<string, Record<string, number>> {\n return projectCampaignCellQuality(cell).judgeScores?.perJudge ?? {}\n}\n\nfunction finiteMetrics(metrics: Record<string, number> | undefined): Record<string, number> {\n const finite: Record<string, number> = {}\n for (const [key, value] of Object.entries(metrics ?? {})) {\n if (Number.isFinite(value)) finite[key] = value\n }\n return finite\n}\n\nfunction mean(values: number[]): number {\n return values.reduce((sum, value) => sum + value, 0) / values.length\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-tool-spans-BZ8MPKFe.js","names":[],"sources":["../src/trace/capture-fetch.ts","../src/trace/otlp-encoding.ts","../src/trace/wire-ids.ts","../src/trace/otel.ts","../src/trace-analyst/prompts.ts","../src/trace-analyst/analyst.ts","../src/trace-analyst/insights.ts","../src/trace/otlp-flat.ts","../src/trace-analyst/store-tool-spans.ts"],"sourcesContent":["/**\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 * The ONE encoding from this package's span values to OTLP wire values.\n *\n * Both exporters emit the same `OtlpSpan` shape, so an attribute typed as a\n * double by one and a string by the other would make the same run read\n * differently depending on which exporter produced it.\n */\n\n/** One OTLP `KeyValue`: the value is tagged with the protocol's type slot. */\nexport interface OtlpAttribute {\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n}\n\n/** OTLP `KeyValue[]` for a flat attribute record. */\nexport function toOtlpAttributes(\n record: Record<string, string | number | boolean>,\n): OtlpAttribute[] {\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\n/** OTLP nanosecond timestamp, as the decimal string the protocol requires. */\nexport function msToUnixNano(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n","/**\n * The ONE mapping from agent-eval's human-readable ids (run ids, span labels)\n * to W3C/OTLP wire ids. Every exporter in this package MUST route through\n * these two functions — two exporters with private paddings once produced\n * DIFFERENT trace ids for the same run, and one emitted invalid hex embedding\n * the raw run id in the wire id (tangle-network/agent-runtime#694).\n *\n * Semantics:\n * - an id that is ALREADY a valid W3C id passes through unchanged, so a\n * trace id received from an inbound `traceparent` survives the round-trip\n * and cross-process correlation is preserved;\n * - anything else is derived with the contract's `deriveHexId`, the only\n * legal derivation — deterministic, so every process that derives from the\n * same human id mints the SAME wire id.\n */\n\nimport { deriveHexId, isW3CSpanId, isW3CTraceId } from '@tangle-network/agent-trace-contract'\n\n/** 32-hex W3C trace id for any id string. */\nexport function traceIdForWire(id: string): string {\n return isW3CTraceId(id) ? id : deriveHexId(id, 16)\n}\n\n/** 16-hex W3C span id for any id string. */\nexport function spanIdForWire(id: string): string {\n return isW3CSpanId(id) ? id : deriveHexId(id, 8)\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 { msToUnixNano, toOtlpAttributes } from './otlp-encoding'\nimport type { Run, Span, TraceEvent } from './schema'\nimport type { TraceStore } from './store'\nimport { spanIdForWire, traceIdForWire } from './wire-ids'\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: toOtlpAttributes({\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: spanIdForWire(span.spanId),\n parentSpanId: span.parentSpanId ? spanIdForWire(span.parentSpanId) : undefined,\n name: span.name,\n kind: 1, // SPAN_KIND_INTERNAL\n startTimeUnixNano: msToUnixNano(span.startedAt),\n endTimeUnixNano: msToUnixNano(endedAt),\n attributes: toOtlpAttributes(flattenSpanAttributes(span)),\n events: events.map((e) => ({\n timeUnixNano: msToUnixNano(e.timestamp),\n name: e.kind,\n attributes: toOtlpAttributes(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 runToTraceId(run: Run): string {\n return traceIdForWire(run.runId)\n}\n","/** General policy for recursive, evidence-backed trace analysis. */\n\nexport const TRACE_ANALYST_ACTOR_DESCRIPTION = `Answer the question by inspecting the OTLP trace dataset with the available tools.\n\n1. Call getDatasetOverview first. Use its real trace ids and dataset size to plan the investigation.\n2. Narrow with queryTraces and countTraces before scanning large payloads.\n3. For a small trace, use viewTrace. For a large trace, use searchTrace and then viewSpans or searchSpan.\n4. Never invent a trace id, span id, tool result, error, frequency, or final outcome.\n5. When a search reports has_more, refine the query before drawing a conclusion.\n6. Use llm_query only over evidence already loaded. A recursive query cannot inspect traces itself.\n7. Cite exact evidence URIs returned by the tools. Include a short exact excerpt when it supports the claim.\n8. Return no finding when the available evidence cannot support one.\n\nThe prose answer must directly answer the question and state important uncertainty.\nThe findings array contains only actionable or decision-relevant claims supported by inspected evidence.`\n\nexport const TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION = 'trace-analyst-research-v1-2026-07-30'\n","import { randomUUID } from 'node:crypto'\nimport type {\n TraceAnalysisEngine,\n TraceAnalysisEngineResult,\n TraceAnalystLimits,\n} from '../analyst/engine'\nimport { runTraceAnalyst } from '../analyst/kind-factory'\nimport type { TraceToolGroupName } from '../analyst/tool-groups'\nimport type { AnalystFinding, AnalystUsageReceipt } from '../analyst/types'\nimport type { CostLedgerHandle } from '../cost-ledger'\nimport { TRACE_ANALYST_ACTOR_DESCRIPTION, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION } from './prompts'\nimport type { TraceAnalysisStore } from './store'\nimport { OtlpFileTraceStore } from './store-otlp'\n\nexport interface AnalyzeTracesInput {\n question: string\n id?: string\n description?: string\n area?: string\n}\n\nexport type AnalyzeTracesResult = TraceAnalysisEngineResult\n\nexport interface AnalyzeTracesOptions {\n /** OTLP JSONL path or a caller-owned store. */\n source: string | TraceAnalysisStore\n /** Recursive research engine. */\n engine: TraceAnalysisEngine\n /** Override the general trace-research policy. */\n instructions?: string\n /** Smallest tool set that can answer the question. Default: all. */\n toolGroup?: TraceToolGroupName\n limits?: Partial<TraceAnalystLimits>\n runId?: string\n budgetUsd?: number\n costLedger?: CostLedgerHandle\n costPhase?: string\n priorFindings?: readonly AnalystFinding[]\n upstreamFindings?: readonly AnalystFinding[]\n recordUsage?: (receipt: AnalystUsageReceipt) => void\n tags?: Record<string, string>\n log?: (message: string, fields?: Record<string, unknown>) => void\n signal?: AbortSignal\n}\n\n/**\n * Answer one question by recursively inspecting a trace store.\n *\n * The returned answer, cited findings, engine steps, call counts, and runtime\n * identity are one audit record. A direct one-shot model call is not used.\n */\nexport async function analyzeTraces(\n input: AnalyzeTracesInput,\n options: AnalyzeTracesOptions,\n): Promise<AnalyzeTracesResult> {\n if (typeof input.question !== 'string' || !input.question.trim()) {\n throw new TypeError('analyzeTraces: input.question must be a non-empty string')\n }\n const id = input.id?.trim() || 'trace-analysis'\n const store =\n typeof options.source === 'string'\n ? new OtlpFileTraceStore({ path: options.source })\n : options.source\n if (store instanceof OtlpFileTraceStore) {\n await store.ensureIndexed(options.signal ? { signal: options.signal } : undefined)\n }\n\n return runTraceAnalyst({\n definition: {\n id,\n description:\n input.description?.trim() ||\n 'Answers a caller-defined question by recursively inspecting trace evidence.',\n area: input.area?.trim() || 'trace-analysis',\n version: TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION,\n question: input.question,\n instructions: options.instructions ?? TRACE_ANALYST_ACTOR_DESCRIPTION,\n toolGroup: options.toolGroup ?? 'all',\n limits: options.limits,\n },\n engine: options.engine,\n store,\n context: {\n runId: options.runId ?? id,\n correlationId: randomUUID(),\n budgetUsd: options.budgetUsd,\n costLedger: options.costLedger,\n costPhase: options.costPhase ?? 'trace-analysis',\n priorFindings: options.priorFindings,\n upstreamFindings: options.upstreamFindings,\n recordUsage: options.recordUsage,\n tags: options.tags,\n log: options.log,\n signal: options.signal,\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","/** Canonical flattened OTLP span shape shared by trace producers and readers. */\n\nimport type { SpanStatus } from './schema'\n\nexport type OtlpStatusCode = 'STATUS_CODE_OK' | 'STATUS_CODE_ERROR' | 'STATUS_CODE_UNSET'\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: OtlpStatusCode\n message?: string\n }\n resource: { attributes: Record<string, unknown> }\n attributes: Record<string, unknown>\n events?: Array<{ name: string; timeUnixNano?: string; attributes?: Record<string, unknown> }>\n}\n\nexport interface CreateOtlpFlatLineInput {\n traceId: string\n spanId: string\n parentSpanId: string | null\n name: string\n kind: string\n startTime: string\n endTime: string\n statusCode: OtlpStatusCode\n statusMessage?: string\n resource: OtlpFlatLine['resource']\n attributes: Record<string, unknown>\n events?: OtlpFlatLine['events']\n}\n\nexport function createOtlpFlatLine(input: CreateOtlpFlatLineInput): OtlpFlatLine {\n return {\n trace_id: input.traceId,\n span_id: input.spanId,\n parent_span_id: input.parentSpanId,\n name: input.name,\n kind: input.kind,\n start_time: input.startTime,\n end_time: input.endTime,\n status: {\n code: input.statusCode,\n ...(input.statusMessage !== undefined ? { message: input.statusMessage } : {}),\n },\n resource: input.resource,\n attributes: input.attributes,\n ...(input.events && input.events.length > 0 ? { events: input.events } : {}),\n }\n}\n\n/** Map the canonical trace status while letting each caller choose its legacy default. */\nexport function spanStatusToOtlp(\n status: SpanStatus | undefined,\n error: string | undefined,\n defaultCode: OtlpStatusCode,\n): OtlpStatusCode {\n if (status === 'error' || error) return 'STATUS_CODE_ERROR'\n if (status === 'ok') return 'STATUS_CODE_OK'\n return defaultCode\n}\n\n/** Convert epoch milliseconds, returning `undefined` for invalid or out-of-range values. */\nexport function epochMillisToIso(value: number): string | undefined {\n if (!Number.isFinite(value)) return undefined\n try {\n return new Date(value).toISOString()\n } catch {\n return undefined\n }\n}\n","import { CaptureIntegrityError } from '../errors'\nimport { applyToolSpanOtlpAttributes, OPENINFERENCE_SPAN_KIND } from '../trace/otlp-attributes'\nimport { createOtlpFlatLine, epochMillisToIso, spanStatusToOtlp } from '../trace/otlp-flat'\nimport type { ToolSpan } from '../trace/schema'\nimport type { TraceAnalysisStore } from './store'\nimport { createOtlpBufferTraceStore, type ToolSpansToTraceAnalysisStoreOptions } from './store-otlp'\n\n/** Missing tool spans cannot distinguish a tool-free run from broken capture. */\nexport class ToolTraceMissingError extends CaptureIntegrityError {\n constructor() {\n super('toolSpansToTraceAnalysisStore: no tool spans supplied; trace evidence is missing')\n }\n}\n\n/**\n * Snapshot canonical tool spans into the read interface used by trace analysts.\n * One run becomes one trace while arguments, results, errors, and timing remain searchable.\n */\nexport function toolSpansToTraceAnalysisStore(\n spans: readonly ToolSpan[] | null | undefined,\n options: ToolSpansToTraceAnalysisStoreOptions = {},\n): TraceAnalysisStore {\n if (!spans || spans.length === 0) throw new ToolTraceMissingError()\n\n const seen = new Set<string>()\n const lines = spans.map((span, index) => {\n assertToolSpanIdentity(span, index)\n const identity = `${span.runId}\\u0000${span.spanId}`\n if (seen.has(identity)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: duplicate span '${span.spanId}' in run '${span.runId}'`,\n )\n }\n seen.add(identity)\n\n const attributes = { ...(span.attributes ?? {}) }\n applyToolSpanOtlpAttributes(attributes, span)\n attributes[OPENINFERENCE_SPAN_KIND] = 'TOOL'\n\n const endedAt = span.endedAt ?? span.startedAt + (span.latencyMs ?? 0)\n const line = createOtlpFlatLine({\n traceId: span.runId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId ?? null,\n name: span.name,\n kind: 'SPAN_KIND_INTERNAL',\n startTime: toolSpanTimeIso(span.startedAt, span.spanId, 'startedAt'),\n endTime: toolSpanTimeIso(endedAt, span.spanId, 'endedAt'),\n statusCode: spanStatusToOtlp(span.status, span.error, 'STATUS_CODE_UNSET'),\n statusMessage: span.error,\n resource: { attributes: {} },\n attributes,\n })\n try {\n return JSON.stringify(line)\n } catch (cause) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' in run '${span.runId}' is not JSON-serializable`,\n { cause },\n )\n }\n })\n\n return createOtlpBufferTraceStore(Buffer.from(`${lines.join('\\n')}\\n`, 'utf8'), options)\n}\n\nfunction assertToolSpanIdentity(span: ToolSpan, index: number): void {\n if (span.kind !== 'tool') {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span at index ${index} has kind '${String(span.kind)}', not 'tool'`,\n )\n }\n if (!span.runId || !span.spanId || !span.name || !span.toolName) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span at index ${index} is missing runId, spanId, name, or toolName`,\n )\n }\n if (!Number.isFinite(span.startedAt)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid startedAt`,\n )\n }\n if (span.endedAt !== undefined && !Number.isFinite(span.endedAt)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid endedAt`,\n )\n }\n if (span.endedAt !== undefined && span.endedAt < span.startedAt) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' ends before it starts`,\n )\n }\n if (span.latencyMs !== undefined && (!Number.isFinite(span.latencyMs) || span.latencyMs < 0)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid latencyMs`,\n )\n }\n}\n\nfunction toolSpanTimeIso(value: number, spanId: string, field: string): string {\n const iso = epochMillisToIso(value)\n if (iso) return iso\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${spanId}' has invalid ${field}`,\n )\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"store-tool-spans-Dt-YdAuE.d.ts","names":[],"sources":["../src/trace-analyst/store-boundary.ts","../src/trace/extract-usage.ts","../src/trace/capture-fetch.ts","../src/trace/otel.ts","../src/trace/otlp-flat.ts","../src/trace/redact.ts","../src/trace-analyst/analyst.ts","../src/trace-analyst/insights.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/store-tool-spans.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-groups-B2bSNaJB.d.ts","names":[],"sources":["../src/analyst/tool-groups.ts"],"mappings":";;;;KAmBY;;;;;;;;;;;;;;;;;;;;iBAyDI,wBACd,OAAO,oBACP,OAAO,qBACN"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-DQ0e2E7y.js","names":[],"sources":["../src/ledger-core/deep-freeze.ts","../src/analyst/usage-receipt.ts","../src/analyst/types.ts"],"sourcesContent":["/** Freeze a detached canonical-JSON graph. Canonicalization has already ruled out cycles.\n *\n * Lives outside canonical.ts so the analyst-benchmark implementation digest,\n * which covers canonical.ts, stays bound to the published benchmark evidence. */\nexport function deepFreezeCanonicalJson<T>(value: T): T {\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n Object.freeze(value)\n for (const nested of Object.values(value)) deepFreezeCanonicalJson(nested)\n }\n return value\n}\n","import type { CostChannel, CostLedgerFilter, CostLedgerHandle } from '../cost-ledger'\nimport type { AnalystUsageReceipt } from './types'\n\nexport const DEFAULT_USAGE_SETTLEMENT_TIMEOUT_MS = 5_000\n\n/** Convert one ledger channel's complete call set into one analyst receipt. */\nexport function usageReceiptFromCostLedger(\n ledger: CostLedgerHandle,\n filter: CostChannel | CostLedgerFilter = 'analyst',\n): AnalystUsageReceipt {\n const resolvedFilter = typeof filter === 'string' ? { channel: filter } : filter\n const summary = ledger.summary(resolvedFilter)\n const receipts = ledger.list(resolvedFilter)\n const hasReasoningUsage = receipts.some((receipt) => receipt.reasoningTokens !== undefined)\n const hasCacheWriteUsage = receipts.some((receipt) => receipt.cacheWriteTokens !== undefined)\n const cost = summary.costProvenance\n return {\n calls: summary.totalCalls + summary.pendingCalls,\n tokens: summary.usageComplete\n ? {\n input: summary.inputTokens,\n output: summary.outputTokens,\n ...(hasReasoningUsage ? { reasoning: summary.reasoningTokens ?? 0 } : {}),\n ...(summary.cachedTokens > 0 ? { cached: summary.cachedTokens } : {}),\n ...(hasCacheWriteUsage ? { cacheWrite: summary.cacheWriteTokens ?? 0 } : {}),\n }\n : null,\n cost,\n ...(cost.kind === 'uncaptured' ? { knownCostUsd: summary.totalCostUsd } : {}),\n }\n}\n\nexport interface SettledUsageReceipt {\n settled: boolean\n pendingCalls: number\n receipt: AnalystUsageReceipt\n}\n\n/** Wait a bounded time for late provider receipts, then take one immutable snapshot. */\nexport async function settleUsageReceiptFromCostLedger(\n ledger: CostLedgerHandle,\n options: CostLedgerFilter & { timeoutMs?: number } = {},\n): Promise<SettledUsageReceipt> {\n const { timeoutMs: requestedTimeoutMs, ...requestedFilter } = options\n const filter: CostLedgerFilter = {\n channel: requestedFilter.channel ?? 'analyst',\n ...(requestedFilter.phase === undefined ? {} : { phase: requestedFilter.phase }),\n ...(requestedFilter.tags === undefined ? {} : { tags: requestedFilter.tags }),\n }\n const timeoutMs = validateUsageSettlementTimeout(requestedTimeoutMs)\n const initial = ledger.summary(filter)\n const waitResult =\n initial.pendingCalls === 0\n ? true\n : ledger.waitForIdle\n ? await ledger.waitForIdle({ timeoutMs })\n : false\n const pendingCalls = ledger.summary(filter).pendingCalls\n return {\n settled: waitResult && pendingCalls === 0,\n pendingCalls,\n receipt: usageReceiptFromCostLedger(ledger, filter),\n }\n}\n\nexport function validateUsageSettlementTimeout(timeoutMs?: number): number {\n const resolved = timeoutMs ?? DEFAULT_USAGE_SETTLEMENT_TIMEOUT_MS\n if (!Number.isSafeInteger(resolved) || resolved < 0 || resolved > 2_147_483_647) {\n throw new TypeError(\n 'settlementTimeoutMs must be a non-negative safe integer no greater than 2147483647',\n )\n }\n return resolved\n}\n\nexport function assertValidAnalystUsageReceipt(\n receipt: AnalystUsageReceipt,\n context = 'AnalystContext.recordUsage',\n): void {\n if (receipt.calls !== null && (!Number.isSafeInteger(receipt.calls) || receipt.calls < 0)) {\n throw new Error(`${context}: calls must be a non-negative safe integer or null`)\n }\n if (receipt.tokens) {\n assertNonNegativeSafeInteger(receipt.tokens.input, 'tokens.input', context)\n assertNonNegativeSafeInteger(receipt.tokens.output, 'tokens.output', context)\n if (receipt.tokens.reasoning !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.reasoning, 'tokens.reasoning', context)\n if (receipt.tokens.reasoning > receipt.tokens.output) {\n throw new Error(`${context}: tokens.reasoning must not exceed tokens.output`)\n }\n }\n if (receipt.tokens.cached !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.cached, 'tokens.cached', context)\n }\n if (receipt.tokens.cacheWrite !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.cacheWrite, 'tokens.cacheWrite', context)\n }\n }\n if (receipt.cost.kind !== 'uncaptured') {\n assertNonNegativeFinite(receipt.cost.usd, 'cost.usd', context)\n } else if (receipt.cost.usd !== null) {\n throw new Error(`${context}: uncaptured cost.usd must be null`)\n }\n if (receipt.knownCostUsd !== undefined) {\n assertNonNegativeFinite(receipt.knownCostUsd, 'knownCostUsd', context)\n }\n if (receipt.partialTokens) {\n const { input, output } = receipt.partialTokens\n if (receipt.tokens) {\n throw new Error(`${context}: partialTokens must be absent when tokens is complete`)\n }\n if (input === null && output === null) {\n throw new Error(`${context}: partialTokens must carry at least one reported side`)\n }\n if (input !== null) assertNonNegativeSafeInteger(input, 'partialTokens.input', context)\n if (output !== null) assertNonNegativeSafeInteger(output, 'partialTokens.output', context)\n }\n}\n\nfunction assertNonNegativeSafeInteger(value: number, field: string, context: string): void {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(`${context}: ${field} must be a non-negative safe integer`)\n }\n}\n\nfunction assertNonNegativeFinite(value: number, field: string, context: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`${context}: ${field} must be a non-negative finite number`)\n }\n}\n","/**\n * Analyst contract — the missing orchestration layer over agent-eval's\n * existing analyzers (analyzeTraces, MultiLayerVerifier,\n * SemanticConceptJudge, JudgeFn, ...).\n *\n * Each existing primitive returns its own output shape. The Analyst\n * contract is the single envelope every primitive lifts into, so a\n * registry can run N analysts against a run and a single renderer can\n * compose findings without knowing which analyzer produced them.\n *\n * The contract is intentionally domain-agnostic: nothing here knows\n * about code, voice, RAG, or any particular agent stack. Analysts\n * declare what INPUT KIND they need (a trace store, an artifact dir,\n * a RunRecord, a JudgeInput, or `custom`), and the registry routes\n * the matching input from `AnalystRunInputs`.\n */\n\nimport { createHash } from 'node:crypto'\nimport type { CostLedgerHandle } from '../cost-ledger'\nimport type { RunCostProvenance, RunRecord, RunTokenUsage } from '../run-record'\nimport type { TraceAnalysisStore } from '../trace-analyst/store'\nimport type { JudgeInput } from '../types'\nimport type { ChatClient } from './chat-client'\n\n/**\n * Unified envelope every analyst emits. Schema-versioned so renderers\n * and time-series diffs survive future field additions.\n */\nexport interface AnalystFinding {\n schema_version: '1.0.0'\n /**\n * Stable hash over identity-defining fields (analyst_id + canonical\n * claim + area + optional subject). Two findings from two runs that\n * \"are the same finding\" share this id — that's what `diffFindings`\n * uses to compute appeared/disappeared sets across runs.\n */\n finding_id: string\n analyst_id: string\n produced_at: string\n severity: AnalystSeverity\n /**\n * Coarse classification. Renderers group by this. Free-form so\n * domain-specific analysts can introduce categories without a\n * schema change ('agent-reasoning', 'verification', 'cost',\n * 'tool-use', 'safety', 'latency', 'data-quality', ...).\n */\n area: string\n claim: string\n rationale?: string\n evidence_refs: EvidenceRef[]\n recommended_action?: string\n validation_plan?: string\n /** 0..1 — the analyst's own confidence. Not calibrated across analysts. */\n confidence: number\n /**\n * Optional subject the finding is about — leaf id, agent id, request\n * id. Included in finding_id when present so per-subject findings\n * diff cleanly across runs.\n */\n subject?: string\n /** True when this finding was lifted from a judge result rather than observed\n * directly in a trace or artifact. Descriptive only: proposal access is\n * controlled by `ProposalFinding.proposal_origin`. */\n derived_from_judge?: boolean\n /** Analyst-private extras; renderers ignore unless they know the analyst. */\n metadata?: Record<string, unknown>\n}\n\n/** Finding severity. `AnalystSeverity` derives from this array, so the type\n * and the schema that validates a finding cannot name different levels. */\nexport const ANALYST_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'] as const\n\nexport type AnalystSeverity = (typeof ANALYST_SEVERITIES)[number]\n\n/** Data sources that candidate generation may intentionally learn from. */\nexport type ProposalFindingOrigin = 'search' | 'production'\n\n/** A finding explicitly admitted as candidate-generation input. */\nexport type ProposalFinding = AnalystFinding & {\n readonly proposal_origin: ProposalFindingOrigin\n}\n\nexport interface EvidenceRef {\n /**\n * Where the evidence lives. `span` and `event` refer to OTLP trace\n * elements; `artifact` to a file inside the run's artifact tree;\n * `finding` to another AnalystFinding (cross-analyst chaining);\n * `metric` to a named scalar reading the renderer knows how to read.\n */\n kind: 'span' | 'event' | 'artifact' | 'finding' | 'metric'\n uri: string\n excerpt?: string\n}\n\n// ── Analyst contract ─────────────────────────────────────────────────\n\n/**\n * The discriminator the registry uses to pass the right input.\n * `custom` is the escape hatch — analysts that need something else\n * (e.g. an embedding cache, a partner SDK handle) read it from\n * `AnalystRunInputs.custom[<analyst id>]`.\n */\nexport type AnalystInputKind =\n | 'trace-store'\n | 'artifact-dir'\n | 'run-record'\n | 'judge-input'\n | 'custom'\n\nexport interface AnalystCost {\n /** `deterministic` analysts MUST NOT call the LLM. */\n kind: 'deterministic' | 'llm'\n /** Optional declared upper bound; the registry can enforce a budget. */\n est_usd_per_run?: number\n /** Models the analyst expects to use (informational). */\n models?: string[]\n /** Maximum post-cancellation wait for provider usage. Model analysts default to 5 seconds. */\n settlement_timeout_ms?: number\n}\n\nexport interface AnalystRequirements {\n /** Min number of shots / samples the analyst needs to produce signal. */\n min_shots?: number\n /** Capabilities the runtime must supply (e.g. ['network', 'gpu']). */\n capabilities?: string[]\n}\n\n/**\n * What's passed to every analyst call. The registry resolves which\n * field the analyst's `inputKind` selects and asserts it's present.\n */\nexport interface AnalystRunInputs {\n traceStore?: TraceAnalysisStore\n artifactDir?: string\n runRecord?: RunRecord\n judgeInput?: JudgeInput\n /** Keyed by analyst id; populated by callers that registered custom analysts. */\n custom?: Record<string, unknown>\n}\n\nexport interface AnalystContext {\n runId: string\n /** Stable correlation id so logs from a single registry.run() share a tag. */\n correlationId: string\n /** Enforced wall-clock deadline (epoch ms). */\n deadlineMs?: number\n /** Per-analyst USD budget. Analysts MAY check before issuing LLM calls. */\n budgetUsd?: number\n /** Shared paid-call account when the analyst runs inside a larger campaign. */\n costLedger?: CostLedgerHandle\n /** Attribution phase used when writing to the shared paid-call account. */\n costPhase?: string\n /**\n * Shared chat client. Analysts that call an LLM go through this so\n * the operator picks transport (sandbox-sdk | router | cli-bridge |\n * direct-provider | mock) at the registry boundary without touching\n * analyst code.\n */\n chat?: ChatClient\n /**\n * Findings from a prior run the operator wants the analyst to see as\n * retrieval context. Kinds that take advantage of cross-run memory\n * (failure-mode \"I saw this cluster last run\", knowledge-gap \"the wiki\n * page I asked for is still missing\") render these into the actor's\n * working set. Filtering is the operator's job: pass the slice that\n * matches the analyst's id, or pass everything and let the kind\n * filter. Empty / absent means no cross-run context.\n */\n priorFindings?: ReadonlyArray<AnalystFinding>\n /**\n * Findings emitted by analysts that completed earlier in this registry run.\n * This is separate from `priorFindings`: upstream findings are dependency\n * context for the current pass, while prior findings are cross-run memory.\n * The registry populates this only when `RegistryRunOpts.chainFindings` is on.\n */\n upstreamFindings?: ReadonlyArray<AnalystFinding>\n /**\n * Report metered work independently of findings. This keeps an empty finding\n * set from erasing token/cost telemetry. Multiple receipts are accumulated.\n */\n recordUsage?: (receipt: AnalystUsageReceipt) => void\n /** Free-form runtime tags (env, host, op). Findings can echo these into metadata. */\n tags?: Record<string, string>\n /** Logger callback — analysts SHOULD prefer this over console.* for testability. */\n log?: (msg: string, fields?: Record<string, unknown>) => void\n /** Optional abort signal. Analysts SHOULD pass it through to LLM calls. */\n signal?: AbortSignal\n /**\n * Optional live-execution port. A runtime that owns a sandbox or checkout\n * fills it so an analyst can execute a bounded probe against the run's\n * produced state instead of reasoning about it from the trace alone. This\n * package defines only the port: no field here reaches for an agent loop,\n * and an absent probe means the analyst works from recorded evidence.\n */\n probe?: ExecutionProbe\n}\n\n// ── Live-execution port ─────────────────────────────────────────────\n\n/** One bounded command an analyst asks the probe to run. */\nexport interface ExecutionProbeRequest {\n command: string\n /** Working directory inside the probed environment. */\n cwd?: string\n /** Hard wall-clock deadline for this one execution. */\n timeoutMs: number\n /** Bytes of combined output retained; the prober truncates beyond it. */\n maxOutputBytes?: number\n signal?: AbortSignal\n}\n\n/**\n * Typed outcome of one probe execution. `succeeded: false` is a PROBE failure\n * (the environment could not run the command); a command that ran and exited\n * non-zero is a successful observation with a non-zero `exitCode`.\n */\nexport type ExecutionProbeOutcome =\n | {\n succeeded: true\n exitCode: number\n stdout: string\n stderr: string\n durationMs: number\n /** True when output was cut at `maxOutputBytes`. */\n truncated: boolean\n }\n | { succeeded: false; error: { class: string; message: string } }\n\n/**\n * The seam a runtime fills to let analysts observe produced state live.\n * Implementations own sandboxing, credentials, and cleanup; analysts only\n * submit bounded requests and read typed outcomes.\n */\nexport interface ExecutionProbe {\n /** One plain sentence naming what is being probed (e.g. a sandbox id). */\n readonly description: string\n execute(request: ExecutionProbeRequest): Promise<ExecutionProbeOutcome>\n}\n\n/**\n * The minimal contract. Concrete analysts can refine `TInput` so\n * implementations stay type-safe (e.g. a trace analyst's `TInput` is\n * `TraceAnalysisStore`); the registry passes the right field from\n * `AnalystRunInputs` based on `inputKind`.\n */\nexport interface Analyst<TInput = unknown> {\n /** Stable identifier — appears in finding_id, telemetry, and registry exclusion lists. */\n readonly id: string\n /** Human-readable. One sentence. */\n readonly description: string\n readonly inputKind: AnalystInputKind\n readonly cost: AnalystCost\n readonly requires?: AnalystRequirements\n /** Bump on breaking changes to claim wording or area so old finding_ids don't collide. */\n readonly version: string\n analyze(input: TInput, ctx: AnalystContext): Promise<AnalystFinding[]>\n}\n\n/** Metered work performed by one analyst call. */\nexport interface AnalystUsageReceipt {\n /** Number of model-usage records observed at the provider boundary. */\n calls: number | null\n /** Null when the provider did not return token accounting. */\n tokens: RunTokenUsage | null\n /** Observed, estimated, or explicitly uncaptured dollar cost. */\n cost: RunCostProvenance\n /** Known lower bound when one or more calls have uncaptured cost. */\n knownCostUsd?: number\n /**\n * Token counts the provider reported on only one side. Present exactly when\n * `tokens` is null and at least one side WAS reported: `RunTokenUsage` has no\n * nullable side, so a one-sided count cannot live in `tokens` without writing\n * a zero nobody measured. Read it as a lower bound, never as a total — the\n * field exists so a null `tokens` cannot hide a real count.\n */\n partialTokens?: { input: number | null; output: number | null }\n /**\n * True when the token counts were DERIVED by the transport (from character\n * lengths, say) rather than measured by the model provider. `cost.kind` is\n * `estimated` both for a rate estimate over exact tokens and for one over\n * derived tokens; this is the field that separates them.\n */\n tokensEstimated?: boolean\n}\n\n// ── finding_id stability ─────────────────────────────────────────────\n\n/**\n * Compute the stable finding_id from the identity-defining fields.\n * Default implementation hashes {analyst_id, area, subject, normalized claim}.\n * Analysts that emit findings whose claim text varies per run (timestamps,\n * counts) SHOULD either: (a) pass an explicit `id_basis` to fix the hash,\n * or (b) move the variable part into `rationale`/`metadata` and keep the\n * `claim` static.\n */\nexport function computeFindingId(input: {\n analyst_id: string\n area: string\n subject?: string\n claim: string\n /** Override the claim for hashing — use when the displayed claim has run-specific bits. */\n id_basis?: string\n}): string {\n const basis = JSON.stringify({\n a: input.analyst_id,\n r: input.area,\n s: input.subject ?? '',\n c: normalizeClaim(input.id_basis ?? input.claim),\n })\n return `f_${createHash('sha256').update(basis).digest('hex').slice(0, 20)}`\n}\n\nfunction normalizeClaim(c: string): string {\n // Lowercase, collapse whitespace, strip trailing punctuation. Goal:\n // \"Leaf X failed install\" and \"Leaf X failed install.\" hash the same.\n return c\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .replace(/[.!?;:,]+$/g, '')\n .trim()\n}\n\n/**\n * Convenience factory: produce a fully-formed AnalystFinding with the\n * id computed automatically. Analyst code stays terse.\n */\nexport function makeFinding(\n init: Omit<AnalystFinding, 'schema_version' | 'finding_id' | 'produced_at'> & {\n id_basis?: string\n produced_at?: string\n },\n): AnalystFinding {\n const { id_basis, produced_at, ...rest } = init\n return {\n schema_version: '1.0.0',\n finding_id: computeFindingId({\n analyst_id: rest.analyst_id,\n area: rest.area,\n subject: rest.subject,\n claim: rest.claim,\n id_basis,\n }),\n produced_at: produced_at ?? new Date().toISOString(),\n ...rest,\n }\n}\n\n/** Build a finding whose source is explicitly allowed during candidate generation. */\nexport function makeProposalFinding(\n init: Omit<ProposalFinding, 'schema_version' | 'finding_id' | 'produced_at'> & {\n id_basis?: string\n produced_at?: string\n },\n): ProposalFinding {\n const { proposal_origin, ...finding } = init\n return { ...makeFinding(finding), proposal_origin }\n}\n\n// ── Registry result envelope ────────────────────────────────────────\n\nexport interface AnalystRunSummary {\n analyst_id: string\n status: 'ok' | 'skipped' | 'failed'\n /** Why skipped — missing input, budget exceeded, capability unmet. */\n reason?: string\n findings_count: number\n latency_ms: number\n /** Additive model usage and cost provenance for this analyst. */\n usage: AnalystUsageReceipt\n /** When `status='failed'`: the error class + message, never the full stack. */\n error?: { class: string; message: string }\n}\n\nexport interface AnalystRunResult {\n run_id: string\n correlation_id: string\n started_at: string\n ended_at: string\n findings: AnalystFinding[]\n per_analyst: AnalystRunSummary[]\n /** Total LLM cost in USD across all analysts in this registry.run(). */\n total_cost_usd: number\n /**\n * Provenance for `total_cost_usd`. When uncaptured, the numeric field is only\n * the known subtotal and must not be treated as the run's total spend.\n */\n total_cost_provenance?: RunCostProvenance\n}\n\n// ── Streaming event envelope ────────────────────────────────────────\n\n/**\n * Events emitted by `AnalystRegistry.runStream(...)` in real time as\n * the registry executes. UIs subscribe via `for await (const ev of\n * registry.runStream(...))`; `registry.run(...)` is a thin collector\n * over the same stream, so the two surfaces share their invariants.\n *\n * Per-finding events are intentionally omitted — analyzers are batch\n * operations (a recursive engine returns the full `findings:json[]` at the\n * end of the responder), so streaming inside one analyst would only\n * emit partial JSON consumers can't render. The kind-completion event\n * is the right granularity; subscribers wanting per-finding rendering\n * iterate `event.findings` themselves.\n */\nexport type AnalystRunEvent =\n | {\n type: 'run-started'\n run_id: string\n correlation_id: string\n started_at: string\n /** The ordered list of analyst ids the registry will run. */\n analyst_ids: ReadonlyArray<string>\n }\n | {\n type: 'analyst-skipped'\n summary: AnalystRunSummary\n }\n | {\n type: 'analyst-started'\n analyst_id: string\n started_at: string\n }\n | {\n type: 'analyst-completed'\n /** `summary.status` is `'ok'` for clean completion or `'failed'` for thrown analysts. */\n summary: AnalystRunSummary\n findings: ReadonlyArray<AnalystFinding>\n }\n | {\n type: 'run-completed'\n result: AnalystRunResult\n }\n"],"mappings":"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"}