@tangle-network/agent-eval 0.187.2 → 0.188.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 (219) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/adapters/http.d.ts +2 -2
  3. package/dist/{agent-profile-uAIQK3Nr.d.ts → agent-profile-CfbuZk8b.d.ts} +4 -4
  4. package/dist/{agent-profile-uAIQK3Nr.d.ts.map → agent-profile-CfbuZk8b.d.ts.map} +1 -1
  5. package/dist/analyst/index.d.ts +12 -12
  6. package/dist/analyst/index.d.ts.map +1 -1
  7. package/dist/analyst/index.js +6 -6
  8. package/dist/{analyze-runs-DapYZz02.d.ts → analyze-runs-CLz5O01x.d.ts} +5 -5
  9. package/dist/{analyze-runs-DapYZz02.d.ts.map → analyze-runs-CLz5O01x.d.ts.map} +1 -1
  10. package/dist/{benchmark-command-DGokT8zd.js → benchmark-command-CdUGku3W.js} +12 -12
  11. package/dist/benchmark-command-CdUGku3W.js.map +1 -0
  12. package/dist/benchmarks/index.d.ts +4 -4
  13. package/dist/benchmarks/index.js +3 -3
  14. package/dist/builder-eval/index.d.ts +3 -3
  15. package/dist/builder-eval/index.js +1 -1
  16. package/dist/campaign/index.d.ts +5 -5
  17. package/dist/campaign/index.js +5 -5
  18. package/dist/{campaign-DlxdTOvw.js → campaign-DZuysBbS.js} +6 -6
  19. package/dist/{campaign-DlxdTOvw.js.map → campaign-DZuysBbS.js.map} +1 -1
  20. package/dist/{chat-client-DqPqWzVV.js → chat-client-C4dg7Ng_.js} +2 -2
  21. package/dist/{chat-client-DqPqWzVV.js.map → chat-client-C4dg7Ng_.js.map} +1 -1
  22. package/dist/{chat-json-call-C-DnDxEy.js → chat-json-call-JVGbfx95.js} +2 -2
  23. package/dist/{chat-json-call-C-DnDxEy.js.map → chat-json-call-JVGbfx95.js.map} +1 -1
  24. package/dist/cli.js +4 -4
  25. package/dist/{client-DCc7a8ZC.d.ts → client-CFj9dfcn.d.ts} +4 -4
  26. package/dist/{client-DCc7a8ZC.d.ts.map → client-CFj9dfcn.d.ts.map} +1 -1
  27. package/dist/contract/index.d.ts +11 -11
  28. package/dist/contract/index.js +6 -6
  29. package/dist/{counterfactual-CLgrwhkY.d.ts → counterfactual-CPaWN99-.d.ts} +4 -4
  30. package/dist/{counterfactual-CLgrwhkY.d.ts.map → counterfactual-CPaWN99-.d.ts.map} +1 -1
  31. package/dist/{counterfactual-Bjq1mlUu.js → counterfactual-DtMWvn7D.js} +2 -2
  32. package/dist/{counterfactual-Bjq1mlUu.js.map → counterfactual-DtMWvn7D.js.map} +1 -1
  33. package/dist/{default-registry-DMxeb4GD.d.ts → default-registry-BLsGfnoO.d.ts} +6 -6
  34. package/dist/{default-registry-DMxeb4GD.d.ts.map → default-registry-BLsGfnoO.d.ts.map} +1 -1
  35. package/dist/{default-registry-Ca2IWH1X.js → default-registry-BtZ_t-9b.js} +2 -2
  36. package/dist/{default-registry-Ca2IWH1X.js.map → default-registry-BtZ_t-9b.js.map} +1 -1
  37. package/dist/{define-agent-eval-C0EqJ9Gz.js → define-agent-eval-ChtddasD.js} +3 -3
  38. package/dist/{define-agent-eval-C0EqJ9Gz.js.map → define-agent-eval-ChtddasD.js.map} +1 -1
  39. package/dist/{define-agent-eval-CGBwPPaq.d.ts → define-agent-eval-CsicmDxt.d.ts} +7 -7
  40. package/dist/{define-agent-eval-CGBwPPaq.d.ts.map → define-agent-eval-CsicmDxt.d.ts.map} +1 -1
  41. package/dist/diagnosis/index.d.ts +38 -96
  42. package/dist/diagnosis/index.d.ts.map +1 -1
  43. package/dist/diagnosis/index.js +83 -134
  44. package/dist/diagnosis/index.js.map +1 -1
  45. package/dist/{dspy-rlm-engine-BE9lCzzL.js → dspy-rlm-engine-sPX7B5ac.js} +3 -3
  46. package/dist/{dspy-rlm-engine-BE9lCzzL.js.map → dspy-rlm-engine-sPX7B5ac.js.map} +1 -1
  47. package/dist/emitter-DbMXUIVP.js +334 -0
  48. package/dist/emitter-DbMXUIVP.js.map +1 -0
  49. package/dist/{emitter-Cs0egaFd.d.ts → emitter-HcCmFQl_.d.ts} +37 -6
  50. package/dist/emitter-HcCmFQl_.d.ts.map +1 -0
  51. package/dist/{engine-DNlKhIm0.d.ts → engine-Gw2n1irt.d.ts} +15 -5
  52. package/dist/engine-Gw2n1irt.d.ts.map +1 -0
  53. package/dist/{eval-campaign-XFHEpN86.js → eval-campaign-CeotQ1ZR.js} +7 -4
  54. package/dist/{eval-campaign-XFHEpN86.js.map → eval-campaign-CeotQ1ZR.js.map} +1 -1
  55. package/dist/evaluation.d.ts +2 -2
  56. package/dist/{exact-types-BEHN7tnq.d.ts → exact-types-CrhPoDp8.d.ts} +2 -2
  57. package/dist/{exact-types-BEHN7tnq.d.ts.map → exact-types-CrhPoDp8.d.ts.map} +1 -1
  58. package/dist/experiment/index.d.ts +3 -3
  59. package/dist/experiment/index.js +1 -2
  60. package/dist/experiment/index.js.map +1 -1
  61. package/dist/{external-optimizer-process-BbhvXTFx.js → external-optimizer-process-D3BLpZyR.js} +2 -2
  62. package/dist/{external-optimizer-process-BbhvXTFx.js.map → external-optimizer-process-D3BLpZyR.js.map} +1 -1
  63. package/dist/{external-optimizer-subprocess-DMgmqTB6.js → external-optimizer-subprocess-BrfsgL92.js} +2 -2
  64. package/dist/{external-optimizer-subprocess-DMgmqTB6.js.map → external-optimizer-subprocess-BrfsgL92.js.map} +1 -1
  65. package/dist/{failure-cluster-OldNRoAt.d.ts → failure-cluster-CbgEDcFJ.d.ts} +3 -3
  66. package/dist/{failure-cluster-OldNRoAt.d.ts.map → failure-cluster-CbgEDcFJ.d.ts.map} +1 -1
  67. package/dist/failure-taxonomy-CjabTATj.js +538 -0
  68. package/dist/failure-taxonomy-CjabTATj.js.map +1 -0
  69. package/dist/{feedback-trajectory-CytTR7u4.d.ts → feedback-trajectory-BJi4t3Vf.d.ts} +6 -6
  70. package/dist/{feedback-trajectory-CytTR7u4.d.ts.map → feedback-trajectory-BJi4t3Vf.d.ts.map} +1 -1
  71. package/dist/hosted/index.d.ts +2 -2
  72. package/dist/{index-CKZa_rnt.d.ts → index-B-s8qDRJ.d.ts} +2 -2
  73. package/dist/{index-CKZa_rnt.d.ts.map → index-B-s8qDRJ.d.ts.map} +1 -1
  74. package/dist/{index-YZrbnBSV.d.ts → index-BD1oSbHr.d.ts} +11 -11
  75. package/dist/{index-YZrbnBSV.d.ts.map → index-BD1oSbHr.d.ts.map} +1 -1
  76. package/dist/{index-vYNHCV2G.d.ts → index-Ca0_IjFu.d.ts} +7 -7
  77. package/dist/{index-vYNHCV2G.d.ts.map → index-Ca0_IjFu.d.ts.map} +1 -1
  78. package/dist/{index-BRsrfSHT.d.ts → index-eTTnPe3r.d.ts} +9 -9
  79. package/dist/{index-BRsrfSHT.d.ts.map → index-eTTnPe3r.d.ts.map} +1 -1
  80. package/dist/index.d.ts +383 -68
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +1482 -207
  83. package/dist/index.js.map +1 -1
  84. package/dist/{insight-report-DpOo-3iL.d.ts → insight-report-DeE1solA.d.ts} +4 -4
  85. package/dist/{insight-report-DpOo-3iL.d.ts.map → insight-report-DeE1solA.d.ts.map} +1 -1
  86. package/dist/{integrity-Cy9WHAtb.js → integrity-BFP4kjGj.js} +6 -1
  87. package/dist/integrity-BFP4kjGj.js.map +1 -0
  88. package/dist/{integrity-rGOfSUle.d.ts → integrity-CaeNeusS.d.ts} +4 -4
  89. package/dist/integrity-CaeNeusS.d.ts.map +1 -0
  90. package/dist/jev.d.ts +2 -2
  91. package/dist/{kind-factory-V79Hw0AU.js → kind-factory-g1ROw67A.js} +15 -4
  92. package/dist/{kind-factory-V79Hw0AU.js.map → kind-factory-g1ROw67A.js.map} +1 -1
  93. package/dist/{llm-client-DDhZ29Vm.js → llm-client-DF9bPNYA.js} +2 -2
  94. package/dist/{llm-client-DDhZ29Vm.js.map → llm-client-DF9bPNYA.js.map} +1 -1
  95. package/dist/{llm-judge-BVso5x-u.js → llm-judge-DF18J3CR.js} +9 -9
  96. package/dist/llm-judge-DF18J3CR.js.map +1 -0
  97. package/dist/{matrix-CPKsRY8Y.d.ts → matrix-BvA1WUpj.d.ts} +2 -2
  98. package/dist/{matrix-CPKsRY8Y.d.ts.map → matrix-BvA1WUpj.d.ts.map} +1 -1
  99. package/dist/meta-eval/index.d.ts +4 -4
  100. package/dist/{mint-BI14xehJ.d.ts → mint-CJFSYBIU.d.ts} +3 -3
  101. package/dist/{mint-BI14xehJ.d.ts.map → mint-CJFSYBIU.d.ts.map} +1 -1
  102. package/dist/multishot/golden/index.d.ts +1 -1
  103. package/dist/multishot/index.d.ts +2 -2
  104. package/dist/openapi.json +1 -1
  105. package/dist/pipelines/index.d.ts +67 -12
  106. package/dist/pipelines/index.d.ts.map +1 -1
  107. package/dist/pipelines/index.js +178 -41
  108. package/dist/pipelines/index.js.map +1 -1
  109. package/dist/{prime-protocol-CDBcL9NM.d.ts → prime-protocol-CF8Z43Fj.d.ts} +2 -2
  110. package/dist/{prime-protocol-CDBcL9NM.d.ts.map → prime-protocol-CF8Z43Fj.d.ts.map} +1 -1
  111. package/dist/{produced-state-Cn9ECr4v.js → produced-state-xsMMjYVc.js} +3 -3
  112. package/dist/{produced-state-Cn9ECr4v.js.map → produced-state-xsMMjYVc.js.map} +1 -1
  113. package/dist/{query-D6W6MaGx.d.ts → query-DBUQhehH.d.ts} +3 -3
  114. package/dist/{query-D6W6MaGx.d.ts.map → query-DBUQhehH.d.ts.map} +1 -1
  115. package/dist/random-DGEyr3zG.d.ts +83 -0
  116. package/dist/random-DGEyr3zG.d.ts.map +1 -0
  117. package/dist/{raw-provider-sink-BQd7mzyT.js → raw-provider-sink-C96CcqeG.js} +19 -56
  118. package/dist/raw-provider-sink-C96CcqeG.js.map +1 -0
  119. package/dist/redact-DPoH1-OW.d.ts +158 -0
  120. package/dist/redact-DPoH1-OW.d.ts.map +1 -0
  121. package/dist/redact-DxwlUAvh.js +824 -0
  122. package/dist/redact-DxwlUAvh.js.map +1 -0
  123. package/dist/{registry-D5Ly3GRV.d.ts → registry-BM2Kdk8T.d.ts} +4 -4
  124. package/dist/{registry-D5Ly3GRV.d.ts.map → registry-BM2Kdk8T.d.ts.map} +1 -1
  125. package/dist/{release-confidence-CSp3MsU4.d.ts → release-confidence-CG4Z9QLB.d.ts} +4 -4
  126. package/dist/{release-confidence-CSp3MsU4.d.ts.map → release-confidence-CG4Z9QLB.d.ts.map} +1 -1
  127. package/dist/{report-command-CSTjzFGY.js → report-command-DKJ_yAIj.js} +21 -12
  128. package/dist/{report-command-CSTjzFGY.js.map → report-command-DKJ_yAIj.js.map} +1 -1
  129. package/dist/reporting.d.ts +3 -3
  130. package/dist/{researcher-D7E92STT.d.ts → researcher-Bjcd_8T_.d.ts} +7 -7
  131. package/dist/{researcher-D7E92STT.d.ts.map → researcher-Bjcd_8T_.d.ts.map} +1 -1
  132. package/dist/{reward-hacking-BIQ2BWLG.d.ts → reward-hacking-DrKXJtgH.d.ts} +2 -2
  133. package/dist/{reward-hacking-BIQ2BWLG.d.ts.map → reward-hacking-DrKXJtgH.d.ts.map} +1 -1
  134. package/dist/rl.d.ts +8 -8
  135. package/dist/rl.js +1 -1
  136. package/dist/rollout/index.d.ts +2 -2
  137. package/dist/{rubric-predictive-validity-CTU8y8Cv.d.ts → rubric-predictive-validity-B14yBAmM.d.ts} +2 -2
  138. package/dist/{rubric-predictive-validity-CTU8y8Cv.d.ts.map → rubric-predictive-validity-B14yBAmM.d.ts.map} +1 -1
  139. package/dist/{run-record-D9wS35fK.d.ts → run-record-xEULpgML.d.ts} +2 -2
  140. package/dist/{run-record-D9wS35fK.d.ts.map → run-record-xEULpgML.d.ts.map} +1 -1
  141. package/dist/{schema-CR5cpjQ3.d.ts → schema-2g7trUwH.d.ts} +17 -2
  142. package/dist/schema-2g7trUwH.d.ts.map +1 -0
  143. package/dist/schema-CSf6qWgZ.js.map +1 -1
  144. package/dist/{semantic-concept-judge-Cnt0TWp0.js → semantic-concept-judge-70LxrCSL.js} +5 -5
  145. package/dist/{semantic-concept-judge-Cnt0TWp0.js.map → semantic-concept-judge-70LxrCSL.js.map} +1 -1
  146. package/dist/{series-convergence-BnMs_uAr.d.ts → series-convergence-DY7ha0kx.d.ts} +2 -2
  147. package/dist/{series-convergence-BnMs_uAr.d.ts.map → series-convergence-DY7ha0kx.d.ts.map} +1 -1
  148. package/dist/{server-DmpcFiVK.js → server-C8XvqCg8.js} +2 -2
  149. package/dist/{server-DmpcFiVK.js.map → server-C8XvqCg8.js.map} +1 -1
  150. package/dist/{skillopt-optimization-method-Cc9SVLqi.js → skillopt-optimization-method-C60h0Got.js} +5 -5
  151. package/dist/{skillopt-optimization-method-Cc9SVLqi.js.map → skillopt-optimization-method-C60h0Got.js.map} +1 -1
  152. package/dist/spans-W0o8pbEg.d.ts +60 -0
  153. package/dist/spans-W0o8pbEg.d.ts.map +1 -0
  154. package/dist/{statistical-heldout-DTmhTW8P.d.ts → statistical-heldout-CPv-y6sK.d.ts} +3 -3
  155. package/dist/{statistical-heldout-DTmhTW8P.d.ts.map → statistical-heldout-CPv-y6sK.d.ts.map} +1 -1
  156. package/dist/{store-BErPvYBr.d.ts → store-C4avFjIi.d.ts} +2 -2
  157. package/dist/{store-BErPvYBr.d.ts.map → store-C4avFjIi.d.ts.map} +1 -1
  158. package/dist/{store-otlp-2gYCy-v0.js → store-otlp-DPgzSQKS.js} +2 -2
  159. package/dist/{store-otlp-2gYCy-v0.js.map → store-otlp-DPgzSQKS.js.map} +1 -1
  160. package/dist/{store-tool-spans-B3bX9yqn.d.ts → store-tool-spans-C2lLwDzg.d.ts} +9 -54
  161. package/dist/store-tool-spans-C2lLwDzg.d.ts.map +1 -0
  162. package/dist/{store-tool-spans-B1e6Auc2.js → store-tool-spans-ClPxcvh2.js} +4 -4
  163. package/dist/{store-tool-spans-B1e6Auc2.js.map → store-tool-spans-ClPxcvh2.js.map} +1 -1
  164. package/dist/storyboard/index.d.ts +1 -1
  165. package/dist/{summary-report-Iy6kXo8x.d.ts → summary-report-SNvJoAvD.d.ts} +3 -3
  166. package/dist/{summary-report-Iy6kXo8x.d.ts.map → summary-report-SNvJoAvD.d.ts.map} +1 -1
  167. package/dist/supervisor-run/index.d.ts.map +1 -1
  168. package/dist/supervisor-run/index.js +1 -1
  169. package/dist/{tool-groups-veQYPiTy.d.ts → tool-groups-CCQqAa16.d.ts} +3 -3
  170. package/dist/tool-groups-CCQqAa16.d.ts.map +1 -0
  171. package/dist/{tool-waste-nbHPAxei.js → tool-waste-CJDfxH45.js} +3 -537
  172. package/dist/tool-waste-CJDfxH45.js.map +1 -0
  173. package/dist/{tool-waste-D23I0zWm.d.ts → tool-waste-CP5DO383.d.ts} +4 -4
  174. package/dist/{tool-waste-D23I0zWm.d.ts.map → tool-waste-CP5DO383.d.ts.map} +1 -1
  175. package/dist/trace-repair/index.d.ts +2 -2
  176. package/dist/traces.d.ts +12 -11
  177. package/dist/traces.d.ts.map +1 -1
  178. package/dist/traces.js +8 -8
  179. package/dist/{trajectory-D7qrNvaN.d.ts → trajectory-Y1fmdlw7.d.ts} +3 -3
  180. package/dist/{trajectory-D7qrNvaN.d.ts.map → trajectory-Y1fmdlw7.d.ts.map} +1 -1
  181. package/dist/trajectory-replay/index.d.ts +3 -3
  182. package/dist/trajectory-replay/index.js +2 -2
  183. package/dist/{types--18oHwVF.d.ts → types-5ak2PqnJ.d.ts} +3 -3
  184. package/dist/{types--18oHwVF.d.ts.map → types-5ak2PqnJ.d.ts.map} +1 -1
  185. package/dist/{types-BTRcIqFr.d.ts → types-B1vDZ694.d.ts} +4 -4
  186. package/dist/{types-BTRcIqFr.d.ts.map → types-B1vDZ694.d.ts.map} +1 -1
  187. package/dist/{types-CBbLtr2J.d.ts → types-C0bWoSKC.d.ts} +10 -11
  188. package/dist/types-C0bWoSKC.d.ts.map +1 -0
  189. package/dist/{types-BjB2wZM9.d.ts → types-DDp2Mb8Y.d.ts} +3 -3
  190. package/dist/{types-BjB2wZM9.d.ts.map → types-DDp2Mb8Y.d.ts.map} +1 -1
  191. package/dist/wire/index.d.ts +3 -3
  192. package/dist/wire/index.js +1 -1
  193. package/docs/diagnosis.md +2 -3
  194. package/docs/eval-surface-map.md +1 -1
  195. package/docs/experiment.md +0 -1
  196. package/docs/redaction.md +59 -0
  197. package/docs/trace-contracts.md +102 -0
  198. package/docs/verdicts.md +1 -1
  199. package/package.json +3 -2
  200. package/dist/benchmark-command-DGokT8zd.js.map +0 -1
  201. package/dist/emitter-Cs0egaFd.d.ts.map +0 -1
  202. package/dist/emitter-DeQHiDMm.js +0 -257
  203. package/dist/emitter-DeQHiDMm.js.map +0 -1
  204. package/dist/engine-DNlKhIm0.d.ts.map +0 -1
  205. package/dist/experiment-tracker-BKEumQug.js +0 -280
  206. package/dist/experiment-tracker-BKEumQug.js.map +0 -1
  207. package/dist/experiment-tracker-URRGP9ek.d.ts +0 -237
  208. package/dist/experiment-tracker-URRGP9ek.d.ts.map +0 -1
  209. package/dist/integrity-Cy9WHAtb.js.map +0 -1
  210. package/dist/integrity-rGOfSUle.d.ts.map +0 -1
  211. package/dist/llm-judge-BVso5x-u.js.map +0 -1
  212. package/dist/raw-provider-sink-BQd7mzyT.js.map +0 -1
  213. package/dist/redact-7Aq1ukl-.js +0 -107
  214. package/dist/redact-7Aq1ukl-.js.map +0 -1
  215. package/dist/schema-CR5cpjQ3.d.ts.map +0 -1
  216. package/dist/store-tool-spans-B3bX9yqn.d.ts.map +0 -1
  217. package/dist/tool-groups-veQYPiTy.d.ts.map +0 -1
  218. package/dist/tool-waste-nbHPAxei.js.map +0 -1
  219. package/dist/types-CBbLtr2J.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { i as JudgeError, o as NotFoundError, r as ConfigError, s as ValidationError, t as AgentEvalError } from "./errors-Dngq5h35.js";
