@tangle-network/agent-eval 0.188.0 → 0.190.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 (240) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +3 -2
  3. package/dist/adapters/http.d.ts +11 -2
  4. package/dist/adapters/http.d.ts.map +1 -1
  5. package/dist/adapters/http.js +75 -7
  6. package/dist/adapters/http.js.map +1 -1
  7. package/dist/{agent-profile-CfbuZk8b.d.ts → agent-profile-DNV_U6QR.d.ts} +3 -3
  8. package/dist/{agent-profile-CfbuZk8b.d.ts.map → agent-profile-DNV_U6QR.d.ts.map} +1 -1
  9. package/dist/analyst/index.d.ts +75 -12
  10. package/dist/analyst/index.d.ts.map +1 -1
  11. package/dist/analyst/index.js +213 -8
  12. package/dist/analyst/index.js.map +1 -1
  13. package/dist/{analyze-runs-CLz5O01x.d.ts → analyze-runs-BvK4-wSs.d.ts} +5 -5
  14. package/dist/{analyze-runs-CLz5O01x.d.ts.map → analyze-runs-BvK4-wSs.d.ts.map} +1 -1
  15. package/dist/{analyze-runs-DCY7LMt4.js → analyze-runs-SCSWYpy0.js} +17 -9
  16. package/dist/analyze-runs-SCSWYpy0.js.map +1 -0
  17. package/dist/{benchmark-command-CdUGku3W.js → benchmark-command-TZlsuAh9.js} +12 -12
  18. package/dist/{benchmark-command-CdUGku3W.js.map → benchmark-command-TZlsuAh9.js.map} +1 -1
  19. package/dist/benchmarks/index.d.ts +4 -4
  20. package/dist/benchmarks/index.js +3 -3
  21. package/dist/campaign/index.d.ts +7 -7
  22. package/dist/campaign/index.js +8 -8
  23. package/dist/{campaign-DZuysBbS.js → campaign-_29Qpc9Z.js} +258 -13
  24. package/dist/campaign-_29Qpc9Z.js.map +1 -0
  25. package/dist/{campaign-evidence-IF1p0oDa.js → campaign-evidence-CWF8pEIk.js} +9 -8
  26. package/dist/campaign-evidence-CWF8pEIk.js.map +1 -0
  27. package/dist/{chat-client-C4dg7Ng_.js → chat-client-DbH06Ek6.js} +2 -2
  28. package/dist/{chat-client-C4dg7Ng_.js.map → chat-client-DbH06Ek6.js.map} +1 -1
  29. package/dist/{chat-json-call-JVGbfx95.js → chat-json-call-B0xTEY0I.js} +2 -2
  30. package/dist/{chat-json-call-JVGbfx95.js.map → chat-json-call-B0xTEY0I.js.map} +1 -1
  31. package/dist/claim-BGOUqoMq.d.ts +38 -0
  32. package/dist/claim-BGOUqoMq.d.ts.map +1 -0
  33. package/dist/cli.js +3 -3
  34. package/dist/{client-CFj9dfcn.d.ts → client-BhEyAdfe.d.ts} +4 -4
  35. package/dist/{client-CFj9dfcn.d.ts.map → client-BhEyAdfe.d.ts.map} +1 -1
  36. package/dist/{client-CXE-U1SA.js → client-QwJpsNYU.js} +5 -1
  37. package/dist/client-QwJpsNYU.js.map +1 -0
  38. package/dist/contract/index.d.ts +10 -10
  39. package/dist/contract/index.js +22 -13
  40. package/dist/contract/index.js.map +1 -1
  41. package/dist/deep-freeze-CurcOQg3.js +16 -0
  42. package/dist/deep-freeze-CurcOQg3.js.map +1 -0
  43. package/dist/{default-registry-BtZ_t-9b.js → default-registry-16I-Bxlf.js} +4 -3
  44. package/dist/default-registry-16I-Bxlf.js.map +1 -0
  45. package/dist/{default-registry-BLsGfnoO.d.ts → default-registry-B5HrwrPM.d.ts} +6 -6
  46. package/dist/{default-registry-BLsGfnoO.d.ts.map → default-registry-B5HrwrPM.d.ts.map} +1 -1
  47. package/dist/{define-agent-eval-CsicmDxt.d.ts → define-agent-eval-BWeyIpny.d.ts} +8 -7
  48. package/dist/define-agent-eval-BWeyIpny.d.ts.map +1 -0
  49. package/dist/{define-agent-eval-ChtddasD.js → define-agent-eval-DrGfrCTZ.js} +8 -8
  50. package/dist/{define-agent-eval-ChtddasD.js.map → define-agent-eval-DrGfrCTZ.js.map} +1 -1
  51. package/dist/diagnosis/index.d.ts +3 -3
  52. package/dist/diagnosis/index.d.ts.map +1 -1
  53. package/dist/diagnosis/index.js +4 -4
  54. package/dist/diagnosis/index.js.map +1 -1
  55. package/dist/{dspy-rlm-engine-sPX7B5ac.js → dspy-rlm-engine-CTIGomgr.js} +3 -3
  56. package/dist/{dspy-rlm-engine-sPX7B5ac.js.map → dspy-rlm-engine-CTIGomgr.js.map} +1 -1
  57. package/dist/{engine-Gw2n1irt.d.ts → engine-BkLCnZQX.d.ts} +4 -4
  58. package/dist/{engine-Gw2n1irt.d.ts.map → engine-BkLCnZQX.d.ts.map} +1 -1
  59. package/dist/{eval-campaign-CeotQ1ZR.js → eval-campaign-CMKRjWl0.js} +3 -3
  60. package/dist/{eval-campaign-CeotQ1ZR.js.map → eval-campaign-CMKRjWl0.js.map} +1 -1
  61. package/dist/evaluation.d.ts +2 -2
  62. package/dist/{exact-types-CrhPoDp8.d.ts → exact-types-CfpP2A4Z.d.ts} +2 -2
  63. package/dist/{exact-types-CrhPoDp8.d.ts.map → exact-types-CfpP2A4Z.d.ts.map} +1 -1
  64. package/dist/experiment/index.d.ts +2 -1
  65. package/dist/experiment/index.d.ts.map +1 -1
  66. package/dist/experiment/index.js +1 -1
  67. package/dist/exporters-XMCYJlqT.d.ts +161 -0
  68. package/dist/exporters-XMCYJlqT.d.ts.map +1 -0
  69. package/dist/{external-optimizer-process-D3BLpZyR.js → external-optimizer-process-Mc83UoWl.js} +3 -3
  70. package/dist/{external-optimizer-process-D3BLpZyR.js.map → external-optimizer-process-Mc83UoWl.js.map} +1 -1
  71. package/dist/{external-optimizer-subprocess-BrfsgL92.js → external-optimizer-subprocess-C0dHXH8e.js} +3 -3
  72. package/dist/{external-optimizer-subprocess-BrfsgL92.js.map → external-optimizer-subprocess-C0dHXH8e.js.map} +1 -1
  73. package/dist/{feedback-trajectory-BJi4t3Vf.d.ts → feedback-trajectory-BYjh7NEM.d.ts} +4 -4
  74. package/dist/{feedback-trajectory-BJi4t3Vf.d.ts.map → feedback-trajectory-BYjh7NEM.d.ts.map} +1 -1
  75. package/dist/hosted/index.d.ts +2 -2
  76. package/dist/hosted/index.d.ts.map +1 -1
  77. package/dist/hosted/index.js +1 -1
  78. package/dist/{index-Ca0_IjFu.d.ts → index-2e_MTznj.d.ts} +7 -7
  79. package/dist/{index-Ca0_IjFu.d.ts.map → index-2e_MTznj.d.ts.map} +1 -1
  80. package/dist/{index-BD1oSbHr.d.ts → index-BR_R1eBE.d.ts} +11 -11
  81. package/dist/{index-BD1oSbHr.d.ts.map → index-BR_R1eBE.d.ts.map} +1 -1
  82. package/dist/{index-u0d1Jp4F.d.ts → index-BqDJ6fUK.d.ts} +45 -24
  83. package/dist/index-BqDJ6fUK.d.ts.map +1 -0
  84. package/dist/{index-eTTnPe3r.d.ts → index-Ci0-EYzc.d.ts} +678 -249
  85. package/dist/index-Ci0-EYzc.d.ts.map +1 -0
  86. package/dist/{index-B-s8qDRJ.d.ts → index-D4pC7Tvd.d.ts} +4 -3
  87. package/dist/index-D4pC7Tvd.d.ts.map +1 -0
  88. package/dist/index.d.ts +81 -32
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +385 -41
  91. package/dist/index.js.map +1 -1
  92. package/dist/{insight-report-DeE1solA.d.ts → insight-report-CvPkEIcC.d.ts} +13 -6
  93. package/dist/insight-report-CvPkEIcC.d.ts.map +1 -0
  94. package/dist/jev.d.ts +2 -2
  95. package/dist/jev.js +2 -1
  96. package/dist/jev.js.map +1 -1
  97. package/dist/{journal-BuRLm6ho.js → journal-CDP0Vhx_.js} +262 -115
  98. package/dist/journal-CDP0Vhx_.js.map +1 -0
  99. package/dist/{kind-factory-g1ROw67A.js → kind-factory-ByZeXDqF.js} +4 -3
  100. package/dist/{kind-factory-g1ROw67A.js.map → kind-factory-ByZeXDqF.js.map} +1 -1
  101. package/dist/ledger-core/index.d.ts +2 -2
  102. package/dist/ledger-core/index.js +1 -1
  103. package/dist/{llm-client-DF9bPNYA.js → llm-client-BqmRnibA.js} +2 -2
  104. package/dist/{llm-client-DF9bPNYA.js.map → llm-client-BqmRnibA.js.map} +1 -1
  105. package/dist/{llm-judge-DF18J3CR.js → llm-judge-bwbgDMP0.js} +1895 -1379
  106. package/dist/llm-judge-bwbgDMP0.js.map +1 -0
  107. package/dist/{matrix-BvA1WUpj.d.ts → matrix-CNypzP-v.d.ts} +2 -2
  108. package/dist/{matrix-BvA1WUpj.d.ts.map → matrix-CNypzP-v.d.ts.map} +1 -1
  109. package/dist/meta-eval/index.d.ts +1 -1
  110. package/dist/mint-C9Lojt1V.d.ts +147 -0
  111. package/dist/mint-C9Lojt1V.d.ts.map +1 -0
  112. package/dist/{mint-B4zgSAJW.js → mint-iCD-W43s.js} +30 -12
  113. package/dist/mint-iCD-W43s.js.map +1 -0
  114. package/dist/multishot/golden/index.d.ts +1 -1
  115. package/dist/multishot/index.d.ts +2 -2
  116. package/dist/openapi.json +1 -1
  117. package/dist/pipelines/index.d.ts +1 -1
  118. package/dist/{prime-protocol-CF8Z43Fj.d.ts → prime-protocol-Fwvctmhm.d.ts} +2 -2
  119. package/dist/{prime-protocol-CF8Z43Fj.d.ts.map → prime-protocol-Fwvctmhm.d.ts.map} +1 -1
  120. package/dist/{produced-state-xsMMjYVc.js → produced-state-zSaGDC_Q.js} +4 -4
  121. package/dist/{produced-state-xsMMjYVc.js.map → produced-state-zSaGDC_Q.js.map} +1 -1
  122. package/dist/{raw-provider-sink-C96CcqeG.js → raw-provider-sink-DIRCZjP_.js} +2 -2
  123. package/dist/{raw-provider-sink-C96CcqeG.js.map → raw-provider-sink-DIRCZjP_.js.map} +1 -1
  124. package/dist/{redact-DxwlUAvh.js → redact-8fX8-uKr.js} +16 -7
  125. package/dist/redact-8fX8-uKr.js.map +1 -0
  126. package/dist/{redact-DPoH1-OW.d.ts → redact-Du3WKUOP.d.ts} +7 -5
  127. package/dist/redact-Du3WKUOP.d.ts.map +1 -0
  128. package/dist/{registry-BM2Kdk8T.d.ts → registry-mAQVtuLx.d.ts} +3 -3
  129. package/dist/{registry-BM2Kdk8T.d.ts.map → registry-mAQVtuLx.d.ts.map} +1 -1
  130. package/dist/{release-confidence-CG4Z9QLB.d.ts → release-confidence-CkoXFx9I.d.ts} +3 -3
  131. package/dist/{release-confidence-CG4Z9QLB.d.ts.map → release-confidence-CkoXFx9I.d.ts.map} +1 -1
  132. package/dist/{release-confidence-RanRUXRW.js → release-confidence-XQm_xjhR.js} +3 -3
  133. package/dist/release-confidence-XQm_xjhR.js.map +1 -0
  134. package/dist/reporting.d.ts +3 -3
  135. package/dist/reporting.js +1 -1
  136. package/dist/{researcher-Bjcd_8T_.d.ts → researcher-DojEMb7E.d.ts} +3 -3
  137. package/dist/{researcher-Bjcd_8T_.d.ts.map → researcher-DojEMb7E.d.ts.map} +1 -1
  138. package/dist/{reward-hacking-DrKXJtgH.d.ts → reward-hacking-Cyk-QHk9.d.ts} +2 -2
  139. package/dist/{reward-hacking-DrKXJtgH.d.ts.map → reward-hacking-Cyk-QHk9.d.ts.map} +1 -1
  140. package/dist/rl.d.ts +10 -8
  141. package/dist/rl.d.ts.map +1 -1
  142. package/dist/rl.js +7 -6
  143. package/dist/rl.js.map +1 -1
  144. package/dist/rollout/index.d.ts +5 -4
  145. package/dist/rollout/index.js +2 -2
  146. package/dist/{rollout-C0Ifk3vK.js → rollout-B-XBReTC.js} +2 -2
  147. package/dist/{rollout-C0Ifk3vK.js.map → rollout-B-XBReTC.js.map} +1 -1
  148. package/dist/{rubric-predictive-validity-B14yBAmM.d.ts → rubric-predictive-validity-DIUwJJ9Y.d.ts} +2 -2
  149. package/dist/{rubric-predictive-validity-B14yBAmM.d.ts.map → rubric-predictive-validity-DIUwJJ9Y.d.ts.map} +1 -1
  150. package/dist/{run-record-tg_5H2IK.js → run-record-BRlM99rX.js} +41 -3
  151. package/dist/run-record-BRlM99rX.js.map +1 -0
  152. package/dist/{run-record-xEULpgML.d.ts → run-record-DF-fuu31.d.ts} +58 -6
  153. package/dist/run-record-DF-fuu31.d.ts.map +1 -0
  154. package/dist/{run-record-CNNzWGpB.js → run-record-DnMFyg_g.js} +26 -13
  155. package/dist/run-record-DnMFyg_g.js.map +1 -0
  156. package/dist/{schema-BzWDXhOR.d.ts → schema-B5LtYvn9.d.ts} +7 -5
  157. package/dist/{schema-BzWDXhOR.d.ts.map → schema-B5LtYvn9.d.ts.map} +1 -1
  158. package/dist/schema-C1aaAxTf.js.map +1 -1
  159. package/dist/search-ledger-types-C9anU2DX.d.ts +489 -0
  160. package/dist/search-ledger-types-C9anU2DX.d.ts.map +1 -0
  161. package/dist/{semantic-concept-judge-70LxrCSL.js → semantic-concept-judge-BY0me-Jq.js} +6 -6
  162. package/dist/{semantic-concept-judge-70LxrCSL.js.map → semantic-concept-judge-BY0me-Jq.js.map} +1 -1
  163. package/dist/{server-C8XvqCg8.js → server-DnJCDLf8.js} +2 -2
  164. package/dist/{server-C8XvqCg8.js.map → server-DnJCDLf8.js.map} +1 -1
  165. package/dist/{skillopt-optimization-method-C60h0Got.js → skillopt-optimization-method-CfnQEjgT.js} +364 -19
  166. package/dist/skillopt-optimization-method-CfnQEjgT.js.map +1 -0
  167. package/dist/{spans-W0o8pbEg.d.ts → spans-D1RftP_w.d.ts} +2 -2
  168. package/dist/{spans-W0o8pbEg.d.ts.map → spans-D1RftP_w.d.ts.map} +1 -1
  169. package/dist/{statistical-heldout-CPv-y6sK.d.ts → statistical-heldout-CLpjYffJ.d.ts} +4 -38
  170. package/dist/statistical-heldout-CLpjYffJ.d.ts.map +1 -0
  171. package/dist/{store-otlp-DPgzSQKS.js → store-otlp-84DH0OEH.js} +2 -2
  172. package/dist/{store-otlp-DPgzSQKS.js.map → store-otlp-84DH0OEH.js.map} +1 -1
  173. package/dist/{store-tool-spans-C2lLwDzg.d.ts → store-tool-spans-BBXs8hDP.d.ts} +6 -6
  174. package/dist/{store-tool-spans-C2lLwDzg.d.ts.map → store-tool-spans-BBXs8hDP.d.ts.map} +1 -1
  175. package/dist/{store-tool-spans-ClPxcvh2.js → store-tool-spans-DSbYpl7f.js} +5 -5
  176. package/dist/{store-tool-spans-ClPxcvh2.js.map → store-tool-spans-DSbYpl7f.js.map} +1 -1
  177. package/dist/{summary-report-SNvJoAvD.d.ts → summary-report-DvvesgR_.d.ts} +5 -4
  178. package/dist/summary-report-DvvesgR_.d.ts.map +1 -0
  179. package/dist/supervisor-run/index.d.ts +2 -2
  180. package/dist/{tool-groups-CCQqAa16.d.ts → tool-groups-W7MJobX_.d.ts} +3 -3
  181. package/dist/tool-groups-W7MJobX_.d.ts.map +1 -0
  182. package/dist/trace-repair/index.d.ts +2 -2
  183. package/dist/traces.d.ts +6 -66
  184. package/dist/traces.d.ts.map +1 -1
  185. package/dist/traces.js +7 -196
  186. package/dist/traces.js.map +1 -1
  187. package/dist/{types-DDp2Mb8Y.d.ts → types-Bay1dh2o.d.ts} +5 -5
  188. package/dist/{types-DDp2Mb8Y.d.ts.map → types-Bay1dh2o.d.ts.map} +1 -1
  189. package/dist/{types-B1vDZ694.d.ts → types-BvmWNjjs.d.ts} +3 -3
  190. package/dist/{types-B1vDZ694.d.ts.map → types-BvmWNjjs.d.ts.map} +1 -1
  191. package/dist/{types-C8VBbiw6.js → types-CW5b90JH.js} +2 -15
  192. package/dist/types-CW5b90JH.js.map +1 -0
  193. package/dist/{types-5ak2PqnJ.d.ts → types-Cvqy7asY.d.ts} +3 -3
  194. package/dist/{types-5ak2PqnJ.d.ts.map → types-Cvqy7asY.d.ts.map} +1 -1
  195. package/dist/{types-Tp5WhYL9.d.ts → types-DRNlLbBR.d.ts} +2 -2
  196. package/dist/{types-Tp5WhYL9.d.ts.map → types-DRNlLbBR.d.ts.map} +1 -1
  197. package/dist/wire/index.d.ts +1 -1
  198. package/dist/wire/index.js +1 -1
  199. package/docs/adapters-observability.md +31 -27
  200. package/docs/charter.md +1 -1
  201. package/docs/code-agent-intake.md +1 -1
  202. package/docs/design/mlbenchmarks-book-review.md +1 -1
  203. package/docs/distributed-driver.md +1 -5
  204. package/docs/experiment.md +15 -0
  205. package/docs/insight-report.md +3 -2
  206. package/docs/public-api.md +174 -68
  207. package/docs/redaction.md +7 -1
  208. package/docs/rollout.md +5 -5
  209. package/docs/search-ledger.md +174 -0
  210. package/docs/trace-contracts.md +48 -3
  211. package/package.json +1 -1
  212. package/dist/analyze-runs-DCY7LMt4.js.map +0 -1
  213. package/dist/campaign-DZuysBbS.js.map +0 -1
  214. package/dist/campaign-evidence-IF1p0oDa.js.map +0 -1
  215. package/dist/client-CXE-U1SA.js.map +0 -1
  216. package/dist/default-registry-BtZ_t-9b.js.map +0 -1
  217. package/dist/define-agent-eval-CsicmDxt.d.ts.map +0 -1
  218. package/dist/index-B-s8qDRJ.d.ts.map +0 -1
  219. package/dist/index-eTTnPe3r.d.ts.map +0 -1
  220. package/dist/index-u0d1Jp4F.d.ts.map +0 -1
  221. package/dist/insight-report-DeE1solA.d.ts.map +0 -1
  222. package/dist/journal-BuRLm6ho.js.map +0 -1
  223. package/dist/llm-judge-DF18J3CR.js.map +0 -1
  224. package/dist/mint-B4zgSAJW.js.map +0 -1
  225. package/dist/mint-CJFSYBIU.d.ts +0 -285
  226. package/dist/mint-CJFSYBIU.d.ts.map +0 -1
  227. package/dist/redact-DPoH1-OW.d.ts.map +0 -1
  228. package/dist/redact-DxwlUAvh.js.map +0 -1
  229. package/dist/release-confidence-RanRUXRW.js.map +0 -1
  230. package/dist/run-record-CNNzWGpB.js.map +0 -1
  231. package/dist/run-record-tg_5H2IK.js.map +0 -1
  232. package/dist/run-record-xEULpgML.d.ts.map +0 -1
  233. package/dist/search-ledger-types-D7KDVg-o.d.ts +0 -302
  234. package/dist/search-ledger-types-D7KDVg-o.d.ts.map +0 -1
  235. package/dist/skillopt-optimization-method-C60h0Got.js.map +0 -1
  236. package/dist/statistical-heldout-CPv-y6sK.d.ts.map +0 -1
  237. package/dist/summary-report-SNvJoAvD.d.ts.map +0 -1
  238. package/dist/tool-groups-CCQqAa16.d.ts.map +0 -1
  239. package/dist/types-C8VBbiw6.js.map +0 -1
  240. package/docs/search-history-receipts.md +0 -232
