@tangle-network/agent-eval 0.183.0 → 0.185.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/adapters/http.d.ts +2 -2
  3. package/dist/{agent-profile-cell-s__adRnK.d.ts → agent-profile-cell-BHcB-mZX.d.ts} +8 -9
  4. package/dist/{agent-profile-cell-s__adRnK.d.ts.map → agent-profile-cell-BHcB-mZX.d.ts.map} +1 -1
  5. package/dist/{agent-profile-cell-Cv6UA-W_.js → agent-profile-cell-DcFW4vOc.js} +16 -15
  6. package/dist/agent-profile-cell-DcFW4vOc.js.map +1 -0
  7. package/dist/{agent-profile-CivaSsSy.d.ts → agent-profile-uAIQK3Nr.d.ts} +3 -3
  8. package/dist/{agent-profile-CivaSsSy.d.ts.map → agent-profile-uAIQK3Nr.d.ts.map} +1 -1
  9. package/dist/analyst/index.d.ts +11 -336
  10. package/dist/analyst/index.d.ts.map +1 -1
  11. package/dist/analyst/index.js +10 -8
  12. package/dist/analyst/index.js.map +1 -1
  13. package/dist/analyze-runs-CrYhqXop.d.ts +75 -0
  14. package/dist/analyze-runs-CrYhqXop.d.ts.map +1 -0
  15. package/dist/{define-agent-eval-CneiWyuA.js → analyze-runs-sTygaDyD.js} +6 -813
  16. package/dist/analyze-runs-sTygaDyD.js.map +1 -0
  17. package/dist/{benchmark-DQKzykkO.js → benchmark-BeQJyrRC.js} +3 -3
  18. package/dist/{benchmark-DQKzykkO.js.map → benchmark-BeQJyrRC.js.map} +1 -1
  19. package/dist/{benchmark-command-NBrqNwgy.js → benchmark-command-kvq7yFY4.js} +17 -54
  20. package/dist/benchmark-command-kvq7yFY4.js.map +1 -0
  21. package/dist/benchmarks/index.d.ts +4 -4
  22. package/dist/benchmarks/index.js +3 -3
  23. package/dist/builder-eval/index.js +1 -1
  24. package/dist/campaign/index.d.ts +6 -5
  25. package/dist/campaign/index.js +10 -9
  26. package/dist/{campaign-BwcEBC91.js → campaign-eJgtRs-W.js} +16 -15
  27. package/dist/{campaign-BwcEBC91.js.map → campaign-eJgtRs-W.js.map} +1 -1
  28. package/dist/{campaign-evidence-PYPUftRy.js → campaign-evidence-BsrCmBSE.js} +7 -258
  29. package/dist/campaign-evidence-BsrCmBSE.js.map +1 -0
  30. package/dist/{canonical-DPyQ_rpt.js → canonical-BsZVgBhW.js} +2 -4
  31. package/dist/canonical-BsZVgBhW.js.map +1 -0
  32. package/dist/cli.js +2 -2
  33. package/dist/{client-kh2jOjTK.d.ts → client-Bc8LANCG.d.ts} +4 -4
  34. package/dist/{client-kh2jOjTK.d.ts.map → client-Bc8LANCG.d.ts.map} +1 -1
  35. package/dist/contract/index.d.ts +10 -10
  36. package/dist/contract/index.js +15 -284
  37. package/dist/contract/index.js.map +1 -1
  38. package/dist/{default-registry-BwDSWVzg.d.ts → default-registry-CXv9kHMt.d.ts} +6 -6
  39. package/dist/{default-registry-BwDSWVzg.d.ts.map → default-registry-CXv9kHMt.d.ts.map} +1 -1
  40. package/dist/{default-registry-C0-N4PkG.js → default-registry-xiHrldW8.js} +6 -4
  41. package/dist/{default-registry-C0-N4PkG.js.map → default-registry-xiHrldW8.js.map} +1 -1
  42. package/dist/define-agent-eval-D4uumjl3.js +813 -0
  43. package/dist/define-agent-eval-D4uumjl3.js.map +1 -0
  44. package/dist/{define-agent-eval-CwOWWQt_.d.ts → define-agent-eval-DE67ECH1.d.ts} +7 -7
  45. package/dist/{define-agent-eval-CwOWWQt_.d.ts.map → define-agent-eval-DE67ECH1.d.ts.map} +1 -1
  46. package/dist/diagnosis/index.d.ts +319 -0
  47. package/dist/diagnosis/index.d.ts.map +1 -0
  48. package/dist/diagnosis/index.js +1328 -0
  49. package/dist/diagnosis/index.js.map +1 -0
  50. package/dist/{dspy-rlm-engine-8pgBSiy7.js → dspy-rlm-engine-BE9lCzzL.js} +3 -3
  51. package/dist/{dspy-rlm-engine-8pgBSiy7.js.map → dspy-rlm-engine-BE9lCzzL.js.map} +1 -1
  52. package/dist/{engine-DS1cysJy.d.ts → engine-cXUK-WHS.d.ts} +5 -77
  53. package/dist/engine-cXUK-WHS.d.ts.map +1 -0
  54. package/dist/equal-terms-Blx9Zk5I.js +25 -0
  55. package/dist/equal-terms-Blx9Zk5I.js.map +1 -0
  56. package/dist/{eval-campaign-CCEkwzoH.js → eval-campaign-XFHEpN86.js} +4 -4
  57. package/dist/{eval-campaign-CCEkwzoH.js.map → eval-campaign-XFHEpN86.js.map} +1 -1
  58. package/dist/evaluation.d.ts +75 -0
  59. package/dist/evaluation.d.ts.map +1 -0
  60. package/dist/evaluation.js +137 -0
  61. package/dist/evaluation.js.map +1 -0
  62. package/dist/{exact-types-BZDe0W2D.d.ts → exact-types-BEHN7tnq.d.ts} +2 -2
  63. package/dist/{exact-types-BZDe0W2D.d.ts.map → exact-types-BEHN7tnq.d.ts.map} +1 -1
  64. package/dist/experiment/index.d.ts +2 -2
  65. package/dist/experiment/index.js +6 -5
  66. package/dist/experiment/index.js.map +1 -1
  67. package/dist/{experiment-tracker-C7PfnF4b.d.ts → experiment-tracker-URRGP9ek.d.ts} +2 -2
  68. package/dist/{experiment-tracker-C7PfnF4b.d.ts.map → experiment-tracker-URRGP9ek.d.ts.map} +1 -1
  69. package/dist/{external-optimizer-process-DIB4YWEe.js → external-optimizer-process-BbhvXTFx.js} +4 -4
  70. package/dist/{external-optimizer-process-DIB4YWEe.js.map → external-optimizer-process-BbhvXTFx.js.map} +1 -1
  71. package/dist/{external-optimizer-subprocess-CjguXN2e.js → external-optimizer-subprocess-DMgmqTB6.js} +3 -3
  72. package/dist/{external-optimizer-subprocess-CjguXN2e.js.map → external-optimizer-subprocess-DMgmqTB6.js.map} +1 -1
  73. package/dist/{feedback-trajectory-CXmtITBo.d.ts → feedback-trajectory-CytTR7u4.d.ts} +3 -3
  74. package/dist/{feedback-trajectory-CXmtITBo.d.ts.map → feedback-trajectory-CytTR7u4.d.ts.map} +1 -1
  75. package/dist/hosted/index.d.ts +2 -2
  76. package/dist/{index-DoykkxW0.d.ts → index-BQWfAFeH.d.ts} +11 -11
  77. package/dist/{index-DoykkxW0.d.ts.map → index-BQWfAFeH.d.ts.map} +1 -1
  78. package/dist/{index-DbG8QbH9.d.ts → index-C8_iU8KL.d.ts} +6 -6
  79. package/dist/{index-DbG8QbH9.d.ts.map → index-C8_iU8KL.d.ts.map} +1 -1
  80. package/dist/{index--_8_Nlpn.d.ts → index-CKZa_rnt.d.ts} +4 -121
  81. package/dist/index-CKZa_rnt.d.ts.map +1 -0
  82. package/dist/{index-Bp_6sj3x.d.ts → index-ww8736Am.d.ts} +20 -315
  83. package/dist/index-ww8736Am.d.ts.map +1 -0
  84. package/dist/index.d.ts +24 -22
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +25 -24
  87. package/dist/index.js.map +1 -1
  88. package/dist/{insight-report-D1qa0HWs.d.ts → insight-report-C3Bfl762.d.ts} +3 -3
  89. package/dist/{insight-report-D1qa0HWs.d.ts.map → insight-report-C3Bfl762.d.ts.map} +1 -1
  90. package/dist/jev-protocol.d.ts +74 -0
  91. package/dist/jev-protocol.d.ts.map +1 -0
  92. package/dist/jev-protocol.js +91 -0
  93. package/dist/jev-protocol.js.map +1 -0
  94. package/dist/jev.d.ts +131 -0
  95. package/dist/jev.d.ts.map +1 -0
  96. package/dist/jev.js +312 -0
  97. package/dist/jev.js.map +1 -0
  98. package/dist/{journal-Cs9f7385.js → journal-BuRLm6ho.js} +2 -2
  99. package/dist/{journal-Cs9f7385.js.map → journal-BuRLm6ho.js.map} +1 -1
  100. package/dist/{kind-factory-DxTzg32u.js → kind-factory-V79Hw0AU.js} +7 -84
  101. package/dist/kind-factory-V79Hw0AU.js.map +1 -0
  102. package/dist/ledger-core/index.js +2 -2
  103. package/dist/{llm-judge-FfaRgz9X.js → llm-judge-FWWhEb31.js} +11 -9
  104. package/dist/{llm-judge-FfaRgz9X.js.map → llm-judge-FWWhEb31.js.map} +1 -1
  105. package/dist/{matrix-CyhW-vgJ.d.ts → matrix-CPKsRY8Y.d.ts} +2 -2
  106. package/dist/{matrix-CyhW-vgJ.d.ts.map → matrix-CPKsRY8Y.d.ts.map} +1 -1
  107. package/dist/meta-eval/index.d.ts +54 -2
  108. package/dist/meta-eval/index.d.ts.map +1 -1
  109. package/dist/meta-eval/index.js +52 -3
  110. package/dist/meta-eval/index.js.map +1 -1
  111. package/dist/{mint-ySIIkKlV.js → mint-B4zgSAJW.js} +63 -14
  112. package/dist/mint-B4zgSAJW.js.map +1 -0
  113. package/dist/mint-BI14xehJ.d.ts +285 -0
  114. package/dist/mint-BI14xehJ.d.ts.map +1 -0
  115. package/dist/multishot/golden/index.d.ts +1 -1
  116. package/dist/multishot/index.d.ts +2 -2
  117. package/dist/openapi.json +1 -1
  118. package/dist/otel-spans-CQY1pNiN.js +275 -0
  119. package/dist/otel-spans-CQY1pNiN.js.map +1 -0
  120. package/dist/otlp-attributes-BpC_blLF.js +83 -0
  121. package/dist/otlp-attributes-BpC_blLF.js.map +1 -0
  122. package/dist/{run-record-DPa2PeHx.js → paired-promotion-decision-ClJh_9nK.js} +2 -215
  123. package/dist/paired-promotion-decision-ClJh_9nK.js.map +1 -0
  124. package/dist/pipelines/index.js +2 -2
  125. package/dist/prime-bridge-transport-Z3cpKGoV.js +43 -0
  126. package/dist/prime-bridge-transport-Z3cpKGoV.js.map +1 -0
  127. package/dist/prime-protocol-CDBcL9NM.d.ts +331 -0
  128. package/dist/prime-protocol-CDBcL9NM.d.ts.map +1 -0
  129. package/dist/{prime-protocol-6tZTVsWm.js → prime-protocol-DcAK9pC8.js} +2 -23
  130. package/dist/prime-protocol-DcAK9pC8.js.map +1 -0
  131. package/dist/{produced-state-CGoVInrl.js → produced-state-CmB02tr2.js} +23 -19
  132. package/dist/{produced-state-CGoVInrl.js.map → produced-state-CmB02tr2.js.map} +1 -1
  133. package/dist/profile-cell.d.ts +1 -1
  134. package/dist/profile-cell.js +1 -1
  135. package/dist/{promotion-policy-BKFrl7CC.js → promotion-policy-DdrYWHDh.js} +3 -3
  136. package/dist/{promotion-policy-BKFrl7CC.js.map → promotion-policy-DdrYWHDh.js.map} +1 -1
  137. package/dist/{query-D1nLIKt7.js → query-DlV0pdx4.js} +2 -2
  138. package/dist/{query-D1nLIKt7.js.map → query-DlV0pdx4.js.map} +1 -1
  139. package/dist/{registry-BRbB6Y0v.d.ts → registry-D5Ly3GRV.d.ts} +3 -3
  140. package/dist/{registry-BRbB6Y0v.d.ts.map → registry-D5Ly3GRV.d.ts.map} +1 -1
  141. package/dist/{release-confidence-BcqeQTHW.d.ts → release-confidence-DsETiO4f.d.ts} +3 -3
  142. package/dist/{release-confidence-BcqeQTHW.d.ts.map → release-confidence-DsETiO4f.d.ts.map} +1 -1
  143. package/dist/{release-confidence-DMg8n18l.js → release-confidence-RanRUXRW.js} +2 -2
  144. package/dist/{release-confidence-DMg8n18l.js.map → release-confidence-RanRUXRW.js.map} +1 -1
  145. package/dist/reporting.d.ts +3 -3
  146. package/dist/reporting.js +2 -2
  147. package/dist/{researcher-64T49THL.d.ts → researcher-CJkH-6Ty.d.ts} +4 -4
  148. package/dist/{researcher-64T49THL.d.ts.map → researcher-CJkH-6Ty.d.ts.map} +1 -1
  149. package/dist/{reward-hacking-uzO_ihep.d.ts → reward-hacking-BIQ2BWLG.d.ts} +2 -2
  150. package/dist/{reward-hacking-uzO_ihep.d.ts.map → reward-hacking-BIQ2BWLG.d.ts.map} +1 -1
  151. package/dist/rl.d.ts +10 -6
  152. package/dist/rl.d.ts.map +1 -1
  153. package/dist/rl.js +22 -7
  154. package/dist/rl.js.map +1 -1
  155. package/dist/rollout/index.d.ts +2 -2
  156. package/dist/rollout/index.js +2 -2
  157. package/dist/{rollout-D_54FZVu.js → rollout-C0Ifk3vK.js} +2 -2
  158. package/dist/{rollout-D_54FZVu.js.map → rollout-C0Ifk3vK.js.map} +1 -1
  159. package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts → rubric-predictive-validity-CTU8y8Cv.d.ts} +2 -2
  160. package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts.map → rubric-predictive-validity-CTU8y8Cv.d.ts.map} +1 -1
  161. package/dist/run-record-CNNzWGpB.js +216 -0
  162. package/dist/run-record-CNNzWGpB.js.map +1 -0
  163. package/dist/{run-record-BiTWauyO.d.ts → run-record-D9wS35fK.d.ts} +2 -2
  164. package/dist/{run-record-BiTWauyO.d.ts.map → run-record-D9wS35fK.d.ts.map} +1 -1
  165. package/dist/{run-record-DualPTn2.js → run-record-tg_5H2IK.js} +2 -2
  166. package/dist/{run-record-DualPTn2.js.map → run-record-tg_5H2IK.js.map} +1 -1
  167. package/dist/search-ledger-types-D7KDVg-o.d.ts +302 -0
  168. package/dist/search-ledger-types-D7KDVg-o.d.ts.map +1 -0
  169. package/dist/{semantic-concept-judge-_3Fp6Q_3.js → semantic-concept-judge-Cnt0TWp0.js} +4 -4
  170. package/dist/{semantic-concept-judge-_3Fp6Q_3.js.map → semantic-concept-judge-Cnt0TWp0.js.map} +1 -1
  171. package/dist/{sequential-D_xHrBZe.js → sequential-PgLEqcTJ.js} +3 -3
  172. package/dist/{sequential-D_xHrBZe.js.map → sequential-PgLEqcTJ.js.map} +1 -1
  173. package/dist/{server-BZQR1f0C.js → server-DmpcFiVK.js} +2 -2
  174. package/dist/{server-BZQR1f0C.js.map → server-DmpcFiVK.js.map} +1 -1
  175. package/dist/{skillopt-optimization-method-DY1aQ-aL.js → skillopt-optimization-method-FSk8b5FQ.js} +8 -7
  176. package/dist/{skillopt-optimization-method-DY1aQ-aL.js.map → skillopt-optimization-method-FSk8b5FQ.js.map} +1 -1
  177. package/dist/{statistical-heldout-CpVd6FmY.d.ts → statistical-heldout-Bu4oNOJh.d.ts} +3 -3
  178. package/dist/{statistical-heldout-CpVd6FmY.d.ts.map → statistical-heldout-Bu4oNOJh.d.ts.map} +1 -1
  179. package/dist/statistical-heldout-CeWT_W7y.js +256 -0
  180. package/dist/statistical-heldout-CeWT_W7y.js.map +1 -0
  181. package/dist/{store-otlp-DAaEbMLf.js → store-otlp-2gYCy-v0.js} +2 -2
  182. package/dist/{store-otlp-DAaEbMLf.js.map → store-otlp-2gYCy-v0.js.map} +1 -1
  183. package/dist/{store-tool-spans-BZ8MPKFe.js → store-tool-spans-B1e6Auc2.js} +69 -6
  184. package/dist/store-tool-spans-B1e6Auc2.js.map +1 -0
  185. package/dist/{store-tool-spans-Dt-YdAuE.d.ts → store-tool-spans-BrdfPaVh.d.ts} +54 -6
  186. package/dist/store-tool-spans-BrdfPaVh.d.ts.map +1 -0
  187. package/dist/{summary-report-IGAOtgPd.js → summary-report-BMvou2oZ.js} +2 -2
  188. package/dist/{summary-report-IGAOtgPd.js.map → summary-report-BMvou2oZ.js.map} +1 -1
  189. package/dist/{summary-report-D1h4dlrK.d.ts → summary-report-BzFS5UhZ.d.ts} +2 -2
  190. package/dist/{summary-report-D1h4dlrK.d.ts.map → summary-report-BzFS5UhZ.d.ts.map} +1 -1
  191. package/dist/{task-failure-attributes-B_JjrOVo.js → task-failure-attributes-B34TiMBe.js} +2 -2
  192. package/dist/{task-failure-attributes-B_JjrOVo.js.map → task-failure-attributes-B34TiMBe.js.map} +1 -1
  193. package/dist/{tool-groups-B2bSNaJB.d.ts → tool-groups-eOOgYGaM.d.ts} +3 -3
  194. package/dist/tool-groups-eOOgYGaM.d.ts.map +1 -0
  195. package/dist/{tool-waste-C7MU9u1e.js → tool-waste-nbHPAxei.js} +2 -2
  196. package/dist/{tool-waste-C7MU9u1e.js.map → tool-waste-nbHPAxei.js.map} +1 -1
  197. package/dist/trace-repair/index.d.ts +2 -2
  198. package/dist/trace-repair/index.js +5 -4
  199. package/dist/trace-repair/index.js.map +1 -1
  200. package/dist/traces.d.ts +5 -5
  201. package/dist/traces.js +8 -7
  202. package/dist/traces.js.map +1 -1
  203. package/dist/trajectory-replay/index.js +1 -1
  204. package/dist/{types-CS0qk_Yp.d.ts → types-BTRcIqFr.d.ts} +3 -3
  205. package/dist/{types-CS0qk_Yp.d.ts.map → types-BTRcIqFr.d.ts.map} +1 -1
  206. package/dist/{types-D7gEdPoQ.d.ts → types-BjB2wZM9.d.ts} +2 -2
  207. package/dist/{types-D7gEdPoQ.d.ts.map → types-BjB2wZM9.d.ts.map} +1 -1
  208. package/dist/types-C8VBbiw6.js +91 -0
  209. package/dist/types-C8VBbiw6.js.map +1 -0
  210. package/dist/{types-BvZoPTGa.d.ts → types-c3ZRTbw9.d.ts} +3 -3
  211. package/dist/{types-BvZoPTGa.d.ts.map → types-c3ZRTbw9.d.ts.map} +1 -1
  212. package/dist/{types-DQ0e2E7y.js → usage-receipt-Cx3xNeyB.js} +2 -89
  213. package/dist/usage-receipt-Cx3xNeyB.js.map +1 -0
  214. package/dist/{verdict-BQ3pCFf8.js → verdict-DhPoXApk.js} +2 -2
  215. package/dist/{verdict-BQ3pCFf8.js.map → verdict-DhPoXApk.js.map} +1 -1
  216. package/dist/{verdict-cache-B3eCVQtY.js → verdict-cache-BQEsVy9n.js} +2 -2
  217. package/dist/{verdict-cache-B3eCVQtY.js.map → verdict-cache-BQEsVy9n.js.map} +1 -1
  218. package/dist/wire/index.d.ts +1 -1
  219. package/dist/wire/index.js +1 -1
  220. package/docs/changes/evaluation-definition-identity.md +27 -0
  221. package/docs/changes/jev-evidence-review.md +18 -0
  222. package/docs/changes/jev-product-adoption.md +18 -0
  223. package/docs/changes/probability-policy-audit.md +81 -0
  224. package/docs/diagnosis.md +42 -0
  225. package/docs/jev-behavior-review.md +174 -0
  226. package/docs/jev-integrations.md +50 -0
  227. package/docs/jev.md +140 -0
  228. package/docs/produced-state.md +13 -0
  229. package/docs/profile-json-identity.md +33 -0
  230. package/package.json +22 -1
  231. package/dist/agent-profile-cell-Cv6UA-W_.js.map +0 -1
  232. package/dist/benchmark-command-NBrqNwgy.js.map +0 -1
  233. package/dist/campaign-evidence-PYPUftRy.js.map +0 -1
  234. package/dist/canonical-DPyQ_rpt.js.map +0 -1
  235. package/dist/define-agent-eval-CneiWyuA.js.map +0 -1
  236. package/dist/engine-DS1cysJy.d.ts.map +0 -1
  237. package/dist/exporters-D98GPi1n.d.ts +0 -161
  238. package/dist/exporters-D98GPi1n.d.ts.map +0 -1
  239. package/dist/index--_8_Nlpn.d.ts.map +0 -1
  240. package/dist/index-Bp_6sj3x.d.ts.map +0 -1
  241. package/dist/kind-factory-DxTzg32u.js.map +0 -1
  242. package/dist/mint-ySIIkKlV.js.map +0 -1
  243. package/dist/prime-protocol-6tZTVsWm.js.map +0 -1
  244. package/dist/run-record-DPa2PeHx.js.map +0 -1
  245. package/dist/store-tool-spans-BZ8MPKFe.js.map +0 -1
  246. package/dist/store-tool-spans-Dt-YdAuE.d.ts.map +0 -1
  247. package/dist/tool-groups-B2bSNaJB.d.ts.map +0 -1
  248. package/dist/types-DQ0e2E7y.js.map +0 -1