3
3
  import { a as hashCanonical, r as canonicalString } from "./canonical-BsZVgBhW.js";
4
- import { a as CODING_HARNESSES, c as agentProfileId, d as harnessAxisOf, i as verifyCompletion, l as agentProfileModelId, n as completionVerdict, o as HARNESS_NATIVE_MODEL, r as createLlmCorrectnessChecker, s as agentProfileHash, t as extractProducedState, u as expandProfileAxes } from "./produced-state-Cn9ECr4v.js";
4
+ import { a as CODING_HARNESSES, c as agentProfileId, d as harnessAxisOf, i as verifyCompletion, l as agentProfileModelId, n as completionVerdict, o as HARNESS_NATIVE_MODEL, r as createLlmCorrectnessChecker, s as agentProfileHash, t as extractProducedState, u as expandProfileAxes } from "./produced-state-xsMMjYVc.js";
5
5
  import { c as groupRunsByAgentProfileCell, d as validateAgentProfileCell, f as verifyAgentProfileCell, h as manifestContentDigest, i as agentProfileCellKey, m as hashJson, r as agentProfileCellHashMaterial, s as buildAgentProfileCell, t as AGENT_PROFILE_KINDS, u as toAgentProfileJson } from "./agent-profile-cell-DcFW4vOc.js";
6
6
  import { t as mulberry32 } from "./random-Dn5fPWkt.js";
7
7
  import { a as spearmanR, c as weightedMean, i as ranks, n as partialCredit, o as summarizeNumberSeries, r as pearsonR, s as weightedComposite, t as confidenceInterval } from "./descriptive-1V17A-qa.js";
8
8
  import { n as calibrateJudgeContinuous, o as verbosityBias, r as continuousAgreement, t as calibrateJudge } from "./judge-calibration-DYmaBtJr.js";
9
- import { a as budgetBreachView, c as INFRA_FAILURE_BLAMES, d as failureBlame, f as corpusInterRaterAgreement, i as failureClusterView, l as classifyFailure, m as interRaterReliability, n as computeToolUseMetrics, o as DEFAULT_FAILURE_REASON_RULES, p as corpusInterRaterAgreementFromJudgeScores, r as judgeAgreementView, s as FAILURE_BLAME, t as toolWasteView, u as classifyFailureReason } from "./tool-waste-nbHPAxei.js";
9
+ import { a as budgetBreachView, c as interRaterReliability, i as failureClusterView, n as computeToolUseMetrics, o as corpusInterRaterAgreement, r as judgeAgreementView, s as corpusInterRaterAgreementFromJudgeScores, t as toolWasteView } from "./tool-waste-CJDfxH45.js";
10
10
  import { i as pairedCohensDz, n as cohensD, r as interpretCliffs, t as cliffsDelta } from "./effect-sizes-DiH8MGOH.js";
11
11
  import { a as requiredSampleSize, c as holm, i as requiredPairedSampleSize, n as mcnemarRequiredN, o as benjaminiHochberg, r as pairedMde, s as bonferroni, t as mcnemarPower } from "./power-and-mde-BJOpt6pq.js";
12
12
  import { _ as passAtK, a as MANN_WHITNEY_EXACT_MAX_STATES, c as mannWhitneyU, d as isBinaryOutcomeVector, f as mcnemar, g as pairedRiskDifferenceScore, h as pairedRiskDifferenceExact, i as DEFAULT_PERMUTATIONS, l as wilcoxonSignedRank, m as pairedRiskDifference, n as pairArms, o as MANN_WHITNEY_EXACT_MAX_WORK, p as pairedBinaryScale, r as pairRunRecords, s as WILCOXON_EXACT_MAX_N, t as comparePairedArms, v as wilson } from "./paired-arms-JSDcs2zx.js";
@@ -21,44 +21,45 @@ import { r as observedSplitScore, t as isRealnessGated } from "./reward-nw2xZGZG
21
21
  import { a as parseRunRecordSafe, c as validateRunRecord, i as modelHasSnapshot, n as UNKNOWN_MODEL, o as roundTripRunRecord, r as isRunRecord, s as runTaskScore, t as RunRecordValidationError } from "./run-record-tg_5H2IK.js";
22
22
  import { a as summaryTable, n as gainHistogram, r as paretoChart } from "./summary-report-BMvou2oZ.js";
23
23
  import { n as contentHash, r as fileVerdictCache, t as canonicalJson } from "./verdict-cache-BQEsVy9n.js";
24
- import { B as DEFAULT_RED_TEAM_CORPUS, H as redTeamReport, N as dominates, P as paretoFrontier, U as scoreRedTeamOutput, V as redTeamDataset, W as runCanaries, X as runCampaign, a as transientDispatchFailure, i as quotaExhaustedUntil, o as aggregateRunScore, s as clamp01, t as llmJudge } from "./llm-judge-BVso5x-u.js";
24
+ import { B as DEFAULT_RED_TEAM_CORPUS, H as redTeamReport, N as dominates, P as paretoFrontier, U as scoreRedTeamOutput, V as redTeamDataset, W as runCanaries, X as runCampaign, a as transientDispatchFailure, i as quotaExhaustedUntil, o as aggregateRunScore, s as clamp01, t as llmJudge } from "./llm-judge-DF18J3CR.js";
25
25
  import { a as resolveModelPricing, i as isModelPriced, n as estimateCost, r as estimateTokens, t as MODEL_PRICING } from "./metrics-DOMpkoeb.js";
26
26
  import { a as CostLedgerPersistenceError, c as costForTokenPricing, i as CostLedger, l as costForUsage, n as CostCallConflictError, o as CostReceiptCaptureError, r as CostCeilingReachedError, s as CostReservationExceededError, t as CostAccountingIncompleteError, u as modelPriceKey } from "./cost-ledger-_IbkejCF.js";
27
27
  import { D as parseReflectionResponse, E as buildReflectionPrompt, G as summarizeBackendIntegrity, U as BackendIntegrityError, W as assertRealBackend, c as ATTESTATION_ALGORITHM, l as attest, u as verifyAttestation, z as surfaceContentHash } from "./campaign-evidence-IF1p0oDa.js";
28
- import { n as REDACTION_VERSION, r as redactString, t as DEFAULT_REDACTION_RULES } from "./redact-7Aq1ukl-.js";
28
+ import { d as redactForShare, f as redactText, n as REDACTION_VERSION, p as shareAllowed, r as assessShareSafety, u as redact } from "./redact-DxwlUAvh.js";
29
29
  import { i as makeProposalFinding, n as computeFindingId, r as makeFinding } from "./types-C8VBbiw6.js";
30
- import { r as selfImprove, t as defineAgentEval } from "./define-agent-eval-C0EqJ9Gz.js";
30
+ import { r as selfImprove, t as defineAgentEval } from "./define-agent-eval-ChtddasD.js";
31
31
  import { n as equivalenceVerdict, t as certificationEvidenceDigest } from "./verdict-DhPoXApk.js";
32
- import { t as TraceEmitter } from "./emitter-DeQHiDMm.js";
32
+ import { t as TraceEmitter } from "./emitter-DbMXUIVP.js";
33
33
  import { t as buildTrajectory } from "./trajectory-D_7rLrvE.js";
34
- import { t as runCounterfactual } from "./counterfactual-Bjq1mlUu.js";
35
- import { U as DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS, V as parseFindingSubject, l as createBoundedTraceAnalysisStore, m as TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, p as DEFAULT_TRACE_ANALYST_BUDGETS, t as createTraceAnalyst } from "./kind-factory-V79Hw0AU.js";
36
- import { _ as completedAnalystReviewQuality, b as validateAnalystReviewDecisions, c as FAILURE_MODE_KIND_SPEC, g as assertUniqueFindingIds, h as analystRunDigest, i as DEFAULT_TRACE_ANALYST_KINDS, m as analystFindingDigest, n as AnalystRegistry, t as buildDefaultAnalystRegistry, v as readAnalystReview, y as snapshotAnalystRun } from "./default-registry-Ca2IWH1X.js";
34
+ import { t as runCounterfactual } from "./counterfactual-DtMWvn7D.js";
35
+ import { H as parseFindingSubject, W as DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS, h as TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, m as DEFAULT_TRACE_ANALYST_BUDGETS, t as createTraceAnalyst, u as createBoundedTraceAnalysisStore } from "./kind-factory-g1ROw67A.js";
36
+ import { _ as completedAnalystReviewQuality, b as validateAnalystReviewDecisions, c as FAILURE_MODE_KIND_SPEC, g as assertUniqueFindingIds, h as analystRunDigest, i as DEFAULT_TRACE_ANALYST_KINDS, m as analystFindingDigest, n as AnalystRegistry, t as buildDefaultAnalystRegistry, v as readAnalystReview, y as snapshotAnalystRun } from "./default-registry-BtZ_t-9b.js";
37
37
  import { OUTPUT_VALUE } from "./trace-attributes.js";
38
38
  import { r as extractUsageFromSse, t as extractUsage } from "./extract-usage-BrQ8mCLX.js";
39
- import { n as InMemoryRawProviderSink, r as NoopRawProviderSink, t as FileSystemRawProviderSink } from "./raw-provider-sink-BQd7mzyT.js";
40
- import { D as captureFetchToRawSink, S as exportRunAsOtlp, _ as tokenizeDomainWords, d as inferDomainKeywords, g as scoreTraceInsightReadiness, l as describeTraceInsightScope, n as toolSpansToTraceAnalysisStore, o as buildTraceInsightContext, s as buildTraceInsightPrompt, u as domainEvidencePattern, v as analyzeTraces } from "./store-tool-spans-B1e6Auc2.js";
41
- import { n as assertRunCaptured, t as RunIntegrityError } from "./integrity-Cy9WHAtb.js";
39
+ import { n as InMemoryRawProviderSink, r as NoopRawProviderSink, t as FileSystemRawProviderSink } from "./raw-provider-sink-C96CcqeG.js";
40
+ import { D as captureFetchToRawSink, S as exportRunAsOtlp, _ as tokenizeDomainWords, d as inferDomainKeywords, g as scoreTraceInsightReadiness, l as describeTraceInsightScope, n as toolSpansToTraceAnalysisStore, o as buildTraceInsightContext, s as buildTraceInsightPrompt, u as domainEvidencePattern, v as analyzeTraces } from "./store-tool-spans-ClPxcvh2.js";
41
+ import { n as assertRunCaptured, t as RunIntegrityError } from "./integrity-BFP4kjGj.js";
42
42
  import { n as InMemoryTraceStore, t as FileSystemTraceStore } from "./store-DNe_Uv1Q.js";
43
43
  import { t as packageVersion$1 } from "./package-version-D7lQHt_-.js";
44
+ import { a as classifyFailure, i as INFRA_FAILURE_BLAMES, o as classifyFailureReason, r as FAILURE_BLAME, s as failureBlame, t as DEFAULT_FAILURE_REASON_RULES } from "./failure-taxonomy-CjabTATj.js";
44
45
  import { n as runBoundedProcess, t as DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS } from "./bounded-process-BBZob7vl.js";
45
- import { t as runEvalCampaign } from "./eval-campaign-XFHEpN86.js";
46
- import { i as improvementVerdict, n as computeExperimentStats } from "./experiment-tracker-BKEumQug.js";
46
+ import { t as runEvalCampaign } from "./eval-campaign-CeotQ1ZR.js";
47
47
  import "./rollout-C0Ifk3vK.js";
48
48
  import { t as mintRolloutRows } from "./mint-B4zgSAJW.js";
49
49
  import { n as pairedEvalueSequence, t as evaluateInterimReleaseConfidence } from "./sequential-CzK5DarL.js";
50
- import { S as judgeFamily, _ as assertServedModels, b as CrossFamilyError, d as stripFencedJson, f as ModelSubstitutionError, h as assertServedModel, i as backoffMs, l as isTransientLlmError, m as assertCrossFamilyServed, o as costReceiptFromLlm, p as ServedCrossFamilyError, r as LlmResponseError, s as costReceiptFromLlmError, t as LlmCallError, u as maximumChargeForLlmRequest, v as checkServedModel, x as assertCrossFamily, y as servedModelAcceptable } from "./llm-client-DDhZ29Vm.js";
51
- import { n as paidJsonChat } from "./chat-json-call-C-DnDxEy.js";
52
- import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-BE9lCzzL.js";
53
- import { a as diffFindings, n as runSemanticConceptJudge, o as createChatTraceEngine, r as FindingsStore, t as SEMANTIC_CONCEPT_JUDGE_VERSION } from "./semantic-concept-judge-Cnt0TWp0.js";
50
+ import { S as judgeFamily, _ as assertServedModels, b as CrossFamilyError, d as stripFencedJson, f as ModelSubstitutionError, h as assertServedModel, i as backoffMs, l as isTransientLlmError, m as assertCrossFamilyServed, o as costReceiptFromLlm, p as ServedCrossFamilyError, r as LlmResponseError, s as costReceiptFromLlmError, t as LlmCallError, u as maximumChargeForLlmRequest, v as checkServedModel, x as assertCrossFamily, y as servedModelAcceptable } from "./llm-client-DF9bPNYA.js";
51
+ import { n as paidJsonChat } from "./chat-json-call-JVGbfx95.js";
52
+ import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-sPX7B5ac.js";
53
+ import { a as diffFindings, n as runSemanticConceptJudge, o as createChatTraceEngine, r as FindingsStore, t as SEMANTIC_CONCEPT_JUDGE_VERSION } from "./semantic-concept-judge-70LxrCSL.js";
54
54
  import { t as analyzeSeries } from "./series-convergence-CjO2QdRW.js";
55
- import { i as otlpTextToTraceAnalysisStore, n as OtlpFileTraceStore } from "./store-otlp-2gYCy-v0.js";
55
+ import { i as otlpTextToTraceAnalysisStore, n as OtlpFileTraceStore } from "./store-otlp-DPgzSQKS.js";
56
56
  import { n as evaluateReleaseConfidence, r as bootstrapCi } from "./release-confidence-RanRUXRW.js";
57
- import { t as createChatClient } from "./chat-client-DqPqWzVV.js";
57
+ import { t as createChatClient } from "./chat-client-C4dg7Ng_.js";
58
58
  import { createHash } from "node:crypto";