@@ -1 +0,0 @@
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,232 +0,0 @@
1
- # Complete optimization search history
2
-
3
- A selected prompt, profile, or patch is not a record of the search that produced it. A trustworthy optimizer must account for what it planned, tried, failed to run, rejected, and left unresolved before its winner is evaluated on untouched final cases.
4
-
5
- Eval already has one rich source of truth for that process: `SearchLedger`. This feature does not add another event log.
6
-
7
- ```text
8
- SearchLedger JSONL canonical facts and rich evidence
9
- │
10
- ├── hash chain mutation and truncation detection
11
- ├── replay audit planned denominator and unresolved work
12
- └── SearchHistoryReceipt bounded proof envelope
13
- │
14
- └── compareOptimizationMethods({
15
- searchHistoryPolicy: 'require-complete'
16
- })
17
- ```
18
-
19
- ## ELI5
20
-
21
- `SearchLedger` is the sealed laboratory notebook. `SearchHistoryReceipt` is the small signed cover sheet saying which notebook, which run, and whether the notebook accounts for the whole planned experiment.
22
-
23
- The cover sheet does not copy every page. To inspect a candidate, failed attempt, missing task id, decision, or accounting gap, open the notebook.
24
-
25
- ## What the receipt contains
26
-
27
- The receipt is bounded by the contract rather than by search length. It carries:
28
-
29
- - the producer and concrete run identity;
30
- - a content-addressed reference to the canonical ledger bytes;
31
- - the digest of the exact replay audit;
32
- - counts and terminal state needed to classify completeness;
33
- - short, count-based incompleteness reasons;
34
- - its own RFC 8785 SHA-256 digest.
35
-
36
- It does not carry event arrays, candidate inventories, attempt records, decisions, or lists of every missing id. Those remain in `SearchLedgerReplay`.
37
-
38
- ## Create a receipt
39
-
40
- Create receipts only from the result returned by `SearchLedger.replay()`:
41
-
42
- ```ts
43
- import {
44
- createSearchHistoryReceipt,
45
- openSearchLedger,
46
- } from '@tangle-network/agent-eval/campaign'
47
-
48
- const searchLedger = openSearchLedger({
49
- path: '/runs/gepa/search-ledger.jsonl',
50
- campaignId: 'gepa-run-42',
51
- })
52
-
53
- const replay = await searchLedger.replay()
54
- const receipt = createSearchHistoryReceipt({
55
- producerId: 'gepa',
56
- runId: 'gepa-run-42',
57
- ledger: {
58
- role: 'search-ledger',
59
- uri: 'artifact://gepa-run-42/search-ledger.jsonl',
60
- sha256: ledgerArtifactDigest,
61
- byteLength: ledgerArtifactBytes,
62
- },
63
- replay,
64
- })
65
- ```
66
-
67
- First-party optimizers do this for you. Application code should not hand-author receipt JSON.
68
-
69
- ## Record a search from the loop
70
-
71
- `runOptimization()` and `selfImprove()` accept `searchLedger` and return the receipt on `searchHistory`:
72
-
73
- ```ts
74
- import { openSearchLedger, runOptimization } from '@tangle-network/agent-eval/campaign'
75
-
76
- const result = await runOptimization({
77
- // ...scenarios, dispatchWithSurface, judges, proposer, populationSize, maxGenerations, runDir
78
- searchLedger: {
79
- ledger: openSearchLedger({ path: `${runDir}/search-ledger.jsonl`, campaignId: runId }),
80
- identity: {
81
- agent: { uri: 'git+https://github.com/acme/agent.git', revision: agentCommit },
82
- proposer: { kind: 'deterministic', source: { uri: proposerUri, revision: proposerCommit } },
83
- search: { uri: searchUri, revision: searchCommit },
84
- model: { provider: 'openai', snapshot: 'gpt-5.4@2026-06-01' },
85
- },
86
- },
87
- })
88
- ```
89
-
90
- The loop emits the plan, one candidate-generation operation per generation, one registration per candidate with the exact parent it mutated, one task attempt per designed cell, one decision per candidate, and the terminal event.
91
-
92
- `identity` carries what the ledger requires and a campaign cannot infer: immutable revisions for the agent, proposer, and search implementations, plus the model the agent runs. A measured value wins wherever execution reported one; a cell that ran a moving model alias is refused rather than recorded as an immutable identity.
93
-
94
- `gepaOptimizationMethod({ searchLedger: { identity } })` records GEPA's own candidate population into the same ledger, so a comparison under `require-complete` accepts it.
95
-
96
- ## Extend a plan for a rolling search
97
-
98
- A search whose length is not known when it starts appends `search-plan-extended` with the extra candidate slots and operations.
99
- The first plan event stays first, the effective plan is the merge, and the generation invariant continues across rounds: a candidate whose parent is a round-one candidate is generation 2, not a restarted 0.
100
-
101
- The planned task denominator does not extend. Extending it would reopen candidates that already closed their tasks.
102
-
103
- A search still uses one ledger. A parent from an earlier ledger enters as a generation-0 `candidate-registered` whose surface artifact references the prior ledger, because a cross-file parent cannot be replayed and verified from these bytes.
104
-
105
- ## Complete means the planned denominator is closed
106
-
107
- A receipt is complete only when canonical replay reports:
108
-
109
- - a search plan;
110
- - a terminal `search-completed` event;
111
- - no unresolved candidate slots;
112
- - no missing planned task outcomes;
113
- - no missing planned operations;
114
- - no pending candidate decisions;
115
- - a terminal status of `selected` or `all-rejected`.
116
-
117
- A first-party recorder appends the terminal event only when replay already accounts for the whole planned denominator. An interrupted run, or a candidate that left a designed cell unscored, stays `in-progress` and reports the exact gap.
118
-
119
- Cost completeness remains a separate contract. Unknown spend stays unknown; it is never converted into zero merely because search history is complete.
120
-
121
- ## Compare methods without exposing final cases
122
-
123
- Existing callers remain compatible. Missing history is reported:
124
-
125
- ```ts
126
- const comparison = await compareOptimizationMethods({
127
- methods,
128
- trainScenarios,
129
- selectionScenarios,
130
- testScenarios,
131
- // existing options
132
- })
133
-
134
- console.log(comparison.searchHistory)
135
- ```
136
-
137
- Autonomous or publication-grade callers fail closed:
138
-
139
- ```ts
140
- const comparison = await compareOptimizationMethods({
141
- methods,
142
- trainScenarios,
143
- selectionScenarios,
144
- testScenarios,
145
- searchHistoryPolicy: 'require-complete',
146
- // existing options
147
- })
148
- ```
149
-
150
- `selfImprove({ method })` accepts the same `searchHistoryPolicy` and `searchHistoryVerification` options.
151
- Both workflows use the same method preparation, result validation, cost reconciliation, and history admission.
152
- `selfImprove` returns `searchHistoryCoverage`; comparison returns coverage for every method.
153
- The default remains `allow-missing` with receipt verification.
154
-
155
- ### Verify referenced history before final assessment
156
-
157
- Set `searchHistoryVerification: 'ledger'` to require the referenced bytes, even with `allow-missing`.
158
- Combine it with `require-complete` to require both verified bytes and complete history.
159
-
160
- ```ts
161
- const comparison = await compareOptimizationMethods({
162
- // ...methods, partitions, dispatch, judges, runDir
163
- searchHistoryPolicy: 'require-complete',
164
- searchHistoryVerification: 'ledger',
165
- storage,
166
- })
167
- ```
168
-
169
- Eval reads the receipt URI through `storage.read`.
170
- A `file:` URI becomes a local path; other URIs remain opaque storage keys.
171
- A custom `CampaignStorage` can resolve retained artifacts without another ledger implementation.
172
- Missing bytes, length or digest mismatches, invalid chains, and replay discrepancies refuse final dispatch.
173
- A verified coverage row carries `ledgerVerified: true`.
174
- Receipt-only coverage does not make that claim.
175
-
176
- Existing search recorders compute `ledger.sha256` with `hashCanonical` over the complete JSONL string.
177
- It hashes that string's canonical JSON encoding, rather than the raw UTF-8 file.
178
- Verification preserves this existing identity scheme.
179
- `byteLength` measures the UTF-8 JSONL bytes.
180
-
181
- Every method finishes optimization before the first untouched-final-test dispatch. Under `require-complete`, missing, malformed, producer-mismatched, interrupted, or denominator-incomplete evidence aborts at that boundary.
182
-
183
- ## Verification boundary
184
-
185
- `verifySearchHistoryReceipt()` verifies the bounded envelope and its canonical digest.
186
-
187
- `assertSearchHistoryMatchesReplay()` additionally proves that the envelope was derived from the supplied canonical replay.
188
-
189
- `verifySearchHistoryArtifact(receipt, storage)` resolves bytes and runs both checks through the canonical journal codec.
190
- The two receipt-only functions do not fetch or retain the ledger artifact. A skeptical consumer must resolve `receipt.ledger`, verify its digest and byte length, replay it with `SearchLedger`, and then call `assertSearchHistoryMatchesReplay()`.
191
-
192
- The receipt does not prove that:
193
-
194
- - the optimizer searched intelligently;
195
- - a candidate is correct, safe, or novel;
196
- - the winner generalizes;
197
- - an external source identity is honest;
198
- - knowledge caused an improvement;
199
- - the artifact URI will remain available.
200
-
201
- Those claims require held-out evaluation, artifact retention, provenance verification, knowledge-use evidence, and causal experiments.
202
-
203
- ## Ownership
204
-
205
- - **Eval** owns search evidence, completeness, held-out comparison, statistics, and release decisions.
206
- - **Runtime** owns execution, checkpoints, cancellation, and resume orchestration while referencing Eval evidence.
207
- - **Knowledge** owns what information was visible, retrieved, and selected for use.
208
- - **Interface** owns portable profiles, diffs, identities, and digest primitives.
209
- - **SDKs** should automate these owner contracts, not copy their types or introduce another optimizer loop.
210
-
211
- ## Bind final measurements to execution evidence
212
-
213
- Both complete-method workflows accept optional `evidence: CampaignEvidenceContext`.
214
- It requires the caller's pursuit, evaluator, environment, authority, and attestation provenance.
215
- Eval does not infer independent authority or certify those external declarations.
216
-
217
- Each measured baseline and winner receives the existing `EvidenceReceipt` format.
218
- Eval derives candidate, input-set, output, and result digests from the executed surface and complete campaign.
219
- A missing or deferred final measurement cannot produce a receipt.
220
- Receipts describe measurements; they do not override the release gate or replace the method's selected winner.
221
-
222
- `createCampaignEvidenceReceipt` on `/experiment` provides the same binding for other complete campaign consumers.
223
- Changing an output changes its output digest; changing a judge result changes its measurement digest.
224
- The final receipt retains caller authority, including `candidate-self-report`, without upgrading it.
225
-
226
- ## Implementation ownership
227
-
228
- `src/campaign/search-ledger.ts` owns validation, canonical event normalization, and composition with the shared ledger journal.
229
- `search-ledger-projector.ts` owns campaign replay invariants and audit projection.
230
- `search-ledger-types.ts` defines the shared data contracts, reexported through the existing facade.
231
- `search-ledger-ordering.ts` shares artifact identity and deterministic string ordering between normalization and replay.
232
- The journal in `src/ledger-core` owns hashing, locking, durable appends, and chain verification.