@@ -0,0 +1,91 @@
1
+ import { createHash } from "node:crypto";
2
+ //#region src/ledger-core/deep-freeze.ts
3
+ /** Freeze a detached canonical-JSON graph. Canonicalization has already ruled out cycles.
4
+ *
5
+ * Lives outside canonical.ts so the analyst-benchmark implementation digest,
6
+ * which covers canonical.ts, stays bound to the published benchmark evidence. */
7
+ function deepFreezeCanonicalJson(value) {
8
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
9
+ Object.freeze(value);
10
+ for (const nested of Object.values(value)) deepFreezeCanonicalJson(nested);
11
+ }
12
+ return value;
13
+ }
14
+ //#endregion
15
+ //#region src/analyst/types.ts
16
+ /**
17
+ * Analyst contract — the missing orchestration layer over agent-eval's
18
+ * existing analyzers (analyzeTraces, MultiLayerVerifier,
19
+ * SemanticConceptJudge, JudgeFn, ...).
20
+ *
21
+ * Each existing primitive returns its own output shape. The Analyst
22
+ * contract is the single envelope every primitive lifts into, so a
23
+ * registry can run N analysts against a run and a single renderer can
24
+ * compose findings without knowing which analyzer produced them.
25
+ *
26
+ * The contract is intentionally domain-agnostic: nothing here knows
27
+ * about code, voice, RAG, or any particular agent stack. Analysts
28
+ * declare what INPUT KIND they need (a trace store, an artifact dir,
29
+ * a RunRecord, a JudgeInput, or `custom`), and the registry routes
30
+ * the matching input from `AnalystRunInputs`.
31
+ */
32
+ /** Finding severity. `AnalystSeverity` derives from this array, so the type
33
+ * and the schema that validates a finding cannot name different levels. */
34
+ const ANALYST_SEVERITIES = [
35
+ "critical",
36
+ "high",
37
+ "medium",
38
+ "low",
39
+ "info"
40
+ ];
41
+ /**
42
+ * Compute the stable finding_id from the identity-defining fields.
43
+ * Default implementation hashes {analyst_id, area, subject, normalized claim}.
44
+ * Analysts that emit findings whose claim text varies per run (timestamps,
45
+ * counts) SHOULD either: (a) pass an explicit `id_basis` to fix the hash,
46
+ * or (b) move the variable part into `rationale`/`metadata` and keep the
47
+ * `claim` static.
48
+ */
49
+ function computeFindingId(input) {
50
+ const basis = JSON.stringify({
51
+ a: input.analyst_id,
52
+ r: input.area,
53
+ s: input.subject ?? "",
54
+ c: normalizeClaim(input.id_basis ?? input.claim)
55
+ });
56
+ return `f_${createHash("sha256").update(basis).digest("hex").slice(0, 20)}`;
57
+ }
58
+ function normalizeClaim(c) {
59
+ return c.toLowerCase().replace(/\s+/g, " ").replace(/[.!?;:,]+$/g, "").trim();
60
+ }
61
+ /**
62
+ * Convenience factory: produce a fully-formed AnalystFinding with the
63
+ * id computed automatically. Analyst code stays terse.
64
+ */
65
+ function makeFinding(init) {
66
+ const { id_basis, produced_at, ...rest } = init;
67
+ return {
68
+ schema_version: "1.0.0",
69
+ finding_id: computeFindingId({
70
+ analyst_id: rest.analyst_id,
71
+ area: rest.area,
72
+ subject: rest.subject,
73
+ claim: rest.claim,
74
+ id_basis
75
+ }),
76
+ produced_at: produced_at ?? (/* @__PURE__ */ new Date()).toISOString(),
77
+ ...rest
78
+ };
79
+ }
80
+ /** Build a finding whose source is explicitly allowed during candidate generation. */
81
+ function makeProposalFinding(init) {
82
+ const { proposal_origin, ...finding } = init;
83
+ return {
84
+ ...makeFinding(finding),
85
+ proposal_origin
86
+ };
87
+ }
88
+ //#endregion
89
+ export { deepFreezeCanonicalJson as a, makeProposalFinding as i, computeFindingId as n, makeFinding as r, ANALYST_SEVERITIES as t };
90
+
91
+ //# sourceMappingURL=types-C8VBbiw6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-C8VBbiw6.js","names":[],"sources":["../src/ledger-core/deep-freeze.ts","../src/analyst/types.ts"],"sourcesContent":["/** Freeze a detached canonical-JSON graph. Canonicalization has already ruled out cycles.\n *\n * Lives outside canonical.ts so the analyst-benchmark implementation digest,\n * which covers canonical.ts, stays bound to the published benchmark evidence. */\nexport function deepFreezeCanonicalJson<T>(value: T): T {\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n Object.freeze(value)\n for (const nested of Object.values(value)) deepFreezeCanonicalJson(nested)\n }\n return value\n}\n","/**\n * Analyst contract — the missing orchestration layer over agent-eval's\n * existing analyzers (analyzeTraces, MultiLayerVerifier,\n * SemanticConceptJudge, JudgeFn, ...).\n *\n * Each existing primitive returns its own output shape. The Analyst\n * contract is the single envelope every primitive lifts into, so a\n * registry can run N analysts against a run and a single renderer can\n * compose findings without knowing which analyzer produced them.\n *\n * The contract is intentionally domain-agnostic: nothing here knows\n * about code, voice, RAG, or any particular agent stack. Analysts\n * declare what INPUT KIND they need (a trace store, an artifact dir,\n * a RunRecord, a JudgeInput, or `custom`), and the registry routes\n * the matching input from `AnalystRunInputs`.\n */\n\nimport { createHash } from 'node:crypto'\nimport type { CostLedgerHandle } from '../cost-ledger'\nimport type { RunCostProvenance, RunRecord, RunTokenUsage } from '../run-record'\nimport type { TraceAnalysisStore } from '../trace-analyst/store'\nimport type { JudgeInput } from '../types'\nimport type { ChatClient } from './chat-client'\n\n/**\n * Unified envelope every analyst emits. Schema-versioned so renderers\n * and time-series diffs survive future field additions.\n */\nexport interface AnalystFinding {\n schema_version: '1.0.0'\n /**\n * Stable hash over identity-defining fields (analyst_id + canonical\n * claim + area + optional subject). Two findings from two runs that\n * \"are the same finding\" share this id — that's what `diffFindings`\n * uses to compute appeared/disappeared sets across runs.\n */\n finding_id: string\n analyst_id: string\n produced_at: string\n severity: AnalystSeverity\n /**\n * Coarse classification. Renderers group by this. Free-form so\n * domain-specific analysts can introduce categories without a\n * schema change ('agent-reasoning', 'verification', 'cost',\n * 'tool-use', 'safety', 'latency', 'data-quality', ...).\n */\n area: string\n claim: string\n rationale?: string\n evidence_refs: EvidenceRef[]\n recommended_action?: string\n validation_plan?: string\n /** 0..1 — the analyst's own confidence. Not calibrated across analysts. */\n confidence: number\n /**\n * Optional subject the finding is about — leaf id, agent id, request\n * id. Included in finding_id when present so per-subject findings\n * diff cleanly across runs.\n */\n subject?: string\n /** True when this finding was lifted from a judge result rather than observed\n * directly in a trace or artifact. Descriptive only: proposal access is\n * controlled by `ProposalFinding.proposal_origin`. */\n derived_from_judge?: boolean\n /** Analyst-private extras; renderers ignore unless they know the analyst. */\n metadata?: Record<string, unknown>\n}\n\n/** Finding severity. `AnalystSeverity` derives from this array, so the type\n * and the schema that validates a finding cannot name different levels. */\nexport const ANALYST_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'] as const\n\nexport type AnalystSeverity = (typeof ANALYST_SEVERITIES)[number]\n\n/** Data sources that candidate generation may intentionally learn from. */\nexport type ProposalFindingOrigin = 'search' | 'production'\n\n/** A finding explicitly admitted as candidate-generation input. */\nexport type ProposalFinding = AnalystFinding & {\n readonly proposal_origin: ProposalFindingOrigin\n}\n\nexport interface EvidenceRef {\n /**\n * Where the evidence lives. `span` and `event` refer to OTLP trace\n * elements; `artifact` to a file inside the run's artifact tree;\n * `finding` to another AnalystFinding (cross-analyst chaining);\n * `metric` to a named scalar reading the renderer knows how to read.\n */\n kind: 'span' | 'event' | 'artifact' | 'finding' | 'metric'\n uri: string\n excerpt?: string\n}\n\n// ── Analyst contract ─────────────────────────────────────────────────\n\n/**\n * The discriminator the registry uses to pass the right input.\n * `custom` is the escape hatch — analysts that need something else\n * (e.g. an embedding cache, a partner SDK handle) read it from\n * `AnalystRunInputs.custom[<analyst id>]`.\n */\nexport type AnalystInputKind =\n | 'trace-store'\n | 'artifact-dir'\n | 'run-record'\n | 'judge-input'\n | 'custom'\n\nexport interface AnalystCost {\n /** `deterministic` analysts MUST NOT call the LLM. */\n kind: 'deterministic' | 'llm'\n /** Optional declared upper bound; the registry can enforce a budget. */\n est_usd_per_run?: number\n /** Models the analyst expects to use (informational). */\n models?: string[]\n /** Maximum post-cancellation wait for provider usage. Model analysts default to 5 seconds. */\n settlement_timeout_ms?: number\n}\n\nexport interface AnalystRequirements {\n /** Min number of shots / samples the analyst needs to produce signal. */\n min_shots?: number\n /** Capabilities the runtime must supply (e.g. ['network', 'gpu']). */\n capabilities?: string[]\n}\n\n/**\n * What's passed to every analyst call. The registry resolves which\n * field the analyst's `inputKind` selects and asserts it's present.\n */\nexport interface AnalystRunInputs {\n traceStore?: TraceAnalysisStore\n artifactDir?: string\n runRecord?: RunRecord\n judgeInput?: JudgeInput\n /** Keyed by analyst id; populated by callers that registered custom analysts. */\n custom?: Record<string, unknown>\n}\n\nexport interface AnalystContext {\n runId: string\n /** Stable correlation id so logs from a single registry.run() share a tag. */\n correlationId: string\n /** Enforced wall-clock deadline (epoch ms). */\n deadlineMs?: number\n /** Per-analyst USD budget. Analysts MAY check before issuing LLM calls. */\n budgetUsd?: number\n /** Shared paid-call account when the analyst runs inside a larger campaign. */\n costLedger?: CostLedgerHandle\n /** Attribution phase used when writing to the shared paid-call account. */\n costPhase?: string\n /**\n * Shared chat client. Analysts that call an LLM go through this so\n * the operator picks transport (sandbox-sdk | router | cli-bridge |\n * direct-provider | mock) at the registry boundary without touching\n * analyst code.\n */\n chat?: ChatClient\n /**\n * Findings from a prior run the operator wants the analyst to see as\n * retrieval context. Kinds that take advantage of cross-run memory\n * (failure-mode \"I saw this cluster last run\", knowledge-gap \"the wiki\n * page I asked for is still missing\") render these into the actor's\n * working set. Filtering is the operator's job: pass the slice that\n * matches the analyst's id, or pass everything and let the kind\n * filter. Empty / absent means no cross-run context.\n */\n priorFindings?: ReadonlyArray<AnalystFinding>\n /**\n * Findings emitted by analysts that completed earlier in this registry run.\n * This is separate from `priorFindings`: upstream findings are dependency\n * context for the current pass, while prior findings are cross-run memory.\n * The registry populates this only when `RegistryRunOpts.chainFindings` is on.\n */\n upstreamFindings?: ReadonlyArray<AnalystFinding>\n /**\n * Report metered work independently of findings. This keeps an empty finding\n * set from erasing token/cost telemetry. Multiple receipts are accumulated.\n */\n recordUsage?: (receipt: AnalystUsageReceipt) => void\n /** Free-form runtime tags (env, host, op). Findings can echo these into metadata. */\n tags?: Record<string, string>\n /** Logger callback — analysts SHOULD prefer this over console.* for testability. */\n log?: (msg: string, fields?: Record<string, unknown>) => void\n /** Optional abort signal. Analysts SHOULD pass it through to LLM calls. */\n signal?: AbortSignal\n /**\n * Optional live-execution port. A runtime that owns a sandbox or checkout\n * fills it so an analyst can execute a bounded probe against the run's\n * produced state instead of reasoning about it from the trace alone. This\n * package defines only the port: no field here reaches for an agent loop,\n * and an absent probe means the analyst works from recorded evidence.\n */\n probe?: ExecutionProbe\n}\n\n// ── Live-execution port ─────────────────────────────────────────────\n\n/** One bounded command an analyst asks the probe to run. */\nexport interface ExecutionProbeRequest {\n command: string\n /** Working directory inside the probed environment. */\n cwd?: string\n /** Hard wall-clock deadline for this one execution. */\n timeoutMs: number\n /** Bytes of combined output retained; the prober truncates beyond it. */\n maxOutputBytes?: number\n signal?: AbortSignal\n}\n\n/**\n * Typed outcome of one probe execution. `succeeded: false` is a PROBE failure\n * (the environment could not run the command); a command that ran and exited\n * non-zero is a successful observation with a non-zero `exitCode`.\n */\nexport type ExecutionProbeOutcome =\n | {\n succeeded: true\n exitCode: number\n stdout: string\n stderr: string\n durationMs: number\n /** True when output was cut at `maxOutputBytes`. */\n truncated: boolean\n }\n | { succeeded: false; error: { class: string; message: string } }\n\n/**\n * The seam a runtime fills to let analysts observe produced state live.\n * Implementations own sandboxing, credentials, and cleanup; analysts only\n * submit bounded requests and read typed outcomes.\n */\nexport interface ExecutionProbe {\n /** One plain sentence naming what is being probed (e.g. a sandbox id). */\n readonly description: string\n execute(request: ExecutionProbeRequest): Promise<ExecutionProbeOutcome>\n}\n\n/**\n * The minimal contract. Concrete analysts can refine `TInput` so\n * implementations stay type-safe (e.g. a trace analyst's `TInput` is\n * `TraceAnalysisStore`); the registry passes the right field from\n * `AnalystRunInputs` based on `inputKind`.\n */\nexport interface Analyst<TInput = unknown> {\n /** Stable identifier — appears in finding_id, telemetry, and registry exclusion lists. */\n readonly id: string\n /** Human-readable. One sentence. */\n readonly description: string\n readonly inputKind: AnalystInputKind\n readonly cost: AnalystCost\n readonly requires?: AnalystRequirements\n /** Bump on breaking changes to claim wording or area so old finding_ids don't collide. */\n readonly version: string\n analyze(input: TInput, ctx: AnalystContext): Promise<AnalystFinding[]>\n}\n\n/** Metered work performed by one analyst call. */\nexport interface AnalystUsageReceipt {\n /** Number of model-usage records observed at the provider boundary. */\n calls: number | null\n /** Null when the provider did not return token accounting. */\n tokens: RunTokenUsage | null\n /** Observed, estimated, or explicitly uncaptured dollar cost. */\n cost: RunCostProvenance\n /** Known lower bound when one or more calls have uncaptured cost. */\n knownCostUsd?: number\n /**\n * Token counts the provider reported on only one side. Present exactly when\n * `tokens` is null and at least one side WAS reported: `RunTokenUsage` has no\n * nullable side, so a one-sided count cannot live in `tokens` without writing\n * a zero nobody measured. Read it as a lower bound, never as a total — the\n * field exists so a null `tokens` cannot hide a real count.\n */\n partialTokens?: { input: number | null; output: number | null }\n /**\n * True when the token counts were DERIVED by the transport (from character\n * lengths, say) rather than measured by the model provider. `cost.kind` is\n * `estimated` both for a rate estimate over exact tokens and for one over\n * derived tokens; this is the field that separates them.\n */\n tokensEstimated?: boolean\n}\n\n// ── finding_id stability ─────────────────────────────────────────────\n\n/**\n * Compute the stable finding_id from the identity-defining fields.\n * Default implementation hashes {analyst_id, area, subject, normalized claim}.\n * Analysts that emit findings whose claim text varies per run (timestamps,\n * counts) SHOULD either: (a) pass an explicit `id_basis` to fix the hash,\n * or (b) move the variable part into `rationale`/`metadata` and keep the\n * `claim` static.\n */\nexport function computeFindingId(input: {\n analyst_id: string\n area: string\n subject?: string\n claim: string\n /** Override the claim for hashing — use when the displayed claim has run-specific bits. */\n id_basis?: string\n}): string {\n const basis = JSON.stringify({\n a: input.analyst_id,\n r: input.area,\n s: input.subject ?? '',\n c: normalizeClaim(input.id_basis ?? input.claim),\n })\n return `f_${createHash('sha256').update(basis).digest('hex').slice(0, 20)}`\n}\n\nfunction normalizeClaim(c: string): string {\n // Lowercase, collapse whitespace, strip trailing punctuation. Goal:\n // \"Leaf X failed install\" and \"Leaf X failed install.\" hash the same.\n return c\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .replace(/[.!?;:,]+$/g, '')\n .trim()\n}\n\n/**\n * Convenience factory: produce a fully-formed AnalystFinding with the\n * id computed automatically. Analyst code stays terse.\n */\nexport function makeFinding(\n init: Omit<AnalystFinding, 'schema_version' | 'finding_id' | 'produced_at'> & {\n id_basis?: string\n produced_at?: string\n },\n): AnalystFinding {\n const { id_basis, produced_at, ...rest } = init\n return {\n schema_version: '1.0.0',\n finding_id: computeFindingId({\n analyst_id: rest.analyst_id,\n area: rest.area,\n subject: rest.subject,\n claim: rest.claim,\n id_basis,\n }),\n produced_at: produced_at ?? new Date().toISOString(),\n ...rest,\n }\n}\n\n/** Build a finding whose source is explicitly allowed during candidate generation. */\nexport function makeProposalFinding(\n init: Omit<ProposalFinding, 'schema_version' | 'finding_id' | 'produced_at'> & {\n id_basis?: string\n produced_at?: string\n },\n): ProposalFinding {\n const { proposal_origin, ...finding } = init\n return { ...makeFinding(finding), proposal_origin }\n}\n\n// ── Registry result envelope ────────────────────────────────────────\n\nexport interface AnalystRunSummary {\n analyst_id: string\n status: 'ok' | 'skipped' | 'failed'\n /** Why skipped — missing input, budget exceeded, capability unmet. */\n reason?: string\n findings_count: number\n latency_ms: number\n /** Additive model usage and cost provenance for this analyst. */\n usage: AnalystUsageReceipt\n /** When `status='failed'`: the error class + message, never the full stack. */\n error?: { class: string; message: string }\n}\n\nexport interface AnalystRunResult {\n run_id: string\n correlation_id: string\n started_at: string\n ended_at: string\n findings: AnalystFinding[]\n per_analyst: AnalystRunSummary[]\n /** Total LLM cost in USD across all analysts in this registry.run(). */\n total_cost_usd: number\n /**\n * Provenance for `total_cost_usd`. When uncaptured, the numeric field is only\n * the known subtotal and must not be treated as the run's total spend.\n */\n total_cost_provenance?: RunCostProvenance\n}\n\n// ── Streaming event envelope ────────────────────────────────────────\n\n/**\n * Events emitted by `AnalystRegistry.runStream(...)` in real time as\n * the registry executes. UIs subscribe via `for await (const ev of\n * registry.runStream(...))`; `registry.run(...)` is a thin collector\n * over the same stream, so the two surfaces share their invariants.\n *\n * Per-finding events are intentionally omitted — analyzers are batch\n * operations (a recursive engine returns the full `findings:json[]` at the\n * end of the responder), so streaming inside one analyst would only\n * emit partial JSON consumers can't render. The kind-completion event\n * is the right granularity; subscribers wanting per-finding rendering\n * iterate `event.findings` themselves.\n */\nexport type AnalystRunEvent =\n | {\n type: 'run-started'\n run_id: string\n correlation_id: string\n started_at: string\n /** The ordered list of analyst ids the registry will run. */\n analyst_ids: ReadonlyArray<string>\n }\n | {\n type: 'analyst-skipped'\n summary: AnalystRunSummary\n }\n | {\n type: 'analyst-started'\n analyst_id: string\n started_at: string\n }\n | {\n type: 'analyst-completed'\n /** `summary.status` is `'ok'` for clean completion or `'failed'` for thrown analysts. */\n summary: AnalystRunSummary\n findings: ReadonlyArray<AnalystFinding>\n }\n | {\n type: 'run-completed'\n result: AnalystRunResult\n }\n"],"mappings":";;;;;;AAIA,SAAgB,wBAA2B,OAAa;CACtD,IAAI,SAAS,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG;EACjE,OAAO,OAAO,KAAK;EACnB,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,GAAG,wBAAwB,MAAM;CAC3E;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AC4DA,MAAa,qBAAqB;CAAC;CAAY;CAAQ;CAAU;CAAO;AAAM;;;;;;;;;AAiO9E,SAAgB,iBAAiB,OAOtB;CACT,MAAM,QAAQ,KAAK,UAAU;EAC3B,GAAG,MAAM;EACT,GAAG,MAAM;EACT,GAAG,MAAM,WAAW;EACpB,GAAG,eAAe,MAAM,YAAY,MAAM,KAAK;CACjD,CAAC;CACD,OAAO,KAAK,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;AAC1E;AAEA,SAAS,eAAe,GAAmB;CAGzC,OAAO,EACJ,YAAY,CAAC,CACb,QAAQ,QAAQ,GAAG,CAAC,CACpB,QAAQ,eAAe,EAAE,CAAC,CAC1B,KAAK;AACV;;;;;AAMA,SAAgB,YACd,MAIgB;CAChB,MAAM,EAAE,UAAU,aAAa,GAAG,SAAS;CAC3C,OAAO;EACL,gBAAgB;EAChB,YAAY,iBAAiB;GAC3B,YAAY,KAAK;GACjB,MAAM,KAAK;GACX,SAAS,KAAK;GACd,OAAO,KAAK;GACZ;EACF,CAAC;EACD,aAAa,gCAAe,IAAI,KAAK,EAAA,CAAE,YAAY;EACnD,GAAG;CACL;AACF;;AAGA,SAAgB,oBACd,MAIiB;CACjB,MAAM,EAAE,iBAAiB,GAAG,YAAY;CACxC,OAAO;EAAE,GAAG,YAAY,OAAO;EAAG;CAAgB;AACpD"}
@@ -1,5 +1,5 @@
1
- import { s as RunSplitTag } from "./run-record-BiTWauyO.js";
2
- import { R as Scenario, d as DispatchContext } from "./types-CS0qk_Yp.js";
1
+ import { s as RunSplitTag } from "./run-record-D9wS35fK.js";
2
+ import { R as Scenario, d as DispatchContext } from "./types-BTRcIqFr.js";
3
3
  //#region src/benchmarks/types.d.ts