59
59
  import { accessSync, appendFileSync, constants, cpSync, existsSync, mkdirSync, promises, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
60
60
  import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
61
61
  import { spawnSync } from "node:child_process";
62
+ import { INPUT_TOKEN_ATTR_KEYS, MODEL_ATTR_KEYS, OUTPUT_TOKEN_ATTR_KEYS, SPAN_KINDS, TOOL_NAME_ATTR_KEYS, firstNumberAttr, firstStringAttr, resolveSpanKind } from "@tangle-network/agent-trace-contract";
62
63
  //#region src/profile/baselines.ts
63
64
  /**
64
65
  * Strong, generically-useful baseline ROLES — the top zone of an `AgentProfile`
@@ -966,7 +967,7 @@ function stableHash(input) {
966
967
  * malformed line never breaks the read. `diffScorecard` compares the latest
967
968
  * entry of each cell against its predecessor with Cohen's d + Welch's t-test.
968
969
  */
969
- function median(xs) {
970
+ function median$1(xs) {
970
971
  if (xs.length === 0) return 0;
971
972
  const sorted = [...xs].sort((a, b) => a - b);
972
973
  const mid = Math.floor(sorted.length / 2);
@@ -1024,7 +1025,7 @@ function recordRuns(runs, opts) {
1024
1025
  commitSha: opts.commitSha,
1025
1026
  timestamp,
1026
1027
  scores,
1027
- composite: median(scores),
1028
+ composite: median$1(scores),
1028
1029
  runIds: scored.map((s) => s.run.runId)
1029
1030
  };
1030
1031
  const perDimension = aggregatePerDimension(scenarioRuns);
@@ -1184,88 +1185,383 @@ function formatScorecardDiff(diff) {
1184
1185
  return lines.join("\n");
1185
1186
  }
1186
1187
  //#endregion
1187
- //#region src/trace-contracts.ts
1188
+ //#region src/trace-contracts/spans.ts
1189
+ const EVAL_KIND_TO_CONTRACT_KIND = /* @__PURE__ */ new Map([["judge", "EVALUATOR"], ["retrieval", "RETRIEVER"]]);
1190
+ /**
1191
+ * The span's contract kind: a declared kind when recognised, else inferred.
1192
+ * A top-level `kind` counts as a declaration only when it names a contract
1193
+ * kind; OTLP words such as `SPAN_KIND_INTERNAL` and the eval kinds `sandbox`
1194
+ * and `custom` fall through to the span-kind attribute and name signals.
1195
+ */
1196
+ function contractSpanKind(span) {
1197
+ const raw = typeof span.kind === "string" ? span.kind : void 0;
1198
+ const mapped = raw === void 0 ? void 0 : EVAL_KIND_TO_CONTRACT_KIND.get(raw) ?? raw.toUpperCase();
1199
+ const declared = mapped !== void 0 && SPAN_KINDS.includes(mapped) ? mapped : void 0;
1200
+ return resolveSpanKind({
1201
+ ...declared === void 0 ? {} : { kind: declared },
1202
+ name: span.name,
1203
+ attributes: span.attributes ?? {}
1204
+ });
1205
+ }
1206
+ /**
1207
+ * Tool name: `span.toolName` (typed ToolSpan) → the tool-name attributes
1208
+ * (`gen_ai.tool.name`, `tool.name`, ..., `toolName`) → `span.name` when the
1209
+ * span is a TOOL span (otel-bridge's `ExportableSpan` drops `toolName`).
1210
+ */
1211
+ function contractSpanToolName(span) {
1212
+ if (typeof span.toolName === "string") return span.toolName;
1213
+ const attributes = span.attributes ?? {};
1214
+ const fromAttr = firstStringAttr(attributes, TOOL_NAME_ATTR_KEYS) ?? firstStringAttr(attributes, ["toolName"]);
1215
+ if (fromAttr !== void 0) return fromAttr;
1216
+ if (typeof span.name === "string" && contractSpanKind(span) === "TOOL") return span.name;
1217
+ }
1218
+ function spanModel(span) {
1219
+ if (typeof span.model === "string" && span.model.length > 0) return span.model;
1220
+ return firstStringAttr(span.attributes ?? {}, MODEL_ATTR_KEYS);
1221
+ }
1222
+ /** Input plus output tokens, or `undefined` when either side is unrecorded. */
1223
+ function spanTotalTokens(span) {
1224
+ const attributes = span.attributes ?? {};
1225
+ const input = finite(span.inputTokens) ?? firstNumberAttr(attributes, INPUT_TOKEN_ATTR_KEYS);
1226
+ const output = finite(span.outputTokens) ?? firstNumberAttr(attributes, OUTPUT_TOKEN_ATTR_KEYS);
1227
+ return input === void 0 || output === void 0 ? void 0 : input + output;
1228
+ }
1229
+ const ARGUMENT_ATTR_KEYS = [
1230
+ "gen_ai.tool.call.arguments",
1231
+ "tool.arguments",
1232
+ "input.value"
1233
+ ];
1234
+ /** The call's arguments: the typed `args` field, else the argument attributes.
1235
+ * JSON strings are parsed; an unparseable string is kept as a string. */
1236
+ function spanArguments(span) {
1237
+ if (span.argsCaptured === false || span.attributes?.["tool.args_captured"] === false) return {
1238
+ known: false,
1239
+ reason: "arguments were not captured"
1240
+ };
1241
+ if (span.args !== void 0) return {
1242
+ known: true,
1243
+ value: parseJsonString(span.args)
1244
+ };
1245
+ for (const key of ARGUMENT_ATTR_KEYS) {
1246
+ const value = span.attributes?.[key];
1247
+ if (value !== void 0 && value !== null) return {
1248
+ known: true,
1249
+ value: parseJsonString(value)
1250
+ };
1251
+ }
1252
+ return {
1253
+ known: false,
1254
+ reason: "the span carries no argument evidence"
1255
+ };
1256
+ }
1257
+ function parseJsonString(value) {
1258
+ if (typeof value !== "string") return value;
1259
+ try {
1260
+ return JSON.parse(value);
1261
+ } catch {
1262
+ return value;
1263
+ }
1264
+ }
1265
+ function finite(value) {
1266
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1267
+ }
1268
+ function isSpanError(span) {
1269
+ return typeof span.status === "string" && /^(?:error|status_code_error)$/i.test(span.status);
1270
+ }
1271
+ //#endregion
1272
+ //#region src/trace-contracts/predicates.ts
1188
1273
  function isSerializedRegex(v) {
1189
1274
  return typeof v === "object" && v !== null && typeof v.$regex === "string" && typeof v.flags === "string";
1190
1275
  }
1276
+ function isOneOfMatcher(v) {
1277
+ return typeof v === "object" && v !== null && Array.isArray(v.oneOf);
1278
+ }
1279
+ function isRegexValue(v) {
1280
+ return v instanceof RegExp || isSerializedRegex(v);
1281
+ }
1191
1282
  function matchText(actual, matcher) {
1192
1283
  if (typeof actual !== "string") return false;
1193
1284
  if (typeof matcher === "string") return actual === matcher;
1194
1285
  if (matcher instanceof RegExp) return matcher.test(actual);
1286
+ if (isOneOfMatcher(matcher)) return matcher.oneOf.includes(actual);
1195
1287
  return new RegExp(matcher.$regex, matcher.flags).test(actual);
1196
1288
  }
1197
- function resolveToolName(span) {
1198
- if (typeof span.toolName === "string") return span.toolName;
1199
- const fromAttr = span.attributes?.["tool.name"] ?? span.attributes?.toolName;
1200
- if (typeof fromAttr === "string") return fromAttr;
1201
- if (span.kind === "tool" && typeof span.name === "string") return span.name;
1289
+ function assertMatcher(m, where) {
1290
+ if (typeof m === "string" || m instanceof RegExp) return;
1291
+ if (isSerializedRegex(m)) {
1292
+ try {
1293
+ new RegExp(m.$regex, m.flags);
1294
+ } catch (error) {
1295
+ throw new ValidationError(`${where}: invalid regex /${m.$regex}/${m.flags}: ${String(error)}`);
1296
+ }
1297
+ return;
1298
+ }
1299
+ if (isOneOfMatcher(m)) {
1300
+ if (m.oneOf.length === 0 || !m.oneOf.every((x) => typeof x === "string")) throw new ValidationError(`${where}: "oneOf" must be a non-empty array of strings`);
1301
+ return;
1302
+ }
1303
+ throw new ValidationError(`${where}: matcher must be string | RegExp | SerializedRegex | { oneOf }`);
1202
1304
  }
1203
1305
  function assertPredicate(value, where) {
1204
- if (value === null || typeof value !== "object") throw new ValidationError(`${where}: predicate must be an object, got ${typeof value}`);
1306
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new ValidationError(`${where}: predicate must be an object, got ${typeof value}`);
1205
1307
  const p = value;
1206
- for (const field of ["name", "tool"]) {
1207
- const m = p[field];
1208
- if (m !== void 0 && typeof m !== "string" && !(m instanceof RegExp) && !isSerializedRegex(m)) throw new ValidationError(`${where}: "${field}" must be string | RegExp | SerializedRegex`);
1209
- }
1308
+ for (const field of [
1309
+ "name",
1310
+ "tool",
1311
+ "model"
1312
+ ]) if (p[field] !== void 0) assertMatcher(p[field], `${where} "${field}"`);
1313
+ if (p.kind !== void 0 && !SPAN_KINDS.includes(p.kind)) throw new ValidationError(`${where}: "kind" must be one of ${SPAN_KINDS.join(", ")}`);
1210
1314
  if (p.attr !== void 0 && (p.attr === null || typeof p.attr !== "object" || Array.isArray(p.attr))) throw new ValidationError(`${where}: "attr" must be a plain object`);
1315
+ for (const [key, expected] of Object.entries(p.attr ?? {})) if (isSerializedRegex(expected)) assertMatcher(expected, `${where} attr "${key}"`);
1316
+ if (p.not !== void 0) assertPredicate(p.not, `${where} "not"`);
1211
1317
  if (p.requiresCustom && typeof p.custom !== "function") throw new ValidationError(`${where}: rule was built with a custom predicate function, which does not survive JSON serialization — re-attach \`custom\` after deserializing or drop the rule`);
1212
1318
  const hasAttr = p.attr !== void 0 && Object.keys(p.attr).length > 0;
1213
- if (p.name === void 0 && p.tool === void 0 && !hasAttr && typeof p.custom !== "function") throw new ValidationError(`${where}: empty predicate would match every span — specify name, tool, attr, or custom`);
1214
- }
1215
- /** Test one span against one predicate. All specified fields must match. */
1216
- function matchSpan(span, predicate) {
1217
- assertPredicate(predicate, "matchSpan");
1218
- if (predicate.name !== void 0 && !matchText(span.name, predicate.name)) return false;
1219
- if (predicate.tool !== void 0 && !matchText(resolveToolName(span), predicate.tool)) return false;
1220
- if (predicate.attr !== void 0) for (const [key, expected] of Object.entries(predicate.attr)) {
1319
+ if (p.name === void 0 && p.tool === void 0 && p.model === void 0 && p.kind === void 0 && p.not === void 0 && !hasAttr && typeof p.custom !== "function") throw new ValidationError(`${where}: empty predicate would match every span — specify name, tool, model, kind, attr, not, or custom`);
1320
+ }
1321
+ function predicateMatches(span, p) {
1322
+ if (p.kind !== void 0 && contractSpanKind(span) !== p.kind) return false;
1323
+ if (p.name !== void 0 && !matchText(span.name, p.name)) return false;
1324
+ if (p.tool !== void 0 && !matchText(contractSpanToolName(span), p.tool)) return false;
1325
+ if (p.model !== void 0 && !matchText(spanModel(span), p.model)) return false;
1326
+ if (p.attr !== void 0) for (const [key, expected] of Object.entries(p.attr)) {
1221
1327
  const actual = span.attributes?.[key];
1222
- if (expected instanceof RegExp || isSerializedRegex(expected)) {
1328
+ if (isRegexValue(expected)) {
1223
1329
  if (!matchText(typeof actual === "string" ? actual : void 0, expected)) return false;
1224
1330
  } else if (actual !== expected) return false;
1225
1331
  }
1226
- if (predicate.custom !== void 0 && !predicate.custom(span)) return false;
1332
+ if (p.not !== void 0 && predicateMatches(span, p.not)) return false;
1333
+ if (p.custom !== void 0 && !p.custom(span)) return false;
1227
1334
  return true;
1228
1335
  }
1336
+ function normalizeMatcher(m) {
1337
+ if (m instanceof RegExp) return {
1338
+ $regex: m.source,
1339
+ flags: m.flags
1340
+ };
1341
+ if (isOneOfMatcher(m)) return { oneOf: [...m.oneOf] };
1342
+ return m;
1343
+ }
1344
+ function normalizePredicate(p, where) {
1345
+ const kind = typeof p?.kind === "string" ? p.kind.toUpperCase() : p?.kind;
1346
+ const withKind = kind === void 0 ? p : {
1347
+ ...p,
1348
+ kind
1349
+ };
1350
+ assertPredicate(withKind, where);
1351
+ const out = {};
1352
+ if (withKind.kind !== void 0) out.kind = withKind.kind;
1353
+ if (withKind.name !== void 0) out.name = normalizeMatcher(withKind.name);
1354
+ if (withKind.tool !== void 0) out.tool = normalizeMatcher(withKind.tool);
1355
+ if (withKind.model !== void 0) out.model = normalizeMatcher(withKind.model);
1356
+ if (withKind.attr !== void 0) out.attr = Object.fromEntries(Object.entries(withKind.attr).map(([k, v]) => [k, v instanceof RegExp ? normalizeMatcher(v) : v]));
1357
+ if (withKind.not !== void 0) out.not = normalizePredicate(withKind.not, `${where} "not"`);
1358
+ if (typeof withKind.custom === "function") {
1359
+ out.custom = withKind.custom;
1360
+ out.requiresCustom = true;
1361
+ }
1362
+ return out;
1363
+ }
1364
+ //#endregion
1365
+ //#region src/trace-contracts/types.ts
1366
+ const ORDER_MODES = [
1367
+ "start-order",
1368
+ "finish-before-start",
1369
+ "all-occurrences"
1370
+ ];
1371
+ const RUN_STATUSES = [
1372
+ "running",
1373
+ "completed",
1374
+ "failed",
1375
+ "aborted"
1376
+ ];
1377
+ const ARGUMENT_OCCURRENCES = [
1378
+ "first",
1379
+ "last",
1380
+ "any",
1381
+ "all"
1382
+ ];
1383
+ const ARGUMENT_TYPES = [
1384
+ "string",
1385
+ "number",
1386
+ "boolean",
1387
+ "object",
1388
+ "array",
1389
+ "null"
1390
+ ];
1391
+ //#endregion
1392
+ //#region src/trace-contracts/validate.ts
1393
+ function assertOrder(order, where) {
1394
+ if (order === void 0) return void 0;
1395
+ if (!ORDER_MODES.includes(order)) throw new ValidationError(`${where}: order must be one of ${ORDER_MODES.join(", ")}`);
1396
+ return order;
1397
+ }
1398
+ function assertCount(max, where) {
1399
+ if (typeof max !== "number" || !Number.isInteger(max) || max < 0) throw new ValidationError(`${where}: max must be a non-negative integer`);
1400
+ }
1401
+ function assertJsonPointer(pointer, where) {
1402
+ if (typeof pointer !== "string" || pointer !== "" && !pointer.startsWith("/")) throw new ValidationError(`${where}: pointer must be an RFC 6901 JSON Pointer ('' or '/a/b')`);
1403
+ if (/~(?![01])/.test(pointer)) throw new ValidationError(`${where}: pointer has an invalid escape; use ~0 for ~ and ~1 for /`);
1404
+ }
1405
+ function assertArgumentCheck(check, where) {
1406
+ const c = check;
1407
+ if (c === null || typeof c !== "object") throw new ValidationError(`${where}: check must be an object`);
1408
+ switch (c.op) {
1409
+ case "exists": return;
1410
+ case "equals":
1411
+ if (!("value" in c)) throw new ValidationError(`${where}: equals needs a value`);
1412
+ return;
1413
+ case "oneOf":
1414
+ if (!Array.isArray(c.values) || c.values.length === 0) throw new ValidationError(`${where}: oneOf needs a non-empty values array`);
1415
+ return;
1416
+ case "type":
1417
+ if (!ARGUMENT_TYPES.includes(c.type)) throw new ValidationError(`${where}: type must be one of ${ARGUMENT_TYPES.join(", ")}`);
1418
+ return;
1419
+ default: throw new ValidationError(`${where}: check.op must be exists, equals, oneOf, or type`);
1420
+ }
1421
+ }
1422
+ function assertRule(rule, where) {
1423
+ switch (rule.kind) {
1424
+ case "always":
1425
+ case "never":
1426
+ case "eventually":
1427
+ assertPredicate(rule.p, `${where} (p)`);
1428
+ return;
1429
+ case "precedes":
1430
+ assertPredicate(rule.a, `${where} (a)`);
1431
+ assertPredicate(rule.b, `${where} (b)`);
1432
+ assertOrder(rule.order, where);
1433
+ return;
1434
+ case "neverUnless":
1435
+ assertPredicate(rule.p, `${where} (p)`);
1436
+ assertPredicate(rule.prior, `${where} (prior)`);
1437
+ assertOrder(rule.order, where);
1438
+ return;
1439
+ case "atMost":
1440
+ case "tokensAtMost":
1441
+ assertPredicate(rule.p, `${where} (p)`);
1442
+ assertCount(rule.max, where);
1443
+ return;
1444
+ case "run":
1445
+ if (rule.requireCompleted === void 0 && rule.allowedStatuses === void 0 && rule.maxDurationMs === void 0) throw new ValidationError(`${where}: run rule checks nothing`);
1446
+ if (rule.requireCompleted !== void 0 && typeof rule.requireCompleted !== "boolean") throw new ValidationError(`${where}: requireCompleted must be a boolean`);
1447
+ if (rule.allowedStatuses !== void 0) {
1448
+ if (!Array.isArray(rule.allowedStatuses) || rule.allowedStatuses.length === 0) throw new ValidationError(`${where}: allowedStatuses must be a non-empty array`);
1449
+ for (const status of rule.allowedStatuses) if (!RUN_STATUSES.includes(status)) throw new ValidationError(`${where}: unknown run status "${String(status)}" — expected one of ${RUN_STATUSES.join(", ")}`);
1450
+ }
1451
+ if (rule.maxDurationMs !== void 0 && (typeof rule.maxDurationMs !== "number" || !Number.isFinite(rule.maxDurationMs) || rule.maxDurationMs <= 0)) throw new ValidationError(`${where}: maxDurationMs must be a positive number`);
1452
+ return;
1453
+ case "argument":
1454
+ assertPredicate(rule.p, `${where} (p)`);
1455
+ assertJsonPointer(rule.pointer, where);
1456
+ assertArgumentCheck(rule.check, where);
1457
+ if (rule.occurrence !== void 0 && !ARGUMENT_OCCURRENCES.includes(rule.occurrence)) throw new ValidationError(`${where}: occurrence must be one of ${ARGUMENT_OCCURRENCES.join(", ")}`);
1458
+ return;
1459
+ default: throw new ValidationError(`${where}: unknown rule kind "${String(rule.kind)}"`);
1460
+ }
1461
+ }
1462
+ function assertRules(rules, where, allowEmpty = false) {
1463
+ if (!Array.isArray(rules) || rules.length === 0 && !allowEmpty) throw new ValidationError(`${where}: no rules — an empty contract would vacuously pass`);
1464
+ const seen = /* @__PURE__ */ new Set();
1465
+ for (const rule of rules) {
1466
+ const ruleWhere = `${where} rule "${rule?.label ?? "<unlabeled>"}"`;
1467
+ if (typeof rule?.label !== "string" || rule.label.length === 0) throw new ValidationError(`${ruleWhere}: label must be a non-empty string`);
1468
+ if (seen.has(rule.label)) throw new ValidationError(`${ruleWhere}: duplicate label would collapse per-rule scores`);
1469
+ seen.add(rule.label);
1470
+ assertRule(rule, ruleWhere);
1471
+ }
1472
+ }
1473
+ function assertContract(contract, where) {
1474
+ if (typeof contract?.name !== "string" || contract.name.length === 0) throw new ValidationError(`${where}: contract.name must be a non-empty string`);
1475
+ const at = `${where} "${contract.name}"`;
1476
+ assertRules(contract.rules, at, Array.isArray(contract.alternatives) && contract.alternatives.length > 0);
1477
+ if (contract.scope !== void 0) assertPredicate(contract.scope?.root, `${at} scope.root`);
1478
+ if (contract.alternatives !== void 0) {
1479
+ if (!Array.isArray(contract.alternatives) || contract.alternatives.length === 0) throw new ValidationError(`${at}: alternatives must be a non-empty array`);
1480
+ const ids = /* @__PURE__ */ new Set();
1481
+ for (const alternative of contract.alternatives) {
1482
+ if (typeof alternative?.id !== "string" || alternative.id.length === 0) throw new ValidationError(`${at}: every alternative needs a non-empty id`);
1483
+ if (ids.has(alternative.id)) throw new ValidationError(`${at}: duplicate alternative id "${alternative.id}"`);
1484
+ ids.add(alternative.id);
1485
+ assertRules(alternative.rules, `${at} alternative "${alternative.id}"`);
1486
+ }
1487
+ }
1488
+ }
1489
+ //#endregion
1490
+ //#region src/trace-contracts/explain.ts
1229
1491
  function describeMatcher(m) {
1230
1492
  if (typeof m === "string") return m;
1231
1493
  if (m instanceof RegExp) return `/${m.source}/${m.flags}`;
1494
+ if (isOneOfMatcher(m)) return `oneOf(${m.oneOf.join("|")})`;
1232
1495
  return `/${m.$regex}/${m.flags}`;
1233
1496
  }
1234
1497
  function describePredicate(p) {
1235
1498
  const parts = [];
1499
+ if (p.kind !== void 0) parts.push(`kind=${p.kind}`);
1236
1500
  if (p.name !== void 0) parts.push(`name=${describeMatcher(p.name)}`);
1237
1501
  if (p.tool !== void 0) parts.push(`tool=${describeMatcher(p.tool)}`);
1238
- if (p.attr !== void 0) for (const [k, v] of Object.entries(p.attr)) parts.push(`attr.${k}=${v instanceof RegExp || isSerializedRegex(v) ? describeMatcher(v) : JSON.stringify(v)}`);
1502
+ if (p.model !== void 0) parts.push(`model=${describeMatcher(p.model)}`);
1503
+ if (p.attr !== void 0) for (const [k, v] of Object.entries(p.attr)) parts.push(`attr.${k}=${isRegexValue(v) ? describeMatcher(v) : JSON.stringify(v)}`);
1504
+ if (p.not !== void 0) parts.push(`not(${describePredicate(p.not)})`);
1239
1505
  if (typeof p.custom === "function") parts.push(`custom=${p.custom.name || "fn"}`);
1240
1506
  return parts.join(",");
1241
1507
  }
1242
- function normalizeMatcher(m) {
1243
- return m instanceof RegExp ? {
1244
- $regex: m.source,
1245
- flags: m.flags
1246
- } : m;
1508
+ function describeCheck(check) {
1509
+ switch (check.op) {
1510
+ case "exists": return "exists";
1511
+ case "equals": return `equals ${JSON.stringify(check.value)}`;
1512
+ case "oneOf": return `oneOf ${JSON.stringify(check.values)}`;
1513
+ case "type": return `type ${check.type}`;
1514
+ }
1247
1515
  }
1248
- function normalizePredicate(p, where) {
1249
- assertPredicate(p, where);
1250
- const out = {};
1251
- if (p.name !== void 0) out.name = normalizeMatcher(p.name);
1252
- if (p.tool !== void 0) out.tool = normalizeMatcher(p.tool);
1253
- if (p.attr !== void 0) out.attr = Object.fromEntries(Object.entries(p.attr).map(([k, v]) => [k, v instanceof RegExp ? normalizeMatcher(v) : v]));
1254
- if (typeof p.custom === "function") {
1255
- out.custom = p.custom;
1256
- out.requiresCustom = true;
1516
+ /** One line per rule, stating what it requires. */
1517
+ function describeRule(rule) {
1518
+ switch (rule.kind) {
1519
+ case "always": return `every span matches ${describePredicate(rule.p)}`;
1520
+ case "never": return `no span matches ${describePredicate(rule.p)}`;
1521
+ case "eventually": return `some span matches ${describePredicate(rule.p)}`;
1522
+ case "precedes": return `${describePredicate(rule.a)} and ${describePredicate(rule.b)} both occur, and the first comes before the second (${rule.order ?? "start-order"})`;
1523
+ case "neverUnless": return `every ${describePredicate(rule.p)} has an earlier ${describePredicate(rule.prior)} (${rule.order ?? "start-order"})`;
1524
+ case "atMost": return `at most ${rule.max} span(s) match ${describePredicate(rule.p)}`;
1525
+ case "tokensAtMost": return `spans matching ${describePredicate(rule.p)} use at most ${rule.max} tokens in total`;
1526
+ case "run": {
1527
+ const parts = [];
1528
+ if (rule.requireCompleted) parts.push("the run reached a terminal status");
1529
+ if (rule.allowedStatuses) parts.push(`its status is one of ${rule.allowedStatuses.join(", ")}`);
1530
+ if (rule.maxDurationMs !== void 0) parts.push(`it took at most ${rule.maxDurationMs} ms`);
1531
+ return parts.join("; ");
1532
+ }
1533
+ case "argument": return `${rule.occurrence ?? "all"} call(s) matching ${describePredicate(rule.p)} have argument ${rule.pointer || "(whole value)"} that ${describeCheck(rule.check)}`;
1534
+ }
1535
+ }
1536
+ /** Plain-language statement of everything a contract checks, one rule per line. */
1537
+ function explainTraceContract(contract) {
1538
+ assertContract(contract, "explainTraceContract");
1539
+ const lines = [`Contract "${contract.name}"${contract.description ? ` — ${contract.description}` : ""}`];
1540
+ if (contract.scope) lines.push(`Scope: only the span matching ${describePredicate(contract.scope.root)} and its descendants; exactly one span must match.`);
1541
+ lines.push("Every rule must pass:");
1542
+ for (const rule of contract.rules) lines.push(` - ${rule.label}: ${describeRule(rule)}`);
1543
+ if (contract.alternatives) {
1544
+ lines.push("And at least one alternative must pass completely:");
1545
+ for (const alternative of contract.alternatives) {
1546
+ lines.push(` ${alternative.id}:`);
1547
+ for (const rule of alternative.rules) lines.push(` - ${rule.label}: ${describeRule(rule)}`);
1548
+ }
1257
1549
  }
1258
- return out;
1550
+ return lines.join("\n");
1259
1551
  }
1260
- var TraceContractBuilder = class {
1552
+ //#endregion
1553
+ //#region src/trace-contracts/builder.ts
1554
+ var TraceContractBuilder = class TraceContractBuilder {
1261
1555
  name;
1262
1556
  rules = [];
1557
+ alternativeList = [];
1558
+ scopeRoot;
1263
1559
  constructor(name) {
1264
1560
  this.name = name;
1265
1561
  }
1266
1562
  /** Every span in the trace must satisfy `p`. */
1267
1563
  always(p, label) {
1268
- const np = normalizePredicate(p, `traceContract("${this.name}").always`);
1564
+ const np = normalizePredicate(p, this.where("always"));
1269
1565
  return this.add({
1270
1566
  kind: "always",
1271
1567
  label: label ?? `always(${describePredicate(np)})`,
@@ -1274,7 +1570,7 @@ var TraceContractBuilder = class {
1274
1570
  }
1275
1571
  /** No span in the trace may satisfy `p`. */
1276
1572
  never(p, label) {
1277
- const np = normalizePredicate(p, `traceContract("${this.name}").never`);
1573
+ const np = normalizePredicate(p, this.where("never"));
1278
1574
  return this.add({
1279
1575
  kind: "never",
1280
1576
  label: label ?? `never(${describePredicate(np)})`,
@@ -1283,41 +1579,114 @@ var TraceContractBuilder = class {
1283
1579
  }
1284
1580
  /** At least one span in the trace must satisfy `p`. */
1285
1581
  eventually(p, label) {
1286
- const np = normalizePredicate(p, `traceContract("${this.name}").eventually`);
1582
+ const np = normalizePredicate(p, this.where("eventually"));
1287
1583
  return this.add({
1288
1584
  kind: "eventually",
1289
1585
  label: label ?? `eventually(${describePredicate(np)})`,
1290
1586
  p: np
1291
1587
  });
1292
1588
  }
1293
- /** Every `b`-match must have a strictly earlier `a`-match. */
1294
- precedes(a, b, label) {
1295
- const na = normalizePredicate(a, `traceContract("${this.name}").precedes (a)`);
1296
- const nb = normalizePredicate(b, `traceContract("${this.name}").precedes (b)`);
1589
+ /** Both `a` and `b` must occur, with `a` first under `options.order`
1590
+ * (default `start-order`). For "every `b` needs an earlier `a`, and a run
1591
+ * without `b` passes", use {@link neverUnless}. */
1592
+ precedes(a, b, label, options = {}) {
1593
+ const na = normalizePredicate(a, this.where("precedes (a)"));
1594
+ const nb = normalizePredicate(b, this.where("precedes (b)"));
1595
+ const order = assertOrder(options.order, this.where("precedes"));
1297
1596
  return this.add({
1298
1597
  kind: "precedes",
1299
1598
  label: label ?? `precedes(${describePredicate(na)} -> ${describePredicate(nb)})`,
1300
1599
  a: na,
1301
- b: nb
1600
+ b: nb,
1601
+ ...order === void 0 ? {} : { order }
1302
1602
  });
1303
1603
  }
1304
- /** Every `p`-match is a violation unless a strictly earlier `prior`-match exists. */
1305
- neverUnless(p, prior, label) {
1306
- const np = normalizePredicate(p, `traceContract("${this.name}").neverUnless (p)`);
1307
- const nprior = normalizePredicate(prior, `traceContract("${this.name}").neverUnless (prior)`);
1604
+ /** Every `p`-match needs an earlier `prior`-match; a run without `p` passes. */
1605
+ neverUnless(p, prior, label, options = {}) {
1606
+ const np = normalizePredicate(p, this.where("neverUnless (p)"));
1607
+ const nprior = normalizePredicate(prior, this.where("neverUnless (prior)"));
1608
+ const order = assertOrder(options.order, this.where("neverUnless"));
1308
1609
  return this.add({
1309
1610
  kind: "neverUnless",
1310
1611
  label: label ?? `neverUnless(${describePredicate(np)} unless ${describePredicate(nprior)})`,
1311
1612
  p: np,
1312
- prior: nprior
1613
+ prior: nprior,
1614
+ ...order === void 0 ? {} : { order }
1313
1615
  });
1314
1616
  }
1617
+ /** At most `max` spans may satisfy `p`. */
1618
+ atMost(p, max, label) {
1619
+ const np = normalizePredicate(p, this.where("atMost"));
1620
+ assertCount(max, this.where("atMost"));
1621
+ return this.add({
1622
+ kind: "atMost",
1623
+ label: label ?? `atMost(${describePredicate(np)}, ${max})`,
1624
+ p: np,
1625
+ max
1626
+ });
1627
+ }
1628
+ /** Spans satisfying `p` may use at most `max` input+output tokens in total. */
1629
+ tokensAtMost(p, max, label) {
1630
+ const np = normalizePredicate(p, this.where("tokensAtMost"));
1631
+ assertCount(max, this.where("tokensAtMost"));
1632
+ return this.add({
1633
+ kind: "tokensAtMost",
1634
+ label: label ?? `tokensAtMost(${describePredicate(np)}, ${max})`,
1635
+ p: np,
1636
+ max
1637
+ });
1638
+ }
1639
+ /** Terminal status and duration of the run. */
1640
+ run(checks, label = "run") {
1641
+ const rule = {
1642
+ kind: "run",
1643
+ label,
1644
+ ...checks
1645
+ };
1646
+ assertRule(rule, this.where("run"));
1647
+ return this.add(rule);
1648
+ }
1649
+ /** A JSON Pointer check on the arguments of calls matching `p`. */
1650
+ argument(p, options, label) {
1651
+ const np = normalizePredicate(p, this.where("argument"));
1652
+ const rule = {
1653
+ kind: "argument",
1654
+ label: label ?? `argument(${describePredicate(np)}, ${options.pointer || "(whole value)"} ${describeCheck(options.check)})`,
1655
+ p: np,
1656
+ pointer: options.pointer,
1657
+ check: options.check,
1658
+ ...options.occurrence === void 0 ? {} : { occurrence: options.occurrence }
1659
+ };
1660
+ assertRule(rule, this.where("argument"));
1661
+ return this.add(rule);
1662
+ }
1663
+ /** Evaluate only the subtree rooted at the one span matching `root`. */
1664
+ scope(root) {
1665
+ this.scopeRoot = normalizePredicate(root, this.where("scope"));
1666
+ return this;
1667
+ }
1668
+ /** A named alternate path; at least one alternative must pass completely. */
1669
+ alternative(id, define) {
1670
+ const branch = define(new TraceContractBuilder(`${this.name}/${id}`));
1671
+ if (branch.scopeRoot !== void 0 || branch.alternativeList.length > 0) throw new ValidationError(`${this.where("alternative")}: alternatives cannot nest scope or alternatives`);
1672
+ this.alternativeList.push({
1673
+ id,
1674
+ rules: [...branch.rules]
1675
+ });
1676
+ return this;
1677
+ }
1315
1678
  build() {
1316
- if (this.rules.length === 0) throw new ValidationError(`traceContract("${this.name}").build(): no rules — an empty contract would vacuously pass`);
1317
- return {
1679
+ const contract = {
1318
1680
  name: this.name,
1319
- rules: [...this.rules]
1681
+ ...this.scopeRoot === void 0 ? {} : { scope: { root: this.scopeRoot } },
1682
+ rules: [...this.rules],
1683
+ ...this.alternativeList.length === 0 ? {} : { alternatives: [...this.alternativeList] }
1320
1684
  };
1685
+ assertContract(contract, `traceContract("${this.name}").build()`);
1686
+ return contract;
1687
+ }
1688
+ where(op) {
1689
+ return `traceContract("${this.name}").${op}`;
1321
1690
  }
1322
1691
  add(rule) {
1323
1692
  let label = rule.label;
@@ -1337,144 +1706,378 @@ function traceContract(name) {
1337
1706
  if (typeof name !== "string" || name.length === 0) throw new ValidationError("traceContract: name must be a non-empty string");
1338
1707
  return new TraceContractBuilder(name);
1339
1708
  }
1340
- function assertContract(contract) {
1341
- if (typeof contract?.name !== "string" || contract.name.length === 0) throw new ValidationError("evaluateTraceContract: contract.name must be a non-empty string");
1342
- if (!Array.isArray(contract.rules) || contract.rules.length === 0) throw new ValidationError(`evaluateTraceContract: contract "${contract.name}" has no rules — an empty contract would vacuously pass`);
1343
- const seen = /* @__PURE__ */ new Set();
1344
- for (const rule of contract.rules) {
1345
- const where = `contract "${contract.name}" rule "${rule?.label ?? "<unlabeled>"}"`;
1346
- if (typeof rule?.label !== "string" || rule.label.length === 0) throw new ValidationError(`${where}: label must be a non-empty string`);
1347
- if (seen.has(rule.label)) throw new ValidationError(`${where}: duplicate label would collapse per-rule scores`);
1348
- seen.add(rule.label);
1349
- switch (rule.kind) {
1350
- case "always":
1351
- case "never":
1352
- case "eventually":
1353
- assertPredicate(rule.p, `${where} (p)`);
1354
- break;
1355
- case "precedes":
1356
- assertPredicate(rule.a, `${where} (a)`);
1357
- assertPredicate(rule.b, `${where} (b)`);
1358
- break;
1359
- case "neverUnless":
1360
- assertPredicate(rule.p, `${where} (p)`);
1361
- assertPredicate(rule.prior, `${where} (prior)`);
1362
- break;
1363
- default: throw new ValidationError(`${where}: unknown rule kind "${String(rule.kind)}"`);
1364
- }
1365
- }
1709
+ //#endregion
1710
+ //#region src/trace-contracts/rules.ts
1711
+ function spanRef(span, index) {
1712
+ return span.spanId ?? `#${index}`;
1713
+ }
1714
+ function indexed(spans, p) {
1715
+ const out = [];
1716
+ spans.forEach((span, i) => {
1717
+ if (predicateMatches(span, p)) out.push({
1718
+ span,
1719
+ ref: spanRef(span, i)
1720
+ });
1721
+ });
1722
+ return out;
1366
1723
  }
1367
1724
  /**
1368
- * Order spans for temporal evaluation: by `startedAt` when EVERY span carries
1369
- * one (stable — ties keep array order), by array order when NONE does. Mixed
1370
- * timestamps throw: neither time order nor array order is a trustworthy total
1371
- * order over a partially-stamped sequence, and guessing would corrupt
1372
- * `precedes` / `neverUnless` verdicts.
1725
+ * Is guarded span `b` preceded by the guard spans under `order`? A span never
1726
+ * witnesses itself. Missing timestamps fail: the checker cannot prove an
1727
+ * order it cannot see.
1373
1728
  */
1374
- function orderSpans(spans) {
1375
- const timed = spans.filter((s) => typeof s.startedAt === "number" && Number.isFinite(s.startedAt)).length;
1376
- if (timed === spans.length) return spans.map((span, i) => ({
1377
- span,
1378
- i
1379
- })).sort((x, y) => x.span.startedAt - y.span.startedAt || x.i - y.i).map((x) => x.span);
1380
- if (timed === 0) return [...spans];
1381
- throw new ValidationError(`evaluateTraceContract: ${timed}/${spans.length} spans carry a finite startedAt — mixed timestamps make ordering ambiguous; stamp every span or none`);
1729
+ function witnessed(b, guards, order) {
1730
+ const bStart = finite(b.span.startedAt);
1731
+ if (bStart === void 0) return {
1732
+ ok: false,
1733
+ detail: `span ${b.ref} has no startedAt, so its order cannot be proven`
1734
+ };
1735
+ const candidates = guards.filter((a) => a.span !== b.span);
1736
+ if (candidates.length === 0) return {
1737
+ ok: false,
1738
+ detail: `span ${b.ref} has no earlier match`
1739
+ };
1740
+ const boundary = order === "start-order" ? "startedAt" : "endedAt";
1741
+ const untimed = candidates.find((a) => finite(a.span[boundary]) === void 0);
1742
+ if (order === "all-occurrences") {
1743
+ if (untimed) return {
1744
+ ok: false,
1745
+ detail: `span ${untimed.ref} has no endedAt, so its order cannot be proven`
1746
+ };
1747
+ const late = candidates.find((a) => a.span.endedAt > bStart);
1748
+ return late ? {
1749
+ ok: false,
1750
+ detail: `span ${late.ref} ends after span ${b.ref} starts`
1751
+ } : { ok: true };
1752
+ }
1753
+ if (candidates.some((a) => {
1754
+ const t = finite(a.span[boundary]);
1755
+ return t !== void 0 && (order === "start-order" ? t < bStart : t <= bStart);
1756
+ })) return { ok: true };
1757
+ if (untimed) return {
1758
+ ok: false,
1759
+ detail: `span ${untimed.ref} has no ${boundary}, so its order cannot be proven`
1760
+ };
1761
+ return {
1762
+ ok: false,
1763
+ detail: order === "start-order" ? `span ${b.ref} has no match that started before it` : `span ${b.ref} has no match that finished before it started`
1764
+ };
1382
1765
  }
1383
- function spanRef(span, index) {
1384
- return span.spanId ?? `#${index}`;
1766
+ function orderViolations(label, guards, guarded, order, describe) {
1767
+ const out = [];
1768
+ for (const b of guarded) {
1769
+ const w = witnessed(b, guards, order);
1770
+ if (!w.ok) out.push({
1771
+ rule: label,
1772
+ spanId: b.span.spanId,
1773
+ detail: `${describe}: ${w.detail}`
1774
+ });
1775
+ }
1776
+ return out;
1777
+ }
1778
+ /** RFC 6901 resolution. `found: false` when any reference token is absent. */
1779
+ function resolveJsonPointer(value, pointer) {
1780
+ if (pointer === "") return {
1781
+ found: true,
1782
+ value
1783
+ };
1784
+ let current = value;
1785
+ for (const raw of pointer.slice(1).split("/")) {
1786
+ const token = raw.replace(/~1/g, "/").replace(/~0/g, "~");
1787
+ if (Array.isArray(current)) {
1788
+ if (!/^(?:0|[1-9]\d*)$/.test(token) || Number(token) >= current.length) return { found: false };
1789
+ current = current[Number(token)];
1790
+ } else if (current !== null && typeof current === "object" && Object.hasOwn(current, token)) current = current[token];
1791
+ else return { found: false };
1792
+ }
1793
+ return {
1794
+ found: true,
1795
+ value: current
1796
+ };
1385
1797
  }
1386
- function checkGuarded(args) {
1798
+ function jsonType(value) {
1799
+ if (value === null) return "null";
1800
+ if (Array.isArray(value)) return "array";
1801
+ const t = typeof value;
1802
+ return t === "string" || t === "number" || t === "boolean" || t === "object" ? t : "undefined";
1803
+ }
1804
+ function jsonEqual(a, b) {
1805
+ if (a === b) return true;
1806
+ const ta = jsonType(a);
1807
+ if (ta !== jsonType(b)) return false;
1808
+ if (ta === "array") {
1809
+ const x = a;
1810
+ const y = b;
1811
+ return x.length === y.length && x.every((v, i) => jsonEqual(v, y[i]));
1812
+ }
1813
+ if (ta === "object") {
1814
+ const x = a;
1815
+ const y = b;
1816
+ const keys = Object.keys(x);
1817
+ return keys.length === Object.keys(y).length && keys.every((k) => Object.hasOwn(y, k) && jsonEqual(x[k], y[k]));
1818
+ }
1819
+ return false;
1820
+ }
1821
+ /** Why `value` fails `check`, or `undefined` when it passes. Never echoes the
1822
+ * actual argument value: arguments can carry customer data. */
1823
+ function argumentFailure(evidence, pointer, check) {
1824
+ if (!evidence.known) return evidence.reason;
1825
+ const resolved = resolveJsonPointer(evidence.value, pointer);
1826
+ if (!resolved.found) return `argument ${pointer || "(whole value)"} is absent`;
1827
+ switch (check.op) {
1828
+ case "exists": return;
1829
+ case "equals": return jsonEqual(resolved.value, check.value) ? void 0 : `argument ${pointer || "(whole value)"} (a ${jsonType(resolved.value)}) does not equal the expected value`;
1830
+ case "oneOf": return check.values.some((v) => jsonEqual(resolved.value, v)) ? void 0 : `argument ${pointer || "(whole value)"} (a ${jsonType(resolved.value)}) is not one of the expected values`;
1831
+ case "type": return jsonType(resolved.value) === check.type ? void 0 : `argument ${pointer || "(whole value)"} is a ${jsonType(resolved.value)}, not a ${check.type}`;
1832
+ }
1833
+ }
1834
+ function checkArgument(rule, spans) {
1835
+ const matches = indexed(spans, rule.p);
1836
+ if (matches.length === 0) return [{
1837
+ rule: rule.label,
1838
+ detail: `no span matches ${describePredicate(rule.p)}, so there is no argument evidence to check`
1839
+ }];
1840
+ const occurrence = rule.occurrence ?? "all";
1841
+ let selected = matches;
1842
+ if ((occurrence === "first" || occurrence === "last") && matches.length > 1) {
1843
+ const untimed = matches.find((m) => finite(m.span.startedAt) === void 0);
1844
+ if (untimed) return [{
1845
+ rule: rule.label,
1846
+ spanId: untimed.span.spanId,
1847
+ detail: `span ${untimed.ref} has no startedAt, so the ${occurrence} call cannot be chosen`
1848
+ }];
1849
+ const sorted = [...matches].sort((x, y) => x.span.startedAt - y.span.startedAt);
1850
+ selected = [occurrence === "first" ? sorted[0] : sorted[sorted.length - 1]];
1851
+ }
1852
+ const failures = selected.map((m) => ({
1853
+ m,
1854
+ why: argumentFailure(spanArguments(m.span), rule.pointer, rule.check)
1855
+ }));
1856
+ const failed = failures.filter((f) => f.why !== void 0);
1857
+ if (occurrence === "any" ? failed.length < failures.length : failed.length === 0) return [];
1858
+ return failed.map((f) => ({
1859
+ rule: rule.label,
1860
+ spanId: f.m.span.spanId,
1861
+ detail: `span ${f.m.ref}: ${f.why}`
1862
+ }));
1863
+ }
1864
+ function checkRun(rule, context) {
1865
+ if ("unknown" in context) return [{
1866
+ rule: rule.label,
1867
+ detail: `run record unavailable: ${context.unknown}`
1868
+ }];
1869
+ const run = context.run;
1387
1870
  const out = [];
1388
- let guardSeen = false;
1389
- for (let i = 0; i < args.ordered.length; i++) {
1390
- const span = args.ordered[i];
1391
- if (!guardSeen && matchSpan(span, args.guarded)) out.push({
1392
- rule: args.label,
1393
- spanId: span.spanId,
1394
- detail: args.detail(spanRef(span, i))
1871
+ if (rule.requireCompleted && (run.status === void 0 || run.status === "running" || finite(run.endedAt) === void 0)) out.push({
1872
+ rule: rule.label,
1873
+ detail: `run did not reach a terminal status (status ${run.status ?? "unknown"})`
1874
+ });
1875
+ if (rule.allowedStatuses && !rule.allowedStatuses.includes(run.status ?? "")) out.push({
1876
+ rule: rule.label,
1877
+ detail: `run status ${run.status ?? "unknown"} is not one of ${rule.allowedStatuses.join(", ")}`
1878
+ });
1879
+ if (rule.maxDurationMs !== void 0) {
1880
+ const start = finite(run.startedAt);
1881
+ const end = finite(run.endedAt);
1882
+ if (start === void 0 || end === void 0) out.push({
1883
+ rule: rule.label,
1884
+ detail: "run duration is unknown: start or end time is missing"
1885
+ });
1886
+ else if (end - start > rule.maxDurationMs) out.push({
1887
+ rule: rule.label,
1888
+ detail: `run took ${end - start} ms, over ${rule.maxDurationMs} ms`
1395
1889
  });
1396
- if (matchSpan(span, args.guard)) guardSeen = true;
1397
1890
  }
1398
1891
  return out;
1399
1892
  }
1400
- function checkRule(rule, ordered) {
1893
+ function checkRule(rule, ctx) {
1894
+ const { spans } = ctx;
1401
1895
  switch (rule.kind) {
1402
- case "always": {
1896
+ case "always": return spans.flatMap((span, i) => predicateMatches(span, rule.p) ? [] : [{
1897
+ rule: rule.label,
1898
+ spanId: span.spanId,
1899
+ detail: `span ${spanRef(span, i)} ("${span.name ?? ""}") fails always(${describePredicate(rule.p)})`
1900
+ }]);
1901
+ case "never": return indexed(spans, rule.p).map(({ span, ref }) => ({
1902
+ rule: rule.label,
1903
+ spanId: span.spanId,
1904
+ detail: `span ${ref} ("${span.name ?? ""}") matches never(${describePredicate(rule.p)})`
1905
+ }));
1906
+ case "eventually": return spans.some((span) => predicateMatches(span, rule.p)) ? [] : [{
1907
+ rule: rule.label,
1908
+ detail: `no span matches eventually(${describePredicate(rule.p)}) over ${spans.length} span(s)`
1909
+ }];
1910
+ case "precedes": {
1911
+ const as = indexed(spans, rule.a);
1912
+ const bs = indexed(spans, rule.b);
1403
1913
  const out = [];
1404
- for (let i = 0; i < ordered.length; i++) {
1405
- const span = ordered[i];
1406
- if (!matchSpan(span, rule.p)) out.push({
1407
- rule: rule.label,
1408
- spanId: span.spanId,
1409
- detail: `span ${spanRef(span, i)} ("${span.name ?? ""}") fails always(${describePredicate(rule.p)})`
1410
- });
1411
- }
1412
- return out;
1914
+ if (as.length === 0) out.push({
1915
+ rule: rule.label,
1916
+ detail: `required predecessor ${describePredicate(rule.a)} never occurred`
1917
+ });
1918
+ if (bs.length === 0) out.push({
1919
+ rule: rule.label,
1920
+ detail: `required successor ${describePredicate(rule.b)} never occurred`
1921
+ });
1922
+ if (out.length > 0) return out;
1923
+ return orderViolations(rule.label, as, bs, rule.order ?? "start-order", `${describePredicate(rule.b)} is not preceded by ${describePredicate(rule.a)}`);
1413
1924
  }
1414
- case "never": {
1415
- const out = [];
1416
- for (let i = 0; i < ordered.length; i++) {
1417
- const span = ordered[i];
1418
- if (matchSpan(span, rule.p)) out.push({
1419
- rule: rule.label,
1420
- spanId: span.spanId,
1421
- detail: `span ${spanRef(span, i)} ("${span.name ?? ""}") matches never(${describePredicate(rule.p)})`
1422
- });
1423
- }
1424
- return out;
1925
+ case "neverUnless": return orderViolations(rule.label, indexed(spans, rule.prior), indexed(spans, rule.p), rule.order ?? "start-order", `${describePredicate(rule.p)} without an earlier ${describePredicate(rule.prior)}`);
1926
+ case "atMost": {
1927
+ const matches = indexed(spans, rule.p);
1928
+ return matches.length <= rule.max ? [] : [{
1929
+ rule: rule.label,
1930
+ spanId: matches[rule.max]?.span.spanId,
1931
+ detail: `${matches.length} span(s) match ${describePredicate(rule.p)}, over the limit of ${rule.max}`
1932
+ }];
1425
1933
  }
1426
- case "eventually": return ordered.some((span) => matchSpan(span, rule.p)) ? [] : [{
1427
- rule: rule.label,
1428
- detail: `no span matches eventually(${describePredicate(rule.p)}) over ${ordered.length} span(s)`
1429
- }];
1430
- case "precedes": return checkGuarded({
1431
- label: rule.label,
1432
- ordered,
1433
- guard: rule.a,
1434
- guarded: rule.b,
1435
- detail: (ref) => `span ${ref} matches ${describePredicate(rule.b)} with no earlier ${describePredicate(rule.a)} match`
1436
- });
1437
- case "neverUnless": return checkGuarded({
1438
- label: rule.label,
1439
- ordered,
1440
- guard: rule.prior,
1441
- guarded: rule.p,
1442
- detail: (ref) => `span ${ref} matches ${describePredicate(rule.p)} with no earlier ${describePredicate(rule.prior)} match`
1443
- });
1934
+ case "tokensAtMost": {
1935
+ const matches = indexed(spans, rule.p);
1936
+ const unknown = matches.find((m) => spanTotalTokens(m.span) === void 0);
1937
+ if (unknown) return [{
1938
+ rule: rule.label,
1939
+ spanId: unknown.span.spanId,
1940
+ detail: `span ${unknown.ref} has no recorded input and output token counts, so the total is unknown`
1941
+ }];
1942
+ const total = matches.reduce((sum, m) => sum + spanTotalTokens(m.span), 0);
1943
+ return total <= rule.max ? [] : [{
1944
+ rule: rule.label,
1945
+ detail: `${total} tokens across ${matches.length} span(s) matching ${describePredicate(rule.p)}, over the limit of ${rule.max}`
1946
+ }];
1947
+ }
1948
+ case "run": return checkRun(rule, ctx.run);
1949
+ case "argument": return checkArgument(rule, spans);
1950
+ }
1951
+ }
1952
+ function executeRule(rule, ctx) {
1953
+ try {
1954
+ const violations = checkRule(rule, ctx);
1955
+ return {
1956
+ status: violations.length === 0 ? "pass" : "fail",
1957
+ violations
1958
+ };
1959
+ } catch (error) {
1960
+ return {
1961
+ status: "error",
1962
+ violations: [],
1963
+ error: error instanceof Error ? error.message : String(error)
1964
+ };
1444
1965
  }
1445
1966
  }
1967
+ //#endregion
1968
+ //#region src/trace-contracts/evaluate.ts
1446
1969
  /**
1447
- * Evaluate one contract over a span sequence. Pure and synchronous — works
1448
- * on `Span[]` from a TraceStore, `ExportableSpan[]` from the otel-bridge
1449
- * flattening, or any array satisfying `ContractSpan`.
1970
+ * A run derived from one span: the `run.status` attribute a run-anchor span
1971
+ * carries (store-to-otlp writes it), else failed on an error status, else
1972
+ * completed once the span ended.
1450
1973
  */
1451
- function evaluateTraceContract(contract, spans) {
1452
- assertContract(contract);
1453
- const ordered = orderSpans(spans);
1454
- const scores = {};
1455
- const violations = [];
1456
- for (const rule of contract.rules) {
1457
- const ruleViolations = checkRule(rule, ordered);
1458
- scores[rule.label] = ruleViolations.length === 0 ? 1 : 0;
1459
- violations.push(...ruleViolations);
1974
+ function runOfSpan(span) {
1975
+ const declared = span.attributes?.["run.status"];
1976
+ return {
1977
+ status: typeof declared === "string" && RUN_STATUSES.includes(declared) ? declared : isSpanError(span) ? "failed" : finite(span.endedAt) !== void 0 ? "completed" : "running",
1978
+ ...finite(span.startedAt) === void 0 ? {} : { startedAt: span.startedAt },
1979
+ ...finite(span.endedAt) === void 0 ? {} : { endedAt: span.endedAt }
1980
+ };
1981
+ }
1982
+ function rootsOf(spans) {
1983
+ const ids = new Set(spans.map((s) => s.spanId).filter((id) => typeof id === "string"));
1984
+ return spans.filter((s) => !s.parentSpanId || !ids.has(s.parentSpanId));
1985
+ }
1986
+ function subtree(spans, root) {
1987
+ if (typeof root.spanId !== "string") return [root];
1988
+ const children = /* @__PURE__ */ new Map();
1989
+ for (const span of spans) if (typeof span.parentSpanId === "string") {
1990
+ const list = children.get(span.parentSpanId) ?? [];
1991
+ list.push(span);
1992
+ children.set(span.parentSpanId, list);
1993
+ }
1994
+ const members = /* @__PURE__ */ new Set([root]);
1995
+ const queue = [root];
1996
+ while (queue.length > 0) {
1997
+ const current = queue.shift();
1998
+ for (const child of typeof current.spanId === "string" && children.get(current.spanId) || []) if (!members.has(child)) {
1999
+ members.add(child);
2000
+ queue.push(child);
2001
+ }
2002
+ }
2003
+ return spans.filter((s) => members.has(s));
2004
+ }
2005
+ function statusOf(outcomes) {
2006
+ if (outcomes.some((o) => o.status === "error")) return "error";
2007
+ return outcomes.every((o) => o.status === "pass") ? "pass" : "fail";
2008
+ }
2009
+ /**
2010
+ * Evaluate one contract over a span sequence. Pure and synchronous — works on
2011
+ * `Span[]` from a TraceStore, `ExportableSpan[]` from the otel-bridge
2012
+ * flattening, or any array satisfying `ContractSpan`. Throws
2013
+ * `ValidationError` for a malformed contract; a rule that cannot be evaluated
2014
+ * is reported as `error` in the verdict instead.
2015
+ */
2016
+ function evaluateTraceContract(contract, spans, options = {}) {
2017
+ assertContract(contract, "evaluateTraceContract");
2018
+ if (!Array.isArray(spans)) throw new ValidationError(`evaluateTraceContract: spans must be an array, got ${typeof spans}`);
2019
+ let subject = spans;
2020
+ let run;
2021
+ let scopeError;
2022
+ if (contract.scope) {
2023
+ const roots = spans.filter((s) => predicateMatches(s, contract.scope.root));
2024
+ if (roots.length === 1) {
2025
+ subject = subtree(spans, roots[0]);
2026
+ run = { run: runOfSpan(roots[0]) };
2027
+ } else {
2028
+ scopeError = `scope root ${describePredicate(contract.scope.root)} matched ${roots.length} spans; exactly one is required`;
2029
+ run = { unknown: scopeError };
2030
+ }
2031
+ } else if (options.run) run = { run: options.run };
2032
+ else {
2033
+ const roots = rootsOf(spans);
2034
+ run = roots.length === 1 ? { run: runOfSpan(roots[0]) } : { unknown: `the trace has ${roots.length} root spans and no run record was passed` };
1460
2035
  }
1461
- const ruleCount = contract.rules.length;
2036
+ const ctx = {
2037
+ spans: subject,
2038
+ run
2039
+ };
2040
+ const execute = (rule) => scopeError === void 0 ? executeRule(rule, ctx) : {
2041
+ status: "error",
2042
+ violations: [],
2043
+ error: scopeError
2044
+ };
2045
+ const base = contract.rules.map(execute);
2046
+ const branches = (contract.alternatives ?? []).map((alternative) => ({
2047
+ alternative,
2048
+ outcomes: alternative.rules.map(execute)
2049
+ }));
2050
+ const passedBranch = branches.find((b) => statusOf(b.outcomes) === "pass");
2051
+ const baseStatus = statusOf(base);
2052
+ let status = baseStatus;
2053
+ if (baseStatus === "pass" && branches.length > 0 && !passedBranch) status = branches.some((b) => statusOf(b.outcomes) === "error") ? "error" : "fail";
2054
+ const ruleExecutions = [...contract.rules.map((rule, i) => execution(rule.label, void 0, base[i])), ...branches.flatMap((b) => b.alternative.rules.map((rule, i) => execution(rule.label, b.alternative.id, b.outcomes[i])))];
2055
+ const violations = base.flatMap((o) => o.violations);
2056
+ if (branches.length > 0 && !passedBranch) for (const b of branches) for (const o of b.outcomes) violations.push(...o.violations.map((v) => ({
2057
+ ...v,
2058
+ rule: `${b.alternative.id}/${v.rule}`
2059
+ })));
2060
+ const errors = ruleExecutions.filter((e) => e.status === "error").map((e) => `${e.alternative ? `${e.alternative}/` : ""}${e.rule}: ${e.error}`);
2061
+ const scores = {};
2062
+ contract.rules.forEach((rule, i) => {
2063
+ const s = base[i].status;
2064
+ if (s !== "error") scores[rule.label] = s === "pass" ? 1 : 0;
2065
+ });
2066
+ if (branches.length > 0 && (passedBranch || status !== "error")) scores.anyOf = passedBranch ? 1 : 0;
2067
+ const total = contract.rules.length + (branches.length > 0 ? 1 : 0);
1462
2068
  const passCount = Object.values(scores).filter((s) => s === 1).length;
1463
2069
  const assumptions = [];
1464
- if (spans.length > 0 && ordered.every((s) => typeof s.startedAt !== "number")) assumptions.push("spans ordered by array position — no startedAt timestamps to order by");
1465
- for (const rule of contract.rules) if ([
1466
- rule.p,
1467
- rule.a,
1468
- rule.b,
1469
- rule.prior
1470
- ].some((p) => p !== void 0 && typeof p.custom === "function")) assumptions.push(`rule '${rule.label}' rests on a custom predicate function`);
2070
+ for (const rule of [...contract.rules, ...branches.flatMap((b) => b.alternative.rules)]) if (rulePredicates(rule).some(usesCustom)) assumptions.push(`rule '${rule.label}' rests on a custom predicate function`);
1471
2071
  return {
1472
2072
  contract: contract.name,
1473
- valid: passCount === ruleCount,
1474
- score: passCount / ruleCount,
2073
+ status,
2074
+ valid: status === "pass",
2075
+ score: passCount / total,
1475
2076
  scores,
1476
2077
  violations,
1477
- notes: `${passCount}/${ruleCount} rules passed`,
2078
+ ruleExecutions,
2079
+ errors,
2080
+ notes: `${passCount}/${total} rules passed` + (errors.length > 0 ? `; ${errors.length} could not be evaluated` : ""),
1478
2081
  certification: {
1479
2082
  strategy: "invariant",
1480
2083
  checker: {
@@ -1484,25 +2087,573 @@ function evaluateTraceContract(contract, spans) {
1484
2087
  assumptions,
1485
2088
  evidenceDigest: certificationEvidenceDigest({
1486
2089
  contract: contract.name,
2090
+ status,
1487
2091
  scores,
1488
- violations
2092
+ violations,
2093
+ ruleExecutions
1489
2094
  })
1490
2095
  }
1491
2096
  };
1492
2097
  }
2098
+ function execution(rule, alternative, outcome) {
2099
+ return {
2100
+ rule,
2101
+ ...alternative === void 0 ? {} : { alternative },
2102
+ status: outcome.status,
2103
+ violations: outcome.violations.length,
2104
+ ...outcome.error === void 0 ? {} : { error: outcome.error }
2105
+ };
2106
+ }
2107
+ function rulePredicates(rule) {
2108
+ switch (rule.kind) {
2109
+ case "precedes": return [rule.a, rule.b];
2110
+ case "neverUnless": return [rule.p, rule.prior];
2111
+ case "run": return [];
2112
+ default: return [rule.p];
2113
+ }
2114
+ }
2115
+ function usesCustom(p) {
2116
+ return typeof p.custom === "function" || p.not !== void 0 && usesCustom(p.not);
2117
+ }
1493
2118
  /**
1494
2119
  * Evaluate many contracts over one span sequence. Throws on an empty
1495
2120
  * contract list — `allValid: true` over zero contracts is a silent pass.
1496
2121
  */
1497
- function checkTraceContracts(spans, contracts) {
2122
+ function checkTraceContracts(spans, contracts, options = {}) {
1498
2123
  if (contracts.length === 0) throw new ValidationError("checkTraceContracts: empty contract list would vacuously pass — supply at least one contract");
1499
- const verdicts = contracts.map((c) => evaluateTraceContract(c, spans));
2124
+ const verdicts = contracts.map((c) => evaluateTraceContract(c, spans, options));
2125
+ const status = verdicts.some((v) => v.status === "error") ? "error" : verdicts.every((v) => v.status === "pass") ? "pass" : "fail";
1500
2126
  return {
1501
2127
  verdicts,
1502
- allValid: verdicts.every((v) => v.valid)
2128
+ status,
2129
+ allValid: status === "pass"
1503
2130
  };
1504
2131
  }
1505
2132
  //#endregion
2133
+ //#region src/trace-contracts/spec.ts
2134
+ /**
2135
+ * The declarative contract form: a JSON document that names tools, model
2136
+ * calls, and run limits, compiled onto the temporal operators.
2137
+ *
2138
+ * ```json
2139
+ * {
2140
+ * "name": "refund-agent",
2141
+ * "run": { "requireCompleted": true, "maxDurationMs": 120000 },
2142
+ * "tools": {
2143
+ * "required": ["lookup_order", "issue_refund"],
2144
+ * "forbidden": ["delete_account"],
2145
+ * "allowed": ["lookup_order", "issue_refund", "send_email"],
2146
+ * "maxCalls": 20,
2147
+ * "requiredOrder": ["lookup_order", "issue_refund"],
2148
+ * "arguments": [{ "tool": "issue_refund", "pointer": "/amount", "type": "number" }]
2149
+ * },
2150
+ * "llm": { "maxCalls": 10, "maxTotalTokens": 50000, "allowedModels": ["claude-sonnet-4-5"] },
2151
+ * "alternatives": { "anyOf": [{ "id": "cache-hit", "tools": { "required": ["read_cache"] } }] }
2152
+ * }
2153
+ * ```
2154
+ *
2155
+ * Parsing is strict: an unknown key anywhere is an error that names the
2156
+ * closest known key, so a typo never silently drops a check. Tool rules match
2157
+ * TOOL spans only and model rules match LLM spans only, so an LLM span that
2158
+ * shares a tool's name never satisfies a tool rule. `rules` accepts the
2159
+ * low-level operators for checks the declarative keys cannot state.
2160
+ */
2161
+ const PATH_KEYS = [
2162
+ "run",
2163
+ "tools",
2164
+ "llm",
2165
+ "rules"
2166
+ ];
2167
+ const SPEC_KEYS = [
2168
+ "name",
2169
+ "description",
2170
+ "scope",
2171
+ "alternatives",
2172
+ ...PATH_KEYS
2173
+ ];
2174
+ const ALTERNATIVE_KEYS = ["id", ...PATH_KEYS];
2175
+ const RUN_KEYS = [
2176
+ "requireCompleted",
2177
+ "allowedStatuses",
2178
+ "maxDurationMs"
2179
+ ];
2180
+ const TOOLS_KEYS = [
2181
+ "required",
2182
+ "forbidden",
2183
+ "allowed",
2184
+ "maxCalls",
2185
+ "maxCallsPerTool",
2186
+ "requiredOrder",
2187
+ "orderMode",
2188
+ "arguments"
2189
+ ];
2190
+ const LLM_KEYS = [
2191
+ "maxCalls",
2192
+ "maxTotalTokens",
2193
+ "allowedModels"
2194
+ ];
2195
+ const ARGUMENT_KEYS = [
2196
+ "tool",
2197
+ "pointer",
2198
+ "occurrence",
2199
+ "exists",
2200
+ "equals",
2201
+ "oneOf",
2202
+ "type"
2203
+ ];
2204
+ const ARGUMENT_CHECK_KEYS = [
2205
+ "exists",
2206
+ "equals",
2207
+ "oneOf",
2208
+ "type"
2209
+ ];
2210
+ const PREDICATE_KEYS = [
2211
+ "name",
2212
+ "tool",
2213
+ "model",
2214
+ "kind",
2215
+ "attr",
2216
+ "not"
2217
+ ];
2218
+ const MATCHER_KEYS = [
2219
+ "$regex",
2220
+ "flags",
2221
+ "oneOf"
2222
+ ];
2223
+ const RULE_KEYS = {
2224
+ always: [
2225
+ "kind",
2226
+ "label",
2227
+ "p"
2228
+ ],
2229
+ never: [
2230
+ "kind",
2231
+ "label",
2232
+ "p"
2233
+ ],
2234
+ eventually: [
2235
+ "kind",
2236
+ "label",
2237
+ "p"
2238
+ ],
2239
+ precedes: [
2240
+ "kind",
2241
+ "label",
2242
+ "a",
2243
+ "b",
2244
+ "order"
2245
+ ],
2246
+ neverUnless: [
2247
+ "kind",
2248
+ "label",
2249
+ "p",
2250
+ "prior",
2251
+ "order"
2252
+ ],
2253
+ atMost: [
2254
+ "kind",
2255
+ "label",
2256
+ "p",
2257
+ "max"
2258
+ ],
2259
+ tokensAtMost: [
2260
+ "kind",
2261
+ "label",
2262
+ "p",
2263
+ "max"
2264
+ ],
2265
+ run: [
2266
+ "kind",
2267
+ "label",
2268
+ ...RUN_KEYS
2269
+ ],
2270
+ argument: [
2271
+ "kind",
2272
+ "label",
2273
+ "p",
2274
+ "pointer",
2275
+ "check",
2276
+ "occurrence"
2277
+ ]
2278
+ };
2279
+ /**
2280
+ * Parse and compile a declarative contract. Throws `ValidationError` naming
2281
+ * the path of the first problem: an unknown key, a wrong type, an unknown
2282
+ * status, or a contract that checks nothing.
2283
+ */
2284
+ function compileTraceContractSpec(input) {
2285
+ const spec = parseSpec(input);
2286
+ const scope = spec.scope ? { root: normalizePredicate(spec.scope.root, "scope.root") } : void 0;
2287
+ const alternatives = spec.alternatives?.anyOf.map((alt) => ({
2288
+ id: alt.id,
2289
+ rules: compilePath(alt, "")
2290
+ }));
2291
+ const contract = {
2292
+ name: spec.name,
2293
+ ...spec.description === void 0 ? {} : { description: spec.description },
2294
+ ...scope === void 0 ? {} : { scope },
2295
+ rules: compilePath(spec, ""),
2296
+ ...alternatives === void 0 ? {} : { alternatives }
2297
+ };
2298
+ assertContract(contract, `contract spec "${spec.name}"`);
2299
+ return contract;
2300
+ }
2301
+ const toolCall = (tool) => ({
2302
+ kind: "TOOL",
2303
+ tool
2304
+ });
2305
+ const ANY_TOOL = { kind: "TOOL" };
2306
+ const ANY_LLM = { kind: "LLM" };
2307
+ function compilePath(path, prefix) {
2308
+ const at = (key) => prefix ? `${prefix}.${key}` : key;
2309
+ const rules = [];
2310
+ if (path.run) rules.push({
2311
+ kind: "run",
2312
+ label: at("run"),
2313
+ ...path.run
2314
+ });
2315
+ const tools = path.tools;
2316
+ if (tools) {
2317
+ for (const tool of tools.required ?? []) rules.push({
2318
+ kind: "eventually",
2319
+ label: at(`tools.required[${tool}]`),
2320
+ p: toolCall(tool)
2321
+ });
2322
+ for (const tool of tools.forbidden ?? []) rules.push({
2323
+ kind: "never",
2324
+ label: at(`tools.forbidden[${tool}]`),
2325
+ p: toolCall(tool)
2326
+ });
2327
+ if (tools.allowed) rules.push({
2328
+ kind: "never",
2329
+ label: at("tools.allowed"),
2330
+ p: {
2331
+ kind: "TOOL",
2332
+ not: { tool: { oneOf: [...tools.allowed] } }
2333
+ }
2334
+ });
2335
+ if (tools.maxCalls !== void 0) rules.push({
2336
+ kind: "atMost",
2337
+ label: at("tools.maxCalls"),
2338
+ p: ANY_TOOL,
2339
+ max: tools.maxCalls
2340
+ });
2341
+ for (const [tool, max] of Object.entries(tools.maxCallsPerTool ?? {})) rules.push({
2342
+ kind: "atMost",
2343
+ label: at(`tools.maxCallsPerTool[${tool}]`),
2344
+ p: toolCall(tool),
2345
+ max
2346
+ });
2347
+ const order = tools.requiredOrder ?? [];
2348
+ for (let i = 1; i < order.length; i++) rules.push({
2349
+ kind: "precedes",
2350
+ label: at(`tools.requiredOrder[${order[i - 1]}->${order[i]}]`),
2351
+ a: toolCall(order[i - 1]),
2352
+ b: toolCall(order[i]),
2353
+ ...tools.orderMode === void 0 ? {} : { order: tools.orderMode }
2354
+ });
2355
+ if (order.length === 1) rules.push({
2356
+ kind: "eventually",
2357
+ label: at(`tools.requiredOrder[${order[0]}]`),
2358
+ p: toolCall(order[0])
2359
+ });
2360
+ tools.arguments?.forEach((arg, i) => {
2361
+ const check = argumentCheck(arg);
2362
+ rules.push({
2363
+ kind: "argument",
2364
+ label: at(`tools.arguments[${i}] ${arg.tool} ${arg.pointer || "(whole value)"} ${describeCheck(check)}`),
2365
+ p: toolCall(arg.tool),
2366
+ pointer: arg.pointer,
2367
+ check,
2368
+ ...arg.occurrence === void 0 ? {} : { occurrence: arg.occurrence }
2369
+ });
2370
+ });
2371
+ }
2372
+ const llm = path.llm;
2373
+ if (llm) {
2374
+ if (llm.maxCalls !== void 0) rules.push({
2375
+ kind: "atMost",
2376
+ label: at("llm.maxCalls"),
2377
+ p: ANY_LLM,
2378
+ max: llm.maxCalls
2379
+ });
2380
+ if (llm.maxTotalTokens !== void 0) rules.push({
2381
+ kind: "tokensAtMost",
2382
+ label: at("llm.maxTotalTokens"),
2383
+ p: ANY_LLM,
2384
+ max: llm.maxTotalTokens
2385
+ });
2386
+ if (llm.allowedModels) rules.push({
2387
+ kind: "never",
2388
+ label: at("llm.allowedModels"),
2389
+ p: {
2390
+ kind: "LLM",
2391
+ not: { model: { oneOf: [...llm.allowedModels] } }
2392
+ }
2393
+ });
2394
+ }
2395
+ for (const rule of path.rules ?? []) rules.push({ ...rule });
2396
+ return rules;
2397
+ }
2398
+ function argumentCheck(arg) {
2399
+ if (arg.exists) return { op: "exists" };
2400
+ if ("equals" in arg) return {
2401
+ op: "equals",
2402
+ value: arg.equals
2403
+ };
2404
+ if (arg.oneOf) return {
2405
+ op: "oneOf",
2406
+ values: arg.oneOf
2407
+ };
2408
+ return {
2409
+ op: "type",
2410
+ type: arg.type
2411
+ };
2412
+ }
2413
+ function parseSpec(input) {
2414
+ const spec = object(input, "contract");
2415
+ strictKeys(spec, SPEC_KEYS, "contract");
2416
+ const name = nonEmptyString(spec.name, "name");
2417
+ if (spec.description !== void 0) nonEmptyString(spec.description, "description");
2418
+ if (spec.scope !== void 0) {
2419
+ const scope = object(spec.scope, "scope");
2420
+ strictKeys(scope, ["root"], "scope");
2421
+ predicate(scope.root, "scope.root");
2422
+ }
2423
+ parsePath(spec, "");
2424
+ if (spec.alternatives !== void 0) {
2425
+ const alternatives = object(spec.alternatives, "alternatives");
2426
+ strictKeys(alternatives, ["anyOf"], "alternatives");
2427
+ nonEmptyArray(alternatives.anyOf, "alternatives.anyOf").forEach((alt, i) => {
2428
+ const where = `alternatives.anyOf[${i}]`;
2429
+ const a = object(alt, where);
2430
+ strictKeys(a, ALTERNATIVE_KEYS, where);
2431
+ nonEmptyString(a.id, `${where}.id`);
2432
+ parsePath(a, where);
2433
+ });
2434
+ }
2435
+ return {
2436
+ ...spec,
2437
+ name
2438
+ };
2439
+ }
2440
+ function parsePath(path, prefix) {
2441
+ const at = (key) => prefix ? `${prefix}.${key}` : key;
2442
+ if (path.run !== void 0) {
2443
+ const run = object(path.run, at("run"));
2444
+ strictKeys(run, RUN_KEYS, at("run"));
2445
+ if (Array.isArray(run.allowedStatuses)) run.allowedStatuses.forEach((status, i) => {
2446
+ oneOfValues(status, RUN_STATUSES, at(`run.allowedStatuses[${i}]`));
2447
+ });
2448
+ assertRule({
2449
+ kind: "run",
2450
+ label: "run",
2451
+ ...run
2452
+ }, at("run"));
2453
+ }
2454
+ if (path.tools !== void 0) {
2455
+ const tools = object(path.tools, at("tools"));
2456
+ strictKeys(tools, TOOLS_KEYS, at("tools"));
2457
+ for (const key of [
2458
+ "required",
2459
+ "forbidden",
2460
+ "allowed",
2461
+ "requiredOrder"
2462
+ ]) if (tools[key] !== void 0) toolNames(tools[key], at(`tools.${key}`));
2463
+ if (tools.maxCalls !== void 0) count(tools.maxCalls, at("tools.maxCalls"));
2464
+ if (tools.maxCallsPerTool !== void 0) {
2465
+ const perTool = object(tools.maxCallsPerTool, at("tools.maxCallsPerTool"));
2466
+ for (const [tool, max] of Object.entries(perTool)) {
2467
+ nonEmptyString(tool, at("tools.maxCallsPerTool key"));
2468
+ count(max, at(`tools.maxCallsPerTool.${tool}`));
2469
+ }
2470
+ }
2471
+ if (tools.orderMode !== void 0) oneOfValues(tools.orderMode, ORDER_MODES, at("tools.orderMode"));
2472
+ if (tools.orderMode !== void 0 && tools.requiredOrder === void 0) throw new ValidationError(`${at("tools.orderMode")}: set only with requiredOrder`);
2473
+ if (tools.arguments !== void 0) nonEmptyArray(tools.arguments, at("tools.arguments")).forEach((arg, i) => {
2474
+ const where = at(`tools.arguments[${i}]`);
2475
+ const a = object(arg, where);
2476
+ strictKeys(a, ARGUMENT_KEYS, where);
2477
+ nonEmptyString(a.tool, `${where}.tool`);
2478
+ const checks = ARGUMENT_CHECK_KEYS.filter((k) => k in a);
2479
+ if (checks.length !== 1) throw new ValidationError(`${where}: set exactly one of ${ARGUMENT_CHECK_KEYS.join(", ")} (found ${checks.length})`);
2480
+ if (a.exists !== void 0 && a.exists !== true) throw new ValidationError(`${where}.exists: must be true`);
2481
+ if (a.oneOf !== void 0) nonEmptyArray(a.oneOf, `${where}.oneOf`);
2482
+ if (a.type !== void 0) oneOfValues(a.type, ARGUMENT_TYPES, `${where}.type`);
2483
+ if (a.occurrence !== void 0) oneOfValues(a.occurrence, ARGUMENT_OCCURRENCES, `${where}.occurrence`);
2484
+ assertRule({
2485
+ kind: "argument",
2486
+ label: "argument",
2487
+ p: toolCall(a.tool),
2488
+ pointer: a.pointer,
2489
+ check: argumentCheck(a)
2490
+ }, where);
2491
+ });
2492
+ }
2493
+ if (path.llm !== void 0) {
2494
+ const llm = object(path.llm, at("llm"));
2495
+ strictKeys(llm, LLM_KEYS, at("llm"));
2496
+ if (llm.maxCalls !== void 0) count(llm.maxCalls, at("llm.maxCalls"));
2497
+ if (llm.maxTotalTokens !== void 0) count(llm.maxTotalTokens, at("llm.maxTotalTokens"));
2498
+ if (llm.allowedModels !== void 0) toolNames(llm.allowedModels, at("llm.allowedModels"));
2499
+ }
2500
+ if (path.rules !== void 0) nonEmptyArray(path.rules, at("rules")).forEach((raw, i) => {
2501
+ const where = at(`rules[${i}]`);
2502
+ const rule = object(raw, where);
2503
+ const kind = oneOfValues(rule.kind, Object.keys(RULE_KEYS), `${where}.kind`);
2504
+ strictKeys(rule, RULE_KEYS[kind], where);
2505
+ for (const key of [
2506
+ "p",
2507
+ "a",
2508
+ "b",
2509
+ "prior"
2510
+ ]) if (rule[key] !== void 0) predicate(rule[key], `${where}.${key}`);
2511
+ if (kind === "argument" && rule.check !== void 0) strictKeys(object(rule.check, `${where}.check`), [
2512
+ "op",
2513
+ "value",
2514
+ "values",
2515
+ "type"
2516
+ ], `${where}.check`);
2517
+ assertRule(rule, where);
2518
+ });
2519
+ }
2520
+ function predicate(value, where) {
2521
+ const p = object(value, where);
2522
+ strictKeys(p, PREDICATE_KEYS, where);
2523
+ for (const key of [
2524
+ "name",
2525
+ "tool",
2526
+ "model"
2527
+ ]) {
2528
+ const m = p[key];
2529
+ if (m !== null && typeof m === "object" && !Array.isArray(m)) strictKeys(m, MATCHER_KEYS, `${where}.${key}`);
2530
+ }
2531
+ if (p.kind !== void 0) oneOfValues(p.kind, SPAN_KINDS, `${where}.kind`);
2532
+ if (p.not !== void 0) predicate(p.not, `${where}.not`);
2533
+ }
2534
+ function strictKeys(value, allowed, where) {
2535
+ for (const key of Object.keys(value)) {
2536
+ if (allowed.includes(key)) continue;
2537
+ const hint = closest(key, allowed);
2538
+ throw new ValidationError(`${where}: unknown key "${key}"${hint ? ` — did you mean "${hint}"?` : ""} (allowed: ${allowed.join(", ")})`);
2539
+ }
2540
+ }
2541
+ function object(value, where) {
2542
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new ValidationError(`${where}: must be an object`);
2543
+ return value;
2544
+ }
2545
+ function nonEmptyString(value, where) {
2546
+ if (typeof value !== "string" || value.trim().length === 0) throw new ValidationError(`${where}: must be a non-empty string`);
2547
+ return value;
2548
+ }
2549
+ function nonEmptyArray(value, where) {
2550
+ if (!Array.isArray(value) || value.length === 0) throw new ValidationError(`${where}: must be a non-empty array`);
2551
+ return value;
2552
+ }
2553
+ function toolNames(value, where) {
2554
+ const names = nonEmptyArray(value, where).map((v, i) => nonEmptyString(v, `${where}[${i}]`));
2555
+ const dup = names.find((n, i) => names.indexOf(n) !== i);
2556
+ if (dup !== void 0) throw new ValidationError(`${where}: "${dup}" is listed twice`);
2557
+ return names;
2558
+ }
2559
+ function count(value, where) {
2560
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) throw new ValidationError(`${where}: must be a non-negative integer`);
2561
+ }
2562
+ function oneOfValues(value, allowed, where) {
2563
+ if (typeof value === "string" && allowed.includes(value)) return value;
2564
+ const hint = typeof value === "string" ? closest(value, allowed) : void 0;
2565
+ throw new ValidationError(`${where}: ${JSON.stringify(value)} is not one of ${allowed.join(", ")}${hint ? ` — did you mean "${hint}"?` : ""}`);
2566
+ }
2567
+ /** The allowed word within edit distance 2 (or a case-insensitive match). */
2568
+ function closest(word, allowed) {
2569
+ let best;
2570
+ for (const candidate of allowed) {
2571
+ const d = candidate.toLowerCase() === word.toLowerCase() ? 0 : editDistance(word.toLowerCase(), candidate.toLowerCase());
2572
+ if (d <= 2 && (!best || d < best.d)) best = {
2573
+ word: candidate,
2574
+ d
2575
+ };
2576
+ }
2577
+ return best?.word;
2578
+ }
2579
+ function editDistance(a, b) {
2580
+ let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
2581
+ for (let i = 1; i <= a.length; i++) {
2582
+ const cur = [i];
2583
+ for (let j = 1; j <= b.length; j++) cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
2584
+ prev = cur;
2585
+ }
2586
+ return prev[b.length];
2587
+ }
2588
+ /**
2589
+ * Find contradictions and likely mistakes in a declarative contract. Parses
2590
+ * strictly first, so a malformed spec throws instead of linting.
2591
+ */
2592
+ function lintTraceContractSpec(input) {
2593
+ const spec = parseSpec(input);
2594
+ const findings = [];
2595
+ lintPath(spec, "", findings);
2596
+ for (const [i, alt] of (spec.alternatives?.anyOf ?? []).entries()) lintPath(alt, `alternatives.anyOf[${i}]`, findings);
2597
+ if (spec.alternatives?.anyOf.length === 1) findings.push({
2598
+ level: "warning",
2599
+ code: "alternatives.single",
2600
+ path: "alternatives.anyOf",
2601
+ message: "one alternative is the same as base checks; move its checks to the base or add another path"
2602
+ });
2603
+ const ids = spec.alternatives?.anyOf.map((a) => a.id) ?? [];
2604
+ const dupId = ids.find((id, i) => ids.indexOf(id) !== i);
2605
+ if (dupId !== void 0) findings.push({
2606
+ level: "error",
2607
+ code: "alternatives.duplicate-id",
2608
+ path: "alternatives.anyOf",
2609
+ message: `alternative id "${dupId}" is used twice`
2610
+ });
2611
+ return findings;
2612
+ }
2613
+ function lintPath(path, prefix, out) {
2614
+ const at = (key) => prefix ? `${prefix}.${key}` : key;
2615
+ const error = (code, key, message) => out.push({
2616
+ level: "error",
2617
+ code,
2618
+ path: at(key),
2619
+ message
2620
+ });
2621
+ const warn = (code, key, message) => out.push({
2622
+ level: "warning",
2623
+ code,
2624
+ path: at(key),
2625
+ message
2626
+ });
2627
+ const t = path.tools ?? {};
2628
+ const forbidden = new Set(t.forbidden ?? []);
2629
+ const allowed = t.allowed ? new Set(t.allowed) : void 0;
2630
+ const needed = [...t.required ?? [], ...t.requiredOrder ?? []];
2631
+ for (const tool of needed) {
2632
+ if (forbidden.has(tool)) error("tools.required-and-forbidden", "tools", `"${tool}" is both required and forbidden`);
2633
+ if (allowed && !allowed.has(tool)) error("tools.required-not-allowed", "tools.allowed", `"${tool}" is required but not in allowed`);
2634
+ if (t.maxCallsPerTool?.[tool] === 0) error("tools.required-capped-at-zero", "tools.maxCallsPerTool", `"${tool}" is required but capped at 0 calls`);
2635
+ }
2636
+ if (t.maxCalls === 0 && needed.length > 0) error("tools.required-but-no-calls", "tools.maxCalls", "tools are required but maxCalls is 0");
2637
+ const distinctNeeded = new Set(needed).size;
2638
+ if (t.maxCalls !== void 0 && t.maxCalls > 0 && distinctNeeded > t.maxCalls) error("tools.max-below-required", "tools.maxCalls", `${distinctNeeded} distinct tools are required but maxCalls is ${t.maxCalls}`);
2639
+ for (const tool of forbidden) {
2640
+ if (allowed?.has(tool)) error("tools.allowed-and-forbidden", "tools", `"${tool}" is both allowed and forbidden`);
2641
+ if (t.maxCallsPerTool?.[tool] !== void 0) warn("tools.cap-on-forbidden", "tools.maxCallsPerTool", `"${tool}" is forbidden, so its call cap never applies`);
2642
+ }
2643
+ for (const tool of Object.keys(t.maxCallsPerTool ?? {})) if (allowed && !allowed.has(tool)) warn("tools.cap-on-disallowed", "tools.maxCallsPerTool", `"${tool}" has a cap but is not in allowed`);
2644
+ for (const [i, arg] of (t.arguments ?? []).entries()) {
2645
+ if (forbidden.has(arg.tool)) error("tools.argument-on-forbidden", `tools.arguments[${i}]`, `"${arg.tool}" is forbidden, so its arguments can never be checked`);
2646
+ if (!needed.includes(arg.tool)) warn("tools.argument-without-required", `tools.arguments[${i}]`, `"${arg.tool}" is not required; a run that never calls it fails this check for missing evidence`);
2647
+ }
2648
+ const order = t.requiredOrder ?? [];
2649
+ const repeated = order.find((tool, i) => order.indexOf(tool) !== i);
2650
+ if (repeated !== void 0) error("tools.order-repeats", "tools.requiredOrder", `"${repeated}" appears twice, so the order contradicts itself`);
2651
+ if (order.length > 1 && t.orderMode === void 0) warn("tools.order-default-mode", "tools.orderMode", "start-order passes when calls overlap; set finish-before-start if each step must finish first");
2652
+ const run = path.run;
2653
+ if (run?.requireCompleted && run.allowedStatuses?.includes("running")) error("run.running-and-completed", "run", "requireCompleted contradicts allowedStatuses containing \"running\"");
2654
+ if (path.llm?.maxCalls === 0 && (path.llm.maxTotalTokens !== void 0 || path.llm.allowedModels)) warn("llm.no-calls", "llm", "maxCalls is 0, so the token and model limits never apply");
2655
+ }
2656
+ //#endregion
1506
2657
  //#region src/active-learning.ts
1507
2658
  async function proposeSynthesisTargets(dataset, traceStore, options = {}) {
1508
2659
  const minPerBand = options.minPerBand ?? 5;
@@ -2108,7 +3259,7 @@ async function runAgentControlLoop(config) {
2108
3259
  const started = Date.now();
2109
3260
  const wallTimer = budget.maxWallMs ? setTimeout(() => controller.abort(/* @__PURE__ */ new Error("control runtime wall timeout")), budget.maxWallMs) : void 0;
2110
3261
  const history = [];
2111
- const emitter = config.store ? new TraceEmitter(config.store) : void 0;
3262
+ const emitter = config.store ? new TraceEmitter(config.store, { onCaptureError: () => void 0 }) : void 0;
2112
3263
  let spentCostUsd = 0;
2113
3264
  const runtimeErrors = [];
2114
3265
  const repeatedDetector = repeatedActionDetector({ maxRepeated: config.stopPolicies?.maxRepeatedActions ?? 0 });
@@ -2117,7 +3268,7 @@ async function runAgentControlLoop(config) {
2117
3268
  minScoreDelta: config.stopPolicies?.minScoreDelta ?? .001
2118
3269
  });
2119
3270
  try {
2120
- if (emitter) await runTrace(runtimeErrors, 0, () => emitter.startRun({
3271
+ if (emitter) await runTrace(emitter, runtimeErrors, 0, () => emitter.startRun({
2121
3272
  scenarioId: config.scenarioId ?? "agent-control-loop",
2122
3273
  projectId: config.projectId,
2123
3274
  variantId: config.variantId,
@@ -2322,7 +3473,7 @@ async function runAgentControlLoop(config) {
2322
3473
  const evalsBefore = evals;
2323
3474
  const scoreBefore = averageScore(evals);
2324
3475
  const actionStarted = Date.now();
2325
- const stepHandle = emitter ? await runTrace(runtimeErrors, stepIndex, () => emitter.tool({
3476
+ const stepHandle = emitter ? await runTrace(emitter, runtimeErrors, stepIndex, () => emitter.tool({
2326
3477
  name: `control-step-${stepIndex}`,
2327
3478
  toolName: "agent-control-action",
2328
3479
  args: decision.action,
@@ -2360,7 +3511,7 @@ async function runAgentControlLoop(config) {
2360
3511
  durationMs: Date.now() - actionStarted
2361
3512
  };
2362
3513
  if (actionFailure === "stop") {
2363
- await runTrace(runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed"));
3514
+ await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed"));
2364
3515
  const step = {
2365
3516
  index: stepIndex,
2366
3517
  decision,
@@ -2411,7 +3562,7 @@ async function runAgentControlLoop(config) {
2411
3562
  endedAt: (/* @__PURE__ */ new Date()).toISOString()
2412
3563
  };
2413
3564
  history.push(step);
2414
- await runTrace(runtimeErrors, stepIndex, () => stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1].message));
3565
+ await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1].message));
2415
3566
  await runOnStep(config.onStep, step, runtimeErrors);
2416
3567
  return finish(emitter, {
2417
3568
  intent: config.intent,
@@ -2452,7 +3603,7 @@ async function runAgentControlLoop(config) {
2452
3603
  endedAt: (/* @__PURE__ */ new Date()).toISOString()
2453
3604
  };
2454
3605
  history.push(step);
2455
- await runTrace(runtimeErrors, stepIndex, () => stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1].message));
3606
+ await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1].message));
2456
3607
  await runOnStep(config.onStep, step, runtimeErrors);
2457
3608
  return finish(emitter, {
2458
3609
  intent: config.intent,
@@ -2490,14 +3641,14 @@ async function runAgentControlLoop(config) {
2490
3641
  endedAt: (/* @__PURE__ */ new Date()).toISOString()
2491
3642
  };
2492
3643
  history.push(step);
2493
- if (actionOutcome.ok) await runTrace(runtimeErrors, stepIndex, () => stepHandle?.end({ attributes: {
3644
+ if (actionOutcome.ok) await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.end({ attributes: {
2494
3645
  actionCostUsd: actionOutcome.costUsd ?? null,
2495
3646
  spentCostUsd,
2496
3647
  scoreBefore: scoreBefore ?? null,
2497
3648
  scoreAfter: scoreAfter ?? null,
2498
3649
  noProgressStreak
2499
3650
  } }));
2500
- else await runTrace(runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed", { attributes: {
3651
+ else await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed", { attributes: {
2501
3652
  spentCostUsd,
2502
3653
  noProgressStreak
2503
3654
  } }));
@@ -2703,7 +3854,7 @@ function budgetStopDecision(budget, spentCostUsd) {
2703
3854
  async function recordCostBudget(emitter, budget, spentCostUsd, handle, runtimeErrors, stepIndex) {
2704
3855
  if (!emitter || budget.maxCostUsd === void 0) return;
2705
3856
  const maxCostUsd = budget.maxCostUsd;
2706
- await runTrace(runtimeErrors, stepIndex, () => emitter.recordBudget({
3857
+ await runTrace(emitter, runtimeErrors, stepIndex, () => emitter.recordBudget({
2707
3858
  dimension: "usd",
2708
3859
  limit: maxCostUsd,
2709
3860
  consumed: spentCostUsd,
@@ -2714,7 +3865,7 @@ async function recordCostBudget(emitter, budget, spentCostUsd, handle, runtimeEr
2714
3865
  }
2715
3866
  async function recordEvalSpans(emitter, evals, phase, runtimeErrors, stepIndex, targetSpanId) {
2716
3867
  if (!emitter) return;
2717
- for (const result of evals) await runTrace(runtimeErrors, stepIndex, () => emitter.recordJudge({
3868
+ for (const result of evals) await runTrace(emitter, runtimeErrors, stepIndex, () => emitter.recordJudge({
2718
3869
  judgeId: result.objective ? "objective-validator" : "subjective-judge",
2719
3870
  targetSpanId: targetSpanId ?? emitter.runId,
2720
3871
  name: `control-eval/${result.id}`,
@@ -2738,13 +3889,24 @@ async function runOnStep(onStep, step, runtimeErrors) {
2738
3889
  runtimeErrors.push(runtimeError("on-step", step.index, err));
2739
3890
  }
2740
3891
  }
2741
- async function runTrace(runtimeErrors, stepIndex, write) {
3892
+ /**
3893
+ * Run trace writes and record a `trace` runtime error when any of them was
3894
+ * dropped. The emitter never throws a failed store write; it counts it, so the
3895
+ * count is what this reads. A throw from building the write is recorded too.
3896
+ */
3897
+ async function runTrace(emitter, runtimeErrors, stepIndex, write) {
3898
+ if (!emitter) return void 0;
3899
+ const droppedBefore = emitter.captureStats().dropped;
3900
+ let value;
2742
3901
  try {
2743
- return await write();
3902
+ value = await write();
2744
3903
  } catch (err) {
2745
3904
  runtimeErrors.push(runtimeError("trace", stepIndex, err));
2746
3905
  return;
2747
3906
  }
3907
+ const after = emitter.captureStats();
3908
+ if (after.dropped > droppedBefore) runtimeErrors.push(runtimeError("trace", stepIndex, after.lastError ?? "trace write dropped"));
3909
+ return value;
2748
3910
  }
2749
3911
  function fingerprintState(state, policies) {
2750
3912
  if (policies?.stateFingerprint) return policies.stateFingerprint(state);
@@ -2778,7 +3940,7 @@ function runtimeError(phase, stepIndex, err) {
2778
3940
  };
2779
3941
  }
2780
3942
  async function finish(emitter, result) {
2781
- await runTrace(result.runtimeErrors, result.steps.length, () => emitter?.endRun({
3943
+ await runTrace(emitter, result.runtimeErrors, result.steps.length, () => emitter?.endRun({
2782
3944
  pass: result.pass,
2783
3945
  score: result.score ?? averageScore(result.finalEvals),
2784
3946
  failureClass: result.failureClass,
@@ -2836,6 +3998,119 @@ async function discoverPersonas(dir, opts = {}) {
2836
3998
  return results;
2837
3999
  }
2838
4000
  //#endregion
4001
+ //#region src/improvement-verdict.ts
4002
+ const DEFAULTS = {
4003
+ keepThreshold: 5,
4004
+ regressionThreshold: 5,
4005
+ iqrUnstableAbove: 10,
4006
+ stddevUnstableAbove: Number.POSITIVE_INFINITY,
4007
+ minRepsForVerdict: 3
4008
+ };
4009
+ function resolveThresholds(t) {
4010
+ const r = {
4011
+ ...DEFAULTS,
4012
+ ...t ?? {}
4013
+ };
4014
+ if (r.keepThreshold < 0) throw new ValidationError(`improvement-verdict: keepThreshold must be >= 0, got ${r.keepThreshold}`);
4015
+ if (r.regressionThreshold < 0) throw new ValidationError(`improvement-verdict: regressionThreshold must be >= 0, got ${r.regressionThreshold}`);
4016
+ if (r.minRepsForVerdict < 1) throw new ValidationError(`improvement-verdict: minRepsForVerdict must be >= 1, got ${r.minRepsForVerdict}`);
4017
+ return r;
4018
+ }
4019
+ function median(sorted) {
4020
+ const n = sorted.length;
4021
+ if (n === 0) return 0;
4022
+ const mid = Math.floor(n / 2);
4023
+ return n % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
4024
+ }
4025
+ /** Population standard deviation (÷n). 0 for fewer than 2 values. */
4026
+ function stddev(values, mean) {
4027
+ if (values.length < 2) return 0;
4028
+ const variance = values.reduce((acc, v) => acc + (v - mean) ** 2, 0) / values.length;
4029
+ return Math.sqrt(variance);
4030
+ }
4031
+ /**
4032
+ * Compute the N-rep statistics for a set of reps. Pure — no I/O. The `stable`
4033
+ * flag is the trust gate the verdict depends on: a sample whose spread exceeds
4034
+ * the configured bounds can't distinguish a real delta from run-to-run noise.
4035
+ */
4036
+ function computeExperimentStats(reps, thresholds) {
4037
+ const t = resolveThresholds(thresholds);
4038
+ const n = reps.length;
4039
+ if (n === 0) return {
4040
+ median: 0,
4041
+ mean: 0,
4042
+ min: 0,
4043
+ max: 0,
4044
+ iqr: 0,
4045
+ stddev: 0,
4046
+ passRate: null,
4047
+ n: 0,
4048
+ stable: false
4049
+ };
4050
+ const scores = reps.map((r) => {
4051
+ if (!Number.isFinite(r.score)) throw new ValidationError(`improvement-verdict: rep ${r.rep} has non-finite score ${r.score}`);
4052
+ return r.score;
4053
+ });
4054
+ const sorted = [...scores].sort((a, b) => a - b);
4055
+ const mean = scores.reduce((s, v) => s + v, 0) / n;
4056
+ const sd = stddev(scores, mean);
4057
+ const spread = iqr(scores);
4058
+ const rated = reps.filter((r) => typeof r.passed === "boolean");
4059
+ const passRate = rated.length === 0 ? null : rated.filter((r) => r.passed).length / rated.length;
4060
+ const stable = spread < t.iqrUnstableAbove && sd < t.stddevUnstableAbove;
4061
+ return {
4062
+ median: median(sorted),
4063
+ mean,
4064
+ min: sorted[0],
4065
+ max: sorted[n - 1],
4066
+ iqr: spread,
4067
+ stddev: sd,
4068
+ passRate,
4069
+ n,
4070
+ stable
4071
+ };
4072
+ }
4073
+ /**
4074
+ * Verdict for a candidate against its parent. Pure — operates on already-computed
4075
+ * stats. KEEP/REGRESSION require both sides to have `>= minRepsForVerdict` reps
4076
+ * AND the candidate to be `stable`; otherwise the result is NOISE (unstable) or
4077
+ * ITERATE (not enough reps / no parent).
4078
+ */
4079
+ function improvementVerdict(candidate, parent, thresholds) {
4080
+ const t = resolveThresholds(thresholds);
4081
+ if (!parent) return {
4082
+ verdict: "ITERATE",
4083
+ medianDelta: null,
4084
+ reason: "no parent experiment to compare against"
4085
+ };
4086
+ if (candidate.n < t.minRepsForVerdict || parent.n < t.minRepsForVerdict) return {
4087
+ verdict: "ITERATE",
4088
+ medianDelta: null,
4089
+ reason: `need >= ${t.minRepsForVerdict} reps on both sides (candidate n=${candidate.n}, parent n=${parent.n})`
4090
+ };
4091
+ if (!candidate.stable) return {
4092
+ verdict: "NOISE",
4093
+ medianDelta: candidate.median - parent.median,
4094
+ reason: `candidate unstable (iqr=${candidate.iqr}, stddev=${candidate.stddev.toFixed(2)})`
4095
+ };
4096
+ const medianDelta = candidate.median - parent.median;
4097
+ if (medianDelta > t.keepThreshold) return {
4098
+ verdict: "KEEP",
4099
+ medianDelta,
4100
+ reason: `median +${medianDelta} > +${t.keepThreshold}`
4101
+ };
4102
+ if (medianDelta < -t.regressionThreshold) return {
4103
+ verdict: "REGRESSION",
4104
+ medianDelta,
4105
+ reason: `median ${medianDelta} < -${t.regressionThreshold}`
4106
+ };
4107
+ return {
4108
+ verdict: "NOISE",
4109
+ medianDelta,
4110
+ reason: `median delta ${medianDelta} inside noise band [-${t.regressionThreshold}, +${t.keepThreshold}]`
4111
+ };
4112
+ }
4113
+ //#endregion
2839
4114
  //#region src/propose-review.ts
2840
4115
  /**
2841
4116
  * Propose / Verify / Review — the core multi-shot primitive.
@@ -8311,6 +9586,6 @@ function rankRows(rows, weights) {
8311
9586
  })).sort((a, b) => b.mean - a.mean);
8312
9587
  }
8313
9588
  //#endregion
8314
- export { AGENT_PROFILE_KINDS, ATTESTATION_ALGORITHM, AgentEvalError, AnalystRegistry, BOOTSTRAP_GATE_MIN_N, BackendIntegrityError, BudgetBreachError, BudgetGuard, CODING_HARNESSES, ConfigError, CostAccountingIncompleteError, CostCallConflictError, CostCeilingReachedError, CostLedger, CostLedgerPersistenceError, CostReceiptCaptureError, CostReservationExceededError, CostTracker, CrossFamilyError, DECISION_PAIRED_DELTA_STATISTIC, DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS, DEFAULT_FAILURE_REASON_RULES, DEFAULT_PERMUTATIONS, DEFAULT_REDACTION_RULES, DEFAULT_RED_TEAM_CORPUS, DEFAULT_TRACE_ANALYST_BUDGETS, DEFAULT_TRACE_ANALYST_KINDS, DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS, ERROR_COUNT_PATTERNS, EquivalenceProtocolError, FAILURE_BLAME, FAILURE_CLASSES, FAILURE_MODE_KIND_SPEC, FileSystemFeedbackTrajectoryStore, FileSystemRawProviderSink, FileSystemTraceStore, FindingsStore, HARNESS_NATIVE_MODEL, HeldOutGate, INFRA_FAILURE_BLAMES, InMemoryFeedbackTrajectoryStore, InMemoryRawProviderSink, InMemoryTraceStore, JudgeError, LOCAL_COMMAND_RUNNER_DEFAULT_CAP_MS, LlmCallError, LlmResponseError, MANN_WHITNEY_EXACT_MAX_STATES, MANN_WHITNEY_EXACT_MAX_WORK, MODEL_PRICING, ModelSubstitutionError, MultiLayerVerifier, NoopRawProviderSink, NotFoundError, OUTPUT_VALUE, OtlpFileTraceStore, POLICY_EDIT_AXES, POLICY_EDIT_CANDIDATE_RECORD_SCHEMA, POLICY_EDIT_TARGET_SURFACES, PairwiseSteeringOptimizer, PolicyEditValidationError, ProductClient, PromptRegistry, REDACTION_VERSION, RunIntegrityError, RunRecordValidationError, SEMANTIC_CONCEPT_JUDGE_VERSION, ServedCrossFamilyError, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TraceEmitter, UNKNOWN_MODEL, VERIFICATION_STRATEGIES, VERIFICATION_STRATEGY_SOURCES, ValidationError, WILCOXON_EXACT_MAX_N, acquisitionPlansForKnowledgeGaps, admitPolicyEdit, agentProfileCellHashMaterial, agentProfileCellKey, agentProfileHash, agentProfileId, aggregateJudgeVerdicts, aggregateRunScore, analystFindingDigest, analystRunDigest, analystRunToFeedbackTrajectory, analystRunToReviewRequests, analyzeAntiSlop, analyzeRuns, analyzeSeries, analyzeTraces, applyPolicyEditToSurface, argHash, assertCapabilityHeadroom, assertCrossFamily, assertCrossFamilyServed, assertNoHiddenLeak, assertNoJudgeVerdict, assertProductBenchmarkRun, assertRealBackend, assertRunCaptured, assertServedModel, assertServedModels, assertSingleBackend, assignFeedbackSplit, attest, benjaminiHochberg, blendHeldout, blockingKnowledgeEval, bonferroni, bootstrapCi, budgetBreachView, buildAgentProfileCell, buildDefaultAnalystRegistry, buildEquivalenceRecord, buildReflectionPrompt, buildTraceInsightContext, buildTraceInsightPrompt, buildTrajectory, calibrateJudge, calibrateJudgeContinuous, canonicalJson, capabilityHeadroom, captureFetchToRawSink, certificationEvidenceDigest, checkCanaries, checkServedModel, checkTraceContracts, clamp01, classifyFailure, classifyFailureReason, cliffsDelta, cohensD, comparePairedArms, completionVerdict, computeExperimentStats, computeFindingId, computePolicyEditId, computeToolUseMetrics, confidenceInterval, contentHash, continuousAgreement, controlRunToFeedbackTrajectory, corpusInterRaterAgreement, corpusInterRaterAgreementFromJudgeScores, costForTokenPricing, costForUsage, costReceiptFromLlm, costReceiptFromLlmError, createAntiSlopJudge, createBoundedTraceAnalysisStore, createChatClient, createChatTraceEngine, createDspyRlmTraceEngine, createFeedbackTrajectory, createLlmCorrectnessChecker, createLlmReviewer, createTraceAnalyst, decidePairedPromotion, defaultBlendWeights, defineAgentEval, defineEquivalenceCheck, deployGateLayer, describeTraceInsightScope, diffFindings, diffScorecard, discoverPersonas, domainEvidencePattern, dominates, eProcess, ensembleJudge, equivalenceVerdict, errorStreakDetector, estimateCost, estimateTokens, evaluateActionPolicy, evaluateInterimReleaseConfidence, evaluateOracles, evaluateReleaseConfidence, expandProfileAxes, exportProductBenchmark, exportProductBenchmarkRuns, exportRunAsOtlp, extractErrorCount, extractProducedState, extractUsage, extractUsageFromSse, failureBlame, failureClusterView, feedbackTrajectoriesToDatasetScenarios, feedbackTrajectoriesToOptimizerRows, feedbackTrajectoryToOptimizerRow, fileVerdictCache, formatScorecardDiff, gainHistogram, gateTreatmentApplied, gradeOnHidden, gradeSemanticStatus, groupRunsByAgentProfileCell, harnessAxisOf, hashContent, hashJson, hiddenGrade, holm, improvementVerdict, inMemoryReviewStore, inferDomainKeywords, interRaterReliability, interpretCliffs, iqr, isBinaryOutcomeVector, isJudgeSpan, isLlmSpan, isModelPriced, isPolicyEdit, isRunRecord, isToolSpan, isTransientLlmError, jsonShape, jsonlReviewStore, jsonlRunRecordBackend, judgeAgreementView, judgeFamily, judgeSpans, knowledgeReadinessTracePayload, leaderboard, llmJudge, loadScorecard, localCommandRunner, makeFinding, makePolicyEdit, makePolicyEditCandidateRecord, makeProposalFinding, manifestContentDigest, mannWhitneyU, maximumChargeForLlmRequest, mcnemar, mcnemarPower, mcnemarRequiredN, minimumPairsForPairedDeltaTest, mintRolloutRows, modelHasSnapshot, modelPriceKey, mulberry32, notBlocked, objectiveEval, observeAll, otlpTextToTraceAnalysisStore, pairArms, pairRunRecords, pairedBinaryScale, pairedBootstrap, pairedCohensDz, pairedDeltaTest, pairedDeltaTieFraction, pairedEvalueSequence, pairedMde, pairedPromotionPower, pairedRiskDifference, pairedRiskDifferenceExact, pairedRiskDifferenceScore, pairedSignTest, pairedTTest, paretoChart, paretoFrontier, parseReflectionResponse, parseRunRecordSafe, partialCredit, partitionHeldOut, partitionTrainSelectionTest, passAtK, pearsonR, policyEditFromFinding, policyEditsFromFindings, preflightModels, productBenchmarkRepoIdentity, profile_exports as profile, projectRuntimeTrajectoryEvidence, proposeSynthesisTargets, quotaExhaustedUntil, ranks, readProductBenchmarkManifest, recordRuns, recordRunsToScorecard, redTeamDataset, redTeamReport, redactString, regexMatches, renderPreferenceMemoryMarkdown, repeatedActionDetector, requiredPairedSampleSize, requiredPairsForPairedPromotion, requiredSampleSize, resolveModelPricing, resolveSeat, roundTripRunRecord, routeFields, runAgentControlLoop, runBoundedProcess, runCampaign, runCanaries, runCounterfactual, runEquivalenceCheck, runEvalCampaign, runIntentMatchJudge, runKeywordCoverageJudge, runKeywordCoverageJudgeUrl, runProposeReview, runProposeReviewAsControlLoop, runSemanticConceptJudge, runTaskScore, runsForScenario, scoreKnowledgeReadiness, scorePolicyEditReadiness, scoreRedTeamOutput, scoreTraceInsightReadiness, seatPresets, selfImprove, servedModelAcceptable, spearmanR, stripFencedJson, subjectiveEval, summarizeBackendIntegrity, summarizeNumberSeries, summarizePreferenceMemory, summaryTable, textInSnapshot, toAgentProfileJson, tokenizeDomainWords, toolSpansToTraceAnalysisStore, toolWasteView, traceContract, transientDispatchFailure, urlContains, userQuestionsForKnowledgeGaps, validatePolicyEdit, validatePolicyEditCandidateRecord, validateRunRecord, verbosityBias, verifyAgentProfileCell, verifyAttestation, verifyCompletion, viteDeployRunner, weightedComposite, weightedMean, wilcoxonSignedRank, wilson, withAssignedFeedbackSplit, withHeldoutBlend, withJudgeRetry, wranglerDeployRunner };
9589
+ export { AGENT_PROFILE_KINDS, ATTESTATION_ALGORITHM, AgentEvalError, AnalystRegistry, BOOTSTRAP_GATE_MIN_N, BackendIntegrityError, BudgetBreachError, BudgetGuard, CODING_HARNESSES, ConfigError, CostAccountingIncompleteError, CostCallConflictError, CostCeilingReachedError, CostLedger, CostLedgerPersistenceError, CostReceiptCaptureError, CostReservationExceededError, CostTracker, CrossFamilyError, DECISION_PAIRED_DELTA_STATISTIC, DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS, DEFAULT_FAILURE_REASON_RULES, DEFAULT_PERMUTATIONS, DEFAULT_RED_TEAM_CORPUS, DEFAULT_TRACE_ANALYST_BUDGETS, DEFAULT_TRACE_ANALYST_KINDS, DEFAULT_TRACE_ANALYST_OUTPUT_TOKENS, ERROR_COUNT_PATTERNS, EquivalenceProtocolError, FAILURE_BLAME, FAILURE_CLASSES, FAILURE_MODE_KIND_SPEC, FileSystemFeedbackTrajectoryStore, FileSystemRawProviderSink, FileSystemTraceStore, FindingsStore, HARNESS_NATIVE_MODEL, HeldOutGate, INFRA_FAILURE_BLAMES, InMemoryFeedbackTrajectoryStore, InMemoryRawProviderSink, InMemoryTraceStore, JudgeError, LOCAL_COMMAND_RUNNER_DEFAULT_CAP_MS, LlmCallError, LlmResponseError, MANN_WHITNEY_EXACT_MAX_STATES, MANN_WHITNEY_EXACT_MAX_WORK, MODEL_PRICING, ModelSubstitutionError, MultiLayerVerifier, NoopRawProviderSink, NotFoundError, OUTPUT_VALUE, OtlpFileTraceStore, POLICY_EDIT_AXES, POLICY_EDIT_CANDIDATE_RECORD_SCHEMA, POLICY_EDIT_TARGET_SURFACES, PairwiseSteeringOptimizer, PolicyEditValidationError, ProductClient, PromptRegistry, REDACTION_VERSION, RunIntegrityError, RunRecordValidationError, SEMANTIC_CONCEPT_JUDGE_VERSION, ServedCrossFamilyError, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TraceEmitter, UNKNOWN_MODEL, VERIFICATION_STRATEGIES, VERIFICATION_STRATEGY_SOURCES, ValidationError, WILCOXON_EXACT_MAX_N, acquisitionPlansForKnowledgeGaps, admitPolicyEdit, agentProfileCellHashMaterial, agentProfileCellKey, agentProfileHash, agentProfileId, aggregateJudgeVerdicts, aggregateRunScore, analystFindingDigest, analystRunDigest, analystRunToFeedbackTrajectory, analystRunToReviewRequests, analyzeAntiSlop, analyzeRuns, analyzeSeries, analyzeTraces, applyPolicyEditToSurface, argHash, assertCapabilityHeadroom, assertCrossFamily, assertCrossFamilyServed, assertNoHiddenLeak, assertNoJudgeVerdict, assertProductBenchmarkRun, assertRealBackend, assertRunCaptured, assertServedModel, assertServedModels, assertSingleBackend, assessShareSafety, assignFeedbackSplit, attest, benjaminiHochberg, blendHeldout, blockingKnowledgeEval, bonferroni, bootstrapCi, budgetBreachView, buildAgentProfileCell, buildDefaultAnalystRegistry, buildEquivalenceRecord, buildReflectionPrompt, buildTraceInsightContext, buildTraceInsightPrompt, buildTrajectory, calibrateJudge, calibrateJudgeContinuous, canonicalJson, capabilityHeadroom, captureFetchToRawSink, certificationEvidenceDigest, checkCanaries, checkServedModel, checkTraceContracts, clamp01, classifyFailure, classifyFailureReason, cliffsDelta, cohensD, comparePairedArms, compileTraceContractSpec, completionVerdict, computeExperimentStats, computeFindingId, computePolicyEditId, computeToolUseMetrics, confidenceInterval, contentHash, continuousAgreement, controlRunToFeedbackTrajectory, corpusInterRaterAgreement, corpusInterRaterAgreementFromJudgeScores, costForTokenPricing, costForUsage, costReceiptFromLlm, costReceiptFromLlmError, createAntiSlopJudge, createBoundedTraceAnalysisStore, createChatClient, createChatTraceEngine, createDspyRlmTraceEngine, createFeedbackTrajectory, createLlmCorrectnessChecker, createLlmReviewer, createTraceAnalyst, decidePairedPromotion, defaultBlendWeights, defineAgentEval, defineEquivalenceCheck, deployGateLayer, describeTraceInsightScope, diffFindings, diffScorecard, discoverPersonas, domainEvidencePattern, dominates, eProcess, ensembleJudge, equivalenceVerdict, errorStreakDetector, estimateCost, estimateTokens, evaluateActionPolicy, evaluateInterimReleaseConfidence, evaluateOracles, evaluateReleaseConfidence, evaluateTraceContract, expandProfileAxes, explainTraceContract, exportProductBenchmark, exportProductBenchmarkRuns, exportRunAsOtlp, extractErrorCount, extractProducedState, extractUsage, extractUsageFromSse, failureBlame, failureClusterView, feedbackTrajectoriesToDatasetScenarios, feedbackTrajectoriesToOptimizerRows, feedbackTrajectoryToOptimizerRow, fileVerdictCache, formatScorecardDiff, gainHistogram, gateTreatmentApplied, gradeOnHidden, gradeSemanticStatus, groupRunsByAgentProfileCell, harnessAxisOf, hashContent, hashJson, hiddenGrade, holm, improvementVerdict, inMemoryReviewStore, inferDomainKeywords, interRaterReliability, interpretCliffs, iqr, isBinaryOutcomeVector, isJudgeSpan, isLlmSpan, isModelPriced, isPolicyEdit, isRunRecord, isToolSpan, isTransientLlmError, jsonShape, jsonlReviewStore, jsonlRunRecordBackend, judgeAgreementView, judgeFamily, judgeSpans, knowledgeReadinessTracePayload, leaderboard, lintTraceContractSpec, llmJudge, loadScorecard, localCommandRunner, makeFinding, makePolicyEdit, makePolicyEditCandidateRecord, makeProposalFinding, manifestContentDigest, mannWhitneyU, maximumChargeForLlmRequest, mcnemar, mcnemarPower, mcnemarRequiredN, minimumPairsForPairedDeltaTest, mintRolloutRows, modelHasSnapshot, modelPriceKey, mulberry32, notBlocked, objectiveEval, observeAll, otlpTextToTraceAnalysisStore, pairArms, pairRunRecords, pairedBinaryScale, pairedBootstrap, pairedCohensDz, pairedDeltaTest, pairedDeltaTieFraction, pairedEvalueSequence, pairedMde, pairedPromotionPower, pairedRiskDifference, pairedRiskDifferenceExact, pairedRiskDifferenceScore, pairedSignTest, pairedTTest, paretoChart, paretoFrontier, parseReflectionResponse, parseRunRecordSafe, partialCredit, partitionHeldOut, partitionTrainSelectionTest, passAtK, pearsonR, policyEditFromFinding, policyEditsFromFindings, preflightModels, productBenchmarkRepoIdentity, profile_exports as profile, projectRuntimeTrajectoryEvidence, proposeSynthesisTargets, quotaExhaustedUntil, ranks, readProductBenchmarkManifest, recordRuns, recordRunsToScorecard, redTeamDataset, redTeamReport, redact, redactForShare, redactText, regexMatches, renderPreferenceMemoryMarkdown, repeatedActionDetector, requiredPairedSampleSize, requiredPairsForPairedPromotion, requiredSampleSize, resolveModelPricing, resolveSeat, roundTripRunRecord, routeFields, runAgentControlLoop, runBoundedProcess, runCampaign, runCanaries, runCounterfactual, runEquivalenceCheck, runEvalCampaign, runIntentMatchJudge, runKeywordCoverageJudge, runKeywordCoverageJudgeUrl, runProposeReview, runProposeReviewAsControlLoop, runSemanticConceptJudge, runTaskScore, runsForScenario, scoreKnowledgeReadiness, scorePolicyEditReadiness, scoreRedTeamOutput, scoreTraceInsightReadiness, seatPresets, selfImprove, servedModelAcceptable, shareAllowed, spearmanR, stripFencedJson, subjectiveEval, summarizeBackendIntegrity, summarizeNumberSeries, summarizePreferenceMemory, summaryTable, textInSnapshot, toAgentProfileJson, tokenizeDomainWords, toolSpansToTraceAnalysisStore, toolWasteView, traceContract, transientDispatchFailure, urlContains, userQuestionsForKnowledgeGaps, validatePolicyEdit, validatePolicyEditCandidateRecord, validateRunRecord, verbosityBias, verifyAgentProfileCell, verifyAttestation, verifyCompletion, viteDeployRunner, weightedComposite, weightedMean, wilcoxonSignedRank, wilson, withAssignedFeedbackSplit, withHeldoutBlend, withJudgeRetry, wranglerDeployRunner };
8315
9590
 
8316
9591
  //# sourceMappingURL=index.js.map