4
4
  type BenchmarkTaskKind = 'retrieval' | 'rag-answer' | 'hallucination' | 'kb-improvement' | 'routing' | 'custom';
5
5
  type BenchmarkFamily = 'beir' | 'mteb-retrieval' | 'msmarco' | 'trec-dl' | 'miracl' | 'lotte' | 'bright' | 'crag' | 'hotpotqa' | 'kilt' | 'ragtruth' | 'faithbench' | 'first-party' | 'custom';
@@ -90,4 +90,4 @@ declare const BENCHMARK_SPLIT_SEED = "agent-eval-v1";
90
90
  declare function deterministicSplit(itemId: string, seed?: string): RunSplitTag;
91
91
  //#endregion
92
92
  export { BenchmarkFamily as a, BenchmarkSource as c, BenchmarkEvaluation as i, BenchmarkTaskKind as l, BenchmarkAdapter as n, BenchmarkResponder as o, BenchmarkDatasetItem as r, BenchmarkScenario as s, BENCHMARK_SPLIT_SEED as t, deterministicSplit as u };
93
- //# sourceMappingURL=types-BvZoPTGa.d.ts.map
93
+ //# sourceMappingURL=types-c3ZRTbw9.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-BvZoPTGa.d.ts","names":[],"sources":["../src/benchmarks/types.ts"],"mappings":";;;KASY;KAQA;UAgBK,qBAAqB;;;EAGpC;;EAEA,SAAS;;EAET,QAAQ;;EAER,SAAS;;EAET,WAAW;;EAEX;;EAEA,SAAS;EACT,WAAW;;UAGI;;;;EAIf;;EAEA;;EAEA,aAAa;;;EAGb,KAAK;EACL;;UAGe;EACf;EACA;EACA;EACA;EACA;;;UAQe,iBAAiB,kBAAkB,oBAAoB;;EAEtE;EACA,SAAS;EACT,WAAW;EACX;EACA,SAAS;EACT;;;;;EAKA,YAAY,OAAO,cAAc,QAAQ,qBAAqB;;EAE9D,SAAS,MAAM,qBAAqB,WAAW,UAAU,YAAY,QAAQ;;;;EAI7E,YAAY,iBAAiB;;UAGd,kBAAkB,4BAA4B;EAC7D;EACA;EACA,QAAQ;EACR,UAAU;EACV,UAAU;EACV,MAAM,qBAAqB;;KAGjB,mBAAmB,oBAAoB,uBAAuB;EACxE,UAAU,kBAAkB;EAC5B,MAAM,qBAAqB;EAC3B,SAAS;MACL,QAAQ,aAAa;;;cAoBd;;;;;;;;;iBAUG,mBACd,gBACA,gBACC"}
1
+ {"version":3,"file":"types-c3ZRTbw9.d.ts","names":[],"sources":["../src/benchmarks/types.ts"],"mappings":";;;KASY;KAQA;UAgBK,qBAAqB;;;EAGpC;;EAEA,SAAS;;EAET,QAAQ;;EAER,SAAS;;EAET,WAAW;;EAEX;;EAEA,SAAS;EACT,WAAW;;UAGI;;;;EAIf;;EAEA;;EAEA,aAAa;;;EAGb,KAAK;EACL;;UAGe;EACf;EACA;EACA;EACA;EACA;;;UAQe,iBAAiB,kBAAkB,oBAAoB;;EAEtE;EACA,SAAS;EACT,WAAW;EACX;EACA,SAAS;EACT;;;;;EAKA,YAAY,OAAO,cAAc,QAAQ,qBAAqB;;EAE9D,SAAS,MAAM,qBAAqB,WAAW,UAAU,YAAY,QAAQ;;;;EAI7E,YAAY,iBAAiB;;UAGd,kBAAkB,4BAA4B;EAC7D;EACA;EACA,QAAQ;EACR,UAAU;EACV,UAAU;EACV,MAAM,qBAAqB;;KAGjB,mBAAmB,oBAAoB,uBAAuB;EACxE,UAAU,kBAAkB;EAC5B,MAAM,qBAAqB;EAC3B,SAAS;MACL,QAAQ,aAAa;;;cAoBd;;;;;;;;;iBAUG,mBACd,gBACA,gBACC"}
@@ -1,16 +1,3 @@
1
- import { createHash } from "node:crypto";
2
- //#region src/ledger-core/deep-freeze.ts
3
- /** Freeze a detached canonical-JSON graph. Canonicalization has already ruled out cycles.
4
- *
5
- * Lives outside canonical.ts so the analyst-benchmark implementation digest,
6
- * which covers canonical.ts, stays bound to the published benchmark evidence. */
7
- function deepFreezeCanonicalJson(value) {
8
- if (value && typeof value === "object" && !Object.isFrozen(value)) {
9
- Object.freeze(value);
10
- for (const nested of Object.values(value)) deepFreezeCanonicalJson(nested);
11
- }
12
- return value;
13
- }
14
1
  /** Convert one ledger channel's complete call set into one analyst receipt. */
15
2
  function usageReceiptFromCostLedger(ledger, filter = "analyst") {
16
3
  const resolvedFilter = typeof filter === "string" ? { channel: filter } : filter;
@@ -84,80 +71,6 @@ function assertNonNegativeFinite(value, field, context) {
84
71
  if (!Number.isFinite(value) || value < 0) throw new Error(`${context}: ${field} must be a non-negative finite number`);
85
72
  }
86
73
  //#endregion
87
- //#region src/analyst/types.ts
88
- /**
89
- * Analyst contract — the missing orchestration layer over agent-eval's
90
- * existing analyzers (analyzeTraces, MultiLayerVerifier,
91
- * SemanticConceptJudge, JudgeFn, ...).
92
- *
93
- * Each existing primitive returns its own output shape. The Analyst
94
- * contract is the single envelope every primitive lifts into, so a
95
- * registry can run N analysts against a run and a single renderer can
96
- * compose findings without knowing which analyzer produced them.
97
- *
98
- * The contract is intentionally domain-agnostic: nothing here knows
99
- * about code, voice, RAG, or any particular agent stack. Analysts
100
- * declare what INPUT KIND they need (a trace store, an artifact dir,
101
- * a RunRecord, a JudgeInput, or `custom`), and the registry routes
102
- * the matching input from `AnalystRunInputs`.
103
- */
104
- /** Finding severity. `AnalystSeverity` derives from this array, so the type
105
- * and the schema that validates a finding cannot name different levels. */
106
- const ANALYST_SEVERITIES = [
107
- "critical",
108
- "high",
109
- "medium",
110
- "low",
111
- "info"
112
- ];
113
- /**
114
- * Compute the stable finding_id from the identity-defining fields.
115
- * Default implementation hashes {analyst_id, area, subject, normalized claim}.
116
- * Analysts that emit findings whose claim text varies per run (timestamps,
117
- * counts) SHOULD either: (a) pass an explicit `id_basis` to fix the hash,
118
- * or (b) move the variable part into `rationale`/`metadata` and keep the
119
- * `claim` static.
120
- */
121
- function computeFindingId(input) {
122
- const basis = JSON.stringify({
123
- a: input.analyst_id,
124
- r: input.area,
125
- s: input.subject ?? "",
126
- c: normalizeClaim(input.id_basis ?? input.claim)
127
- });
128
- return `f_${createHash("sha256").update(basis).digest("hex").slice(0, 20)}`;
129
- }
130
- function normalizeClaim(c) {
131
- return c.toLowerCase().replace(/\s+/g, " ").replace(/[.!?;:,]+$/g, "").trim();
132
- }
133
- /**
134
- * Convenience factory: produce a fully-formed AnalystFinding with the
135
- * id computed automatically. Analyst code stays terse.
136
- */
137
- function makeFinding(init) {
138
- const { id_basis, produced_at, ...rest } = init;
139
- return {
140
- schema_version: "1.0.0",
141
- finding_id: computeFindingId({
142
- analyst_id: rest.analyst_id,
143
- area: rest.area,
144
- subject: rest.subject,
145
- claim: rest.claim,
146
- id_basis
147
- }),
148
- produced_at: produced_at ?? (/* @__PURE__ */ new Date()).toISOString(),
149
- ...rest
150
- };
151
- }
152
- /** Build a finding whose source is explicitly allowed during candidate generation. */
153
- function makeProposalFinding(init) {
154
- const { proposal_origin, ...finding } = init;
155
- return {
156
- ...makeFinding(finding),
157
- proposal_origin
158
- };
159
- }
160
- //#endregion
161
- export { assertValidAnalystUsageReceipt as a, validateUsageSettlementTimeout as c, makeProposalFinding as i, deepFreezeCanonicalJson as l, computeFindingId as n, settleUsageReceiptFromCostLedger as o, makeFinding as r, usageReceiptFromCostLedger as s, ANALYST_SEVERITIES as t };
74
+ export { validateUsageSettlementTimeout as i, settleUsageReceiptFromCostLedger as n, usageReceiptFromCostLedger as r, assertValidAnalystUsageReceipt as t };
162
75
 
163
- //# sourceMappingURL=types-DQ0e2E7y.js.map
76
+ //# sourceMappingURL=usage-receipt-Cx3xNeyB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-receipt-Cx3xNeyB.js","names":[],"sources":["../src/analyst/usage-receipt.ts"],"sourcesContent":["import type { CostChannel, CostLedgerFilter, CostLedgerHandle } from '../cost-ledger'\nimport type { AnalystUsageReceipt } from './types'\n\nexport const DEFAULT_USAGE_SETTLEMENT_TIMEOUT_MS = 5_000\n\n/** Convert one ledger channel's complete call set into one analyst receipt. */\nexport function usageReceiptFromCostLedger(\n ledger: CostLedgerHandle,\n filter: CostChannel | CostLedgerFilter = 'analyst',\n): AnalystUsageReceipt {\n const resolvedFilter = typeof filter === 'string' ? { channel: filter } : filter\n const summary = ledger.summary(resolvedFilter)\n const receipts = ledger.list(resolvedFilter)\n const hasReasoningUsage = receipts.some((receipt) => receipt.reasoningTokens !== undefined)\n const hasCacheWriteUsage = receipts.some((receipt) => receipt.cacheWriteTokens !== undefined)\n const cost = summary.costProvenance\n return {\n calls: summary.totalCalls + summary.pendingCalls,\n tokens: summary.usageComplete\n ? {\n input: summary.inputTokens,\n output: summary.outputTokens,\n ...(hasReasoningUsage ? { reasoning: summary.reasoningTokens ?? 0 } : {}),\n ...(summary.cachedTokens > 0 ? { cached: summary.cachedTokens } : {}),\n ...(hasCacheWriteUsage ? { cacheWrite: summary.cacheWriteTokens ?? 0 } : {}),\n }\n : null,\n cost,\n ...(cost.kind === 'uncaptured' ? { knownCostUsd: summary.totalCostUsd } : {}),\n }\n}\n\nexport interface SettledUsageReceipt {\n settled: boolean\n pendingCalls: number\n receipt: AnalystUsageReceipt\n}\n\n/** Wait a bounded time for late provider receipts, then take one immutable snapshot. */\nexport async function settleUsageReceiptFromCostLedger(\n ledger: CostLedgerHandle,\n options: CostLedgerFilter & { timeoutMs?: number } = {},\n): Promise<SettledUsageReceipt> {\n const { timeoutMs: requestedTimeoutMs, ...requestedFilter } = options\n const filter: CostLedgerFilter = {\n channel: requestedFilter.channel ?? 'analyst',\n ...(requestedFilter.phase === undefined ? {} : { phase: requestedFilter.phase }),\n ...(requestedFilter.tags === undefined ? {} : { tags: requestedFilter.tags }),\n }\n const timeoutMs = validateUsageSettlementTimeout(requestedTimeoutMs)\n const initial = ledger.summary(filter)\n const waitResult =\n initial.pendingCalls === 0\n ? true\n : ledger.waitForIdle\n ? await ledger.waitForIdle({ timeoutMs })\n : false\n const pendingCalls = ledger.summary(filter).pendingCalls\n return {\n settled: waitResult && pendingCalls === 0,\n pendingCalls,\n receipt: usageReceiptFromCostLedger(ledger, filter),\n }\n}\n\nexport function validateUsageSettlementTimeout(timeoutMs?: number): number {\n const resolved = timeoutMs ?? DEFAULT_USAGE_SETTLEMENT_TIMEOUT_MS\n if (!Number.isSafeInteger(resolved) || resolved < 0 || resolved > 2_147_483_647) {\n throw new TypeError(\n 'settlementTimeoutMs must be a non-negative safe integer no greater than 2147483647',\n )\n }\n return resolved\n}\n\nexport function assertValidAnalystUsageReceipt(\n receipt: AnalystUsageReceipt,\n context = 'AnalystContext.recordUsage',\n): void {\n if (receipt.calls !== null && (!Number.isSafeInteger(receipt.calls) || receipt.calls < 0)) {\n throw new Error(`${context}: calls must be a non-negative safe integer or null`)\n }\n if (receipt.tokens) {\n assertNonNegativeSafeInteger(receipt.tokens.input, 'tokens.input', context)\n assertNonNegativeSafeInteger(receipt.tokens.output, 'tokens.output', context)\n if (receipt.tokens.reasoning !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.reasoning, 'tokens.reasoning', context)\n if (receipt.tokens.reasoning > receipt.tokens.output) {\n throw new Error(`${context}: tokens.reasoning must not exceed tokens.output`)\n }\n }\n if (receipt.tokens.cached !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.cached, 'tokens.cached', context)\n }\n if (receipt.tokens.cacheWrite !== undefined) {\n assertNonNegativeSafeInteger(receipt.tokens.cacheWrite, 'tokens.cacheWrite', context)\n }\n }\n if (receipt.cost.kind !== 'uncaptured') {\n assertNonNegativeFinite(receipt.cost.usd, 'cost.usd', context)\n } else if (receipt.cost.usd !== null) {\n throw new Error(`${context}: uncaptured cost.usd must be null`)\n }\n if (receipt.knownCostUsd !== undefined) {\n assertNonNegativeFinite(receipt.knownCostUsd, 'knownCostUsd', context)\n }\n if (receipt.partialTokens) {\n const { input, output } = receipt.partialTokens\n if (receipt.tokens) {\n throw new Error(`${context}: partialTokens must be absent when tokens is complete`)\n }\n if (input === null && output === null) {\n throw new Error(`${context}: partialTokens must carry at least one reported side`)\n }\n if (input !== null) assertNonNegativeSafeInteger(input, 'partialTokens.input', context)\n if (output !== null) assertNonNegativeSafeInteger(output, 'partialTokens.output', context)\n }\n}\n\nfunction assertNonNegativeSafeInteger(value: number, field: string, context: string): void {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(`${context}: ${field} must be a non-negative safe integer`)\n }\n}\n\nfunction assertNonNegativeFinite(value: number, field: string, context: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`${context}: ${field} must be a non-negative finite number`)\n }\n}\n"],"mappings":";AAMA,SAAgB,2BACd,QACA,SAAyC,WACpB;CACrB,MAAM,iBAAiB,OAAO,WAAW,WAAW,EAAE,SAAS,OAAO,IAAI;CAC1E,MAAM,UAAU,OAAO,QAAQ,cAAc;CAC7C,MAAM,WAAW,OAAO,KAAK,cAAc;CAC3C,MAAM,oBAAoB,SAAS,MAAM,YAAY,QAAQ,oBAAoB,KAAA,CAAS;CAC1F,MAAM,qBAAqB,SAAS,MAAM,YAAY,QAAQ,qBAAqB,KAAA,CAAS;CAC5F,MAAM,OAAO,QAAQ;CACrB,OAAO;EACL,OAAO,QAAQ,aAAa,QAAQ;EACpC,QAAQ,QAAQ,gBACZ;GACE,OAAO,QAAQ;GACf,QAAQ,QAAQ;GAChB,GAAI,oBAAoB,EAAE,WAAW,QAAQ,mBAAmB,EAAE,IAAI,CAAC;GACvE,GAAI,QAAQ,eAAe,IAAI,EAAE,QAAQ,QAAQ,aAAa,IAAI,CAAC;GACnE,GAAI,qBAAqB,EAAE,YAAY,QAAQ,oBAAoB,EAAE,IAAI,CAAC;EAC5E,IACA;EACJ;EACA,GAAI,KAAK,SAAS,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;CAC7E;AACF;;AASA,eAAsB,iCACpB,QACA,UAAqD,CAAC,GACxB;CAC9B,MAAM,EAAE,WAAW,oBAAoB,GAAG,oBAAoB;CAC9D,MAAM,SAA2B;EAC/B,SAAS,gBAAgB,WAAW;EACpC,GAAI,gBAAgB,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,gBAAgB,MAAM;EAC9E,GAAI,gBAAgB,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,gBAAgB,KAAK;CAC7E;CACA,MAAM,YAAY,+BAA+B,kBAAkB;CAEnE,MAAM,aADU,OAAO,QAAQ,MAEvB,CAAC,CAAC,iBAAiB,IACrB,OACA,OAAO,cACL,MAAM,OAAO,YAAY,EAAE,UAAU,CAAC,IACtC;CACR,MAAM,eAAe,OAAO,QAAQ,MAAM,CAAC,CAAC;CAC5C,OAAO;EACL,SAAS,cAAc,iBAAiB;EACxC;EACA,SAAS,2BAA2B,QAAQ,MAAM;CACpD;AACF;AAEA,SAAgB,+BAA+B,WAA4B;CACzE,MAAM,WAAW,aAAA;CACjB,IAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,WAAW,KAAK,WAAW,YAChE,MAAM,IAAI,UACR,oFACF;CAEF,OAAO;AACT;AAEA,SAAgB,+BACd,SACA,UAAU,8BACJ;CACN,IAAI,QAAQ,UAAU,SAAS,CAAC,OAAO,cAAc,QAAQ,KAAK,KAAK,QAAQ,QAAQ,IACrF,MAAM,IAAI,MAAM,GAAG,QAAQ,oDAAoD;CAEjF,IAAI,QAAQ,QAAQ;EAClB,6BAA6B,QAAQ,OAAO,OAAO,gBAAgB,OAAO;EAC1E,6BAA6B,QAAQ,OAAO,QAAQ,iBAAiB,OAAO;EAC5E,IAAI,QAAQ,OAAO,cAAc,KAAA,GAAW;GAC1C,6BAA6B,QAAQ,OAAO,WAAW,oBAAoB,OAAO;GAClF,IAAI,QAAQ,OAAO,YAAY,QAAQ,OAAO,QAC5C,MAAM,IAAI,MAAM,GAAG,QAAQ,iDAAiD;EAEhF;EACA,IAAI,QAAQ,OAAO,WAAW,KAAA,GAC5B,6BAA6B,QAAQ,OAAO,QAAQ,iBAAiB,OAAO;EAE9E,IAAI,QAAQ,OAAO,eAAe,KAAA,GAChC,6BAA6B,QAAQ,OAAO,YAAY,qBAAqB,OAAO;CAExF;CACA,IAAI,QAAQ,KAAK,SAAS,cACxB,wBAAwB,QAAQ,KAAK,KAAK,YAAY,OAAO;MACxD,IAAI,QAAQ,KAAK,QAAQ,MAC9B,MAAM,IAAI,MAAM,GAAG,QAAQ,mCAAmC;CAEhE,IAAI,QAAQ,iBAAiB,KAAA,GAC3B,wBAAwB,QAAQ,cAAc,gBAAgB,OAAO;CAEvE,IAAI,QAAQ,eAAe;EACzB,MAAM,EAAE,OAAO,WAAW,QAAQ;EAClC,IAAI,QAAQ,QACV,MAAM,IAAI,MAAM,GAAG,QAAQ,uDAAuD;EAEpF,IAAI,UAAU,QAAQ,WAAW,MAC/B,MAAM,IAAI,MAAM,GAAG,QAAQ,sDAAsD;EAEnF,IAAI,UAAU,MAAM,6BAA6B,OAAO,uBAAuB,OAAO;EACtF,IAAI,WAAW,MAAM,6BAA6B,QAAQ,wBAAwB,OAAO;CAC3F;AACF;AAEA,SAAS,6BAA6B,OAAe,OAAe,SAAuB;CACzF,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAC1C,MAAM,IAAI,MAAM,GAAG,QAAQ,IAAI,MAAM,qCAAqC;AAE9E;AAEA,SAAS,wBAAwB,OAAe,OAAe,SAAuB;CACpF,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,GAAG,QAAQ,IAAI,MAAM,sCAAsC;AAE/E"}
@@ -1,4 +1,4 @@
1
- import { n as contentHash } from "./verdict-cache-B3eCVQtY.js";
1
+ import { n as contentHash } from "./verdict-cache-BQEsVy9n.js";
2
2
  //#region src/verdict.ts
3
3
  /**
4
4
  * Validator-output verdict — substrate primitive for "did this output pass,
@@ -58,4 +58,4 @@ function equivalenceVerdict(record) {
58
58
  //#endregion
59
59
  export { equivalenceVerdict as n, certificationEvidenceDigest as t };
60
60
 
61
- //# sourceMappingURL=verdict-BQ3pCFf8.js.map
61
+ //# sourceMappingURL=verdict-DhPoXApk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verdict-BQ3pCFf8.js","names":[],"sources":["../src/verdict.ts"],"sourcesContent":["/**\n * Validator-output verdict — substrate primitive for \"did this output pass,\n * and how well?\"\n *\n * Used by:\n * - `@tangle-network/agent-eval/matrix` — verdict per cell in the cartesian.\n * - `@tangle-network/agent-runtime` — Validator<Output, Verdict = DefaultVerdict>.\n * Runtime keeps `Validator` because it's coupled to runtime-shaped\n * `ValidationCtx` (iteration, signal, traceEmitter); the verdict TYPE\n * itself is a substrate concept and lives here.\n *\n * Repo layering: agent-eval is the substrate (no upward deps). Both\n * agent-runtime and agent-knowledge consume this type FROM agent-eval —\n * never the other way around. See CLAUDE.md \"Repo layering\" for the rule.\n */\n\nimport { contentHash } from './verdict-cache'\nimport type {\n CheckerIdentity,\n EquivalenceRecord,\n VerificationStrategySource,\n} from './verification-strategy'\n\n/**\n * What certified a verdict — the epistemics a bare `valid` + `score` pair\n * cannot carry. A kernel-checked proof and an LLM judge can produce the\n * same `{ valid: true, score: 1 }`; this record is what tells them apart.\n *\n * Every field is required on purpose. A certification without a checker\n * identity or an evidence digest is exactly the unverifiable claim this\n * record exists to kill.\n */\nexport interface VerdictCertification {\n /**\n * Which verification-strategy member produced the certificate. Each\n * member's failure mode is documented on the family type and in\n * `VERIFICATION_STRATEGIES` (src/verification-strategy.ts).\n */\n strategy: VerificationStrategySource\n /**\n * Exact checker identity, e.g. `{ name: 'lean4', version: '4.33.0',\n * pins: { mathlib: 'db584cd6d46c' } }` for a kernel, or a judge model\n * id + snapshot for a judge.\n */\n checker: CheckerIdentity\n /**\n * Every step the certificate rests on that the checker did NOT verify,\n * e.g. 'diagonal embedding argued in prose' or 'agreement arms share\n * training-corpus blind spots'. An empty array is the producer's\n * explicit, auditable claim that there are none — it is not a default.\n */\n assumptions: string[]\n /** Digest (e.g. sha256) of the evidence artifact the checker consumed or produced. */\n evidenceDigest: string\n}\n\n/**\n * Minimal verdict shape — `valid` + `score` are required; `scores` +\n * `notes` are optional surface. Validators that need richer shapes\n * parameterise `Validator<Output, MyVerdict>` with their own type.\n *\n * Need structured extras? Extend DefaultVerdict with typed fields — never\n * serialize extras into `notes`.\n */\nexport interface DefaultVerdict {\n /** Whether the output meets the validator's pass criteria. */\n valid: boolean\n /** Aggregate score in [0, 1]. Drivers use this for winner selection. */\n score: number\n /** Per-dimension scores. Free-form; weighted into `score` by the validator. */\n scores?: Record<string, number>\n /** Human-readable rationale; surfaces in trace + final-result `winner.verdict`. */\n notes?: string\n /**\n * What certified this verdict, when anything did. Absent = uncertified:\n * scored, but no strategy vouches for it. A consumer that cares reads\n * `certification.strategy` to tell a kernel-checked verdict from a\n * judge-scored one; a consumer that does not read it sees the exact\n * verdict it always saw.\n */\n certification?: VerdictCertification\n}\n\n/**\n * Digest a certification's evidence artifact: sha-256 over the canonical\n * JSON of the evidence AS SERIALIZED. The JSON round-trip drops\n * `undefined`-valued fields on purpose — certified verdicts persist as\n * JSON, so the digest must cover exactly what a reader of the persisted\n * artifact can re-digest, nothing the wire cannot carry. Throws when the\n * evidence has no JSON form at all.\n */\nexport function certificationEvidenceDigest(evidence: unknown): string {\n const serialized = JSON.stringify(evidence)\n if (serialized === undefined) {\n throw new Error(\n 'certificationEvidenceDigest: evidence has no JSON form — a certificate over nothing is the unverifiable claim this record exists to kill',\n )\n }\n return contentHash(JSON.parse(serialized))\n}\n\n/**\n * Land a finished statement-equivalence record in the shared verdict\n * spine. `valid` answers the protocol's question — are the two blind\n * statements equivalent — so a refutation is `valid: false` even though a\n * separating witness in hand is a successful protocol outcome.\n *\n * Certification is present exactly when the obligation was discharged\n * (proved or refuted): the checker vouches for the discharge either way.\n * An unresolved obligation certifies nothing and keeps its reason in\n * `notes`.\n */\nexport function equivalenceVerdict(record: EquivalenceRecord): DefaultVerdict {\n const { obligation, spec, arms } = record\n const discharged = obligation.status !== 'unresolved'\n const notes =\n obligation.status === 'proved'\n ? `statements equivalent: ${spec.artifact}`\n : obligation.status === 'refuted-with-separating-witness'\n ? `formalization gap witnessed: ${obligation.separatingWitness}`\n : `obligation undischarged: ${obligation.unresolvedReason}`\n return {\n valid: obligation.status === 'proved',\n score: obligation.status === 'proved' ? 1 : 0,\n notes,\n ...(discharged && obligation.evidenceDigest !== undefined\n ? {\n certification: {\n strategy: spec.source,\n checker: obligation.checker,\n // The arms' blindness declarations are attested by the arms,\n // never verified by the checker — the one step every\n // equivalence certificate rests on.\n assumptions: [\n `arm '${arms[0].armId}' and arm '${arms[1].armId}' self-declare blind derivation`,\n ],\n evidenceDigest: obligation.evidenceDigest,\n } satisfies VerdictCertification,\n }\n : {}),\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,SAAgB,4BAA4B,UAA2B;CACrE,MAAM,aAAa,KAAK,UAAU,QAAQ;CAC1C,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,MACR,0IACF;CAEF,OAAO,YAAY,KAAK,MAAM,UAAU,CAAC;AAC3C;;;;;;;;;;;;AAaA,SAAgB,mBAAmB,QAA2C;CAC5E,MAAM,EAAE,YAAY,MAAM,SAAS;CACnC,MAAM,aAAa,WAAW,WAAW;CACzC,MAAM,QACJ,WAAW,WAAW,WAClB,0BAA0B,KAAK,aAC/B,WAAW,WAAW,oCACpB,gCAAgC,WAAW,sBAC3C,4BAA4B,WAAW;CAC/C,OAAO;EACL,OAAO,WAAW,WAAW;EAC7B,OAAO,WAAW,WAAW,WAAW,IAAI;EAC5C;EACA,GAAI,cAAc,WAAW,mBAAmB,KAAA,IAC5C,EACE,eAAe;GACb,UAAU,KAAK;GACf,SAAS,WAAW;GAIpB,aAAa,CACX,QAAQ,KAAK,EAAE,CAAC,MAAM,aAAa,KAAK,EAAE,CAAC,MAAM,gCACnD;GACA,gBAAgB,WAAW;EAC7B,EACF,IACA,CAAC;CACP;AACF"}
1
+ {"version":3,"file":"verdict-DhPoXApk.js","names":[],"sources":["../src/verdict.ts"],"sourcesContent":["/**\n * Validator-output verdict — substrate primitive for \"did this output pass,\n * and how well?\"\n *\n * Used by:\n * - `@tangle-network/agent-eval/matrix` — verdict per cell in the cartesian.\n * - `@tangle-network/agent-runtime` — Validator<Output, Verdict = DefaultVerdict>.\n * Runtime keeps `Validator` because it's coupled to runtime-shaped\n * `ValidationCtx` (iteration, signal, traceEmitter); the verdict TYPE\n * itself is a substrate concept and lives here.\n *\n * Repo layering: agent-eval is the substrate (no upward deps). Both\n * agent-runtime and agent-knowledge consume this type FROM agent-eval —\n * never the other way around. See CLAUDE.md \"Repo layering\" for the rule.\n */\n\nimport { contentHash } from './verdict-cache'\nimport type {\n CheckerIdentity,\n EquivalenceRecord,\n VerificationStrategySource,\n} from './verification-strategy'\n\n/**\n * What certified a verdict — the epistemics a bare `valid` + `score` pair\n * cannot carry. A kernel-checked proof and an LLM judge can produce the\n * same `{ valid: true, score: 1 }`; this record is what tells them apart.\n *\n * Every field is required on purpose. A certification without a checker\n * identity or an evidence digest is exactly the unverifiable claim this\n * record exists to kill.\n */\nexport interface VerdictCertification {\n /**\n * Which verification-strategy member produced the certificate. Each\n * member's failure mode is documented on the family type and in\n * `VERIFICATION_STRATEGIES` (src/verification-strategy.ts).\n */\n strategy: VerificationStrategySource\n /**\n * Exact checker identity, e.g. `{ name: 'lean4', version: '4.33.0',\n * pins: { mathlib: 'db584cd6d46c' } }` for a kernel, or a judge model\n * id + snapshot for a judge.\n */\n checker: CheckerIdentity\n /**\n * Every step the certificate rests on that the checker did NOT verify,\n * e.g. 'diagonal embedding argued in prose' or 'agreement arms share\n * training-corpus blind spots'. An empty array is the producer's\n * explicit, auditable claim that there are none — it is not a default.\n */\n assumptions: string[]\n /** Digest (e.g. sha256) of the evidence artifact the checker consumed or produced. */\n evidenceDigest: string\n}\n\n/**\n * Minimal verdict shape — `valid` + `score` are required; `scores` +\n * `notes` are optional surface. Validators that need richer shapes\n * parameterise `Validator<Output, MyVerdict>` with their own type.\n *\n * Need structured extras? Extend DefaultVerdict with typed fields — never\n * serialize extras into `notes`.\n */\nexport interface DefaultVerdict {\n /** Whether the output meets the validator's pass criteria. */\n valid: boolean\n /** Aggregate score in [0, 1]. Drivers use this for winner selection. */\n score: number\n /** Per-dimension scores. Free-form; weighted into `score` by the validator. */\n scores?: Record<string, number>\n /** Human-readable rationale; surfaces in trace + final-result `winner.verdict`. */\n notes?: string\n /**\n * What certified this verdict, when anything did. Absent = uncertified:\n * scored, but no strategy vouches for it. A consumer that cares reads\n * `certification.strategy` to tell a kernel-checked verdict from a\n * judge-scored one; a consumer that does not read it sees the exact\n * verdict it always saw.\n */\n certification?: VerdictCertification\n}\n\n/**\n * Digest a certification's evidence artifact: sha-256 over the canonical\n * JSON of the evidence AS SERIALIZED. The JSON round-trip drops\n * `undefined`-valued fields on purpose — certified verdicts persist as\n * JSON, so the digest must cover exactly what a reader of the persisted\n * artifact can re-digest, nothing the wire cannot carry. Throws when the\n * evidence has no JSON form at all.\n */\nexport function certificationEvidenceDigest(evidence: unknown): string {\n const serialized = JSON.stringify(evidence)\n if (serialized === undefined) {\n throw new Error(\n 'certificationEvidenceDigest: evidence has no JSON form — a certificate over nothing is the unverifiable claim this record exists to kill',\n )\n }\n return contentHash(JSON.parse(serialized))\n}\n\n/**\n * Land a finished statement-equivalence record in the shared verdict\n * spine. `valid` answers the protocol's question — are the two blind\n * statements equivalent — so a refutation is `valid: false` even though a\n * separating witness in hand is a successful protocol outcome.\n *\n * Certification is present exactly when the obligation was discharged\n * (proved or refuted): the checker vouches for the discharge either way.\n * An unresolved obligation certifies nothing and keeps its reason in\n * `notes`.\n */\nexport function equivalenceVerdict(record: EquivalenceRecord): DefaultVerdict {\n const { obligation, spec, arms } = record\n const discharged = obligation.status !== 'unresolved'\n const notes =\n obligation.status === 'proved'\n ? `statements equivalent: ${spec.artifact}`\n : obligation.status === 'refuted-with-separating-witness'\n ? `formalization gap witnessed: ${obligation.separatingWitness}`\n : `obligation undischarged: ${obligation.unresolvedReason}`\n return {\n valid: obligation.status === 'proved',\n score: obligation.status === 'proved' ? 1 : 0,\n notes,\n ...(discharged && obligation.evidenceDigest !== undefined\n ? {\n certification: {\n strategy: spec.source,\n checker: obligation.checker,\n // The arms' blindness declarations are attested by the arms,\n // never verified by the checker — the one step every\n // equivalence certificate rests on.\n assumptions: [\n `arm '${arms[0].armId}' and arm '${arms[1].armId}' self-declare blind derivation`,\n ],\n evidenceDigest: obligation.evidenceDigest,\n } satisfies VerdictCertification,\n }\n : {}),\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,SAAgB,4BAA4B,UAA2B;CACrE,MAAM,aAAa,KAAK,UAAU,QAAQ;CAC1C,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,MACR,0IACF;CAEF,OAAO,YAAY,KAAK,MAAM,UAAU,CAAC;AAC3C;;;;;;;;;;;;AAaA,SAAgB,mBAAmB,QAA2C;CAC5E,MAAM,EAAE,YAAY,MAAM,SAAS;CACnC,MAAM,aAAa,WAAW,WAAW;CACzC,MAAM,QACJ,WAAW,WAAW,WAClB,0BAA0B,KAAK,aAC/B,WAAW,WAAW,oCACpB,gCAAgC,WAAW,sBAC3C,4BAA4B,WAAW;CAC/C,OAAO;EACL,OAAO,WAAW,WAAW;EAC7B,OAAO,WAAW,WAAW,WAAW,IAAI;EAC5C;EACA,GAAI,cAAc,WAAW,mBAAmB,KAAA,IAC5C,EACE,eAAe;GACb,UAAU,KAAK;GACf,SAAS,WAAW;GAIpB,aAAa,CACX,QAAQ,KAAK,EAAE,CAAC,MAAM,aAAa,KAAK,EAAE,CAAC,MAAM,gCACnD;GACA,gBAAgB,WAAW;EAC7B,EACF,IACA,CAAC;CACP;AACF"}
@@ -1,4 +1,4 @@
1
- import { a as hashCanonical, r as canonicalString } from "./canonical-DPyQ_rpt.js";
1
+ import { a as hashCanonical, r as canonicalString } from "./canonical-BsZVgBhW.js";
2
2
  import { appendFileSync, existsSync, readFileSync } from "node:fs";
3
3
  //#region src/verdict-cache.ts
4
4
  /**
@@ -85,4 +85,4 @@ function fileVerdictCache(path) {
85
85
  //#endregion
86
86
  export { contentHash as n, fileVerdictCache as r, canonicalJson as t };
87
87
 
88
- //# sourceMappingURL=verdict-cache-B3eCVQtY.js.map
88
+ //# sourceMappingURL=verdict-cache-BQEsVy9n.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verdict-cache-B3eCVQtY.js","names":[],"sources":["../src/verdict-cache.ts"],"sourcesContent":["/**\n * Content-addressed judge-verdict caching.\n *\n * LAW: cache JUDGE VERDICTS only — judging the same artifact with the same\n * judge+rubric is pure. NEVER cache agent rollouts. (A router that cached\n * identical fanout prompts silently destroyed best-of-N diversity; rollout\n * caching reintroduces that failure class. Judging has no diversity to\n * destroy — same artifact + same rubric ⇒ same verdict is the desired\n * property, not a bug.)\n *\n * The cache key is `v2:` + a sha-256 over the canonical JSON of everything\n * that can change a verdict: the artifact content, the scenario id, the judge\n * name, the full dimension list (key + description — the description IS the\n * rubric text shown to the judge), and a caller-supplied `judgeVersion`.\n * `judgeVersion` is REQUIRED: a judge whose prompt/model/ensemble changes\n * without a version bump would otherwise silently serve stale verdicts.\n * The `v2:` prefix names the key scheme; a store written under another scheme\n * misses once and repopulates.\n *\n * Canonical JSON is RFC 8785 from `ledger-core/canonical` — the package's one\n * identity scheme. It refuses `undefined`, functions, symbols, non-finite\n * numbers, class instances (including `Date`), `Map`, `Set`, cycles, and\n * unpaired surrogates: an artifact that cannot be unambiguously serialized\n * cannot be content-addressed, and coercing it would let two different\n * artifacts collide on one key. Pass timestamps as ISO strings.\n */\n\nimport { appendFileSync, existsSync, readFileSync } from 'node:fs'\nimport type { JudgeConfig, JudgeScore, Scenario } from './campaign/types'\nimport { canonicalString, hashCanonical } from './ledger-core/canonical'\n\n// ── canonical JSON + content hash ─────────────────────────────────────────\n\n/** Key scheme of every entry `cachedJudge` writes. */\nexport const VERDICT_CACHE_KEY_SCHEME = 'v2'\n\n/**\n * Canonical JSON (RFC 8785): object keys sorted recursively, so two\n * semantically equal values produce byte-identical output regardless of key\n * insertion order. Throws `LedgerCanonicalizationError` on any value with no\n * faithful JSON form — see `ledger-core/canonical`.\n */\nexport function canonicalJson(value: unknown): string {\n return canonicalString(value)\n}\n\n/** Hex sha-256 over `canonicalJson(value)`. The content address used by the\n * verdict cache and report attestation. Equals `hashCanonical(value)` with\n * the `sha256:` prefix removed. */\nexport function contentHash(value: unknown): string {\n return hashCanonical(value).slice('sha256:'.length)\n}\n\n// ── store contract ─────────────────────────────────────────────────────────\n\n/** Pluggable verdict store. Sync or async on both legs — `cachedJudge`\n * awaits the results either way. */\nexport interface VerdictCacheStore {\n get(key: string): Promise<JudgeScore | undefined> | JudgeScore | undefined\n set(key: string, score: JudgeScore): Promise<void> | void\n}\n\n/** Process-local Map-backed store. */\nexport function inMemoryVerdictCache(): VerdictCacheStore {\n const entries = new Map<string, JudgeScore>()\n return {\n get: (key) => entries.get(key),\n set: (key, score) => {\n entries.set(key, score)\n },\n }\n}\n\ninterface VerdictCacheLine {\n key: string\n score: JudgeScore\n}\n\nfunction parseCacheLine(line: string, path: string, lineNo: number): VerdictCacheLine {\n let parsed: unknown\n try {\n parsed = JSON.parse(line)\n } catch (err) {\n throw new Error(\n `fileVerdictCache: corrupt JSONL at ${path}:${lineNo} — ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n const rec = parsed as Partial<VerdictCacheLine>\n if (\n typeof rec !== 'object' ||\n rec === null ||\n typeof rec.key !== 'string' ||\n typeof rec.score !== 'object' ||\n rec.score === null ||\n typeof rec.score.composite !== 'number' ||\n typeof rec.score.dimensions !== 'object'\n ) {\n throw new Error(\n `fileVerdictCache: invalid record shape at ${path}:${lineNo} — expected {key, score:{dimensions, composite, notes}}`,\n )\n }\n return rec as VerdictCacheLine\n}\n\n/**\n * JSONL-file-backed store: the full file is loaded into an in-memory index at\n * construction; every `set` appends one line synchronously (durable before\n * the verdict is returned). A corrupt or malformed line throws at load with\n * file:line — a skipped line would silently re-judge (cost) or, worse, mask\n * a half-written file that needs operator attention.\n */\nexport function fileVerdictCache(path: string): VerdictCacheStore {\n const entries = new Map<string, JudgeScore>()\n if (existsSync(path)) {\n const lines = readFileSync(path, 'utf8').split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (line === undefined || line.trim() === '') continue\n const rec = parseCacheLine(line, path, i + 1)\n entries.set(rec.key, rec.score)\n }\n }\n return {\n get: (key) => entries.get(key),\n set: (key, score) => {\n appendFileSync(path, `${JSON.stringify({ key, score })}\\n`, 'utf8')\n entries.set(key, score)\n },\n }\n}\n\n// ── cached judge wrapper ───────────────────────────────────────────────────\n\nexport interface VerdictCacheStats {\n hits: number\n misses: number\n}\n\nexport interface CachedJudgeOptions {\n /** REQUIRED — part of the cache key. Bump on any change to the judge's\n * prompt, model, ensemble, or scoring logic; silent judge upgrades must\n * never serve stale verdicts. */\n judgeVersion: string\n}\n\n/** The wrapped judge: same `JudgeConfig` seam, plus hit/miss observability. */\nexport type CachedJudge<TArtifact, TScenario extends Scenario = Scenario> = JudgeConfig<\n TArtifact,\n TScenario\n> & {\n stats(): VerdictCacheStats\n}\n\n/**\n * Wrap a `JudgeConfig` so repeat judgments of the same artifact are served\n * from the store instead of re-invoking `score()`. The wrapper is generic\n * over the judge's own type parameters and preserves `appliesTo` — it is a\n * drop-in replacement anywhere a `JudgeConfig` is accepted.\n *\n * A judge that throws is NOT cached: the error propagates and the next\n * attempt re-judges (caching a failure would pin a transient outage forever).\n */\nexport function cachedJudge<TArtifact, TScenario extends Scenario = Scenario>(\n judge: JudgeConfig<TArtifact, TScenario>,\n store: VerdictCacheStore,\n options: CachedJudgeOptions,\n): CachedJudge<TArtifact, TScenario> {\n if (typeof options.judgeVersion !== 'string' || options.judgeVersion.trim() === '') {\n throw new Error('cachedJudge: judgeVersion is required and must be a non-empty string')\n }\n const stats: VerdictCacheStats = { hits: 0, misses: 0 }\n const wrapped: CachedJudge<TArtifact, TScenario> = {\n name: judge.name,\n dimensions: judge.dimensions,\n judgeVersion: options.judgeVersion,\n async score(input) {\n const key = `${VERDICT_CACHE_KEY_SCHEME}:${contentHash({\n artifact: canonicalJson(input.artifact),\n scenarioId: input.scenario.id,\n judgeName: judge.name,\n dimensions: judge.dimensions,\n judgeVersion: options.judgeVersion,\n })}`\n const cached = await store.get(key)\n if (cached !== undefined) {\n stats.hits += 1\n return cached\n }\n const score = await judge.score(input)\n await store.set(key, score)\n stats.misses += 1\n return score\n },\n stats: () => ({ ...stats }),\n }\n if (judge.appliesTo) wrapped.appliesTo = judge.appliesTo\n return wrapped\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,cAAc,OAAwB;CACpD,OAAO,gBAAgB,KAAK;AAC9B;;;;AAKA,SAAgB,YAAY,OAAwB;CAClD,OAAO,cAAc,KAAK,CAAC,CAAC,MAAM,CAAgB;AACpD;AA2BA,SAAS,eAAe,MAAc,MAAc,QAAkC;CACpF,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,SAAS,KAAK;EACZ,MAAM,IAAI,MACR,sCAAsC,KAAK,GAAG,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC3G;CACF;CACA,MAAM,MAAM;CACZ,IACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,IAAI,QAAQ,YACnB,OAAO,IAAI,UAAU,YACrB,IAAI,UAAU,QACd,OAAO,IAAI,MAAM,cAAc,YAC/B,OAAO,IAAI,MAAM,eAAe,UAEhC,MAAM,IAAI,MACR,6CAA6C,KAAK,GAAG,OAAO,wDAC9D;CAEF,OAAO;AACT;;;;;;;;AASA,SAAgB,iBAAiB,MAAiC;CAChE,MAAM,0BAAU,IAAI,IAAwB;CAC5C,IAAI,WAAW,IAAI,GAAG;EACpB,MAAM,QAAQ,aAAa,MAAM,MAAM,CAAC,CAAC,MAAM,IAAI;EACnD,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,IAAI,SAAS,KAAA,KAAa,KAAK,KAAK,MAAM,IAAI;GAC9C,MAAM,MAAM,eAAe,MAAM,MAAM,IAAI,CAAC;GAC5C,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAK;EAChC;CACF;CACA,OAAO;EACL,MAAM,QAAQ,QAAQ,IAAI,GAAG;EAC7B,MAAM,KAAK,UAAU;GACnB,eAAe,MAAM,GAAG,KAAK,UAAU;IAAE;IAAK;GAAM,CAAC,EAAE,KAAK,MAAM;GAClE,QAAQ,IAAI,KAAK,KAAK;EACxB;CACF;AACF"}
1
+ {"version":3,"file":"verdict-cache-BQEsVy9n.js","names":[],"sources":["../src/verdict-cache.ts"],"sourcesContent":["/**\n * Content-addressed judge-verdict caching.\n *\n * LAW: cache JUDGE VERDICTS only — judging the same artifact with the same\n * judge+rubric is pure. NEVER cache agent rollouts. (A router that cached\n * identical fanout prompts silently destroyed best-of-N diversity; rollout\n * caching reintroduces that failure class. Judging has no diversity to\n * destroy — same artifact + same rubric ⇒ same verdict is the desired\n * property, not a bug.)\n *\n * The cache key is `v2:` + a sha-256 over the canonical JSON of everything\n * that can change a verdict: the artifact content, the scenario id, the judge\n * name, the full dimension list (key + description — the description IS the\n * rubric text shown to the judge), and a caller-supplied `judgeVersion`.\n * `judgeVersion` is REQUIRED: a judge whose prompt/model/ensemble changes\n * without a version bump would otherwise silently serve stale verdicts.\n * The `v2:` prefix names the key scheme; a store written under another scheme\n * misses once and repopulates.\n *\n * Canonical JSON is RFC 8785 from `ledger-core/canonical` — the package's one\n * identity scheme. It refuses `undefined`, functions, symbols, non-finite\n * numbers, class instances (including `Date`), `Map`, `Set`, cycles, and\n * unpaired surrogates: an artifact that cannot be unambiguously serialized\n * cannot be content-addressed, and coercing it would let two different\n * artifacts collide on one key. Pass timestamps as ISO strings.\n */\n\nimport { appendFileSync, existsSync, readFileSync } from 'node:fs'\nimport type { JudgeConfig, JudgeScore, Scenario } from './campaign/types'\nimport { canonicalString, hashCanonical } from './ledger-core/canonical'\n\n// ── canonical JSON + content hash ─────────────────────────────────────────\n\n/** Key scheme of every entry `cachedJudge` writes. */\nexport const VERDICT_CACHE_KEY_SCHEME = 'v2'\n\n/**\n * Canonical JSON (RFC 8785): object keys sorted recursively, so two\n * semantically equal values produce byte-identical output regardless of key\n * insertion order. Throws `LedgerCanonicalizationError` on any value with no\n * faithful JSON form — see `ledger-core/canonical`.\n */\nexport function canonicalJson(value: unknown): string {\n return canonicalString(value)\n}\n\n/** Hex sha-256 over `canonicalJson(value)`. The content address used by the\n * verdict cache and report attestation. Equals `hashCanonical(value)` with\n * the `sha256:` prefix removed. */\nexport function contentHash(value: unknown): string {\n return hashCanonical(value).slice('sha256:'.length)\n}\n\n// ── store contract ─────────────────────────────────────────────────────────\n\n/** Pluggable verdict store. Sync or async on both legs — `cachedJudge`\n * awaits the results either way. */\nexport interface VerdictCacheStore {\n get(key: string): Promise<JudgeScore | undefined> | JudgeScore | undefined\n set(key: string, score: JudgeScore): Promise<void> | void\n}\n\n/** Process-local Map-backed store. */\nexport function inMemoryVerdictCache(): VerdictCacheStore {\n const entries = new Map<string, JudgeScore>()\n return {\n get: (key) => entries.get(key),\n set: (key, score) => {\n entries.set(key, score)\n },\n }\n}\n\ninterface VerdictCacheLine {\n key: string\n score: JudgeScore\n}\n\nfunction parseCacheLine(line: string, path: string, lineNo: number): VerdictCacheLine {\n let parsed: unknown\n try {\n parsed = JSON.parse(line)\n } catch (err) {\n throw new Error(\n `fileVerdictCache: corrupt JSONL at ${path}:${lineNo} — ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n const rec = parsed as Partial<VerdictCacheLine>\n if (\n typeof rec !== 'object' ||\n rec === null ||\n typeof rec.key !== 'string' ||\n typeof rec.score !== 'object' ||\n rec.score === null ||\n typeof rec.score.composite !== 'number' ||\n typeof rec.score.dimensions !== 'object'\n ) {\n throw new Error(\n `fileVerdictCache: invalid record shape at ${path}:${lineNo} — expected {key, score:{dimensions, composite, notes}}`,\n )\n }\n return rec as VerdictCacheLine\n}\n\n/**\n * JSONL-file-backed store: the full file is loaded into an in-memory index at\n * construction; every `set` appends one line synchronously (durable before\n * the verdict is returned). A corrupt or malformed line throws at load with\n * file:line — a skipped line would silently re-judge (cost) or, worse, mask\n * a half-written file that needs operator attention.\n */\nexport function fileVerdictCache(path: string): VerdictCacheStore {\n const entries = new Map<string, JudgeScore>()\n if (existsSync(path)) {\n const lines = readFileSync(path, 'utf8').split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (line === undefined || line.trim() === '') continue\n const rec = parseCacheLine(line, path, i + 1)\n entries.set(rec.key, rec.score)\n }\n }\n return {\n get: (key) => entries.get(key),\n set: (key, score) => {\n appendFileSync(path, `${JSON.stringify({ key, score })}\\n`, 'utf8')\n entries.set(key, score)\n },\n }\n}\n\n// ── cached judge wrapper ───────────────────────────────────────────────────\n\nexport interface VerdictCacheStats {\n hits: number\n misses: number\n}\n\nexport interface CachedJudgeOptions {\n /** REQUIRED — part of the cache key. Bump on any change to the judge's\n * prompt, model, ensemble, or scoring logic; silent judge upgrades must\n * never serve stale verdicts. */\n judgeVersion: string\n}\n\n/** The wrapped judge: same `JudgeConfig` seam, plus hit/miss observability. */\nexport type CachedJudge<TArtifact, TScenario extends Scenario = Scenario> = JudgeConfig<\n TArtifact,\n TScenario\n> & {\n stats(): VerdictCacheStats\n}\n\n/**\n * Wrap a `JudgeConfig` so repeat judgments of the same artifact are served\n * from the store instead of re-invoking `score()`. The wrapper is generic\n * over the judge's own type parameters and preserves `appliesTo` — it is a\n * drop-in replacement anywhere a `JudgeConfig` is accepted.\n *\n * A judge that throws is NOT cached: the error propagates and the next\n * attempt re-judges (caching a failure would pin a transient outage forever).\n */\nexport function cachedJudge<TArtifact, TScenario extends Scenario = Scenario>(\n judge: JudgeConfig<TArtifact, TScenario>,\n store: VerdictCacheStore,\n options: CachedJudgeOptions,\n): CachedJudge<TArtifact, TScenario> {\n if (typeof options.judgeVersion !== 'string' || options.judgeVersion.trim() === '') {\n throw new Error('cachedJudge: judgeVersion is required and must be a non-empty string')\n }\n const stats: VerdictCacheStats = { hits: 0, misses: 0 }\n const wrapped: CachedJudge<TArtifact, TScenario> = {\n name: judge.name,\n dimensions: judge.dimensions,\n judgeVersion: options.judgeVersion,\n async score(input) {\n const key = `${VERDICT_CACHE_KEY_SCHEME}:${contentHash({\n artifact: canonicalJson(input.artifact),\n scenarioId: input.scenario.id,\n judgeName: judge.name,\n dimensions: judge.dimensions,\n judgeVersion: options.judgeVersion,\n })}`\n const cached = await store.get(key)\n if (cached !== undefined) {\n stats.hits += 1\n return cached\n }\n const score = await judge.score(input)\n await store.set(key, score)\n stats.misses += 1\n return score\n },\n stats: () => ({ ...stats }),\n }\n if (judge.appliesTo) wrapped.appliesTo = judge.appliesTo\n return wrapped\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,cAAc,OAAwB;CACpD,OAAO,gBAAgB,KAAK;AAC9B;;;;AAKA,SAAgB,YAAY,OAAwB;CAClD,OAAO,cAAc,KAAK,CAAC,CAAC,MAAM,CAAgB;AACpD;AA2BA,SAAS,eAAe,MAAc,MAAc,QAAkC;CACpF,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,SAAS,KAAK;EACZ,MAAM,IAAI,MACR,sCAAsC,KAAK,GAAG,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC3G;CACF;CACA,MAAM,MAAM;CACZ,IACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,IAAI,QAAQ,YACnB,OAAO,IAAI,UAAU,YACrB,IAAI,UAAU,QACd,OAAO,IAAI,MAAM,cAAc,YAC/B,OAAO,IAAI,MAAM,eAAe,UAEhC,MAAM,IAAI,MACR,6CAA6C,KAAK,GAAG,OAAO,wDAC9D;CAEF,OAAO;AACT;;;;;;;;AASA,SAAgB,iBAAiB,MAAiC;CAChE,MAAM,0BAAU,IAAI,IAAwB;CAC5C,IAAI,WAAW,IAAI,GAAG;EACpB,MAAM,QAAQ,aAAa,MAAM,MAAM,CAAC,CAAC,MAAM,IAAI;EACnD,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,IAAI,SAAS,KAAA,KAAa,KAAK,KAAK,MAAM,IAAI;GAC9C,MAAM,MAAM,eAAe,MAAM,MAAM,IAAI,CAAC;GAC5C,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAK;EAChC;CACF;CACA,OAAO;EACL,MAAM,QAAQ,QAAQ,IAAI,GAAG;EAC7B,MAAM,KAAK,UAAU;GACnB,eAAe,MAAM,GAAG,KAAK,UAAU;IAAE;IAAK;GAAM,CAAC,EAAE,KAAK,MAAM;GAClE,QAAQ,IAAI,KAAK,KAAK;EACxB;CACF;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { b as CustomTokenPricing, c as CostLedgerHandle } from "../cost-ledger-DbQdN3nO.js";
2
2
  import { x as ChatClient } from "../types-CBbLtr2J.js";
3
3
  import { s as TraceStore } from "../store-BErPvYBr.js";
4
- import { m as FeedbackTrajectoryStore } from "../feedback-trajectory-CXmtITBo.js";
4
+ import { m as FeedbackTrajectoryStore } from "../feedback-trajectory-CytTR7u4.js";
5
5
  import { z } from "zod";
6
6
  import { ServerType } from "@hono/node-server";
7
7
  import { Hono } from "hono";
@@ -1,2 +1,2 @@
1
- import { A as WIRE_VERSION, C as RUBRIC_VERSION_SCHEME, D as TracesIngestRequestSchema, E as TraceEventSchema, O as TracesIngestResponseSchema, S as ListRubricsResponseSchema, T as RubricSchema, _ as FeedbackIngestResponseSchema, a as runRpcBatch, b as JudgeRequestSchema, c as WireError, d as handleListRubrics, f as handleTracesIngest, g as ErrorResponseSchema, h as listBuiltinRubrics, i as dispatchRpc, j as hashRubric, k as VersionResponseSchema, l as handleFeedbackIngest, m as getBuiltinRubric, n as startServer, o as runRpcOnce, p as handleVersion, r as startServerAsync, s as buildOpenApi, t as createApp, u as handleJudge, v as FeedbackTrajectorySchema, w as RubricDimensionSchema, x as JudgeResultSchema, y as HealthResponseSchema } from "../server-BZQR1f0C.js";
1
+ import { A as WIRE_VERSION, C as RUBRIC_VERSION_SCHEME, D as TracesIngestRequestSchema, E as TraceEventSchema, O as TracesIngestResponseSchema, S as ListRubricsResponseSchema, T as RubricSchema, _ as FeedbackIngestResponseSchema, a as runRpcBatch, b as JudgeRequestSchema, c as WireError, d as handleListRubrics, f as handleTracesIngest, g as ErrorResponseSchema, h as listBuiltinRubrics, i as dispatchRpc, j as hashRubric, k as VersionResponseSchema, l as handleFeedbackIngest, m as getBuiltinRubric, n as startServer, o as runRpcOnce, p as handleVersion, r as startServerAsync, s as buildOpenApi, t as createApp, u as handleJudge, v as FeedbackTrajectorySchema, w as RubricDimensionSchema, x as JudgeResultSchema, y as HealthResponseSchema } from "../server-DmpcFiVK.js";
2
2
  export { ErrorResponseSchema, FeedbackIngestResponseSchema, FeedbackTrajectorySchema, HealthResponseSchema, JudgeRequestSchema, JudgeResultSchema, ListRubricsResponseSchema, RUBRIC_VERSION_SCHEME, RubricDimensionSchema, RubricSchema, TraceEventSchema, TracesIngestRequestSchema, TracesIngestResponseSchema, VersionResponseSchema, WIRE_VERSION, WireError, buildOpenApi, createApp, dispatchRpc, getBuiltinRubric, handleFeedbackIngest, handleJudge, handleListRubrics, handleTracesIngest, handleVersion, hashRubric, listBuiltinRubrics, runRpcBatch, runRpcOnce, startServer, startServerAsync };
@@ -0,0 +1,27 @@
1
+ # Unreleased: evaluation definition identity
2
+
3
+ Static `jevJudge` and `jevAnalyst` versions now bind authored question order and
4
+ Choice alternative order in addition to their canonical content. The request is
5
+ not sorted or rewritten. Optional undefined SDK fields remain absent from the
6
+ JSON document, so JSON round-trips retain the same identity.
7
+
8
+ This intentionally changes static evaluator version hashes. A cached verdict from
9
+ the previous identity scheme must not be treated as evidence for a reordered
10
+ classifier definition. Existing caches remain stored under their previous versions;
11
+ this change does not delete or migrate them.
12
+
13
+ `asJudge` and `asAnalyst` capture callback references when constructed and detach
14
+ metadata arrays/objects from the supplied options. Replacing `options.evaluate`,
15
+ `options.map` or `options.record` later no longer changes an already-versioned
16
+ adapter. Construct another adapter with a new version for an intentional change.
17
+
18
+ This is not a sandbox or closure serializer. Callers must still version opaque
19
+ renderer/mapping behavior and mutable state captured inside their own functions.
20
+ Dynamic question builders remain supported; retain each actual request through
21
+ the existing observation path. No model calls, thresholds, domain policies,
22
+ transport defaults or execution machinery are added.
23
+
24
+ Regression tests cover version collisions from reordering, preserved dispatch
25
+ order, SDK-style undefined fields, metadata mutation and callback replacement
26
+ through the real paid-call ledger. They establish code contracts, not classifier
27
+ quality or deployed outcome improvements.
@@ -0,0 +1,18 @@
1
+ # Unreleased: opt-in evidence reviews on native evaluations
2
+
3
+ `@tangle-network/agent-eval/jev` adds `prepareJevReview`, `assessJevReview` and
4
+ `jevReviewFindings`. Callers retain ownership of questions, hypotheses, evidence, severity,
5
+ thresholds and result policy. Review identity includes authored option order; request JSON is
6
+ not sorted before dispatch. Missing or partial negative evidence cannot become a clean review.
7
+
8
+ The optional `examples/jev-behavior-review.ts` recipe covers reward gaming, evaluator tampering,
9
+ policy/authorization/data-boundary breaches, injection-following, contradicted completion,
10
+ oversight bypass, matched-baseline anomalies and cross-run behavior. It composes the existing
11
+ `jevAnalyst`; the taxonomy is not installed in the generic evaluator and is not a calibrated
12
+ safety detector. See [behavioral reviews](../jev-behavior-review.md) for evidence and limits.
13
+
14
+ No dependency, transport, scheduler, package entrypoint, default model, production action or
15
+ spending policy changes. Existing evaluator, judge, analyst and protocol APIs remain unchanged.
16
+ Use existing deterministic control/reward checks and independent final assessment alongside
17
+ semantic reviews. Adversarial model quality and product/harness adoption remain tracked in
18
+ #772/#771 and the cross-repository roadmap #768.
@@ -0,0 +1,18 @@
1
+ # 0.184.0: installed product adoption
2
+
3
+ The new version publishes the merged typed evaluator and Jev APIs that were not in the
4
+ previously published 0.183.0 artifact. JS and Python distribution versions remain in lockstep.
5
+
6
+ `@tangle-network/agent-eval/jev/protocol` is a leaf export of the existing protocol implementation.
7
+ Products can validate native requests/responses without importing analyst/campaign execution.
8
+ Native extension metadata is preserved, not projected away; lossy non-JSON metadata is rejected
9
+ before consumers persist an apparently valid but changed observation. Already-paid receipts remain
10
+ recorded when answer validation fails.
11
+
12
+ `examples/jev-decision-benchmark.ts` compares caller-defined classifier configurations with the
13
+ existing matrix runner. It separates independent expected labels from model input, retains
14
+ abstention, records complete observations and paid failures, and groups results by configuration.
15
+ It is a recipe, not another optimizer or universal scoring policy.
16
+
17
+ Release this version through the existing verify-and-publish workflow before merging consumers
18
+ pinned to 0.184.0. A source manifest version is not evidence that the npm artifact is available.
@@ -0,0 +1,81 @@
1
+ # Unreleased: audit a frozen probability policy
2
+
3
+ Added `auditProbabilityPolicy`, `ProbabilityPolicyAuditInput` and
4
+ `ProbabilityPolicyAuditReport` to `@tangle-network/agent-eval/meta-eval`.
5
+ Existing `auditEvaluator` behavior and report hashes are unchanged. No dependency,
6
+ model call, scheduler or automatic promotion is added.
7
+
8
+ Use this when a product turns a probability into accept, reject or escalation.
9
+ The caller supplies both thresholds and independently labeled observations. The
10
+ helper maps the observations, then uses the existing `auditEvaluator` statistics,
11
+ independent-unit counting, development-exposure exclusion and authority checks.
12
+
13
+ ```ts
14
+ import { readFile } from 'node:fs/promises'
15
+ import { auditProbabilityPolicy } from '@tangle-network/agent-eval/meta-eval'
16
+
17
+ const path = process.argv[2]
18
+ if (!path) throw new Error('Supply the frozen audit JSON path')
19
+ const report = auditProbabilityPolicy(JSON.parse(await readFile(path, 'utf8')))
20
+ console.log(JSON.stringify(report, null, 2))
21
+ ```
22
+
23
+ The input has the existing evaluator audit fields: `evaluatorDigest`, `population`,
24
+ `samplingFrame`, `authority`, `policy` and `observations`. Add explicit `thresholds`
25
+ with `rejectAtOrBelow` and `acceptAtOrAbove`. Every observation carries `id`,
26
+ `independentUnitId`, `evidenceRef`, independently checked `expected` (`accept` or
27
+ `reject`), `exposure` (`fresh` or `development`), and `acceptProbability` instead
28
+ of `observed`.
29
+
30
+ `acceptProbability` is P(the event the caller defines as acceptable), in [0,1], or
31
+ null for missing output. For Jev, a caller can use a suitable Noul or a named Choice
32
+ probability. Do not substitute Jev's distribution-confidence statistic or an
33
+ arbitrarily scaled numeric grade. Other providers work without pretending to be Jev.
34
+
35
+ Probabilities at or above `acceptAtOrAbove` map to accept. Those at or below
36
+ `rejectAtOrBelow` map to reject. The open interval between them and null map to
37
+ unknown. Thresholds must be finite, in [0,1], and strictly separated. Nothing
38
+ chooses thresholds or inserts a default cutoff for the application.
39
+
40
+ ## Read the result correctly
41
+
42
+ The result retains the existing admit/reject/inconclusive verdict, error bounds,
43
+ coverage, exclusions, authority and mapped observations. Unknown judgments remain
44
+ in the conservative error bounds, never measured successes. The helper does not
45
+ quietly discard escalated or unavailable cases to improve apparent accuracy.
46
+ `coverage.eligibleCases - coverage.unknownCases` is the number of decided eligible
47
+ cases; the full denominator remains `eligibleCases`.
48
+
49
+ `probabilityPolicy` retains the original classifier digest, thresholds and exact
50
+ probabilities keyed by observation id. `evaluatorDigest` identifies the composed
51
+ classifier-plus-threshold program. `inputDigest` binds the complete validated
52
+ probability-audit input (sorted by observation id), including probability changes
53
+ that do not change the selected action. `reportDigest` covers the complete report.
54
+
55
+ The original evaluator digest must identify the actual frozen classifier, question
56
+ and evidence-rendering definition. An arbitrary string or a model alias is not
57
+ an independently verified program identity. Hashes establish identity, not truth.
58
+
59
+ ## Keep selection and final assessment separate
60
+
61
+ Tune thresholds on development data, freeze them, then use fresh independent cases
62
+ for the final audit. A development-exposed source excludes its fresh-looking
63
+ variants too. Duplicate observation ids and identical declared author/auditor
64
+ identities are refused. Distinct declared names do not prove real-world independence;
65
+ the execution owner must enforce it and supply evidence.
66
+
67
+ The output audits this fixed binary decision policy. It does not prove probability
68
+ calibration, downstream workflow correctness, cost savings, causal repair quality
69
+ or external-action authorization. Use existing calibration/comparison utilities
70
+ and actual task outcomes for those claims. A small or entirely missing dataset is
71
+ inconclusive rather than perfect evidence. Real datasets, task slices, cost/latency
72
+ comparisons and deployed validation remain tracked in issue #771 under roadmap #768.
73
+
74
+ ## Checks
75
+
76
+ `pnpm exec vitest run tests/probability-policy-audit.test.ts tests/evaluator-admission.test.ts`
77
+
78
+ Regressions cover boundary decisions, missing data, invalid probabilities, overlapping
79
+ thresholds, digest identity, input immutability, independent-unit denominators,
80
+ development leakage, authority checks and unchanged underlying error bounds. These
81
+ are executable arithmetic/contract tests, not live Jev quality measurements.
@@ -0,0 +1,42 @@
1
+ # Agent-failure diagnosis
2
+
3
+ `@tangle-network/agent-eval/diagnosis` exports one engine: `diagnoseSpans(spans, context, options)`.
4
+ It reads flat spans and returns a findings document that validates against the diagnosis kit's schema, `https://tangle.tools/schemas/diagnosis-findings-v1.json`.
5
+
6
+ The engine is a plain function.
7
+ It keeps no storage, files no issues, and retains nothing.
8
+ In model mode its only network use is the caller's transport; in deterministic mode it makes no call.
9
+ The caller owns where the spans come from and where the findings go, so one engine serves an internal mining run and a customer diagnosis on separate data paths.
10
+
11
+ ## Input
12
+
13
+ Each span is one object in the flat shape that trace-adapters and the traces CLI emit:
14
+ `{trace_id, span_id, parent_span_id, name, start_time, end_time, status | status_code, status_message, attributes, resource?}`.
15
+ Times may be OTLP nanosecond strings, epoch milliseconds, or ISO-8601.
16
+
17
+ `context` names the subject (`internal` or `customer`), a label in the owner's words, an optional `focus` question, and `contentIncluded`.
18
+ Content is excluded by default: prompt, response, and tool payload attributes are dropped before anything reads the spans.
19
+ Only an internal context may carry a `topology` (a run graph); a customer context with one is refused.
20
+
21
+ ## Order of operations
22
+
23
+ 1. The secret filter runs on every string: span attributes, names, status messages, the focus question, and the topology.
24
+ `DIAGNOSIS_SECRET_RULES` holds trace-archive's line-anchored credential-assignment pattern plus token shapes (`sk-`, `sk-ant-`, GitHub, Slack, AWS, Google, JWT, bearer headers, URL passwords, PEM blocks, and JSON or inline `...key=` values).
25
+ A match becomes `[REDACTED:<rule>]`, and the document's `coverage.redaction` counts matches by rule.
26
+ 2. The deterministic pass reports the trace contract's capability table with the trace's own reasons, execution facts with token and cost accounting, and `observed` findings.
27
+ Each observed finding carries a measure with its denominator and cites the spans it counted.
28
+ 3. Model mode reads the runs with the most errors through the prime protocol (`runPrimeExchange`).
29
+ A run larger than the inline budget is read as whole segments, most errors first; the segments not read are listed in `coverage.skipped`.
30
+ 4. Every cited span id must exist in the input and belong to one run.
31
+ A model row that cites an unknown or shared id is rejected with its reason in `result.rejected`.
32
+
33
+ ## Output
34
+
35
+ `result.document` is the only part a customer report renders.
36
+ Every finding has `confidence`: `observed` for a fact read off the spans, `inferred` for the model's reading.
37
+ `result.questions`, `result.notes` (operator critique and topology, internal only), `result.facts`, `result.model.usage`, and `result.rejected` support the report without entering the document.
38
+
39
+ ## Model transport
40
+
41
+ `options.model.transport` is a `PrimeBridgeTransport`: an HTTP bridge (`nodeHttpPrimeBridgeTransport`) or any local runner with the same shape.
42
+ tangle-tools `trace-insights/mine` runs prime-agent on the Tangle router with `deepseek/deepseek-v4.1-flash`, in a throwaway home that is deleted after each call.