@tangle-network/agent-eval 0.179.0 → 0.181.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 (236) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +119 -146
  3. package/dist/adapters/http.d.ts +2 -2
  4. package/dist/{agent-profile-B7yErX0q.d.ts → agent-profile-CivaSsSy.d.ts} +4 -4
  5. package/dist/{agent-profile-B7yErX0q.d.ts.map → agent-profile-CivaSsSy.d.ts.map} +1 -1
  6. package/dist/{agent-profile-cell-0gSi5ffD.js → agent-profile-cell-Cv6UA-W_.js} +20 -57
  7. package/dist/agent-profile-cell-Cv6UA-W_.js.map +1 -0
  8. package/dist/{agent-profile-cell-CTOZJUuE.d.ts → agent-profile-cell-s__adRnK.d.ts} +3 -3
  9. package/dist/agent-profile-cell-s__adRnK.d.ts.map +1 -0
  10. package/dist/analyst/index.d.ts +10 -10
  11. package/dist/analyst/index.js +4 -4
  12. package/dist/ast-CP9ae9B0.js +557 -0
  13. package/dist/ast-CP9ae9B0.js.map +1 -0
  14. package/dist/ast-hI-vjW6J.d.ts +457 -0
  15. package/dist/ast-hI-vjW6J.d.ts.map +1 -0
  16. package/dist/{benchmark-command-CY6Dg5t5.js → benchmark-command-B57n9vjz.js} +7 -6
  17. package/dist/{benchmark-command-CY6Dg5t5.js.map → benchmark-command-B57n9vjz.js.map} +1 -1
  18. package/dist/benchmarks/index.d.ts +4 -4
  19. package/dist/benchmarks/index.js +3 -3
  20. package/dist/campaign/index.d.ts +6 -6
  21. package/dist/campaign/index.js +8 -8
  22. package/dist/{campaign-BGEurASO.js → campaign-4_ppJW5X.js} +12 -12
  23. package/dist/{campaign-BGEurASO.js.map → campaign-4_ppJW5X.js.map} +1 -1
  24. package/dist/{campaign-evidence-D8DBLqLI.js → campaign-evidence-B8oF9xQ6.js} +515 -471
  25. package/dist/campaign-evidence-B8oF9xQ6.js.map +1 -0
  26. package/dist/cli.js +5 -8
  27. package/dist/cli.js.map +1 -1
  28. package/dist/{client-BlLY6o2w.js → client-CXE-U1SA.js} +3 -1
  29. package/dist/client-CXE-U1SA.js.map +1 -0
  30. package/dist/{client-CuQgX33c.d.ts → client-kh2jOjTK.d.ts} +4 -4
  31. package/dist/{client-CuQgX33c.d.ts.map → client-kh2jOjTK.d.ts.map} +1 -1
  32. package/dist/contract/index.d.ts +13 -13
  33. package/dist/contract/index.js +11 -10
  34. package/dist/contract/index.js.map +1 -1
  35. package/dist/{default-registry-IGDE9XIC.d.ts → default-registry-BwDSWVzg.d.ts} +6 -6
  36. package/dist/{default-registry-IGDE9XIC.d.ts.map → default-registry-BwDSWVzg.d.ts.map} +1 -1
  37. package/dist/{default-registry-BryMEmr8.js → default-registry-aL7xUrUz.js} +2 -2
  38. package/dist/{default-registry-BryMEmr8.js.map → default-registry-aL7xUrUz.js.map} +1 -1
  39. package/dist/{define-agent-eval-Cx4Ls9ta.d.ts → define-agent-eval-CwOWWQt_.d.ts} +33 -12
  40. package/dist/define-agent-eval-CwOWWQt_.d.ts.map +1 -0
  41. package/dist/{define-agent-eval-Dzidv34q.js → define-agent-eval-Ddu33JH9.js} +134 -67
  42. package/dist/define-agent-eval-Ddu33JH9.js.map +1 -0
  43. package/dist/{dspy-rlm-engine-xKiWmj_G.js → dspy-rlm-engine-S53V0HhE.js} +2 -2
  44. package/dist/{dspy-rlm-engine-xKiWmj_G.js.map → dspy-rlm-engine-S53V0HhE.js.map} +1 -1
  45. package/dist/{engine-CX8ReXkn.d.ts → engine-DS1cysJy.d.ts} +10 -7
  46. package/dist/engine-DS1cysJy.d.ts.map +1 -0
  47. package/dist/{eval-campaign-Cs-7MiCs.js → eval-campaign-aYdtjtJR.js} +4 -4
  48. package/dist/{eval-campaign-Cs-7MiCs.js.map → eval-campaign-aYdtjtJR.js.map} +1 -1
  49. package/dist/{exact-types-B7LC1EyX.d.ts → exact-types-BZDe0W2D.d.ts} +2 -2
  50. package/dist/{exact-types-B7LC1EyX.d.ts.map → exact-types-BZDe0W2D.d.ts.map} +1 -1
  51. package/dist/experiment/index.d.ts +27 -477
  52. package/dist/experiment/index.d.ts.map +1 -1
  53. package/dist/experiment/index.js +95 -559
  54. package/dist/experiment/index.js.map +1 -1
  55. package/dist/{experiment-tracker-B3TiF5-u.d.ts → experiment-tracker-C7PfnF4b.d.ts} +2 -2
  56. package/dist/{experiment-tracker-B3TiF5-u.d.ts.map → experiment-tracker-C7PfnF4b.d.ts.map} +1 -1
  57. package/dist/{external-optimizer-process-Dlz8YxrT.js → external-optimizer-process-QDRURJAM.js} +3 -3
  58. package/dist/{external-optimizer-process-Dlz8YxrT.js.map → external-optimizer-process-QDRURJAM.js.map} +1 -1
  59. package/dist/{external-optimizer-subprocess-q3VzlGAO.js → external-optimizer-subprocess-D4dzUBZI.js} +3 -2
  60. package/dist/{external-optimizer-subprocess-q3VzlGAO.js.map → external-optimizer-subprocess-D4dzUBZI.js.map} +1 -1
  61. package/dist/{feedback-trajectory-eHWNv5Aj.d.ts → feedback-trajectory-CXmtITBo.d.ts} +3 -3
  62. package/dist/{feedback-trajectory-eHWNv5Aj.d.ts.map → feedback-trajectory-CXmtITBo.d.ts.map} +1 -1
  63. package/dist/hosted/index.d.ts +2 -2
  64. package/dist/hosted/index.d.ts.map +1 -1
  65. package/dist/hosted/index.js +1 -1
  66. package/dist/{index-BxWvILU8.d.ts → index-Bp_6sj3x.d.ts} +109 -56
  67. package/dist/index-Bp_6sj3x.d.ts.map +1 -0
  68. package/dist/{index-e7LXeRVa.d.ts → index-CJ3LhKIX.d.ts} +2 -2
  69. package/dist/{index-e7LXeRVa.d.ts.map → index-CJ3LhKIX.d.ts.map} +1 -1
  70. package/dist/{index-CbLmrWCa.d.ts → index-DNntP4ch.d.ts} +8 -8
  71. package/dist/{index-CbLmrWCa.d.ts.map → index-DNntP4ch.d.ts.map} +1 -1
  72. package/dist/{index-DxNYmx4a.d.ts → index-DoykkxW0.d.ts} +11 -11
  73. package/dist/{index-DxNYmx4a.d.ts.map → index-DoykkxW0.d.ts.map} +1 -1
  74. package/dist/index.d.ts +28 -28
  75. package/dist/index.js +25 -16
  76. package/dist/index.js.map +1 -1
  77. package/dist/{insight-report-DETqPc_A.d.ts → insight-report-D1qa0HWs.d.ts} +9 -5
  78. package/dist/{insight-report-DETqPc_A.d.ts.map → insight-report-D1qa0HWs.d.ts.map} +1 -1
  79. package/dist/{integrity-DsHWCebQ.js → integrity-DH5ng72x.js} +2 -2
  80. package/dist/{integrity-DsHWCebQ.js.map → integrity-DH5ng72x.js.map} +1 -1
  81. package/dist/{integrity-BKTcA-HP.d.ts → integrity-rGOfSUle.d.ts} +2 -2
  82. package/dist/{integrity-BKTcA-HP.d.ts.map → integrity-rGOfSUle.d.ts.map} +1 -1
  83. package/dist/{ledger-core-Cs9f7385.js → journal-Cs9f7385.js} +1 -1
  84. package/dist/journal-Cs9f7385.js.map +1 -0
  85. package/dist/{judge-calibration-C5CbMYce.d.ts → judge-calibration-DFtEMlde.d.ts} +31 -2
  86. package/dist/judge-calibration-DFtEMlde.d.ts.map +1 -0
  87. package/dist/{judge-calibration-BnpVKtnb.js → judge-calibration-DYmaBtJr.js} +48 -2
  88. package/dist/{judge-calibration-BnpVKtnb.js.map → judge-calibration-DYmaBtJr.js.map} +1 -1
  89. package/dist/ledger-core/index.d.ts +1 -1
  90. package/dist/ledger-core/index.js +1 -1
  91. package/dist/{llm-judge-v80Kmu9g.js → llm-judge-DEFZeSiu.js} +645 -456
  92. package/dist/llm-judge-DEFZeSiu.js.map +1 -0
  93. package/dist/{matrix-DeMmnWrP.d.ts → matrix-CyhW-vgJ.d.ts} +2 -2
  94. package/dist/{matrix-DeMmnWrP.d.ts.map → matrix-CyhW-vgJ.d.ts.map} +1 -1
  95. package/dist/meta-eval/index.d.ts +138 -7
  96. package/dist/meta-eval/index.d.ts.map +1 -1
  97. package/dist/meta-eval/index.js +245 -97
  98. package/dist/meta-eval/index.js.map +1 -1
  99. package/dist/{mint-Cc1_zwRQ.js → mint-ySIIkKlV.js} +2 -2
  100. package/dist/{mint-Cc1_zwRQ.js.map → mint-ySIIkKlV.js.map} +1 -1
  101. package/dist/multishot/golden/index.d.ts +1 -1
  102. package/dist/multishot/index.d.ts +2 -2
  103. package/dist/openapi.json +1 -1
  104. package/dist/outcome-store-BXlkwMPR.js +131 -0
  105. package/dist/outcome-store-BXlkwMPR.js.map +1 -0
  106. package/dist/{outcome-store-BYHIuO0e.d.ts → outcome-store-CNt4iZ67.d.ts} +18 -25
  107. package/dist/outcome-store-CNt4iZ67.d.ts.map +1 -0
  108. package/dist/{paired-promotion-decision-CGzg0cI_.d.ts → paired-promotion-decision-DPsMQm-0.d.ts} +13 -7
  109. package/dist/{paired-promotion-decision-CGzg0cI_.d.ts.map → paired-promotion-decision-DPsMQm-0.d.ts.map} +1 -1
  110. package/dist/pipelines/index.js +1 -1
  111. package/dist/{produced-state-Cv0kJJuP.js → produced-state-BHboMaab.js} +3 -3
  112. package/dist/{produced-state-Cv0kJJuP.js.map → produced-state-BHboMaab.js.map} +1 -1
  113. package/dist/profile-cell.d.ts +1 -1
  114. package/dist/profile-cell.js +1 -1
  115. package/dist/{promotion-policy-DWOm70gx.js → promotion-policy-CDMMxzb6.js} +28 -40
  116. package/dist/promotion-policy-CDMMxzb6.js.map +1 -0
  117. package/dist/{registry-ByVld1-5.d.ts → registry-BRbB6Y0v.d.ts} +4 -4
  118. package/dist/{registry-ByVld1-5.d.ts.map → registry-BRbB6Y0v.d.ts.map} +1 -1
  119. package/dist/{release-confidence-BAcNYOf1.d.ts → release-confidence-BcqeQTHW.d.ts} +3 -3
  120. package/dist/{release-confidence-BAcNYOf1.d.ts.map → release-confidence-BcqeQTHW.d.ts.map} +1 -1
  121. package/dist/{release-confidence-BcGCclTB.js → release-confidence-DMg8n18l.js} +2 -2
  122. package/dist/{release-confidence-BcGCclTB.js.map → release-confidence-DMg8n18l.js.map} +1 -1
  123. package/dist/{report-command-DKlXfU5r.js → report-command-V1ecVgAv.js} +27 -3
  124. package/dist/report-command-V1ecVgAv.js.map +1 -0
  125. package/dist/reporting.d.ts +4 -4
  126. package/dist/reporting.js +3 -3
  127. package/dist/{researcher-jsW1X94L.d.ts → researcher-64T49THL.d.ts} +6 -6
  128. package/dist/{researcher-jsW1X94L.d.ts.map → researcher-64T49THL.d.ts.map} +1 -1
  129. package/dist/{reward-hacking-ZXEi9VCq.d.ts → reward-hacking-uzO_ihep.d.ts} +2 -2
  130. package/dist/{reward-hacking-ZXEi9VCq.d.ts.map → reward-hacking-uzO_ihep.d.ts.map} +1 -1
  131. package/dist/rl.d.ts +53 -99
  132. package/dist/rl.d.ts.map +1 -1
  133. package/dist/rl.js +182 -169
  134. package/dist/rl.js.map +1 -1
  135. package/dist/rollout/index.d.ts +1 -1
  136. package/dist/rollout/index.js +2 -2
  137. package/dist/{rollout-DmoJVqrF.js → rollout-B-UF5R6w.js} +2 -2
  138. package/dist/{rollout-DmoJVqrF.js.map → rollout-B-UF5R6w.js.map} +1 -1
  139. package/dist/rubric-predictive-validity-Bmj2_cll.d.ts +79 -0
  140. package/dist/rubric-predictive-validity-Bmj2_cll.d.ts.map +1 -0
  141. package/dist/rubric-predictive-validity-CCK-1B7w.js +178 -0
  142. package/dist/rubric-predictive-validity-CCK-1B7w.js.map +1 -0
  143. package/dist/{run-record-DTv1MdjK.d.ts → run-record-BiTWauyO.d.ts} +2 -2
  144. package/dist/{run-record-DTv1MdjK.d.ts.map → run-record-BiTWauyO.d.ts.map} +1 -1
  145. package/dist/run-record-Br-Yzt_k.js +464 -0
  146. package/dist/run-record-Br-Yzt_k.js.map +1 -0
  147. package/dist/{run-record-DQpSf7t-.js → run-record-DualPTn2.js} +2 -2
  148. package/dist/{run-record-DQpSf7t-.js.map → run-record-DualPTn2.js.map} +1 -1
  149. package/dist/{semantic-concept-judge-Bi6_iGqg.js → semantic-concept-judge-Bm5JDEKO.js} +3 -3
  150. package/dist/{semantic-concept-judge-Bi6_iGqg.js.map → semantic-concept-judge-Bm5JDEKO.js.map} +1 -1
  151. package/dist/{sequential-B5gXgcyp.js → sequential-DAsyV2T9.js} +42 -25
  152. package/dist/sequential-DAsyV2T9.js.map +1 -0
  153. package/dist/{series-convergence-DeG33RpC.d.ts → series-convergence-BnMs_uAr.d.ts} +3 -3
  154. package/dist/{series-convergence-DeG33RpC.d.ts.map → series-convergence-BnMs_uAr.d.ts.map} +1 -1
  155. package/dist/{skillopt-optimization-method-C3oYul8v.js → skillopt-optimization-method-CL_0aArC.js} +5 -5
  156. package/dist/{skillopt-optimization-method-C3oYul8v.js.map → skillopt-optimization-method-CL_0aArC.js.map} +1 -1
  157. package/dist/{statistical-heldout-0La5ZTlv.d.ts → statistical-heldout-CpVd6FmY.d.ts} +207 -144
  158. package/dist/statistical-heldout-CpVd6FmY.d.ts.map +1 -0
  159. package/dist/{store-tool-spans-4J1EDElP.d.ts → store-tool-spans-Dt-YdAuE.d.ts} +6 -6
  160. package/dist/{store-tool-spans-4J1EDElP.d.ts.map → store-tool-spans-Dt-YdAuE.d.ts.map} +1 -1
  161. package/dist/{summary-report-gMrbYawB.d.ts → summary-report-D1h4dlrK.d.ts} +3 -3
  162. package/dist/{summary-report-gMrbYawB.d.ts.map → summary-report-D1h4dlrK.d.ts.map} +1 -1
  163. package/dist/{summary-report-B16xy9Kd.js → summary-report-e-MaOAHV.js} +2 -2
  164. package/dist/{summary-report-B16xy9Kd.js.map → summary-report-e-MaOAHV.js.map} +1 -1
  165. package/dist/supervisor-run/index.d.ts +4 -2
  166. package/dist/supervisor-run/index.d.ts.map +1 -1
  167. package/dist/supervisor-run/index.js +3 -3
  168. package/dist/{terminal-record-Ce9_UjRz.js → terminal-record-BtPwKTSr.js} +58 -26
  169. package/dist/terminal-record-BtPwKTSr.js.map +1 -0
  170. package/dist/{tool-groups-2QA0S7dK.d.ts → tool-groups-B2bSNaJB.d.ts} +3 -3
  171. package/dist/tool-groups-B2bSNaJB.d.ts.map +1 -0
  172. package/dist/{tool-waste-B9tdWV6g.js → tool-waste-C7MU9u1e.js} +2 -2
  173. package/dist/{tool-waste-B9tdWV6g.js.map → tool-waste-C7MU9u1e.js.map} +1 -1
  174. package/dist/trace-repair/index.d.ts +2 -2
  175. package/dist/traces.d.ts +6 -6
  176. package/dist/traces.js +1 -1
  177. package/dist/{types-BmlkCrg0.d.ts → types-BvZoPTGa.d.ts} +3 -3
  178. package/dist/{types-BmlkCrg0.d.ts.map → types-BvZoPTGa.d.ts.map} +1 -1
  179. package/dist/{types-gvRsyJLh.d.ts → types-CBbLtr2J.d.ts} +38 -3
  180. package/dist/{types-gvRsyJLh.d.ts.map → types-CBbLtr2J.d.ts.map} +1 -1
  181. package/dist/{types-C34V4Vto.d.ts → types-CS0qk_Yp.d.ts} +4 -4
  182. package/dist/{types-C34V4Vto.d.ts.map → types-CS0qk_Yp.d.ts.map} +1 -1
  183. package/dist/{types-DzuaM493.d.ts → types-D7gEdPoQ.d.ts} +3 -3
  184. package/dist/{types-DzuaM493.d.ts.map → types-D7gEdPoQ.d.ts.map} +1 -1
  185. package/dist/{types-vUdAx2Cj.d.ts → types-lPkDQNqJ.d.ts} +20 -2
  186. package/dist/{types-vUdAx2Cj.d.ts.map → types-lPkDQNqJ.d.ts.map} +1 -1
  187. package/dist/wire/index.d.ts +2 -2
  188. package/docs/adapters-observability.md +14 -0
  189. package/docs/campaign-proposers.md +86 -128
  190. package/docs/charter.md +108 -112
  191. package/docs/concepts.md +157 -69
  192. package/docs/design/mlbenchmarks-book-review.md +440 -0
  193. package/docs/design/mlbenchmarks-review/observations.json +713 -0
  194. package/docs/design/mlbenchmarks-review/probes.mts +476 -0
  195. package/docs/design/mlbenchmarks-review/sources.json +200 -0
  196. package/docs/design/self-improvement-evidence-audit.md +263 -0
  197. package/docs/design.md +2 -1
  198. package/docs/eval-surface-map.md +95 -42
  199. package/docs/evaluation-integrity.md +220 -0
  200. package/docs/experiment.md +111 -55
  201. package/docs/feature-guide.md +5 -6
  202. package/docs/hosted-ingest-spec.md +4 -11
  203. package/docs/insight-report.md +187 -455
  204. package/docs/outcome-validity.md +182 -0
  205. package/docs/product-eval-adoption.md +1 -2
  206. package/docs/research-report-methodology.md +7 -7
  207. package/docs/search-history-receipts.md +8 -0
  208. package/docs/statistical-evidence.md +129 -0
  209. package/docs/verdicts.md +76 -49
  210. package/package.json +1 -1
  211. package/dist/agent-profile-cell-0gSi5ffD.js.map +0 -1
  212. package/dist/agent-profile-cell-CTOZJUuE.d.ts.map +0 -1
  213. package/dist/campaign-evidence-D8DBLqLI.js.map +0 -1
  214. package/dist/client-BlLY6o2w.js.map +0 -1
  215. package/dist/define-agent-eval-Cx4Ls9ta.d.ts.map +0 -1
  216. package/dist/define-agent-eval-Dzidv34q.js.map +0 -1
  217. package/dist/engine-CX8ReXkn.d.ts.map +0 -1
  218. package/dist/index-BxWvILU8.d.ts.map +0 -1
  219. package/dist/judge-calibration-C5CbMYce.d.ts.map +0 -1
  220. package/dist/ledger-core-Cs9f7385.js.map +0 -1
  221. package/dist/llm-judge-v80Kmu9g.js.map +0 -1
  222. package/dist/outcome-store-BYHIuO0e.d.ts.map +0 -1
  223. package/dist/outcome-store-ChBKlTd_.js +0 -75
  224. package/dist/outcome-store-ChBKlTd_.js.map +0 -1
  225. package/dist/promotion-policy-DWOm70gx.js.map +0 -1
  226. package/dist/report-command-DKlXfU5r.js.map +0 -1
  227. package/dist/rubric-predictive-validity-2D5Gw9z9.js +0 -131
  228. package/dist/rubric-predictive-validity-2D5Gw9z9.js.map +0 -1
  229. package/dist/rubric-predictive-validity-Dl1dvKCv.d.ts +0 -75
  230. package/dist/rubric-predictive-validity-Dl1dvKCv.d.ts.map +0 -1
  231. package/dist/run-record-CR63CpHK.js +0 -216
  232. package/dist/run-record-CR63CpHK.js.map +0 -1
  233. package/dist/sequential-B5gXgcyp.js.map +0 -1
  234. package/dist/statistical-heldout-0La5ZTlv.d.ts.map +0 -1
  235. package/dist/terminal-record-Ce9_UjRz.js.map +0 -1
  236. package/dist/tool-groups-2QA0S7dK.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["populations"],"sources":["../../src/experiment/ast.ts","../../src/experiment/budget.ts","../../src/experiment/funnel.ts","../../src/experiment/define.ts","../../src/experiment/evidence-record.ts","../../src/experiment/power.ts"],"sourcesContent":["/**\n * The registered-rule AST: every rule an experiment registers is DATA.\n *\n * A closure cannot be canonicalized or hashed; a node tree can. `sealExperiment`\n * hashes the whole tree, and every interpreter in this file takes only a node\n * plus evidence records — no parameter for alpha, threshold, metric, or\n * stopping rule exists on any executable surface. The registered object and\n * the executed object are therefore the same object, and registered-vs-ran\n * drift is unrepresentable rather than checked.\n *\n * Node families:\n * Predicate closed-key comparisons — the only leaf\n * AdmissionRule monotone funnel stages with registered waivers\n * SelectionRule deterministic subsets over a closed field set\n * Estimand what the experiment measures\n * IntervalSpec how uncertainty is computed, seed included\n * Condition decision guards over named derived quantities\n * DecisionRule ordered verdict table, or a registered absence of one\n * Obligation a control that must exist before a verdict class is read\n * ValidityGate pre-spend design checks\n * HaltRule gates as prerequisites — failure refuses the spend\n * BudgetRule spend schedules with a named ledger\n * MatchedBudgetRule arm budget matching as a refusal\n * ReissuePolicy carrier faults are reissued; model outcomes stand\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** JSON-serializable value — everything a sealed node may carry. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue }\n\n/** Evidence row shape. Fields are addressed by dot-separated paths. */\nexport type EvidenceRecord = Record<string, unknown>\n\n/** A decision rule's branches did not cover the evidence. */\nclass DecisionTableNotTotalError extends ValidationError {}\n\n// ── Predicate ────────────────────────────────────────────────────────\n\n/**\n * Closed-key comparison over a declared record schema. The only leaf node.\n * `field` is a dot-separated path into an evidence record.\n */\nexport type Predicate =\n | {\n kind: 'compare'\n field: string\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte'\n value: JsonValue\n }\n | { kind: 'in'; field: string; values: JsonValue[] }\n | { kind: 'all'; of: Predicate[] }\n | { kind: 'any'; of: Predicate[] }\n | { kind: 'not'; of: Predicate }\n\n/** Read a dot-separated field path. Missing segments yield `undefined`. */\nexport function readField(record: EvidenceRecord, path: string): unknown {\n let current: unknown = record\n for (const key of path.split('.')) {\n if (current === null || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n}\n\n/** Evaluate a predicate against one evidence record. */\nexport function evaluatePredicate(predicate: Predicate, record: EvidenceRecord): boolean {\n switch (predicate.kind) {\n case 'compare':\n return compareValues(readField(record, predicate.field), predicate.op, predicate.value)\n case 'in':\n return predicate.values.includes(readField(record, predicate.field) as JsonValue)\n case 'all':\n return predicate.of.every((p) => evaluatePredicate(p, record))\n case 'any':\n return predicate.of.some((p) => evaluatePredicate(p, record))\n case 'not':\n return !evaluatePredicate(predicate.of, record)\n }\n}\n\n/** Numbers compare numerically; everything else compares as strings. */\nfunction compareValues(\n value: unknown,\n op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte',\n target: JsonValue,\n): boolean {\n if (op === 'eq') return value === target\n if (op === 'ne') return value !== target\n const numeric = typeof value === 'number' && typeof target === 'number'\n const left = numeric ? (value as number) : String(value)\n const right = numeric ? (target as number) : String(target)\n switch (op) {\n case 'lt':\n return left < right\n case 'lte':\n return left <= right\n case 'gt':\n return left > right\n case 'gte':\n return left >= right\n }\n}\n\n// ── Admission ────────────────────────────────────────────────────────\n\n/**\n * One monotone funnel stage. `waives` names substrate admission conditions\n * deliberately NOT applied, so a waiver is registered, never implicit.\n */\nexport interface AdmissionStage {\n id: string\n keep: Predicate\n waives?: string[]\n}\n\n/** A partition is a set reported separately and never pooled. */\nexport interface AdmissionPartition {\n id: string\n /** Stage whose dropped rows this partition draws from. */\n from: string\n keep: Predicate\n pooling: 'never'\n}\n\n/** Declarative row-admission funnel. Stages only remove rows. */\nexport interface AdmissionRule {\n population: string\n stages: AdmissionStage[]\n partitions?: AdmissionPartition[]\n}\n\n// ── Selection ────────────────────────────────────────────────────────\n\n/**\n * Deterministic subset selection. `reads` is the closed field set the rule\n * may touch — outcome-contaminated selection is unrepresentable because an\n * outcome field is simply not in the list.\n */\nexport type SelectionRule =\n | {\n kind: 'round-robin'\n groupBy: string\n groupOrder: 'lex-asc'\n withinOrder: { field: string; dir: 'asc' | 'desc' }\n take: number\n reads: string[]\n }\n | {\n kind: 'filter-of'\n /** Name of the sealed subset or selection this rule filters. */\n base: string\n keep: Predicate\n order: { field: string; dir: 'asc' | 'desc' }\n }\n\n/**\n * Execute a selection rule.\n *\n * Round-robin walks groups in lexicographic order and takes ids in\n * within-group order until `take` ids are chosen. Filter-of keeps the ids of\n * `bases[rule.base]` whose record satisfies the predicate, in the registered\n * order. Ids absent from `records` are evaluated on their id alone (fields\n * derived from the id via `idFields`), so a sealed base outlives its source\n * records.\n */\nexport function runSelectionRule(\n rule: SelectionRule,\n records: readonly EvidenceRecord[],\n options: {\n /** Field carrying a row's identity. */\n idField: string\n /** Sealed or previously-computed subsets, by name. */\n bases?: Record<string, readonly string[]>\n /** Derive predicate-readable fields from a bare id when its record is absent. */\n idFields?: (id: string) => EvidenceRecord\n },\n): string[] {\n if (rule.kind === 'round-robin') {\n const allowed = new Set(rule.reads)\n for (const field of [rule.groupBy, rule.withinOrder.field]) {\n if (!allowed.has(field)) {\n throw new ValidationError(\n `runSelectionRule: round-robin reads '${field}' but its closed read set is [${rule.reads.join(', ')}]`,\n )\n }\n }\n const byGroup = new Map<string, string[]>()\n for (const record of records) {\n const group = String(readField(record, rule.groupBy))\n const id = String(readField(record, rule.withinOrder.field))\n const bucket = byGroup.get(group)\n if (bucket) bucket.push(id)\n else byGroup.set(group, [id])\n }\n for (const ids of byGroup.values()) {\n ids.sort()\n if (rule.withinOrder.dir === 'desc') ids.reverse()\n }\n const groups = [...byGroup.keys()].sort()\n const chosen: string[] = []\n let cursor = 0\n while (chosen.length < rule.take && groups.some((g) => byGroup.get(g)!.length > 0)) {\n const group = groups[cursor % groups.length]!\n const ids = byGroup.get(group)!\n if (ids.length > 0) chosen.push(ids.shift()!)\n cursor += 1\n }\n return chosen\n }\n\n const base = options.bases?.[rule.base]\n if (!base) {\n throw new ValidationError(`runSelectionRule: filter-of base '${rule.base}' was not provided`)\n }\n const index = new Map(records.map((r) => [String(readField(r, options.idField)), r]))\n const kept = base.filter((id) => {\n const record = index.get(id) ?? options.idFields?.(id)\n if (!record) {\n throw new ValidationError(\n `runSelectionRule: base id '${id}' has no record and no idFields derivation`,\n )\n }\n return evaluatePredicate(rule.keep, record)\n })\n const sorted = [...kept].sort()\n if (rule.order.dir === 'desc') sorted.reverse()\n return sorted\n}\n\n// ── Estimands ────────────────────────────────────────────────────────\n\n/** A named set of row identities, built from arm rows and an event predicate. */\nexport type SetExpr =\n | { kind: 'rows-where'; arm: string; event: Predicate }\n | { kind: 'intersect'; of: SetExpr[] }\n\n/**\n * What the experiment measures. Every estimand names the fields it reads, so\n * the sealed tree records the full data dependency of the number.\n */\nexport type Estimand =\n | { kind: 'rate'; event: Predicate; over: 'rollouts' }\n | { kind: 'rate-at-least-once'; event: Predicate; groupBy: string }\n | {\n kind: 'paired-mean-diff'\n armField: string\n treatment: string\n control: string\n pairBy: string\n /**\n * Field path to the per-row outcome. A boolean reads as 1 or 0, so a\n * binary pass/fail outcome gives the risk difference directly.\n */\n value: string\n /** A pair one arm did not answer contributes a difference of exactly zero. */\n missing: 'zero-diff'\n }\n | {\n kind: 'set-ratio'\n armField: string\n idField: string\n numerator: SetExpr\n denominator: SetExpr\n }\n\nexport interface EstimandResult {\n value: number\n numerator: number\n denominator: number\n}\n\nfunction evaluateSetExpr(\n expr: SetExpr,\n rows: readonly EvidenceRecord[],\n armField: string,\n idField: string,\n): Set<string> {\n if (expr.kind === 'rows-where') {\n const ids = new Set<string>()\n for (const row of rows) {\n if (String(readField(row, armField)) !== expr.arm) continue\n if (evaluatePredicate(expr.event, row)) ids.add(String(readField(row, idField)))\n }\n return ids\n }\n if (expr.of.length === 0) throw new ValidationError('computeEstimand: empty intersect')\n const sets = expr.of.map((e) => evaluateSetExpr(e, rows, armField, idField))\n const [first, ...rest] = sets\n const out = new Set<string>()\n for (const id of first!) {\n if (rest.every((s) => s.has(id))) out.add(id)\n }\n return out\n}\n\n/**\n * Read one registered outcome field as a number.\n *\n * A binary outcome reaches evidence as `true` or `false`. Its mean is the pass\n * rate and the mean of its paired differences is the risk difference, so\n * `true` reads as 1 and `false` as 0 — the same quantity a caller would\n * otherwise encode by hand, and the same reading in every interpreter here.\n * Every other type, and a non-finite number, is a measurement defect: it\n * rejects instead of poisoning the mean with `NaN` or a coerced zero.\n */\nfunction readNumericOutcome(raw: unknown, context: string, field: string, where: string): number {\n if (typeof raw === 'boolean') return raw ? 1 : 0\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw\n throw new ValidationError(\n `${context}: value field '${field}' is not a finite number or a boolean on ${where}`,\n )\n}\n\n/** Compute an estimand over evidence rows. Pure; reads only registered fields. */\nexport function computeEstimand(\n estimand: Estimand,\n rows: readonly EvidenceRecord[],\n): EstimandResult {\n switch (estimand.kind) {\n case 'rate': {\n const numerator = rows.filter((r) => evaluatePredicate(estimand.event, r)).length\n if (rows.length === 0) throw new ValidationError('computeEstimand: rate over zero rows')\n return { value: numerator / rows.length, numerator, denominator: rows.length }\n }\n case 'rate-at-least-once': {\n const byGroup = new Map<string, boolean>()\n for (const row of rows) {\n const group = String(readField(row, estimand.groupBy))\n const hit = evaluatePredicate(estimand.event, row)\n byGroup.set(group, (byGroup.get(group) ?? false) || hit)\n }\n if (byGroup.size === 0) {\n throw new ValidationError('computeEstimand: rate-at-least-once over zero groups')\n }\n const numerator = [...byGroup.values()].filter(Boolean).length\n return { value: numerator / byGroup.size, numerator, denominator: byGroup.size }\n }\n case 'paired-mean-diff': {\n const byPair = new Map<string, { treatment?: number; control?: number }>()\n for (const row of rows) {\n const arm = String(readField(row, estimand.armField))\n if (arm !== estimand.treatment && arm !== estimand.control) continue\n const pair = String(readField(row, estimand.pairBy))\n const value = readNumericOutcome(\n readField(row, estimand.value),\n 'computeEstimand paired-mean-diff',\n estimand.value,\n `pair '${pair}'`,\n )\n const slot = byPair.get(pair) ?? {}\n if (arm === estimand.treatment) slot.treatment = value\n else slot.control = value\n byPair.set(pair, slot)\n }\n if (byPair.size === 0) {\n throw new ValidationError('computeEstimand: paired-mean-diff over zero pairs')\n }\n let sum = 0\n for (const slot of byPair.values()) {\n // missing: 'zero-diff' — an unanswered side contributes zero, never a drop\n sum += (slot.treatment ?? 0) - (slot.control ?? 0)\n }\n return { value: sum / byPair.size, numerator: sum, denominator: byPair.size }\n }\n case 'set-ratio': {\n const numeratorSet = evaluateSetExpr(\n estimand.numerator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n const denominatorSet = evaluateSetExpr(\n estimand.denominator,\n rows,\n estimand.armField,\n estimand.idField,\n )\n if (denominatorSet.size === 0) {\n throw new ValidationError('computeEstimand: set-ratio denominator set is empty')\n }\n return {\n value: numeratorSet.size / denominatorSet.size,\n numerator: numeratorSet.size,\n denominator: denominatorSet.size,\n }\n }\n }\n}\n\n// ── Intervals ────────────────────────────────────────────────────────\n\n/** How uncertainty is computed. The seed is part of the registration. */\nexport type IntervalSpec =\n | {\n kind: 'cluster-bootstrap'\n clusterBy: string\n resamples: number\n seed: number\n level: number\n method: 'percentile'\n }\n | { kind: 'clopper-pearson'; level: number }\n\nexport interface ComputedInterval {\n lower: number\n upper: number\n level: number\n}\n\n/**\n * Execute an interval spec.\n *\n * Cluster-bootstrap resamples whole clusters of the per-row `value` field and\n * takes percentile bounds of the pooled mean. Clopper-Pearson computes the\n * exact binomial interval and requires `successes`/`trials` evidence instead\n * of rows.\n */\nexport function computeInterval(\n spec: IntervalSpec,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n): ComputedInterval {\n if (spec.kind === 'cluster-bootstrap') {\n if (evidence.kind !== 'rows') {\n throw new ValidationError('computeInterval: cluster-bootstrap requires row evidence')\n }\n const clusters = new Map<string, number[]>()\n for (const row of evidence.rows) {\n const cluster = String(readField(row, spec.clusterBy))\n const value = readNumericOutcome(\n readField(row, evidence.value),\n 'computeInterval cluster-bootstrap',\n evidence.value,\n `cluster '${cluster}'`,\n )\n const bucket = clusters.get(cluster)\n if (bucket) bucket.push(value)\n else clusters.set(cluster, [value])\n }\n const clusterValues = [...clusters.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([, values]) => values)\n if (clusterValues.length < 2) {\n throw new ValidationError(\n `computeInterval: cluster-bootstrap needs >= 2 clusters, got ${clusterValues.length}`,\n )\n }\n const rng = mulberry32(spec.seed)\n const means = new Array<number>(spec.resamples)\n for (let draw = 0; draw < spec.resamples; draw++) {\n let sum = 0\n let count = 0\n for (let pick = 0; pick < clusterValues.length; pick++) {\n const cluster = clusterValues[Math.floor(rng() * clusterValues.length)]!\n for (const value of cluster) sum += value\n count += cluster.length\n }\n means[draw] = sum / count\n }\n means.sort((a, b) => a - b)\n const alpha = 1 - spec.level\n const lowerIndex = Math.floor((alpha / 2) * spec.resamples)\n const upperIndex = Math.min(spec.resamples - 1, Math.ceil((1 - alpha / 2) * spec.resamples) - 1)\n return {\n lower: means[lowerIndex]!,\n upper: means[Math.max(lowerIndex, upperIndex)]!,\n level: spec.level,\n }\n }\n\n if (evidence.kind !== 'binomial') {\n throw new ValidationError('computeInterval: clopper-pearson requires binomial evidence')\n }\n const { successes, trials } = evidence\n if (!Number.isInteger(successes) || !Number.isInteger(trials) || trials <= 0 || successes < 0) {\n throw new ValidationError(\n `computeInterval: clopper-pearson needs 0 <= successes <= trials, got ${successes}/${trials}`,\n )\n }\n if (successes > trials) {\n throw new ValidationError(\n `computeInterval: clopper-pearson successes ${successes} exceed trials ${trials}`,\n )\n }\n const alpha = 1 - spec.level\n const lower = successes === 0 ? 0 : binomialQuantile(successes, trials, alpha / 2, 'lower')\n const upper = successes === trials ? 1 : binomialQuantile(successes, trials, alpha / 2, 'upper')\n return { lower, upper, level: spec.level }\n}\n\n/**\n * Clopper-Pearson bound by bisection on the binomial tail. The lower bound is\n * the p with P(X >= successes | p) = alpha; the upper is the p with\n * P(X <= successes | p) = alpha. Deterministic, no special functions.\n */\nfunction binomialQuantile(\n successes: number,\n trials: number,\n alpha: number,\n side: 'lower' | 'upper',\n): number {\n const tail = (p: number): number => {\n // log-space binomial pmf accumulation for numeric stability\n let sum = 0\n for (let k = 0; k <= trials; k++) {\n const inTail = side === 'lower' ? k >= successes : k <= successes\n if (!inTail) continue\n sum += Math.exp(logBinomialPmf(k, trials, p))\n }\n return sum\n }\n let lo = 0\n let hi = 1\n for (let iter = 0; iter < 100; iter++) {\n const mid = (lo + hi) / 2\n if (tail(mid) < alpha) {\n if (side === 'lower') lo = mid\n else hi = mid\n } else {\n if (side === 'lower') hi = mid\n else lo = mid\n }\n }\n return (lo + hi) / 2\n}\n\nfunction logBinomialPmf(k: number, n: number, p: number): number {\n if (p <= 0) return k === 0 ? 0 : Number.NEGATIVE_INFINITY\n if (p >= 1) return k === n ? 0 : Number.NEGATIVE_INFINITY\n return logChoose(n, k) + k * Math.log(p) + (n - k) * Math.log(1 - p)\n}\n\nfunction logChoose(n: number, k: number): number {\n return logFactorial(n) - logFactorial(k) - logFactorial(n - k)\n}\n\nconst LOG_FACTORIAL_CACHE: number[] = [0]\nfunction logFactorial(n: number): number {\n for (let i = LOG_FACTORIAL_CACHE.length; i <= n; i++) {\n LOG_FACTORIAL_CACHE[i] = LOG_FACTORIAL_CACHE[i - 1]! + Math.log(i)\n }\n return LOG_FACTORIAL_CACHE[n]!\n}\n\n// ── Conditions and decisions ─────────────────────────────────────────\n\n/** Decision guards read only named derived quantities — never raw rows. */\nexport type Condition =\n | { kind: 'interval-excludes-zero'; interval: string; sign: 'positive' | 'negative' }\n | { kind: 'interval-includes-zero'; interval: string }\n | { kind: 'quantity-threshold'; quantity: string; op: 'gte' | 'lte' | 'gt' | 'lt'; value: number }\n | { kind: 'obligation-met'; obligation: string }\n | { kind: 'all'; of: Condition[] }\n | { kind: 'any'; of: Condition[] }\n | { kind: 'not'; of: Condition }\n\n/** The named quantities a decision rule may read. Nothing else reaches it. */\nexport interface DerivedQuantities {\n intervals: Record<string, { lower: number; upper: number }>\n quantities: Record<string, number>\n obligationsMet: Record<string, boolean>\n}\n\nexport function evaluateCondition(condition: Condition, evidence: DerivedQuantities): boolean {\n switch (condition.kind) {\n case 'interval-excludes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n const excludes = interval.lower > 0 || interval.upper < 0\n return excludes && (condition.sign === 'positive' ? interval.lower > 0 : interval.upper < 0)\n }\n case 'interval-includes-zero': {\n const interval = evidence.intervals[condition.interval]\n if (!interval) {\n throw new ValidationError(\n `evaluateCondition: interval '${condition.interval}' is not in the evidence`,\n )\n }\n return interval.lower <= 0 && interval.upper >= 0\n }\n case 'quantity-threshold': {\n const value = evidence.quantities[condition.quantity]\n if (value === undefined) {\n throw new ValidationError(\n `evaluateCondition: quantity '${condition.quantity}' is not in the evidence`,\n )\n }\n return compareValues(value, condition.op, condition.value)\n }\n case 'obligation-met':\n return evidence.obligationsMet[condition.obligation] === true\n case 'all':\n return condition.of.every((c) => evaluateCondition(c, evidence))\n case 'any':\n return condition.of.some((c) => evaluateCondition(c, evidence))\n case 'not':\n return !evaluateCondition(condition.of, evidence)\n }\n}\n\nexport interface DecisionBranch {\n when: Condition\n verdict: string\n report: string[]\n}\n\n/**\n * Ordered decision table: the first branch whose condition holds fires, and a\n * table no branch matches throws — a non-total registration is a defect, not\n * an implicit verdict. `report-only` registers the ABSENCE of a verdict\n * branch: the estimate and the per-row table are the finding, and the\n * registered meaning prose rides as non-executable interpretation data.\n */\nexport type DecisionRule =\n | { kind: 'table'; branches: DecisionBranch[] }\n | {\n kind: 'report-only'\n estimands: string[]\n intervals: string[]\n perRow: string[]\n interpretation?: { onQualitative: string; consequence: string }[]\n }\n\nexport interface DecisionOutcome {\n verdict: string\n report: string[]\n}\n\nexport function executeDecisionRule(\n rule: DecisionRule,\n evidence: DerivedQuantities,\n): DecisionOutcome {\n if (rule.kind === 'report-only') {\n return { verdict: 'report-only', report: [...rule.estimands, ...rule.intervals] }\n }\n for (const branch of rule.branches) {\n if (evaluateCondition(branch.when, evidence)) {\n return { verdict: branch.verdict, report: branch.report }\n }\n }\n throw new DecisionTableNotTotalError(\n 'executeDecisionRule: decision table is not total — no branch matched the evidence',\n )\n}\n\n/** A registered control that must exist before a class of verdicts is read. */\nexport interface Obligation {\n id: string\n appliesToVerdicts: string[]\n control: string\n}\n\n// ── Validity gates and halt ──────────────────────────────────────────\n\n/** Pre-spend design checks. Each returns pass/fail plus its evidence. */\nexport type ValidityGate =\n | {\n kind: 'oracle-determinism'\n unit: 'suite' | 'assertion'\n replicates: number\n maxFlipRate: number\n }\n | {\n kind: 'population-reproducibility'\n joinOn: string\n compare: string[]\n maxChangedRows: number\n }\n | { kind: 'provenance-assertion'; claim: Predicate }\n | {\n kind: 'power-floor'\n target: number\n effectGrid: number[]\n sim: { trials: number; resamples: number; seed: number }\n }\n | { kind: 'identity'; field: 'served-model'; op: 'basename-eq'; onFail: 'abort' }\n\nexport interface GateResult {\n id: string\n passed: boolean\n evidence: JsonValue\n}\n\n/**\n * Replicate-flip counting over graded states. A state whose replicates split\n * between pass and fail is flipping; its flip rate is the minority share.\n */\nexport function evaluateOracleDeterminismGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'oracle-determinism' }>,\n repsByState: Record<string, readonly boolean[]>,\n): GateResult {\n const evidence: Record<string, JsonValue> = {}\n let passed = true\n for (const [state, reps] of Object.entries(repsByState)) {\n const passes = reps.filter(Boolean).length\n const flipRate = reps.length === 0 ? 0 : Math.min(passes, reps.length - passes) / reps.length\n evidence[state] = { passes, replicates: reps.length, flipRate }\n if (flipRate > gate.maxFlipRate) passed = false\n }\n return { id, passed, evidence }\n}\n\n/**\n * Join two population snapshots on `joinOn` and compare the registered fields.\n * Only rows present in both snapshots are compared; a presence change is a\n * different failure and needs its own gate.\n */\nexport function evaluatePopulationReproducibilityGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'population-reproducibility' }>,\n populations: { left: readonly EvidenceRecord[]; right: readonly EvidenceRecord[] },\n): GateResult {\n const rightByKey = new Map(populations.right.map((r) => [String(readField(r, gate.joinOn)), r]))\n const changed: string[] = []\n for (const left of populations.left) {\n const key = String(readField(left, gate.joinOn))\n const right = rightByKey.get(key)\n if (!right) continue\n const moved = gate.compare.filter((f) => readField(left, f) !== readField(right, f))\n if (moved.length > 0) {\n changed.push(\n `${key} ${moved.map((f) => `${f}:${String(readField(left, f))}->${String(readField(right, f))}`).join(' ')}`,\n )\n }\n }\n return { id, passed: changed.length <= gate.maxChangedRows, evidence: changed }\n}\n\n/** The registered claim about provenance must hold on the provenance record. */\nexport function evaluateProvenanceGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'provenance-assertion' }>,\n provenance: EvidenceRecord,\n): GateResult {\n const passed = evaluatePredicate(gate.claim, provenance)\n return { id, passed, evidence: { claimHolds: passed } }\n}\n\n/** Final path segment equality between the pinned and the served identity. */\nexport function evaluateIdentityGate(\n id: string,\n _gate: Extract<ValidityGate, { kind: 'identity' }>,\n identities: { pinned: string; served: string },\n): GateResult {\n const basename = (s: string): string => s.split('/').pop() ?? s\n const passed = basename(identities.pinned) === basename(identities.served)\n return {\n id,\n passed,\n evidence: { pinned: identities.pinned, served: identities.served, matched: passed },\n }\n}\n\n/**\n * The design's power curve must reach the registered target at some grid\n * effect. The curve must cover the registered effect grid exactly — a curve\n * computed on a different grid is different evidence and is refused.\n */\nexport function evaluatePowerFloorGate(\n id: string,\n gate: Extract<ValidityGate, { kind: 'power-floor' }>,\n curve: readonly { effect: number; power: number }[],\n): GateResult {\n const byEffect = new Map(curve.map((point) => [point.effect, point.power]))\n const missing = gate.effectGrid.filter((effect) => !byEffect.has(effect))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluatePowerFloorGate: curve does not cover registered effects [${missing.join(', ')}]`,\n )\n }\n const powers = gate.effectGrid.map((effect) => byEffect.get(effect)!)\n const maxPower = Math.max(...powers)\n return {\n id,\n passed: maxPower >= gate.target,\n evidence: {\n target: gate.target,\n maxPower,\n curve: gate.effectGrid.map((effect) => ({ effect, power: byEffect.get(effect)! })),\n },\n }\n}\n\n/** Checks as prerequisites: any named gate failing refuses the spend. */\nexport interface HaltRule {\n when: { kind: 'any-gate-failed'; gates: string[] }\n action: 'refuse-spend'\n report: 'settling-n'\n}\n\nexport interface HaltOutcome {\n fired: boolean\n action: 'refuse-spend' | null\n failedGates: string[]\n}\n\nexport function evaluateHaltRule(halt: HaltRule, gates: readonly GateResult[]): HaltOutcome {\n const seen = new Map(gates.map((g) => [g.id, g]))\n const missing = halt.when.gates.filter((id) => !seen.has(id))\n if (missing.length > 0) {\n throw new ValidationError(\n `evaluateHaltRule: halt references gates that were not evaluated: [${missing.join(', ')}]`,\n )\n }\n const failed = halt.when.gates.filter((id) => !seen.get(id)!.passed)\n return failed.length > 0\n ? { fired: true, action: halt.action, failedGates: failed }\n : { fired: false, action: null, failedGates: [] }\n}\n\n// ── Budget rules ─────────────────────────────────────────────────────\n\n/**\n * Spend schedules as data. `ledger` names every entry the ceiling counts, so\n * what the gate reads is registered, not improvised at gate time.\n */\nexport type BudgetRule =\n | {\n kind: 'uniform-pass'\n ceilingUsd: number\n maxPasses: number\n projection: 'last-pass-cost'\n costSource: 'priced-per-call'\n ledger: { id: string; usd: number }[]\n partialPass: 'report-never-lift'\n }\n | {\n kind: 'n-ladder'\n steps: number[]\n ceilingUsd: number\n projection: 'unit-cost-times-rows-times-n'\n onExhaust: 'refuse-report-projection'\n }\n\nexport interface UniformPassDecision {\n pass: number\n cumulativeBefore: number\n projected: number\n go: boolean\n}\n\nexport interface UniformPassSchedule {\n decisions: UniformPassDecision[]\n uniformN: number\n}\n\n/**\n * Execute the uniform-pass schedule against measured pass costs. Pass 1 always\n * runs; each later pass runs only when the cumulative spend plus the last\n * measured pass cost stays at or under the registered ceiling. The registered\n * ledger is the pre-spend the ceiling counts.\n */\nexport function runUniformPassBudget(\n rule: Extract<BudgetRule, { kind: 'uniform-pass' }>,\n measuredPassCosts: readonly number[],\n): UniformPassSchedule {\n const preSpend = rule.ledger.reduce((sum, entry) => sum + entry.usd, 0)\n let cumulative = preSpend\n const decisions: UniformPassDecision[] = []\n let uniformN = 0\n for (let pass = 1; pass <= rule.maxPasses; pass++) {\n if (pass === 1) {\n if (measuredPassCosts[0] === undefined) break\n cumulative += measuredPassCosts[0]\n uniformN = 1\n continue\n }\n const projected = measuredPassCosts[pass - 2]\n if (projected === undefined) break\n const go = cumulative + projected <= rule.ceilingUsd\n decisions.push({ pass, cumulativeBefore: cumulative, projected, go })\n if (!go || measuredPassCosts[pass - 1] === undefined) break\n cumulative += measuredPassCosts[pass - 1]!\n uniformN = pass\n }\n return { decisions, uniformN }\n}\n\nexport interface NLadderProjection {\n chosenN: number | null\n projections: { n: number; projectedUsd: number; affordable: boolean }[]\n refusal: null | { onExhaust: 'refuse-report-projection'; reason: string }\n}\n\n/**\n * Walk the registered n-ladder and pick the first affordable step. When no\n * step fits the ceiling, the rule refuses and reports the projection instead\n * of shrinking the row set — \"never subset rows\" is the registered invariant.\n */\nexport function projectNLadderBudget(\n rule: Extract<BudgetRule, { kind: 'n-ladder' }>,\n measured: { unitCostUsd: number; rows: number },\n): NLadderProjection {\n const projections = rule.steps.map((n) => {\n const projectedUsd = measured.unitCostUsd * measured.rows * n\n return { n, projectedUsd, affordable: projectedUsd <= rule.ceilingUsd }\n })\n const first = projections.find((p) => p.affordable)\n if (first) return { chosenN: first.n, projections, refusal: null }\n return {\n chosenN: null,\n projections,\n refusal: {\n onExhaust: rule.onExhaust,\n reason: `no ladder step fits the ${rule.ceilingUsd} USD ceiling at ${measured.rows} rows x ${measured.unitCostUsd} USD per unit`,\n },\n }\n}\n\n// ── Matched budget and reissue ───────────────────────────────────────\n\n/** Arm budget matching as a refusal, not prose. Verified by `verifyMatchedBudgets`. */\nexport interface MatchedBudgetRule {\n measure: 'realized-tokens'\n tolerance: number\n onFail: 'refuse-contrast'\n}\n\n/** Carrier faults are reissued; model outcomes stand. Closed enumeration. */\nexport interface ReissuePolicy {\n carrierEvents: ('http-status' | 'transport-error' | 'deadline' | 'empty-content')[]\n modelOutcomesStand: true\n maxIssues: number\n}\n\nexport type ReissueVerdict = 'reissue' | 'stands' | 'exhausted'\n\n/**\n * Classify one rollout event under the registered reissue policy. A carrier\n * event within the issue budget is reissued; a model outcome always stands;\n * a carrier event past `maxIssues` is exhausted and reported, never retried.\n */\nexport function classifyReissue(\n policy: ReissuePolicy,\n event: string,\n issuesSoFar: number,\n): ReissueVerdict {\n if (!(policy.carrierEvents as string[]).includes(event)) return 'stands'\n return issuesSoFar < policy.maxIssues ? 'reissue' : 'exhausted'\n}\n","/**\n * Matched-budget verification between arms, as a refusal object.\n *\n * A paired contrast is only meaningful when both arms spent comparable\n * resources; \"realized prompt and completion tokens must agree within 5%\" is\n * a registered rule, so its verification returns a verdict artifact — the\n * refusal lives inside the result, never in prose beside it.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport type { MatchedBudgetRule } from './ast'\n\n/** Arms whose realized budgets diverge past the registered tolerance. */\nexport class MatchedBudgetError extends CaptureIntegrityError {}\n\nexport interface ArmRealizedBudget {\n armId: string\n /** Realized prompt + completion tokens the arm actually consumed. */\n realizedTokens: number\n}\n\nexport interface MatchedBudgetVerdict {\n rule: MatchedBudgetRule\n arms: ArmRealizedBudget[]\n /** (max - min) / max over all arms; 0 when every arm spent nothing. */\n maxRelativeGap: number\n /** The two arms with the widest gap; null when fewer than two arms. */\n widestPair: [string, string] | null\n matched: boolean\n /** Populated exactly when `matched` is false. */\n refusal: null | { onFail: 'refuse-contrast'; reason: string }\n}\n\n/**\n * Compare realized per-arm spend under the registered tolerance. Requires at\n * least two arms — a single arm has nothing to match against. Negative or\n * non-finite token counts are refused as evidence corruption, not compared.\n */\nexport function verifyMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n if (arms.length < 2) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: need >= 2 arms to match budgets, got ${arms.length}`,\n )\n }\n for (const arm of arms) {\n if (!Number.isFinite(arm.realizedTokens) || arm.realizedTokens < 0) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: arm '${arm.armId}' has invalid realized tokens ${arm.realizedTokens}`,\n )\n }\n }\n const sorted = [...arms].sort((a, b) => a.realizedTokens - b.realizedTokens)\n const min = sorted[0]!\n const max = sorted[sorted.length - 1]!\n const maxRelativeGap =\n max.realizedTokens === 0 ? 0 : (max.realizedTokens - min.realizedTokens) / max.realizedTokens\n const matched = maxRelativeGap <= rule.tolerance\n return {\n rule,\n arms: [...arms],\n maxRelativeGap,\n widestPair: [min.armId, max.armId],\n matched,\n refusal: matched\n ? null\n : {\n onFail: rule.onFail,\n reason:\n `realized ${rule.measure} diverge ${(maxRelativeGap * 100).toFixed(1)}% between ` +\n `'${min.armId}' (${min.realizedTokens}) and '${max.armId}' (${max.realizedTokens}) — ` +\n `registered tolerance is ${(rule.tolerance * 100).toFixed(1)}%; the contrast is refused`,\n },\n }\n}\n\n/** Throw the refusal for callers that gate the contrast on it. */\nexport function assertMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n const verdict = verifyMatchedBudgets(rule, arms)\n if (verdict.refusal) throw new MatchedBudgetError(verdict.refusal.reason)\n return verdict\n}\n","/**\n * The denominator chain as a first-class object.\n *\n * A benchmark whose denominator is not auditable is not a benchmark. Every\n * stage names what entered, what it removed, and what survived, so\n * `input = surviving + sum(excluded)` reads off the table instead of being\n * trusted. A stage that gains rows is refused at construction — a funnel is\n * monotone by definition, and a non-monotone one is a broken denominator,\n * not a formatting choice.\n *\n * The object is its own JSON render; `renderFunnelTable` is the text render.\n * `executeAdmissionRule` produces one by running a sealed {@link AdmissionRule}\n * over evidence records.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport { type AdmissionRule, type EvidenceRecord, evaluatePredicate } from './ast'\n\n/** A funnel stage gained rows, double-counted them, or failed to reconcile. */\nexport class FunnelIntegrityError extends CaptureIntegrityError {}\n\nexport interface FunnelStageCount {\n id: string\n entering: number\n excluded: number\n remaining: number\n /** Named exclusion reasons summing to `excluded`, when the stage has them. */\n exclusions?: Record<string, number>\n /** Substrate checks this stage deliberately does not apply. Registered, never implicit. */\n waives?: string[]\n}\n\nexport interface FunnelPartitionCount {\n id: string\n /** Stage whose excluded rows the partition draws from. */\n from: string\n count: number\n /** A partition is reported separately and never pooled into the survivors. */\n pooling: 'never'\n}\n\nexport interface ExperimentFunnel {\n population: string\n input: number\n stages: FunnelStageCount[]\n surviving: number\n partitions: FunnelPartitionCount[]\n}\n\nexport interface FunnelStageInput {\n id: string\n /** Rows this stage removed. */\n excluded: number\n exclusions?: Record<string, number>\n waives?: string[]\n}\n\n/**\n * Build a funnel from counts and refuse anything non-monotone.\n *\n * Refusals: a negative count, a stage that gains rows (excluded < 0 is the\n * only way to gain — `remaining = entering - excluded` by construction, so a\n * gain cannot be smuggled in through `remaining`), named exclusions that do\n * not sum to the stage total, and a partition drawing from an unknown stage\n * or exceeding what that stage excluded.\n */\nexport function buildFunnel(input: {\n population: string\n input: number\n stages: FunnelStageInput[]\n partitions?: { id: string; from: string; count: number }[]\n}): ExperimentFunnel {\n if (!Number.isInteger(input.input) || input.input < 0) {\n throw new FunnelIntegrityError(\n `funnel input must be a non-negative integer, got ${input.input}`,\n )\n }\n let entering = input.input\n const stages: FunnelStageCount[] = []\n for (const stage of input.stages) {\n if (!Number.isInteger(stage.excluded)) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excluded count must be an integer, got ${stage.excluded}`,\n )\n }\n if (stage.excluded < 0) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' gains ${-stage.excluded} rows — a funnel stage can only remove rows`,\n )\n }\n if (stage.excluded > entering) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excludes ${stage.excluded} rows but only ${entering} entered`,\n )\n }\n if (stage.exclusions) {\n const sum = Object.values(stage.exclusions).reduce((a, b) => a + b, 0)\n if (sum !== stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' names exclusions summing to ${sum} but excludes ${stage.excluded}`,\n )\n }\n }\n const remaining = entering - stage.excluded\n stages.push({\n id: stage.id,\n entering,\n excluded: stage.excluded,\n remaining,\n ...(stage.exclusions ? { exclusions: { ...stage.exclusions } } : {}),\n ...(stage.waives ? { waives: [...stage.waives] } : {}),\n })\n entering = remaining\n }\n const byStage = new Map(stages.map((s) => [s.id, s]))\n const partitions: FunnelPartitionCount[] = (input.partitions ?? []).map((partition) => {\n const source = byStage.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n if (partition.count < 0 || partition.count > source.excluded) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' counts ${partition.count} rows but stage '${partition.from}' excluded ${source.excluded}`,\n )\n }\n return { id: partition.id, from: partition.from, count: partition.count, pooling: 'never' }\n })\n const funnel: ExperimentFunnel = {\n population: input.population,\n input: input.input,\n stages,\n surviving: entering,\n partitions,\n }\n assertFunnelReconciles(funnel)\n return funnel\n}\n\n/** A chain that does not add up is a broken denominator, so this throws. */\nexport function assertFunnelReconciles(funnel: ExperimentFunnel): void {\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n if (funnel.input !== funnel.surviving + excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' does not reconcile: input ${funnel.input} != surviving ${funnel.surviving} + excluded ${excluded}`,\n )\n }\n let entering = funnel.input\n for (const stage of funnel.stages) {\n if (stage.entering !== entering || stage.remaining !== stage.entering - stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' does not chain: ` +\n `entering ${stage.entering} (expected ${entering}), remaining ${stage.remaining}`,\n )\n }\n if (stage.remaining > stage.entering) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' gains rows: ${stage.entering} -> ${stage.remaining}`,\n )\n }\n entering = stage.remaining\n }\n}\n\nexport interface AdmissionExecution {\n funnel: ExperimentFunnel\n survivors: EvidenceRecord[]\n /** Partition rows by partition id, reported separately and never pooled. */\n partitionRows: Record<string, EvidenceRecord[]>\n}\n\n/**\n * Run a sealed admission rule over evidence records. Each stage keeps the rows\n * its predicate accepts; partitions draw from the rows their source stage\n * dropped. The result embeds the funnel, so the denominator chain and the\n * surviving rows can never disagree.\n */\nexport function executeAdmissionRule(\n rule: AdmissionRule,\n records: readonly EvidenceRecord[],\n): AdmissionExecution {\n let current = [...records]\n const droppedAt = new Map<string, EvidenceRecord[]>()\n const stageInputs: FunnelStageInput[] = []\n for (const stage of rule.stages) {\n const kept: EvidenceRecord[] = []\n const dropped: EvidenceRecord[] = []\n for (const record of current) {\n if (evaluatePredicate(stage.keep, record)) kept.push(record)\n else dropped.push(record)\n }\n droppedAt.set(stage.id, dropped)\n stageInputs.push({\n id: stage.id,\n excluded: dropped.length,\n ...(stage.waives ? { waives: stage.waives } : {}),\n })\n current = kept\n }\n const partitionRows: Record<string, EvidenceRecord[]> = {}\n const partitionCounts: { id: string; from: string; count: number }[] = []\n for (const partition of rule.partitions ?? []) {\n const source = droppedAt.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n const rows = source.filter((record) => evaluatePredicate(partition.keep, record))\n partitionRows[partition.id] = rows\n partitionCounts.push({ id: partition.id, from: partition.from, count: rows.length })\n }\n const funnel = buildFunnel({\n population: rule.population,\n input: records.length,\n stages: stageInputs,\n partitions: partitionCounts,\n })\n return { funnel, survivors: current, partitionRows }\n}\n\n/**\n * Chain two funnels whose boundary agrees: the second funnel's input must be\n * exactly the first funnel's survivors. Anything else is a gap or an\n * injection, and both are refused.\n */\nexport function composeFunnels(\n first: ExperimentFunnel,\n second: ExperimentFunnel,\n): ExperimentFunnel {\n if (second.input !== first.surviving) {\n throw new FunnelIntegrityError(\n `cannot compose funnels: '${first.population}' survives ${first.surviving} rows but '${second.population}' starts from ${second.input}`,\n )\n }\n return buildFunnel({\n population: first.population,\n input: first.input,\n stages: [...first.stages, ...second.stages].map((stage) => ({\n id: stage.id,\n excluded: stage.excluded,\n ...(stage.exclusions ? { exclusions: stage.exclusions } : {}),\n ...(stage.waives ? { waives: stage.waives } : {}),\n })),\n partitions: [...first.partitions, ...second.partitions].map((partition) => ({\n id: partition.id,\n from: partition.from,\n count: partition.count,\n })),\n })\n}\n\n/**\n * Text render of the chain. One row per stage; the reconciliation line at the\n * bottom restates `input = surviving + excluded` so a reader can check the\n * arithmetic without a tool.\n */\nexport function renderFunnelTable(funnel: ExperimentFunnel): string {\n const rows = funnel.stages.map((stage) => [\n stage.id + (stage.waives?.length ? ` (waives: ${stage.waives.join(', ')})` : ''),\n String(stage.entering),\n String(stage.excluded),\n String(stage.remaining),\n ])\n const header = ['stage', 'entering', 'excluded', 'remaining']\n const widths = header.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col]!.length)))\n const line = (cells: string[]): string =>\n cells.map((cell, col) => cell.padEnd(widths[col]!)).join(' ')\n const out: string[] = [\n `population: ${funnel.population}`,\n `input: ${funnel.input}`,\n line(header),\n line(widths.map((w) => '-'.repeat(w))),\n ...rows.map((r) => line(r)),\n ]\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n out.push(\n `surviving: ${funnel.surviving} (input ${funnel.input} = surviving ${funnel.surviving} + excluded ${excluded})`,\n )\n for (const partition of funnel.partitions) {\n out.push(\n `partition ${partition.id}: ${partition.count} rows from '${partition.from}' — reported separately, never pooled`,\n )\n }\n return out.join('\\n')\n}\n","/**\n * Define, seal, and execute experiments whose every rule is registered data.\n *\n * `defineExperiment` validates the cross-references inside a spec and freezes\n * it. `sealExperiment` canonicalizes and hashes the whole tree — arms, row\n * admission, selection, estimands, intervals, decision rule, gates, halt,\n * budget — into one digest that lands on every downstream artifact. Changing\n * what is decided requires a new digest: an amendment is a re-seal with a\n * reason and blindness attestations, and the digest history is the audit\n * trail.\n *\n * `openSealedExperiment` is the only execution surface. It verifies the seal\n * and returns executors bound to the sealed spec; none of them takes a\n * parameter for alpha, threshold, metric, or stopping rule, so\n * registered-vs-ran drift is unrepresentable rather than checked.\n */\n\nimport { createHash } from 'node:crypto'\nimport { ValidationError } from '../errors'\nimport { canonicalString } from '../ledger-core/canonical'\nimport {\n type AdmissionRule,\n type BudgetRule,\n type ComputedInterval,\n type Condition,\n computeEstimand,\n computeInterval,\n type DecisionOutcome,\n type DecisionRule,\n type DerivedQuantities,\n type Estimand,\n type EstimandResult,\n type EvidenceRecord,\n evaluateHaltRule,\n evaluateIdentityGate,\n evaluateOracleDeterminismGate,\n evaluatePopulationReproducibilityGate,\n evaluatePowerFloorGate,\n evaluateProvenanceGate,\n executeDecisionRule,\n type GateResult,\n type HaltOutcome,\n type HaltRule,\n type IntervalSpec,\n type JsonValue,\n type MatchedBudgetRule,\n type NLadderProjection,\n type Obligation,\n projectNLadderBudget,\n type ReissuePolicy,\n runSelectionRule,\n runUniformPassBudget,\n type SelectionRule,\n type UniformPassSchedule,\n type ValidityGate,\n} from './ast'\nimport { type ArmRealizedBudget, type MatchedBudgetVerdict, verifyMatchedBudgets } from './budget'\nimport { type AdmissionExecution, executeAdmissionRule } from './funnel'\n\n/** A sealed experiment whose digest no longer matches its spec. */\nexport class SealIntegrityError extends ValidationError {}\n\n// ── Spec ─────────────────────────────────────────────────────────────\n\nexport interface ArmSpec {\n id: string\n role: 'treatment' | 'control'\n /** Digest of the AgentProfile the arm runs under. */\n profileDigest?: string\n /** Digest of the pinned execution policy the arm runs under. */\n policyDigest?: string\n /** Registered arm pins (model, seed, step budget, ...) as data. */\n pins?: Record<string, JsonValue>\n}\n\nexport type OutcomeSpec =\n | {\n kind: 'binary'\n /** Where the pass verdict comes from, e.g. 'injected-suite'. */\n source?: string\n digestVerified?: boolean\n /** What counts as a pass, e.g. 'exit-0' or 'reward-file-contains-1'. */\n pass?: string\n /** Errored rollouts stay in the denominator; dropping them is unregistered. */\n droppedRollouts?: 'forbidden'\n }\n | {\n kind: 'bounded-score'\n min: number\n max: number\n orientation: 'higher-is-better' | 'lower-is-better'\n }\n\n/**\n * Per-rollout seed derivation as a closed source list. `arm` is not in the\n * union, so arm-dependent seeding is unrepresentable.\n */\nexport interface SeedDerivation {\n from: ('seed' | 'rowId' | 'rolloutIndex')[]\n}\n\nexport interface ExperimentSpec {\n id: string\n /** Human prose for the audit trail — never executable. */\n hypothesis?: string\n arms: ArmSpec[]\n outcome: OutcomeSpec\n admission?: AdmissionRule\n /** Named deterministic subset rules. */\n selections?: Record<string, SelectionRule>\n /**\n * Selection OUTPUTS pinned into the seal. A filter-of base resolves here, so\n * reusing an earlier draw is registered and a re-draw is a new digest.\n */\n sealedSubsets?: Record<string, string[]>\n estimands?: Record<string, Estimand>\n intervals?: Record<string, IntervalSpec>\n decision: DecisionRule\n obligations?: Obligation[]\n /** Named pre-spend validity gates; the halt rule references these names. */\n gates?: Record<string, ValidityGate>\n halt?: HaltRule\n budget?: BudgetRule\n matchedBudget?: MatchedBudgetRule\n reissue?: ReissuePolicy\n seedDerivation?: SeedDerivation\n seed?: number\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nfunction conditionRefs(condition: Condition): {\n intervals: string[]\n quantities: string[]\n obligations: string[]\n} {\n switch (condition.kind) {\n case 'interval-excludes-zero':\n case 'interval-includes-zero':\n return { intervals: [condition.interval], quantities: [], obligations: [] }\n case 'quantity-threshold':\n return { intervals: [], quantities: [condition.quantity], obligations: [] }\n case 'obligation-met':\n return { intervals: [], quantities: [], obligations: [condition.obligation] }\n case 'all':\n case 'any': {\n const nested = condition.of.map(conditionRefs)\n return {\n intervals: nested.flatMap((r) => r.intervals),\n quantities: nested.flatMap((r) => r.quantities),\n obligations: nested.flatMap((r) => r.obligations),\n }\n }\n case 'not':\n return conditionRefs(condition.of)\n }\n}\n\n/**\n * Validate every cross-reference inside a spec and freeze it.\n *\n * A decision condition may only read a registered interval, a registered\n * estimand, or a registered obligation; a halt rule may only reference\n * registered gates; a filter-of base must resolve to a registered selection\n * or sealed subset. Anything else is refused here, before sealing.\n */\nexport function defineExperiment(spec: ExperimentSpec): ExperimentSpec {\n const problems: string[] = []\n if (!spec.id || spec.id.trim().length === 0) problems.push('id is empty')\n if (spec.arms.length === 0) problems.push('at least one arm is required')\n const armIds = new Set<string>()\n for (const arm of spec.arms) {\n if (armIds.has(arm.id)) problems.push(`duplicate arm id '${arm.id}'`)\n armIds.add(arm.id)\n }\n if (!spec.arms.some((arm) => arm.role === 'treatment')) {\n problems.push('at least one arm must have role treatment')\n }\n\n const intervalNames = new Set(Object.keys(spec.intervals ?? {}))\n const estimandNames = new Set(Object.keys(spec.estimands ?? {}))\n const obligationIds = new Set((spec.obligations ?? []).map((o) => o.id))\n const gateNames = new Set(Object.keys(spec.gates ?? {}))\n const selectionNames = new Set(Object.keys(spec.selections ?? {}))\n const sealedSubsetNames = new Set(Object.keys(spec.sealedSubsets ?? {}))\n\n const checkCondition = (condition: Condition, where: string): void => {\n const refs = conditionRefs(condition)\n for (const name of refs.intervals) {\n if (!intervalNames.has(name)) problems.push(`${where} reads unregistered interval '${name}'`)\n }\n for (const name of refs.quantities) {\n if (!estimandNames.has(name)) problems.push(`${where} reads unregistered quantity '${name}'`)\n }\n for (const name of refs.obligations) {\n if (!obligationIds.has(name))\n problems.push(`${where} reads unregistered obligation '${name}'`)\n }\n }\n\n if (spec.decision.kind === 'table') {\n if (spec.decision.branches.length === 0) problems.push('decision table has no branches')\n spec.decision.branches.forEach((branch, index) => {\n checkCondition(branch.when, `decision branch ${index} ('${branch.verdict}')`)\n })\n } else {\n for (const name of spec.decision.estimands) {\n if (!estimandNames.has(name)) {\n problems.push(`report-only decision names unregistered estimand '${name}'`)\n }\n }\n for (const name of spec.decision.intervals) {\n if (!intervalNames.has(name)) {\n problems.push(`report-only decision names unregistered interval '${name}'`)\n }\n }\n }\n\n if (spec.decision.kind === 'table' && spec.obligations) {\n const verdicts = new Set(spec.decision.branches.map((b) => b.verdict))\n for (const obligation of spec.obligations) {\n for (const verdict of obligation.appliesToVerdicts) {\n if (!verdicts.has(verdict)) {\n problems.push(\n `obligation '${obligation.id}' applies to verdict '${verdict}' which no branch produces`,\n )\n }\n }\n }\n }\n\n if (spec.halt) {\n for (const gate of spec.halt.when.gates) {\n if (!gateNames.has(gate)) problems.push(`halt rule references unregistered gate '${gate}'`)\n }\n }\n\n for (const [name, selection] of Object.entries(spec.selections ?? {})) {\n if (selection.kind === 'filter-of') {\n if (!selectionNames.has(selection.base) && !sealedSubsetNames.has(selection.base)) {\n problems.push(\n `selection '${name}' filters unregistered base '${selection.base}' (not a selection or sealed subset)`,\n )\n }\n }\n }\n\n if (spec.admission) {\n const stageIds = new Set<string>()\n for (const stage of spec.admission.stages) {\n if (stageIds.has(stage.id)) problems.push(`duplicate admission stage id '${stage.id}'`)\n stageIds.add(stage.id)\n }\n for (const partition of spec.admission.partitions ?? []) {\n if (!stageIds.has(partition.from)) {\n problems.push(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n }\n }\n\n if (problems.length > 0) {\n throw new ValidationError(`defineExperiment('${spec.id}'): ${problems.join('; ')}`)\n }\n return deepFreeze(structuredClone(spec))\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const key of Object.keys(value as object)) {\n deepFreeze((value as Record<string, unknown>)[key])\n }\n Object.freeze(value)\n }\n return value\n}\n\n// ── Seal ─────────────────────────────────────────────────────────────\n\nexport interface SealAmendment {\n /** ISO8601 timestamp of the re-seal. */\n at: string\n reason: string\n /** Blindness attestations: what was verifiably unseen when the amendment was made. */\n blind: string[]\n /** Digest of the spec after this amendment. */\n digest: string\n}\n\n/**\n * Digest scheme of a sealed experiment. Both are sha256 hex over the\n * serialized spec and differ only in the serialization: `'sha256-rfc8785'` is\n * RFC 8785 canonical JSON, `'sha256-content'` is key-sorted `JSON.stringify`.\n */\nexport type SealAlgo = 'sha256-content' | 'sha256-rfc8785'\n\nexport interface SealedExperiment {\n spec: ExperimentSpec\n /** sha256 over the serialized spec, under the scheme `algo` names. */\n digest: string\n /**\n * Digest scheme of `digest`. `'sha256-rfc8785'` is what {@link sealExperiment}\n * emits; `'sha256-content'` is read-only, carried by seals from an earlier\n * release, and still verifies.\n */\n algo: SealAlgo\n sealedAt: string\n /** Digest of the original registration, before any amendment. */\n initialDigest: string\n amendments: SealAmendment[]\n}\n\n/** Validate, canonicalize, and hash a spec into its registration. */\nexport async function sealExperiment(\n spec: ExperimentSpec,\n options: { sealedAt?: string } = {},\n): Promise<SealedExperiment> {\n const validated = defineExperiment(spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: options.sealedAt ?? new Date().toISOString(),\n initialDigest: digest,\n amendments: [],\n }\n}\n\n/**\n * Amend a sealed experiment. The current seal is verified first, the new spec\n * is validated and re-hashed, and the amendment appends to the digest chain.\n * There is no way to change what is decided without producing a new digest.\n */\nexport async function amendExperiment(\n sealed: SealedExperiment,\n amendment: { spec: ExperimentSpec; reason: string; blind: string[]; at?: string },\n): Promise<SealedExperiment> {\n await assertSealIntact(sealed)\n const validated = defineExperiment(amendment.spec)\n const digest = specDigest(validated, 'sha256-rfc8785')\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: sealed.sealedAt,\n initialDigest: sealed.initialDigest,\n amendments: [\n ...sealed.amendments,\n {\n at: amendment.at ?? new Date().toISOString(),\n reason: amendment.reason,\n blind: [...amendment.blind],\n digest,\n },\n ],\n }\n}\n\n/** True when the sealed digest still matches the spec it carries, under the\n * scheme the seal declares. */\nexport async function verifySealedExperiment(sealed: SealedExperiment): Promise<boolean> {\n return specDigest(sealed.spec, sealed.algo) === sealed.digest\n}\n\n/**\n * Serialize a spec under `algo` and digest it. `'sha256-content'` is read-only\n * — it exists so a seal written by an earlier release still verifies, and no\n * path that WRITES a digest may pass it.\n */\nfunction specDigest(spec: ExperimentSpec, algo: SealAlgo): string {\n const serialized =\n algo === 'sha256-rfc8785' ? canonicalString(spec) : JSON.stringify(sortKeysDeep(spec))\n return createHash('sha256').update(serialized, 'utf8').digest('hex')\n}\n\nfunction sortKeysDeep(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map(sortKeysDeep)\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n out[key] = sortKeysDeep((value as Record<string, unknown>)[key])\n }\n return out\n}\n\nasync function assertSealIntact(sealed: SealedExperiment): Promise<void> {\n if (!(await verifySealedExperiment(sealed))) {\n throw new SealIntegrityError(\n `sealed experiment '${sealed.spec.id}' digest ${sealed.digest} does not match its spec — the registration was tampered with`,\n )\n }\n}\n\n// ── Sealed execution ─────────────────────────────────────────────────\n\n/** Evidence a gate executor consumes, discriminated to match the gate kind. */\nexport type GateEvidence =\n | { kind: 'oracle-determinism'; repsByState: Record<string, readonly boolean[]> }\n | {\n kind: 'population-reproducibility'\n left: readonly EvidenceRecord[]\n right: readonly EvidenceRecord[]\n }\n | { kind: 'provenance-assertion'; provenance: EvidenceRecord }\n | { kind: 'identity'; pinned: string; served: string }\n | { kind: 'power-floor'; curve: readonly { effect: number; power: number }[] }\n\n/**\n * Executors bound to one verified seal. Every method reads its rule from the\n * sealed spec; evidence is the only argument anywhere.\n */\nexport interface RegisteredExperiment {\n readonly sealed: SealedExperiment\n /** Execute the registered decision rule on derived quantities. */\n decide(evidence: DerivedQuantities): DecisionOutcome\n /** Run the registered admission funnel over evidence rows. */\n admit(records: readonly EvidenceRecord[]): AdmissionExecution\n /** Run a registered selection rule. Filter-of bases resolve to sealed subsets. */\n select(name: string, records: readonly EvidenceRecord[], options: { idField: string }): string[]\n /** Evaluate a registered validity gate on evidence of the matching kind. */\n gate(name: string, evidence: GateEvidence): GateResult\n /** Evaluate the registered halt rule over gate results. */\n halt(gates: readonly GateResult[]): HaltOutcome\n /** Execute the registered uniform-pass budget schedule. */\n runUniformPassBudget(measuredPassCosts: readonly number[]): UniformPassSchedule\n /** Project the registered n-ladder budget. */\n projectNLadderBudget(measured: { unitCostUsd: number; rows: number }): NLadderProjection\n /** Verify realized arm budgets under the registered matched-budget rule. */\n matchedBudgets(arms: readonly ArmRealizedBudget[]): MatchedBudgetVerdict\n /** Compute a registered estimand over evidence rows. */\n estimate(name: string, rows: readonly EvidenceRecord[]): EstimandResult\n /** Compute a registered interval spec. */\n interval(\n name: string,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[]; value: string }\n | { kind: 'binomial'; successes: number; trials: number },\n ): ComputedInterval\n}\n\n/**\n * Verify the seal and return executors bound to it. This is the module's only\n * execution surface: a rule that is not in the sealed spec cannot run, and a\n * rule that is cannot run differently.\n */\nexport async function openSealedExperiment(\n sealed: SealedExperiment,\n): Promise<RegisteredExperiment> {\n await assertSealIntact(sealed)\n const spec = sealed.spec\n const need = <T>(value: T | undefined, what: string): T => {\n if (value === undefined) {\n throw new ValidationError(`experiment '${spec.id}' registered no ${what}`)\n }\n return value\n }\n return {\n sealed,\n decide: (evidence) => executeDecisionRule(spec.decision, evidence),\n admit: (records) => executeAdmissionRule(need(spec.admission, 'admission rule'), records),\n select: (name, records, options) => {\n const rule = need(spec.selections?.[name], `selection '${name}'`)\n return runSelectionRule(rule, records, {\n idField: options.idField,\n bases: spec.sealedSubsets,\n })\n },\n gate: (name, evidence) => {\n const gate = need(spec.gates?.[name], `gate '${name}'`)\n if (gate.kind !== evidence.kind) {\n throw new ValidationError(\n `gate '${name}' is registered as ${gate.kind} but received ${evidence.kind} evidence`,\n )\n }\n switch (gate.kind) {\n case 'oracle-determinism':\n return evaluateOracleDeterminismGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'oracle-determinism' }>).repsByState,\n )\n case 'population-reproducibility': {\n const populations = evidence as Extract<\n GateEvidence,\n { kind: 'population-reproducibility' }\n >\n return evaluatePopulationReproducibilityGate(name, gate, populations)\n }\n case 'provenance-assertion':\n return evaluateProvenanceGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'provenance-assertion' }>).provenance,\n )\n case 'identity':\n return evaluateIdentityGate(\n name,\n gate,\n evidence as Extract<GateEvidence, { kind: 'identity' }>,\n )\n case 'power-floor':\n return evaluatePowerFloorGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'power-floor' }>).curve,\n )\n }\n },\n halt: (gates) => evaluateHaltRule(need(spec.halt, 'halt rule'), gates),\n runUniformPassBudget: (measuredPassCosts) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'uniform-pass') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not uniform-pass`,\n )\n }\n return runUniformPassBudget(budget, measuredPassCosts)\n },\n projectNLadderBudget: (measured) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'n-ladder') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not n-ladder`,\n )\n }\n return projectNLadderBudget(budget, measured)\n },\n matchedBudgets: (arms) =>\n verifyMatchedBudgets(need(spec.matchedBudget, 'matched-budget rule'), arms),\n estimate: (name, rows) =>\n computeEstimand(need(spec.estimands?.[name], `estimand '${name}'`), rows),\n interval: (name, evidence) =>\n computeInterval(need(spec.intervals?.[name], `interval '${name}'`), evidence),\n }\n}\n","/**\n * The evidence registry record — the canonical, machine-readable unit for a\n * measured claim about an agent, a prompt, a policy, or an instrument.\n *\n * One record answers, in typed fields, the questions a scattered results doc\n * leaves to prose: what was claimed, what instrument measured it, the exact\n * command that reproduces it, which arms ran, the denominator, what it cost,\n * what confounds the comparison, and how much trust the evidence has earned.\n *\n * Records live as JSON files in `evidence/records/` at the repo root — one\n * file per claim, filename `<id>.json`. The registry lives in agent-eval\n * because the measurement substrate owns evidence legitimacy; every other\n * repo keeps at most a pointer file. `scripts/render-evidence-index.ts`\n * generates the human index from these records, so prose can never drift\n * from data, and `pnpm run evidence:check` (part of `verify:package`) fails\n * on an invalid record or a stale index.\n *\n * The shape extends the `.evolve/experiments.jsonl` session-log vocabulary\n * (ts/hypothesis/change/result/evidence) into a curated registry record.\n * Session logs stay append-only diaries; a registry record is the durable,\n * addressable claim distilled from them.\n */\n\nimport { z } from 'zod'\n\n/**\n * Trust ladder for a recorded claim, strongest first.\n *\n * - `CERTIFIED` — pre-registered rule, sealed or held-out data, and either a\n * defended challenge or a check that re-runs in the suite.\n * - `MEASURED-ONCE` — one honest measurement on the real path, not replicated.\n * - `RESOLVED-NULL` — measured with an adequate instrument; the effect did not\n * appear under the registered rule. A null is a result, not a failure.\n * - `UNVERIFIED` — stated somewhere load-bearing, but no independent check has\n * run. Admitting this state is what keeps folklore out of the other four.\n * - `KILLED` — refuted, invalidated, or superseded by a stronger record.\n */\nexport const EVIDENCE_STATES = [\n 'CERTIFIED',\n 'MEASURED-ONCE',\n 'RESOLVED-NULL',\n 'UNVERIFIED',\n 'KILLED',\n] as const\n\nexport type EvidenceState = (typeof EVIDENCE_STATES)[number]\n\nconst idPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst datePattern = /^\\d{4}-\\d{2}-\\d{2}$/\nconst sha256Pattern = /^[0-9a-f]{64}$/\n\n/** Denominator of the measurement. A claim without an `n` is prose, not evidence. */\nconst evidenceDenominatorSchema = z.strictObject({\n value: z.number().positive().finite(),\n /** What one unit is: rows, cases, rollouts, records, leaves… */\n unit: z.string().min(1),\n /** Clustering, reps, split names — whatever the bare number hides. */\n detail: z.string().min(1).optional(),\n})\n\nexport type EvidenceDenominator = z.infer<typeof evidenceDenominatorSchema>\n\nexport const evidenceRegistryRecordSchema = z.strictObject({\n /** Stable kebab-case identity; the registry filename is `<id>.json`. */\n id: z.string().regex(idPattern),\n /** Date the decisive measurement completed, `YYYY-MM-DD`. */\n date: z.string().regex(datePattern),\n /** The one-sentence load-bearing claim, stated so it can fail. */\n claim: z.string().min(1),\n /** Domain the claim lives in: trace-repair, multishot, analyst, vertical-bench… */\n domain: z.string().min(1),\n /** The instrument that produced the number — script, harness, oracle, judge. */\n instrument: z.string().min(1),\n /**\n * The exact invocation that reproduces the measurement.\n * `null` means the invocation was not preserved — a named gap, never a guess.\n */\n command: z.string().min(1).nullable(),\n /** Compared arms. Empty for a single-arm measurement. */\n arms: z.array(z.string().min(1)),\n n: evidenceDenominatorSchema,\n /** The measured numbers, with uncertainty when it exists. Numbers, not adjectives. */\n result: z.string().min(1),\n evidenceState: z.enum(EVIDENCE_STATES),\n /** Where the raw data lives: repo paths, PR/gist URLs, run directories. Never empty. */\n artifacts: z.array(z.string().min(1)).min(1),\n /**\n * Measured spend in USD. `0` is a true zero (deterministic, no paid calls);\n * `null` means spend was not captured — a named gap, never a silent zero.\n */\n costUsd: z.number().nonnegative().nullable(),\n /** Every known asymmetry or threat to validity. Empty only when none is known. */\n confounds: z.array(z.string().min(1)),\n /** Repo whose work produced the evidence (the registry itself lives here). */\n sourceRepo: z.string().min(1),\n /** Seal digest of the registered experiment (`./experiment`), when one governed the run. */\n experimentDigest: z.string().regex(sha256Pattern).optional(),\n /** Ids of records this one supersedes. */\n supersedes: z.array(z.string().regex(idPattern)).optional(),\n notes: z.string().min(1).optional(),\n})\n\nexport type EvidenceRegistryRecord = z.infer<typeof evidenceRegistryRecordSchema>\n\n/** Parse one record; throws with the zod issue list on any violation. */\nexport function parseEvidenceRegistryRecord(raw: unknown): EvidenceRegistryRecord {\n return evidenceRegistryRecordSchema.parse(raw)\n}\n\nclass EvidenceRegistryError extends Error {}\n\n/**\n * Validate a set of records as one registry: every record parses, ids are\n * unique, and every `supersedes` target exists. Returns records sorted in\n * the registry's canonical order (trust ladder, then date desc, then id).\n */\nexport function validateEvidenceRegistry(raws: readonly unknown[]): EvidenceRegistryRecord[] {\n const records = raws.map((raw) => parseEvidenceRegistryRecord(raw))\n const seen = new Set<string>()\n for (const record of records) {\n if (seen.has(record.id)) {\n throw new EvidenceRegistryError(`duplicate evidence record id: ${record.id}`)\n }\n seen.add(record.id)\n }\n for (const record of records) {\n for (const target of record.supersedes ?? []) {\n if (!seen.has(target)) {\n throw new EvidenceRegistryError(`record ${record.id} supersedes unknown record: ${target}`)\n }\n }\n }\n const stateRank = new Map(EVIDENCE_STATES.map((state, index) => [state, index]))\n return [...records].sort((a, b) => {\n const byState = (stateRank.get(a.evidenceState) ?? 0) - (stateRank.get(b.evidenceState) ?? 0)\n if (byState !== 0) return byState\n if (a.date !== b.date) return a.date < b.date ? 1 : -1\n return a.id < b.id ? -1 : 1\n })\n}\n\nfunction mdEscape(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ')\n}\n\nfunction formatCost(costUsd: number | null): string {\n if (costUsd === null) return 'not captured'\n return `$${costUsd.toFixed(2)}`\n}\n\nfunction formatN(n: EvidenceDenominator): string {\n const base = `${n.value} ${n.unit}`\n return n.detail ? `${base} (${n.detail})` : base\n}\n\n/**\n * Render the registry's human index from records. Deterministic: identical\n * records always produce identical output, so a byte diff against the\n * committed index is the freshness check. No clocks, no environment.\n */\nexport function renderEvidenceIndex(raws: readonly unknown[]): string {\n const records = validateEvidenceRegistry(raws)\n const lines: string[] = [\n '# Evidence index',\n '',\n '<!-- GENERATED by scripts/render-evidence-index.ts from evidence/records/*.json.',\n ' Edit the records, run `pnpm run evidence:render`, and commit both.',\n ' `pnpm run evidence:check` (inside verify:package) fails when this file drifts. -->',\n '',\n `${records.length} records. States: ${EVIDENCE_STATES.join(' > ')}.`,\n '',\n '| state | date | id | claim | result |',\n '| --- | --- | --- | --- | --- |',\n ]\n for (const r of records) {\n lines.push(\n `| ${r.evidenceState} | ${r.date} | [\\`${r.id}\\`](#${r.id}) | ${mdEscape(r.claim)} | ${mdEscape(r.result)} |`,\n )\n }\n for (const r of records) {\n lines.push('', `## ${r.id}`, '')\n lines.push(`**${r.evidenceState}** · ${r.date} · ${r.domain} · source repo \\`${r.sourceRepo}\\``)\n lines.push('', `**Claim.** ${r.claim}`, '', `**Result.** ${r.result}`, '')\n lines.push(`- **Instrument**: ${r.instrument}`)\n lines.push(`- **Command**: ${r.command === null ? 'not preserved' : `\\`${r.command}\\``}`)\n lines.push(`- **Arms**: ${r.arms.length === 0 ? 'single-arm' : r.arms.join(' vs ')}`)\n lines.push(`- **n**: ${formatN(r.n)}`)\n lines.push(`- **Cost**: ${formatCost(r.costUsd)}`)\n if (r.experimentDigest) lines.push(`- **Experiment seal**: \\`${r.experimentDigest}\\``)\n lines.push(`- **Artifacts**:`)\n for (const artifact of r.artifacts) lines.push(` - ${artifact}`)\n if (r.confounds.length === 0) {\n lines.push('- **Confounds**: none recorded')\n } else {\n lines.push('- **Confounds**:')\n for (const confound of r.confounds) lines.push(` - ${confound}`)\n }\n if (r.supersedes && r.supersedes.length > 0) {\n lines.push(`- **Supersedes**: ${r.supersedes.map((s) => `\\`${s}\\``).join(', ')}`)\n }\n if (r.notes) lines.push(`- **Notes**: ${r.notes}`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n","/**\n * Design-time power for task-clustered paired designs, with a refusal verdict.\n *\n * The failure this prevents (measured): a pre-registered kill test fixed a\n * task-clustered bootstrap over 14 rows in 4 task clusters. Simulated at the\n * registered seed, the design's power topped out at 0.69 — at a per-row\n * effect of 1.0. \"Four clusters cannot certify any effect size, including\n * 1.0\" was learned by running the experiment; this module computes it before\n * a dollar is spent.\n *\n * Two floors, one simulation:\n * - Closed form, zero spend: with C independent clusters the exact\n * whole-cluster sign-flip test can never produce a two-sided p below\n * 2^(1-C). C=4 gives 0.125; C=3 gives 0.25 — both above a 0.05 alpha, so\n * those designs are refused at ANY effect size, before simulation.\n * - Seeded simulation: per-row paired contrasts drawn under a registered\n * effect model, a whole-cluster percentile bootstrap on each trial, power =\n * the fraction of trials whose interval excludes zero.\n *\n * The refusal is a verdict INSIDE the returned artifact (the powerPreflight\n * shape, made cluster-aware); `assertDesignAdequate` turns it into a throw for\n * callers that want configuration-time failure.\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** A design refused at configuration time, before any spend. */\nexport class DesignRefusalError extends ValidationError {}\n\nexport interface ClusteredPowerOptions {\n /** Rows per independent cluster, e.g. [6, 3, 3, 2]. */\n clusterSizes: number[]\n /** Per-row effect grid: each effect is P(win) - P(loss) added to the base rates. */\n effects: number[]\n /** Deterministic seed for outcome draws and bootstrap resampling. */\n seed: number\n /** Simulated experiments per effect. Default 2000. */\n trials?: number\n /** Whole-cluster bootstrap draws per trial. Default 4000. */\n resamples?: number\n /** Percentile interval level. Default 0.95. */\n confidence?: number\n /** Sign-flip alpha the closed-form floor is checked against. Default 0.05. */\n alpha?: number\n /** Power the design must reach at some grid effect. Default 0.8. */\n targetPower?: number\n /** Base P(row favors treatment) with no effect. Default 0.10 (tie-heavy rows). */\n baseWinRate?: number\n /** Base P(row favors control). Default 0.10. */\n baseLossRate?: number\n /**\n * Clusters whose rows carry outcome noise instead of signal: each row wins\n * with `flipRate` and loses with `flipRate`, independent of the effect.\n * Index into `clusterSizes`.\n */\n noisyClusters?: { index: number; flipRate: number }[]\n}\n\nexport interface ClusteredPowerPoint {\n effect: number\n power: number\n medianCiWidth: number\n}\n\nexport interface SignFlipFloor {\n /** Smallest achievable two-sided p: 2^(1-C) for C clusters. */\n twoSidedP: number\n /** Smallest achievable one-sided p: 2^-C. */\n oneSidedP: number\n alpha: number\n /** False when the cluster count can never certify at `alpha`, at any effect. */\n certifiableAtAlpha: boolean\n /** Smallest cluster count whose two-sided floor is at or under `alpha`. */\n minClustersForAlpha: number\n}\n\nexport interface ClusteredPowerRefusal {\n verdict: 'underpowered'\n reasons: string[]\n recommendation: string\n}\n\nexport interface ClusteredPowerResult {\n clusterCount: number\n totalRows: number\n trials: number\n resamples: number\n seed: number\n confidence: number\n targetPower: number\n curve: ClusteredPowerPoint[]\n /** Maximum simulated power across the effect grid. */\n maxPower: number\n signFlipFloor: SignFlipFloor\n /** True only when the sign-flip floor certifies AND simulation reaches target. */\n adequate: boolean\n /** Populated exactly when `adequate` is false. The refusal lives in the artifact. */\n refusal: ClusteredPowerRefusal | null\n}\n\n/**\n * Simulate the power of a whole-cluster percentile-bootstrap design and refuse\n * a structure that cannot reach the target at any registered effect.\n */\nexport function clusteredPower(options: ClusteredPowerOptions): ClusteredPowerResult {\n const clusterSizes = options.clusterSizes\n if (clusterSizes.length === 0 || clusterSizes.some((n) => !Number.isInteger(n) || n <= 0)) {\n throw new ValidationError(\n `clusteredPower: clusterSizes must be positive integers, got [${clusterSizes.join(', ')}]`,\n )\n }\n if (options.effects.length === 0) {\n throw new ValidationError('clusteredPower: effects grid is empty')\n }\n if (!Number.isInteger(options.seed)) {\n throw new ValidationError(`clusteredPower: seed must be an integer, got ${options.seed}`)\n }\n const trials = options.trials ?? 2000\n const resamples = options.resamples ?? 4000\n if (!Number.isInteger(trials) || trials <= 0 || !Number.isInteger(resamples) || resamples <= 0) {\n throw new ValidationError(\n `clusteredPower: trials and resamples must be positive integers, got ${trials}/${resamples}`,\n )\n }\n const confidence = options.confidence ?? 0.95\n if (confidence <= 0 || confidence >= 1) {\n throw new ValidationError(`clusteredPower: confidence must be in (0,1), got ${confidence}`)\n }\n const alpha = options.alpha ?? 0.05\n const targetPower = options.targetPower ?? 0.8\n const baseWinRate = options.baseWinRate ?? 0.1\n const baseLossRate = options.baseLossRate ?? 0.1\n const noisy = new Map<number, number>()\n for (const cluster of options.noisyClusters ?? []) {\n if (cluster.index < 0 || cluster.index >= clusterSizes.length) {\n throw new ValidationError(\n `clusteredPower: noisy cluster index ${cluster.index} outside [0,${clusterSizes.length - 1}]`,\n )\n }\n noisy.set(cluster.index, cluster.flipRate)\n }\n\n const clusterCount = clusterSizes.length\n const totalRows = clusterSizes.reduce((a, b) => a + b, 0)\n const signFlipFloor = computeSignFlipFloor(clusterCount, alpha)\n\n const curve: ClusteredPowerPoint[] = []\n for (const effect of options.effects) {\n curve.push(\n simulateEffect(effect, {\n clusterSizes,\n seed: options.seed,\n trials,\n resamples,\n confidence,\n baseWinRate,\n baseLossRate,\n noisy,\n }),\n )\n }\n const maxPower = Math.max(...curve.map((point) => point.power))\n\n const reasons: string[] = []\n if (!signFlipFloor.certifiableAtAlpha) {\n reasons.push(\n `${clusterCount} clusters cannot certify any effect size, including 1.0: the exact ` +\n `whole-cluster sign-flip test's smallest two-sided p is 2^(1-${clusterCount}) = ` +\n `${signFlipFloor.twoSidedP} > alpha ${alpha}; at least ` +\n `${signFlipFloor.minClustersForAlpha} clusters are needed`,\n )\n }\n if (maxPower < targetPower) {\n const best = curve.reduce((a, b) => (b.power > a.power ? b : a))\n reasons.push(\n `simulated power tops out at ${maxPower.toFixed(3)} (effect ${best.effect}) across the ` +\n `registered grid — below the ${targetPower} target at every effect`,\n )\n }\n const adequate = reasons.length === 0\n return {\n clusterCount,\n totalRows,\n trials,\n resamples,\n seed: options.seed,\n confidence,\n targetPower,\n curve,\n maxPower,\n signFlipFloor,\n adequate,\n refusal: adequate\n ? null\n : {\n verdict: 'underpowered',\n reasons,\n recommendation:\n `Do not spend on this structure. Add independent clusters (>= ` +\n `${Math.max(signFlipFloor.minClustersForAlpha, clusterCount)}) or register a design ` +\n `whose simulated power reaches ${targetPower}, then re-run clusteredPower.`,\n },\n }\n}\n\n/** Throw the refusal for callers that want configuration-time failure. */\nexport function assertDesignAdequate(result: ClusteredPowerResult): void {\n if (result.refusal) {\n throw new DesignRefusalError(\n `design refused (underpowered): ${result.refusal.reasons.join('; ')}`,\n )\n }\n}\n\nfunction computeSignFlipFloor(clusterCount: number, alpha: number): SignFlipFloor {\n const twoSidedP = 2 ** (1 - clusterCount)\n const oneSidedP = 2 ** -clusterCount\n let minClusters = 1\n while (2 ** (1 - minClusters) > alpha) minClusters += 1\n return {\n twoSidedP,\n oneSidedP,\n alpha,\n certifiableAtAlpha: twoSidedP <= alpha,\n minClustersForAlpha: minClusters,\n }\n}\n\ninterface SimulationConfig {\n clusterSizes: number[]\n seed: number\n trials: number\n resamples: number\n confidence: number\n baseWinRate: number\n baseLossRate: number\n noisy: Map<number, number>\n}\n\n/**\n * One effect point. Per row the paired contrast is +1 with probability\n * min(baseWin + effect, 1), -1 with the base loss rate (capped by what\n * remains), else 0. Noisy clusters draw win and loss independently at their\n * flip rate. Each trial computes a whole-cluster percentile bootstrap of the\n * pooled row mean; the trial counts toward power when the interval excludes\n * zero.\n */\nfunction simulateEffect(effect: number, config: SimulationConfig): ClusteredPowerPoint {\n const rng = mulberry32(mixSeed(config.seed, effect))\n const clusterCount = config.clusterSizes.length\n let excludes = 0\n const widths = new Array<number>(config.trials)\n const sums = new Array<number>(clusterCount)\n const means = new Array<number>(config.resamples)\n for (let trial = 0; trial < config.trials; trial++) {\n for (let cluster = 0; cluster < clusterCount; cluster++) {\n const size = config.clusterSizes[cluster]!\n const flipRate = config.noisy.get(cluster)\n let sum = 0\n for (let row = 0; row < size; row++) {\n if (flipRate !== undefined) {\n const win = rng() < flipRate ? 1 : 0\n const loss = rng() < flipRate ? 1 : 0\n sum += win - loss\n } else {\n const winRate = Math.min(1, config.baseWinRate + effect)\n const lossRate = Math.min(1 - winRate, config.baseLossRate)\n const u = rng()\n sum += u < winRate ? 1 : u < winRate + lossRate ? -1 : 0\n }\n }\n sums[cluster] = sum\n }\n for (let draw = 0; draw < config.resamples; draw++) {\n let pooledSum = 0\n let pooledRows = 0\n for (let pick = 0; pick < clusterCount; pick++) {\n const index = Math.floor(rng() * clusterCount)\n pooledSum += sums[index]!\n pooledRows += config.clusterSizes[index]!\n }\n means[draw] = pooledSum / pooledRows\n }\n means.sort((a, b) => a - b)\n const tail = 1 - config.confidence\n const lower = means[Math.floor((tail / 2) * config.resamples)]!\n const upper =\n means[\n Math.max(\n Math.floor((tail / 2) * config.resamples),\n Math.min(config.resamples - 1, Math.ceil((1 - tail / 2) * config.resamples) - 1),\n )\n ]!\n widths[trial] = upper - lower\n if (lower > 0 || upper < 0) excludes += 1\n }\n widths.sort((a, b) => a - b)\n return {\n effect,\n power: excludes / config.trials,\n medianCiWidth: widths[Math.floor(config.trials / 2)]!,\n }\n}\n\n/** Fold the effect into the seed so every grid point draws an independent stream. */\nfunction mixSeed(seed: number, effect: number): number {\n const scaled = Math.round(effect * 1_000_003)\n return ((seed ^ (scaled * 0x9e3779b9)) >>> 0) | 0\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["populations"],"sources":["../../src/experiment/budget.ts","../../src/experiment/funnel.ts","../../src/experiment/define.ts","../../src/experiment/evidence-record.ts","../../src/experiment/power.ts"],"sourcesContent":["/**\n * Matched-budget verification between arms, as a refusal object.\n *\n * A paired contrast is only meaningful when both arms spent comparable\n * resources; \"realized prompt and completion tokens must agree within 5%\" is\n * a registered rule, so its verification returns a verdict artifact — the\n * refusal lives inside the result, never in prose beside it.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport type { MatchedBudgetRule } from './ast'\n\n/** Arms whose realized budgets diverge past the registered tolerance. */\nexport class MatchedBudgetError extends CaptureIntegrityError {}\n\nexport interface ArmRealizedBudget {\n armId: string\n /** Realized prompt + completion tokens the arm actually consumed. */\n realizedTokens: number\n}\n\nexport interface MatchedBudgetVerdict {\n rule: MatchedBudgetRule\n arms: ArmRealizedBudget[]\n /** (max - min) / max over all arms; 0 when every arm spent nothing. */\n maxRelativeGap: number\n /** The two arms with the widest gap; null when fewer than two arms. */\n widestPair: [string, string] | null\n matched: boolean\n /** Populated exactly when `matched` is false. */\n refusal: null | { onFail: 'refuse-contrast'; reason: string }\n}\n\n/**\n * Compare realized per-arm spend under the registered tolerance. Requires at\n * least two arms — a single arm has nothing to match against. Negative or\n * non-finite token counts are refused as evidence corruption, not compared.\n */\nexport function verifyMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n if (arms.length < 2) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: need >= 2 arms to match budgets, got ${arms.length}`,\n )\n }\n for (const arm of arms) {\n if (!Number.isFinite(arm.realizedTokens) || arm.realizedTokens < 0) {\n throw new MatchedBudgetError(\n `verifyMatchedBudgets: arm '${arm.armId}' has invalid realized tokens ${arm.realizedTokens}`,\n )\n }\n }\n const sorted = [...arms].sort((a, b) => a.realizedTokens - b.realizedTokens)\n const min = sorted[0]!\n const max = sorted[sorted.length - 1]!\n const maxRelativeGap =\n max.realizedTokens === 0 ? 0 : (max.realizedTokens - min.realizedTokens) / max.realizedTokens\n const matched = maxRelativeGap <= rule.tolerance\n return {\n rule,\n arms: [...arms],\n maxRelativeGap,\n widestPair: [min.armId, max.armId],\n matched,\n refusal: matched\n ? null\n : {\n onFail: rule.onFail,\n reason:\n `realized ${rule.measure} diverge ${(maxRelativeGap * 100).toFixed(1)}% between ` +\n `'${min.armId}' (${min.realizedTokens}) and '${max.armId}' (${max.realizedTokens}) — ` +\n `registered tolerance is ${(rule.tolerance * 100).toFixed(1)}%; the contrast is refused`,\n },\n }\n}\n\n/** Throw the refusal for callers that gate the contrast on it. */\nexport function assertMatchedBudgets(\n rule: MatchedBudgetRule,\n arms: readonly ArmRealizedBudget[],\n): MatchedBudgetVerdict {\n const verdict = verifyMatchedBudgets(rule, arms)\n if (verdict.refusal) throw new MatchedBudgetError(verdict.refusal.reason)\n return verdict\n}\n","/**\n * The denominator chain as a first-class object.\n *\n * A benchmark whose denominator is not auditable is not a benchmark. Every\n * stage names what entered, what it removed, and what survived, so\n * `input = surviving + sum(excluded)` reads off the table instead of being\n * trusted. A stage that gains rows is refused at construction — a funnel is\n * monotone by definition, and a non-monotone one is a broken denominator,\n * not a formatting choice.\n *\n * The object is its own JSON render; `renderFunnelTable` is the text render.\n * `executeAdmissionRule` produces one by running a sealed {@link AdmissionRule}\n * over evidence records.\n */\n\nimport { CaptureIntegrityError } from '../errors'\nimport { type AdmissionRule, type EvidenceRecord, evaluatePredicate } from './ast'\n\n/** A funnel stage gained rows, double-counted them, or failed to reconcile. */\nexport class FunnelIntegrityError extends CaptureIntegrityError {}\n\nexport interface FunnelStageCount {\n id: string\n entering: number\n excluded: number\n remaining: number\n /** Named exclusion reasons summing to `excluded`, when the stage has them. */\n exclusions?: Record<string, number>\n /** Substrate checks this stage deliberately does not apply. Registered, never implicit. */\n waives?: string[]\n}\n\nexport interface FunnelPartitionCount {\n id: string\n /** Stage whose excluded rows the partition draws from. */\n from: string\n count: number\n /** A partition is reported separately and never pooled into the survivors. */\n pooling: 'never'\n}\n\nexport interface ExperimentFunnel {\n population: string\n input: number\n stages: FunnelStageCount[]\n surviving: number\n partitions: FunnelPartitionCount[]\n}\n\nexport interface FunnelStageInput {\n id: string\n /** Rows this stage removed. */\n excluded: number\n exclusions?: Record<string, number>\n waives?: string[]\n}\n\n/**\n * Build a funnel from counts and refuse anything non-monotone.\n *\n * Refusals: a negative count, a stage that gains rows (excluded < 0 is the\n * only way to gain — `remaining = entering - excluded` by construction, so a\n * gain cannot be smuggled in through `remaining`), named exclusions that do\n * not sum to the stage total, and a partition drawing from an unknown stage\n * or exceeding what that stage excluded.\n */\nexport function buildFunnel(input: {\n population: string\n input: number\n stages: FunnelStageInput[]\n partitions?: { id: string; from: string; count: number }[]\n}): ExperimentFunnel {\n if (!Number.isInteger(input.input) || input.input < 0) {\n throw new FunnelIntegrityError(\n `funnel input must be a non-negative integer, got ${input.input}`,\n )\n }\n let entering = input.input\n const stages: FunnelStageCount[] = []\n for (const stage of input.stages) {\n if (!Number.isInteger(stage.excluded)) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excluded count must be an integer, got ${stage.excluded}`,\n )\n }\n if (stage.excluded < 0) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' gains ${-stage.excluded} rows — a funnel stage can only remove rows`,\n )\n }\n if (stage.excluded > entering) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' excludes ${stage.excluded} rows but only ${entering} entered`,\n )\n }\n if (stage.exclusions) {\n const sum = Object.values(stage.exclusions).reduce((a, b) => a + b, 0)\n if (sum !== stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel stage '${stage.id}' names exclusions summing to ${sum} but excludes ${stage.excluded}`,\n )\n }\n }\n const remaining = entering - stage.excluded\n stages.push({\n id: stage.id,\n entering,\n excluded: stage.excluded,\n remaining,\n ...(stage.exclusions ? { exclusions: { ...stage.exclusions } } : {}),\n ...(stage.waives ? { waives: [...stage.waives] } : {}),\n })\n entering = remaining\n }\n const byStage = new Map(stages.map((s) => [s.id, s]))\n const partitions: FunnelPartitionCount[] = (input.partitions ?? []).map((partition) => {\n const source = byStage.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n if (partition.count < 0 || partition.count > source.excluded) {\n throw new FunnelIntegrityError(\n `funnel partition '${partition.id}' counts ${partition.count} rows but stage '${partition.from}' excluded ${source.excluded}`,\n )\n }\n return { id: partition.id, from: partition.from, count: partition.count, pooling: 'never' }\n })\n const funnel: ExperimentFunnel = {\n population: input.population,\n input: input.input,\n stages,\n surviving: entering,\n partitions,\n }\n assertFunnelReconciles(funnel)\n return funnel\n}\n\n/** A chain that does not add up is a broken denominator, so this throws. */\nexport function assertFunnelReconciles(funnel: ExperimentFunnel): void {\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n if (funnel.input !== funnel.surviving + excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' does not reconcile: input ${funnel.input} != surviving ${funnel.surviving} + excluded ${excluded}`,\n )\n }\n let entering = funnel.input\n for (const stage of funnel.stages) {\n if (stage.entering !== entering || stage.remaining !== stage.entering - stage.excluded) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' does not chain: ` +\n `entering ${stage.entering} (expected ${entering}), remaining ${stage.remaining}`,\n )\n }\n if (stage.remaining > stage.entering) {\n throw new FunnelIntegrityError(\n `funnel '${funnel.population}' stage '${stage.id}' gains rows: ${stage.entering} -> ${stage.remaining}`,\n )\n }\n entering = stage.remaining\n }\n}\n\nexport interface AdmissionExecution {\n funnel: ExperimentFunnel\n survivors: EvidenceRecord[]\n /** Partition rows by partition id, reported separately and never pooled. */\n partitionRows: Record<string, EvidenceRecord[]>\n}\n\n/**\n * Run a sealed admission rule over evidence records. Each stage keeps the rows\n * its predicate accepts; partitions draw from the rows their source stage\n * dropped. The result embeds the funnel, so the denominator chain and the\n * surviving rows can never disagree.\n */\nexport function executeAdmissionRule(\n rule: AdmissionRule,\n records: readonly EvidenceRecord[],\n): AdmissionExecution {\n let current = [...records]\n const droppedAt = new Map<string, EvidenceRecord[]>()\n const stageInputs: FunnelStageInput[] = []\n for (const stage of rule.stages) {\n const kept: EvidenceRecord[] = []\n const dropped: EvidenceRecord[] = []\n for (const record of current) {\n if (evaluatePredicate(stage.keep, record)) kept.push(record)\n else dropped.push(record)\n }\n droppedAt.set(stage.id, dropped)\n stageInputs.push({\n id: stage.id,\n excluded: dropped.length,\n ...(stage.waives ? { waives: stage.waives } : {}),\n })\n current = kept\n }\n const partitionRows: Record<string, EvidenceRecord[]> = {}\n const partitionCounts: { id: string; from: string; count: number }[] = []\n for (const partition of rule.partitions ?? []) {\n const source = droppedAt.get(partition.from)\n if (!source) {\n throw new FunnelIntegrityError(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n const rows = source.filter((record) => evaluatePredicate(partition.keep, record))\n partitionRows[partition.id] = rows\n partitionCounts.push({ id: partition.id, from: partition.from, count: rows.length })\n }\n const funnel = buildFunnel({\n population: rule.population,\n input: records.length,\n stages: stageInputs,\n partitions: partitionCounts,\n })\n return { funnel, survivors: current, partitionRows }\n}\n\n/**\n * Chain two funnels whose boundary agrees: the second funnel's input must be\n * exactly the first funnel's survivors. Anything else is a gap or an\n * injection, and both are refused.\n */\nexport function composeFunnels(\n first: ExperimentFunnel,\n second: ExperimentFunnel,\n): ExperimentFunnel {\n if (second.input !== first.surviving) {\n throw new FunnelIntegrityError(\n `cannot compose funnels: '${first.population}' survives ${first.surviving} rows but '${second.population}' starts from ${second.input}`,\n )\n }\n return buildFunnel({\n population: first.population,\n input: first.input,\n stages: [...first.stages, ...second.stages].map((stage) => ({\n id: stage.id,\n excluded: stage.excluded,\n ...(stage.exclusions ? { exclusions: stage.exclusions } : {}),\n ...(stage.waives ? { waives: stage.waives } : {}),\n })),\n partitions: [...first.partitions, ...second.partitions].map((partition) => ({\n id: partition.id,\n from: partition.from,\n count: partition.count,\n })),\n })\n}\n\n/**\n * Text render of the chain. One row per stage; the reconciliation line at the\n * bottom restates `input = surviving + excluded` so a reader can check the\n * arithmetic without a tool.\n */\nexport function renderFunnelTable(funnel: ExperimentFunnel): string {\n const rows = funnel.stages.map((stage) => [\n stage.id + (stage.waives?.length ? ` (waives: ${stage.waives.join(', ')})` : ''),\n String(stage.entering),\n String(stage.excluded),\n String(stage.remaining),\n ])\n const header = ['stage', 'entering', 'excluded', 'remaining']\n const widths = header.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col]!.length)))\n const line = (cells: string[]): string =>\n cells.map((cell, col) => cell.padEnd(widths[col]!)).join(' ')\n const out: string[] = [\n `population: ${funnel.population}`,\n `input: ${funnel.input}`,\n line(header),\n line(widths.map((w) => '-'.repeat(w))),\n ...rows.map((r) => line(r)),\n ]\n const excluded = funnel.stages.reduce((sum, stage) => sum + stage.excluded, 0)\n out.push(\n `surviving: ${funnel.surviving} (input ${funnel.input} = surviving ${funnel.surviving} + excluded ${excluded})`,\n )\n for (const partition of funnel.partitions) {\n out.push(\n `partition ${partition.id}: ${partition.count} rows from '${partition.from}' — reported separately, never pooled`,\n )\n }\n return out.join('\\n')\n}\n","/**\n * Define, seal, and execute experiments whose every rule is registered data.\n *\n * `defineExperiment` validates the cross-references inside a spec and freezes\n * it. `sealExperiment` canonicalizes and hashes the whole tree — arms, row\n * admission, selection, estimands, intervals, decision rule, gates, halt,\n * budget — into one digest that lands on every downstream artifact. Changing\n * what is decided requires a new digest: an amendment is a re-seal with a\n * reason and blindness attestations, and the digest history is the audit\n * trail.\n *\n * `openSealedExperiment` is the only execution surface. It verifies the seal\n * and returns executors bound to the sealed spec; none of them takes a\n * parameter for alpha, threshold, metric, or stopping rule, so\n * registered-vs-ran drift is unrepresentable rather than checked.\n */\n\nimport { ValidationError } from '../errors'\nimport { hashCanonical } from '../ledger-core/canonical'\nimport {\n type AdmissionRule,\n type BudgetRule,\n type ComputedInterval,\n type Condition,\n computeEstimand,\n computeInterval,\n type DecisionOutcome,\n type DecisionRule,\n type DerivedQuantities,\n type Estimand,\n type EstimandResult,\n type EvidenceRecord,\n evaluateHaltRule,\n evaluateIdentityGate,\n evaluateOracleDeterminismGate,\n evaluatePopulationReproducibilityGate,\n evaluatePowerFloorGate,\n evaluateProvenanceGate,\n executeDecisionRule,\n type GateResult,\n type HaltOutcome,\n type HaltRule,\n type IntervalSpec,\n intervalSpecProblems,\n type JsonValue,\n type MatchedBudgetRule,\n type NLadderProjection,\n type Obligation,\n powerFloorProblems,\n projectNLadderBudget,\n type ReissuePolicy,\n runSelectionRule,\n runUniformPassBudget,\n type SelectionRule,\n type UniformPassSchedule,\n type ValidityGate,\n} from './ast'\nimport { type ArmRealizedBudget, type MatchedBudgetVerdict, verifyMatchedBudgets } from './budget'\nimport {\n defineEvaluationClaim,\n type EvaluationClaim,\n type EvaluationUnitSummary,\n summarizeEvaluationUnits,\n} from './claim'\nimport { type AdmissionExecution, executeAdmissionRule } from './funnel'\n\n/** A sealed experiment whose digest no longer matches its spec. */\nexport class SealIntegrityError extends ValidationError {}\n\n// ── Spec ─────────────────────────────────────────────────────────────\n\nexport interface ArmSpec {\n id: string\n role: 'treatment' | 'control'\n /** Digest of the AgentProfile the arm runs under. */\n profileDigest?: string\n /** Digest of the pinned execution policy the arm runs under. */\n policyDigest?: string\n /** Registered arm pins (model, seed, step budget, ...) as data. */\n pins?: Record<string, JsonValue>\n}\n\nexport type OutcomeSpec =\n | {\n kind: 'binary'\n /** Where the pass verdict comes from, e.g. 'injected-suite'. */\n source?: string\n digestVerified?: boolean\n /** What counts as a pass, e.g. 'exit-0' or 'reward-file-contains-1'. */\n pass?: string\n /** Errored rollouts stay in the denominator; dropping them is unregistered. */\n droppedRollouts?: 'forbidden'\n }\n | {\n kind: 'bounded-score'\n min: number\n max: number\n orientation: 'higher-is-better' | 'lower-is-better'\n }\n\n/**\n * Per-rollout seed derivation as a closed source list. `arm` is not in the\n * union, so arm-dependent seeding is unrepresentable.\n */\nexport interface SeedDerivation {\n from: ('seed' | 'rowId' | 'rolloutIndex')[]\n}\n\nexport interface ExperimentSpec {\n id: string\n /** Population and independent observation unit for the intended use of this result. */\n claim?: EvaluationClaim\n /** Human prose for the audit trail — never executable. */\n hypothesis?: string\n arms: ArmSpec[]\n outcome: OutcomeSpec\n admission?: AdmissionRule\n /** Named deterministic subset rules. */\n selections?: Record<string, SelectionRule>\n /**\n * Selection OUTPUTS pinned into the seal. A filter-of base resolves here, so\n * reusing an earlier draw is registered and a re-draw is a new digest.\n */\n sealedSubsets?: Record<string, string[]>\n estimands?: Record<string, Estimand>\n intervals?: Record<string, IntervalSpec>\n decision: DecisionRule\n obligations?: Obligation[]\n /** Named pre-spend validity gates; the halt rule references these names. */\n gates?: Record<string, ValidityGate>\n halt?: HaltRule\n budget?: BudgetRule\n matchedBudget?: MatchedBudgetRule\n reissue?: ReissuePolicy\n seedDerivation?: SeedDerivation\n seed?: number\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nfunction conditionRefs(condition: Condition): {\n intervals: string[]\n quantities: string[]\n obligations: string[]\n} {\n switch (condition.kind) {\n case 'interval-excludes-zero':\n case 'interval-includes-zero':\n return { intervals: [condition.interval], quantities: [], obligations: [] }\n case 'quantity-threshold':\n return { intervals: [], quantities: [condition.quantity], obligations: [] }\n case 'obligation-met':\n return { intervals: [], quantities: [], obligations: [condition.obligation] }\n case 'all':\n case 'any': {\n const nested = condition.of.map(conditionRefs)\n return {\n intervals: nested.flatMap((r) => r.intervals),\n quantities: nested.flatMap((r) => r.quantities),\n obligations: nested.flatMap((r) => r.obligations),\n }\n }\n case 'not':\n return conditionRefs(condition.of)\n }\n}\n\n/**\n * Validate every cross-reference inside a spec and freeze it.\n *\n * A decision condition may only read a registered interval, a registered\n * estimand, or a registered obligation; a halt rule may only reference\n * registered gates; a filter-of base must resolve to a registered selection\n * or sealed subset. Anything else is refused here, before sealing.\n */\nexport function defineExperiment(spec: ExperimentSpec): ExperimentSpec {\n const problems: string[] = []\n const claim = spec.claim === undefined ? undefined : defineEvaluationClaim(spec.claim)\n if (!spec.id || spec.id.trim().length === 0) problems.push('id is empty')\n if (spec.arms.length === 0) problems.push('at least one arm is required')\n const armIds = new Set<string>()\n for (const arm of spec.arms) {\n if (armIds.has(arm.id)) problems.push(`duplicate arm id '${arm.id}'`)\n armIds.add(arm.id)\n }\n if (!spec.arms.some((arm) => arm.role === 'treatment')) {\n problems.push('at least one arm must have role treatment')\n }\n\n const intervalNames = new Set(Object.keys(spec.intervals ?? {}))\n const estimandNames = new Set(Object.keys(spec.estimands ?? {}))\n const obligationIds = new Set((spec.obligations ?? []).map((o) => o.id))\n const gateNames = new Set(Object.keys(spec.gates ?? {}))\n const selectionNames = new Set(Object.keys(spec.selections ?? {}))\n const sealedSubsetNames = new Set(Object.keys(spec.sealedSubsets ?? {}))\n\n for (const [name, interval] of Object.entries(spec.intervals ?? {})) {\n problems.push(\n ...intervalSpecProblems(interval).map((problem) => `interval '${name}': ${problem}`),\n )\n }\n\n for (const [name, gate] of Object.entries(spec.gates ?? {})) {\n if (gate.kind !== 'power-floor') continue\n problems.push(...powerFloorProblems(gate).map((problem) => `gate '${name}': ${problem}`))\n if (claim?.minimumEffect !== undefined && gate.minimumEffect !== claim.minimumEffect) {\n problems.push(`gate '${name}' minimumEffect differs from the evaluation claim`)\n }\n }\n if (claim?.generalization === 'new-units') {\n for (const [name, interval] of Object.entries(spec.intervals ?? {})) {\n if (interval?.kind === 'cluster-bootstrap' && interval.clusterBy !== claim.independentUnit) {\n problems.push(\n `interval '${name}' must resample '${claim.independentUnit}' from the evaluation claim`,\n )\n }\n }\n }\n\n const checkCondition = (condition: Condition, where: string): void => {\n const refs = conditionRefs(condition)\n for (const name of refs.intervals) {\n if (!intervalNames.has(name)) problems.push(`${where} reads unregistered interval '${name}'`)\n }\n for (const name of refs.quantities) {\n if (!estimandNames.has(name)) problems.push(`${where} reads unregistered quantity '${name}'`)\n }\n for (const name of refs.obligations) {\n if (!obligationIds.has(name))\n problems.push(`${where} reads unregistered obligation '${name}'`)\n }\n }\n\n if (spec.decision.kind === 'table') {\n if (spec.decision.branches.length === 0) problems.push('decision table has no branches')\n spec.decision.branches.forEach((branch, index) => {\n checkCondition(branch.when, `decision branch ${index} ('${branch.verdict}')`)\n })\n } else {\n for (const name of spec.decision.estimands) {\n if (!estimandNames.has(name)) {\n problems.push(`report-only decision names unregistered estimand '${name}'`)\n }\n }\n for (const name of spec.decision.intervals) {\n if (!intervalNames.has(name)) {\n problems.push(`report-only decision names unregistered interval '${name}'`)\n }\n }\n }\n\n if (spec.decision.kind === 'table' && spec.obligations) {\n const verdicts = new Set(spec.decision.branches.map((b) => b.verdict))\n for (const obligation of spec.obligations) {\n for (const verdict of obligation.appliesToVerdicts) {\n if (!verdicts.has(verdict)) {\n problems.push(\n `obligation '${obligation.id}' applies to verdict '${verdict}' which no branch produces`,\n )\n }\n }\n }\n }\n\n if (spec.halt) {\n for (const gate of spec.halt.when.gates) {\n if (!gateNames.has(gate)) problems.push(`halt rule references unregistered gate '${gate}'`)\n }\n }\n\n for (const [name, selection] of Object.entries(spec.selections ?? {})) {\n if (selection.kind === 'filter-of') {\n if (!selectionNames.has(selection.base) && !sealedSubsetNames.has(selection.base)) {\n problems.push(\n `selection '${name}' filters unregistered base '${selection.base}' (not a selection or sealed subset)`,\n )\n }\n }\n }\n\n if (spec.admission) {\n const stageIds = new Set<string>()\n for (const stage of spec.admission.stages) {\n if (stageIds.has(stage.id)) problems.push(`duplicate admission stage id '${stage.id}'`)\n stageIds.add(stage.id)\n }\n for (const partition of spec.admission.partitions ?? []) {\n if (!stageIds.has(partition.from)) {\n problems.push(\n `admission partition '${partition.id}' draws from unknown stage '${partition.from}'`,\n )\n }\n }\n }\n\n if (problems.length > 0) {\n throw new ValidationError(`defineExperiment('${spec.id}'): ${problems.join('; ')}`)\n }\n return deepFreeze(structuredClone({ ...spec, ...(claim ? { claim } : {}) }))\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const key of Object.keys(value as object)) {\n deepFreeze((value as Record<string, unknown>)[key])\n }\n Object.freeze(value)\n }\n return value\n}\n\n// ── Seal ─────────────────────────────────────────────────────────────\n\nexport interface SealAmendment {\n /** ISO8601 timestamp of the re-seal. */\n at: string\n reason: string\n /** Blindness attestations: what was verifiably unseen when the amendment was made. */\n blind: string[]\n /** Digest of the spec after this amendment. */\n digest: string\n}\n\n/** SHA-256 over the RFC 8785 canonical JSON encoding of the experiment. */\nexport type SealAlgo = 'sha256-rfc8785'\n\nexport interface SealedExperiment {\n spec: ExperimentSpec\n /** sha256 over the serialized spec, under the scheme `algo` names. */\n digest: string\n /** Required digest scheme. Unsupported or missing schemes cannot execute. */\n algo: SealAlgo\n sealedAt: string\n /** Digest of the original registration, before any amendment. */\n initialDigest: string\n amendments: SealAmendment[]\n}\n\n/** Validate, canonicalize, and hash a spec into its registration. */\nexport async function sealExperiment(\n spec: ExperimentSpec,\n options: { sealedAt?: string } = {},\n): Promise<SealedExperiment> {\n const validated = defineExperiment(spec)\n const digest = specDigest(validated)\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: options.sealedAt ?? new Date().toISOString(),\n initialDigest: digest,\n amendments: [],\n }\n}\n\n/**\n * Amend a sealed experiment. The current seal is verified first, the new spec\n * is validated and re-hashed, and the amendment appends to the digest chain.\n * There is no way to change what is decided without producing a new digest.\n */\nexport async function amendExperiment(\n sealed: SealedExperiment,\n amendment: { spec: ExperimentSpec; reason: string; blind: string[]; at?: string },\n): Promise<SealedExperiment> {\n const captured = structuredClone(sealed)\n const requested = structuredClone(amendment)\n await assertSealIntact(captured)\n const validated = defineExperiment(requested.spec)\n const digest = specDigest(validated)\n return {\n spec: validated,\n digest,\n algo: 'sha256-rfc8785',\n sealedAt: captured.sealedAt,\n initialDigest: captured.initialDigest,\n amendments: [\n ...captured.amendments,\n {\n at: requested.at ?? new Date().toISOString(),\n reason: requested.reason,\n blind: [...requested.blind],\n digest,\n },\n ],\n }\n}\n\n/** True when the supported seal matches its canonical spec. */\nexport async function verifySealedExperiment(sealed: SealedExperiment): Promise<boolean> {\n if (sealed.algo !== 'sha256-rfc8785') return false\n try {\n return specDigest(sealed.spec) === sealed.digest\n } catch {\n return false\n }\n}\n\nfunction specDigest(spec: ExperimentSpec): string {\n return hashCanonical(spec).slice('sha256:'.length)\n}\n\nasync function assertSealIntact(sealed: SealedExperiment): Promise<void> {\n if (!(await verifySealedExperiment(sealed))) {\n throw new SealIntegrityError(\n `sealed experiment '${sealed.spec.id}' has an unsupported digest scheme or its digest does not match its canonical spec`,\n )\n }\n}\n\n// ── Sealed execution ─────────────────────────────────────────────────\n\n/** Evidence a gate executor consumes, discriminated to match the gate kind. */\nexport type GateEvidence =\n | { kind: 'oracle-determinism'; repsByState: Record<string, readonly boolean[]> }\n | {\n kind: 'population-reproducibility'\n left: readonly EvidenceRecord[]\n right: readonly EvidenceRecord[]\n }\n | { kind: 'provenance-assertion'; provenance: EvidenceRecord }\n | { kind: 'identity'; pinned: string; served: string }\n | { kind: 'power-floor'; curve: readonly { effect: number; power: number }[] }\n\n/**\n * Executors bound to one verified seal. Every method reads its rule from the\n * sealed spec; evidence is the only argument anywhere.\n */\nexport interface RegisteredExperiment {\n readonly sealed: SealedExperiment\n /** Count independent units separately from repeated observations under the sealed claim. */\n units(records: readonly EvidenceRecord[]): EvaluationUnitSummary\n /** Execute the registered decision rule on derived quantities. */\n decide(evidence: DerivedQuantities): DecisionOutcome\n /** Run the registered admission funnel over evidence rows. */\n admit(records: readonly EvidenceRecord[]): AdmissionExecution\n /** Run a registered selection rule. Filter-of bases resolve to sealed subsets. */\n select(name: string, records: readonly EvidenceRecord[], options: { idField: string }): string[]\n /** Evaluate a registered validity gate on evidence of the matching kind. */\n gate(name: string, evidence: GateEvidence): GateResult\n /** Evaluate the registered halt rule over gate results. */\n halt(gates: readonly GateResult[]): HaltOutcome\n /** Execute the registered uniform-pass budget schedule. */\n runUniformPassBudget(measuredPassCosts: readonly number[]): UniformPassSchedule\n /** Project the registered n-ladder budget. */\n projectNLadderBudget(measured: { unitCostUsd: number; rows: number }): NLadderProjection\n /** Verify realized arm budgets under the registered matched-budget rule. */\n matchedBudgets(arms: readonly ArmRealizedBudget[]): MatchedBudgetVerdict\n /** Compute a registered estimand over evidence rows. */\n estimate(name: string, rows: readonly EvidenceRecord[]): EstimandResult\n /** Compute a registered interval spec. */\n interval(\n name: string,\n evidence:\n | { kind: 'rows'; rows: readonly EvidenceRecord[] }\n | { kind: 'binomial'; successes: number; trials: number; unitIds?: readonly string[] },\n ): ComputedInterval & { units?: EvaluationUnitSummary }\n}\n\n/**\n * Verify the seal and return executors bound to it. This is the module's only\n * execution surface: a rule that is not in the sealed spec cannot run, and a\n * rule that is cannot run differently.\n */\nexport async function openSealedExperiment(\n sealed: SealedExperiment,\n): Promise<RegisteredExperiment> {\n const captured = structuredClone(sealed)\n await assertSealIntact(captured)\n const spec = defineExperiment(captured.spec)\n const frozenSeal = deepFreeze({ ...captured, spec })\n const need = <T>(value: T | undefined, what: string): T => {\n if (value === undefined) {\n throw new ValidationError(`experiment '${spec.id}' registered no ${what}`)\n }\n return value\n }\n return {\n sealed: frozenSeal,\n units: (records) => summarizeEvaluationUnits(need(spec.claim, 'evaluation claim'), records),\n decide: (evidence) => executeDecisionRule(spec.decision, evidence),\n admit: (records) => executeAdmissionRule(need(spec.admission, 'admission rule'), records),\n select: (name, records, options) => {\n const rule = need(spec.selections?.[name], `selection '${name}'`)\n return runSelectionRule(rule, records, {\n idField: options.idField,\n bases: spec.sealedSubsets,\n })\n },\n gate: (name, evidence) => {\n const gate = need(spec.gates?.[name], `gate '${name}'`)\n if (gate.kind !== evidence.kind) {\n throw new ValidationError(\n `gate '${name}' is registered as ${gate.kind} but received ${evidence.kind} evidence`,\n )\n }\n switch (gate.kind) {\n case 'oracle-determinism':\n return evaluateOracleDeterminismGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'oracle-determinism' }>).repsByState,\n )\n case 'population-reproducibility': {\n const populations = evidence as Extract<\n GateEvidence,\n { kind: 'population-reproducibility' }\n >\n return evaluatePopulationReproducibilityGate(name, gate, populations)\n }\n case 'provenance-assertion':\n return evaluateProvenanceGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'provenance-assertion' }>).provenance,\n )\n case 'identity':\n return evaluateIdentityGate(\n name,\n gate,\n evidence as Extract<GateEvidence, { kind: 'identity' }>,\n )\n case 'power-floor':\n return evaluatePowerFloorGate(\n name,\n gate,\n (evidence as Extract<GateEvidence, { kind: 'power-floor' }>).curve,\n )\n }\n },\n halt: (gates) => evaluateHaltRule(need(spec.halt, 'halt rule'), gates),\n runUniformPassBudget: (measuredPassCosts) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'uniform-pass') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not uniform-pass`,\n )\n }\n return runUniformPassBudget(budget, measuredPassCosts)\n },\n projectNLadderBudget: (measured) => {\n const budget = need(spec.budget, 'budget rule')\n if (budget.kind !== 'n-ladder') {\n throw new ValidationError(\n `experiment '${spec.id}' registered a ${budget.kind} budget, not n-ladder`,\n )\n }\n return projectNLadderBudget(budget, measured)\n },\n matchedBudgets: (arms) =>\n verifyMatchedBudgets(need(spec.matchedBudget, 'matched-budget rule'), arms),\n estimate: (name, rows) =>\n computeEstimand(need(spec.estimands?.[name], `estimand '${name}'`), rows),\n interval: (name, evidence) => {\n const interval = need(spec.intervals?.[name], `interval '${name}'`)\n const claim = spec.claim\n let units: EvaluationUnitSummary | undefined\n if (claim && evidence.kind === 'rows') {\n units = summarizeEvaluationUnits(claim, evidence.rows)\n } else if (claim?.generalization === 'new-units' && evidence.kind === 'binomial') {\n if (\n evidence.unitIds === undefined ||\n evidence.unitIds.length !== evidence.trials ||\n new Set(evidence.unitIds).size !== evidence.trials ||\n evidence.unitIds.some((id) => typeof id !== 'string' || !id.trim() || id.trim() !== id)\n ) {\n throw new ValidationError(\n 'claimed binomial interval needs one unique unitId per independent trial',\n )\n }\n units = {\n observations: evidence.trials,\n independentUnits: evidence.trials,\n units: evidence.unitIds.map((id) => ({ id, observations: 1 })),\n }\n }\n return { ...computeInterval(interval, evidence), ...(units ? { units } : {}) }\n },\n }\n}\n","/**\n * The evidence registry record — the canonical, machine-readable unit for a\n * measured claim about an agent, a prompt, a policy, or an instrument.\n *\n * One record answers, in typed fields, the questions a scattered results doc\n * leaves to prose: what was claimed, what instrument measured it, the exact\n * command that reproduces it, which arms ran, the denominator, what it cost,\n * what confounds the comparison, and how much trust the evidence has earned.\n *\n * Records live as JSON files in `evidence/records/` at the repo root — one\n * file per claim, filename `<id>.json`. The registry lives in agent-eval\n * because the measurement substrate owns evidence legitimacy; every other\n * repo keeps at most a pointer file. `scripts/render-evidence-index.ts`\n * generates the human index from these records, so prose can never drift\n * from data, and `pnpm run evidence:check` (part of `verify:package`) fails\n * on an invalid record or a stale index.\n *\n * The shape extends the `.evolve/experiments.jsonl` session-log vocabulary\n * (ts/hypothesis/change/result/evidence) into a curated registry record.\n * Session logs stay append-only diaries; a registry record is the durable,\n * addressable claim distilled from them.\n */\n\nimport { z } from 'zod'\n\n/**\n * Trust ladder for a recorded claim, strongest first.\n *\n * - `CERTIFIED` — pre-registered rule, sealed or held-out data, and either a\n * defended challenge or a check that re-runs in the suite.\n * - `MEASURED-ONCE` — one honest measurement on the real path, not replicated.\n * - `RESOLVED-NULL` — measured with an adequate instrument; the effect did not\n * appear under the registered rule. A null is a result, not a failure.\n * - `UNVERIFIED` — stated somewhere load-bearing, but no independent check has\n * run. Admitting this state is what keeps folklore out of the other four.\n * - `KILLED` — refuted, invalidated, or superseded by a stronger record.\n */\nexport const EVIDENCE_STATES = [\n 'CERTIFIED',\n 'MEASURED-ONCE',\n 'RESOLVED-NULL',\n 'UNVERIFIED',\n 'KILLED',\n] as const\n\nexport type EvidenceState = (typeof EVIDENCE_STATES)[number]\n\nconst idPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst datePattern = /^\\d{4}-\\d{2}-\\d{2}$/\nconst sha256Pattern = /^[0-9a-f]{64}$/\n\n/** Denominator of the measurement. A claim without an `n` is prose, not evidence. */\nconst evidenceDenominatorSchema = z.strictObject({\n value: z.number().positive().finite(),\n /** What one unit is: rows, cases, rollouts, records, leaves… */\n unit: z.string().min(1),\n /** Clustering, reps, split names — whatever the bare number hides. */\n detail: z.string().min(1).optional(),\n})\n\nexport type EvidenceDenominator = z.infer<typeof evidenceDenominatorSchema>\n\nexport const evidenceRegistryRecordSchema = z.strictObject({\n /** Stable kebab-case identity; the registry filename is `<id>.json`. */\n id: z.string().regex(idPattern),\n /** Date the decisive measurement completed, `YYYY-MM-DD`. */\n date: z.string().regex(datePattern),\n /** The one-sentence load-bearing claim, stated so it can fail. */\n claim: z.string().min(1),\n /** Domain the claim lives in: trace-repair, multishot, analyst, vertical-bench… */\n domain: z.string().min(1),\n /** The instrument that produced the number — script, harness, oracle, judge. */\n instrument: z.string().min(1),\n /**\n * The exact invocation that reproduces the measurement.\n * `null` means the invocation was not preserved — a named gap, never a guess.\n */\n command: z.string().min(1).nullable(),\n /** Compared arms. Empty for a single-arm measurement. */\n arms: z.array(z.string().min(1)),\n n: evidenceDenominatorSchema,\n /** The measured numbers, with uncertainty when it exists. Numbers, not adjectives. */\n result: z.string().min(1),\n evidenceState: z.enum(EVIDENCE_STATES),\n /** Where the raw data lives: repo paths, PR/gist URLs, run directories. Never empty. */\n artifacts: z.array(z.string().min(1)).min(1),\n /**\n * Measured spend in USD. `0` is a true zero (deterministic, no paid calls);\n * `null` means spend was not captured — a named gap, never a silent zero.\n */\n costUsd: z.number().nonnegative().nullable(),\n /** Every known asymmetry or threat to validity. Empty only when none is known. */\n confounds: z.array(z.string().min(1)),\n /** Repo whose work produced the evidence (the registry itself lives here). */\n sourceRepo: z.string().min(1),\n /** Seal digest of the registered experiment (`./experiment`), when one governed the run. */\n experimentDigest: z.string().regex(sha256Pattern).optional(),\n /** Ids of records this one supersedes. */\n supersedes: z.array(z.string().regex(idPattern)).optional(),\n notes: z.string().min(1).optional(),\n})\n\nexport type EvidenceRegistryRecord = z.infer<typeof evidenceRegistryRecordSchema>\n\n/** Parse one record; throws with the zod issue list on any violation. */\nexport function parseEvidenceRegistryRecord(raw: unknown): EvidenceRegistryRecord {\n return evidenceRegistryRecordSchema.parse(raw)\n}\n\nclass EvidenceRegistryError extends Error {}\n\n/**\n * Validate a set of records as one registry: every record parses, ids are\n * unique, and every `supersedes` target exists. Returns records sorted in\n * the registry's canonical order (trust ladder, then date desc, then id).\n */\nexport function validateEvidenceRegistry(raws: readonly unknown[]): EvidenceRegistryRecord[] {\n const records = raws.map((raw) => parseEvidenceRegistryRecord(raw))\n const seen = new Set<string>()\n for (const record of records) {\n if (seen.has(record.id)) {\n throw new EvidenceRegistryError(`duplicate evidence record id: ${record.id}`)\n }\n seen.add(record.id)\n }\n for (const record of records) {\n for (const target of record.supersedes ?? []) {\n if (!seen.has(target)) {\n throw new EvidenceRegistryError(`record ${record.id} supersedes unknown record: ${target}`)\n }\n }\n }\n const stateRank = new Map(EVIDENCE_STATES.map((state, index) => [state, index]))\n return [...records].sort((a, b) => {\n const byState = (stateRank.get(a.evidenceState) ?? 0) - (stateRank.get(b.evidenceState) ?? 0)\n if (byState !== 0) return byState\n if (a.date !== b.date) return a.date < b.date ? 1 : -1\n return a.id < b.id ? -1 : 1\n })\n}\n\nfunction mdEscape(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ')\n}\n\nfunction formatCost(costUsd: number | null): string {\n if (costUsd === null) return 'not captured'\n return `$${costUsd.toFixed(2)}`\n}\n\nfunction formatN(n: EvidenceDenominator): string {\n const base = `${n.value} ${n.unit}`\n return n.detail ? `${base} (${n.detail})` : base\n}\n\n/**\n * Render the registry's human index from records. Deterministic: identical\n * records always produce identical output, so a byte diff against the\n * committed index is the freshness check. No clocks, no environment.\n */\nexport function renderEvidenceIndex(raws: readonly unknown[]): string {\n const records = validateEvidenceRegistry(raws)\n const lines: string[] = [\n '# Evidence index',\n '',\n '<!-- GENERATED by scripts/render-evidence-index.ts from evidence/records/*.json.',\n ' Edit the records, run `pnpm run evidence:render`, and commit both.',\n ' `pnpm run evidence:check` (inside verify:package) fails when this file drifts. -->',\n '',\n `${records.length} records. States: ${EVIDENCE_STATES.join(' > ')}.`,\n '',\n '| state | date | id | claim | result |',\n '| --- | --- | --- | --- | --- |',\n ]\n for (const r of records) {\n lines.push(\n `| ${r.evidenceState} | ${r.date} | [\\`${r.id}\\`](#${r.id}) | ${mdEscape(r.claim)} | ${mdEscape(r.result)} |`,\n )\n }\n for (const r of records) {\n lines.push('', `## ${r.id}`, '')\n lines.push(`**${r.evidenceState}** · ${r.date} · ${r.domain} · source repo \\`${r.sourceRepo}\\``)\n lines.push('', `**Claim.** ${r.claim}`, '', `**Result.** ${r.result}`, '')\n lines.push(`- **Instrument**: ${r.instrument}`)\n lines.push(`- **Command**: ${r.command === null ? 'not preserved' : `\\`${r.command}\\``}`)\n lines.push(`- **Arms**: ${r.arms.length === 0 ? 'single-arm' : r.arms.join(' vs ')}`)\n lines.push(`- **n**: ${formatN(r.n)}`)\n lines.push(`- **Cost**: ${formatCost(r.costUsd)}`)\n if (r.experimentDigest) lines.push(`- **Experiment seal**: \\`${r.experimentDigest}\\``)\n lines.push(`- **Artifacts**:`)\n for (const artifact of r.artifacts) lines.push(` - ${artifact}`)\n if (r.confounds.length === 0) {\n lines.push('- **Confounds**: none recorded')\n } else {\n lines.push('- **Confounds**:')\n for (const confound of r.confounds) lines.push(` - ${confound}`)\n }\n if (r.supersedes && r.supersedes.length > 0) {\n lines.push(`- **Supersedes**: ${r.supersedes.map((s) => `\\`${s}\\``).join(', ')}`)\n }\n if (r.notes) lines.push(`- **Notes**: ${r.notes}`)\n }\n lines.push('')\n return lines.join('\\n')\n}\n","/**\n * Design-time power for task-clustered paired designs, with a refusal verdict.\n *\n * The failure this prevents (measured): a pre-registered kill test fixed a\n * task-clustered bootstrap over 14 rows in 4 task clusters. Simulated at the\n * registered seed, the design's power topped out at 0.69 — at a per-row\n * effect of 1.0. \"Four clusters cannot certify any effect size, including\n * 1.0\" was learned by running the experiment; this module computes it before\n * a dollar is spent.\n *\n * Two floors, one simulation:\n * - Closed form, zero spend: with C independent clusters the exact\n * whole-cluster sign-flip test can never produce a two-sided p below\n * 2^(1-C). C=4 gives 0.125; C=3 gives 0.25 — both above a 0.05 alpha, so\n * those designs are refused at ANY effect size, before simulation.\n * - Seeded simulation: per-row paired contrasts drawn under a registered\n * effect model, a whole-cluster percentile bootstrap on each trial, power =\n * the fraction of trials whose interval excludes zero.\n *\n * The refusal is a verdict INSIDE the returned artifact (the powerPreflight\n * shape, made cluster-aware); `assertDesignAdequate` turns it into a throw for\n * callers that want configuration-time failure.\n */\n\nimport { ValidationError } from '../errors'\nimport { mulberry32 } from '../statistics'\n\n/** A design refused at configuration time, before any spend. */\nexport class DesignRefusalError extends ValidationError {}\n\nexport interface ClusteredPowerOptions {\n /** Rows per independent cluster, e.g. [6, 3, 3, 2]. */\n clusterSizes: number[]\n /** P(win) − P(loss) in signal clusters; noisy clusters retain zero expected contrast. */\n effects: number[]\n /** Minimum worthwhile effect under the declared outcome model; must occur in effects. */\n minimumEffect: number\n /** Deterministic seed for outcome draws and bootstrap resampling. */\n seed: number\n /** Simulated experiments per effect. Default 2000. */\n trials?: number\n /** Whole-cluster bootstrap draws per trial. Default 4000. */\n resamples?: number\n /** Percentile interval level. Default 0.95. */\n confidence?: number\n /** Sign-flip alpha the closed-form floor is checked against. Default 0.05. */\n alpha?: number\n /** Power required at minimumEffect. Default 0.8. */\n targetPower?: number\n /** P(row favors treatment) under the zero-effect model. Must equal baseLossRate. Default 0.10. */\n baseWinRate?: number\n /** P(row favors control) under the zero-effect model. Must equal baseWinRate. Default 0.10. */\n baseLossRate?: number\n /**\n * Clusters whose rows carry outcome noise instead of signal: each row wins\n * with `flipRate` and loses with `flipRate`, independent of the effect.\n * Index into `clusterSizes`.\n */\n noisyClusters?: { index: number; flipRate: number }[]\n}\n\nexport interface ClusteredPowerPoint {\n effect: number\n power: number\n medianCiWidth: number\n}\n\nexport interface SignFlipFloor {\n /** Smallest achievable two-sided p: 2^(1-C) for C clusters. */\n twoSidedP: number\n /** Smallest achievable one-sided p: 2^-C. */\n oneSidedP: number\n alpha: number\n /** False when the cluster count can never certify at `alpha`, at any effect. */\n certifiableAtAlpha: boolean\n /** Smallest cluster count whose two-sided floor is at or under `alpha`. */\n minClustersForAlpha: number\n}\n\nexport interface ClusteredPowerRefusal {\n verdict: 'underpowered'\n reasons: string[]\n recommendation: string\n}\n\nexport interface ClusteredPowerResult {\n clusterCount: number\n totalRows: number\n trials: number\n resamples: number\n seed: number\n confidence: number\n targetPower: number\n minimumEffect: number\n powerAtMinimumEffect: number\n curve: ClusteredPowerPoint[]\n /** Maximum simulated power across the effect grid. */\n maxPower: number\n signFlipFloor: SignFlipFloor\n /** True when the sign-flip floor certifies and power at minimumEffect reaches target. */\n adequate: boolean\n /** Populated exactly when `adequate` is false. The refusal lives in the artifact. */\n refusal: ClusteredPowerRefusal | null\n}\n\n/**\n * Simulate the power of a whole-cluster percentile-bootstrap design and refuse\n * a structure that cannot reach target power at the declared minimum effect.\n */\nexport function clusteredPower(options: ClusteredPowerOptions): ClusteredPowerResult {\n const clusterSizes = options.clusterSizes\n if (clusterSizes.length === 0 || clusterSizes.some((n) => !Number.isInteger(n) || n <= 0)) {\n throw new ValidationError(\n `clusteredPower: clusterSizes must be positive integers, got [${clusterSizes.join(', ')}]`,\n )\n }\n if (options.effects.length === 0) {\n throw new ValidationError('clusteredPower: effects grid is empty')\n }\n if (\n options.effects.some((effect) => !Number.isFinite(effect) || effect < 0 || effect > 1) ||\n new Set(options.effects).size !== options.effects.length\n ) {\n throw new ValidationError('clusteredPower: effects must be unique finite values in [0,1]')\n }\n if (\n !Number.isFinite(options.minimumEffect) ||\n options.minimumEffect <= 0 ||\n options.minimumEffect > 1\n ) {\n throw new ValidationError('clusteredPower: minimumEffect must be in (0,1]')\n }\n if (!options.effects.includes(options.minimumEffect)) {\n throw new ValidationError(\n 'clusteredPower: effects must contain minimumEffect exactly; no interpolation is assumed',\n )\n }\n if (!Number.isInteger(options.seed)) {\n throw new ValidationError(`clusteredPower: seed must be an integer, got ${options.seed}`)\n }\n const trials = options.trials ?? 2000\n const resamples = options.resamples ?? 4000\n if (!Number.isInteger(trials) || trials <= 0 || !Number.isInteger(resamples) || resamples <= 0) {\n throw new ValidationError(\n `clusteredPower: trials and resamples must be positive integers, got ${trials}/${resamples}`,\n )\n }\n const confidence = options.confidence ?? 0.95\n if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {\n throw new ValidationError(`clusteredPower: confidence must be in (0,1), got ${confidence}`)\n }\n const alpha = options.alpha ?? 0.05\n const targetPower = options.targetPower ?? 0.8\n if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {\n throw new ValidationError('clusteredPower: alpha must be in (0,1)')\n }\n if (!Number.isFinite(targetPower) || targetPower <= 0 || targetPower > 1) {\n throw new ValidationError('clusteredPower: targetPower must be in (0,1]')\n }\n const baseWinRate = options.baseWinRate ?? 0.1\n const baseLossRate = options.baseLossRate ?? 0.1\n if (\n !Number.isFinite(baseWinRate) ||\n !Number.isFinite(baseLossRate) ||\n baseWinRate < 0 ||\n baseLossRate < 0 ||\n baseWinRate + baseLossRate > 1\n ) {\n throw new ValidationError(\n 'clusteredPower: base win/loss rates must be nonnegative and sum to at most 1',\n )\n }\n if (baseWinRate !== baseLossRate) {\n throw new ValidationError(\n 'clusteredPower: the zero-effect model requires equal baseWinRate and baseLossRate',\n )\n }\n const noisy = new Map<number, number>()\n for (const cluster of options.noisyClusters ?? []) {\n if (\n !Number.isInteger(cluster.index) ||\n cluster.index < 0 ||\n cluster.index >= clusterSizes.length\n ) {\n throw new ValidationError(\n `clusteredPower: noisy cluster index ${cluster.index} outside [0,${clusterSizes.length - 1}]`,\n )\n }\n if (\n noisy.has(cluster.index) ||\n !Number.isFinite(cluster.flipRate) ||\n cluster.flipRate < 0 ||\n cluster.flipRate > 1\n ) {\n throw new ValidationError(\n 'clusteredPower: noisy clusters need unique indices and flipRate in [0,1]',\n )\n }\n noisy.set(cluster.index, cluster.flipRate)\n }\n\n const clusterCount = clusterSizes.length\n const totalRows = clusterSizes.reduce((a, b) => a + b, 0)\n const signFlipFloor = computeSignFlipFloor(clusterCount, alpha)\n\n const curve: ClusteredPowerPoint[] = []\n for (const effect of options.effects) {\n curve.push(\n simulateEffect(effect, {\n clusterSizes,\n seed: options.seed,\n trials,\n resamples,\n confidence,\n baseWinRate,\n baseLossRate,\n noisy,\n }),\n )\n }\n const maxPower = Math.max(...curve.map((point) => point.power))\n const powerAtMinimumEffect = curve.find((point) => point.effect === options.minimumEffect)!.power\n\n const reasons: string[] = []\n if (!signFlipFloor.certifiableAtAlpha) {\n reasons.push(\n `${clusterCount} clusters cannot certify any effect size, including 1.0: the exact ` +\n `whole-cluster sign-flip test's smallest two-sided p is 2^(1-${clusterCount}) = ` +\n `${signFlipFloor.twoSidedP} > alpha ${alpha}; at least ` +\n `${signFlipFloor.minClustersForAlpha} clusters are needed`,\n )\n }\n if (powerAtMinimumEffect < targetPower) {\n reasons.push(\n `simulated power ${powerAtMinimumEffect.toFixed(3)} at minimum worthwhile effect ` +\n `${options.minimumEffect} is below target ${targetPower}; maximum grid power ` +\n `${maxPower.toFixed(3)} does not establish adequacy at that effect`,\n )\n }\n const adequate = reasons.length === 0\n return {\n clusterCount,\n totalRows,\n trials,\n resamples,\n seed: options.seed,\n confidence,\n targetPower,\n minimumEffect: options.minimumEffect,\n powerAtMinimumEffect,\n curve,\n maxPower,\n signFlipFloor,\n adequate,\n refusal: adequate\n ? null\n : {\n verdict: 'underpowered',\n reasons,\n recommendation:\n `Do not spend on this structure. Add independent clusters (>= ` +\n `${Math.max(signFlipFloor.minClustersForAlpha, clusterCount)}) or register a design ` +\n `whose simulated power reaches ${targetPower} at effect ${options.minimumEffect}, ` +\n `then re-run clusteredPower.`,\n },\n }\n}\n\n/** Throw the refusal for callers that want configuration-time failure. */\nexport function assertDesignAdequate(result: ClusteredPowerResult): void {\n if (result.refusal) {\n throw new DesignRefusalError(\n `design refused (underpowered): ${result.refusal.reasons.join('; ')}`,\n )\n }\n}\n\nfunction computeSignFlipFloor(clusterCount: number, alpha: number): SignFlipFloor {\n const twoSidedP = 2 ** (1 - clusterCount)\n const oneSidedP = 2 ** -clusterCount\n let minClusters = 1\n while (2 ** (1 - minClusters) > alpha) minClusters += 1\n return {\n twoSidedP,\n oneSidedP,\n alpha,\n certifiableAtAlpha: twoSidedP <= alpha,\n minClustersForAlpha: minClusters,\n }\n}\n\ninterface SimulationConfig {\n clusterSizes: number[]\n seed: number\n trials: number\n resamples: number\n confidence: number\n baseWinRate: number\n baseLossRate: number\n noisy: Map<number, number>\n}\n\n/**\n * One effect point. Loss probability is min(baseLoss, (1-effect)/2) and\n * win probability is loss probability plus effect. Their difference equals\n * effect, including near the probability boundary. Noisy clusters draw win\n * and loss independently at their\n * flip rate. Each trial computes a whole-cluster percentile bootstrap of the\n * pooled row mean; the trial counts toward power when the interval excludes\n * zero.\n */\nfunction simulateEffect(effect: number, config: SimulationConfig): ClusteredPowerPoint {\n const rng = mulberry32(mixSeed(config.seed, effect))\n const clusterCount = config.clusterSizes.length\n let excludes = 0\n const widths = new Array<number>(config.trials)\n const sums = new Array<number>(clusterCount)\n const means = new Array<number>(config.resamples)\n for (let trial = 0; trial < config.trials; trial++) {\n for (let cluster = 0; cluster < clusterCount; cluster++) {\n const size = config.clusterSizes[cluster]!\n const flipRate = config.noisy.get(cluster)\n let sum = 0\n for (let row = 0; row < size; row++) {\n if (flipRate !== undefined) {\n const win = rng() < flipRate ? 1 : 0\n const loss = rng() < flipRate ? 1 : 0\n sum += win - loss\n } else {\n const lossRate = Math.min(config.baseLossRate, (1 - effect) / 2)\n const winRate = lossRate + effect\n const u = rng()\n sum += u < winRate ? 1 : u < winRate + lossRate ? -1 : 0\n }\n }\n sums[cluster] = sum\n }\n for (let draw = 0; draw < config.resamples; draw++) {\n let pooledSum = 0\n let pooledRows = 0\n for (let pick = 0; pick < clusterCount; pick++) {\n const index = Math.floor(rng() * clusterCount)\n pooledSum += sums[index]!\n pooledRows += config.clusterSizes[index]!\n }\n means[draw] = pooledSum / pooledRows\n }\n means.sort((a, b) => a - b)\n const tail = 1 - config.confidence\n const lower = means[Math.floor((tail / 2) * config.resamples)]!\n const upper =\n means[\n Math.max(\n Math.floor((tail / 2) * config.resamples),\n Math.min(config.resamples - 1, Math.ceil((1 - tail / 2) * config.resamples) - 1),\n )\n ]!\n widths[trial] = upper - lower\n if (lower > 0 || upper < 0) excludes += 1\n }\n widths.sort((a, b) => a - b)\n return {\n effect,\n power: excludes / config.trials,\n medianCiWidth: widths[Math.floor(config.trials / 2)]!,\n }\n}\n\n/** Fold the effect into the seed so every grid point draws an independent stream. */\nfunction mixSeed(seed: number, effect: number): number {\n const scaled = Math.round(effect * 1_000_003)\n return ((seed ^ (scaled * 0x9e3779b9)) >>> 0) | 0\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { p as EvidenceRef } from "./types-DzuaM493.js";
1
+ import { p as EvidenceRef } from "./types-D7gEdPoQ.js";
2
2
  //#region src/statistics/power-and-mde.d.ts
3
3
  /**
4
4
  * Required N per arm for a two-sample comparison at target effect size,
@@ -234,4 +234,4 @@ declare class ExperimentTracker {
234
234
  }
235
235
  //#endregion
236
236
  export { requiredSampleSize as _, ExperimentVerdict as a, computeExperimentStats as c, inMemoryExperimentStore as d, mulberry32 as f, requiredPairedSampleSize as g, pairedMde as h, ExperimentTracker as i, fileExperimentStore as l, mcnemarRequiredN as m, ExperimentRep as n, ImprovementThresholds as o, mcnemarPower as p, ExperimentStats as r, ImprovementVerdictResult as s, Experiment as t, improvementVerdict as u };
237
- //# sourceMappingURL=experiment-tracker-B3TiF5-u.d.ts.map
237
+ //# sourceMappingURL=experiment-tracker-C7PfnF4b.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"experiment-tracker-B3TiF5-u.d.ts","names":[],"sources":["../src/statistics/power-and-mde.ts","../src/statistics/random.ts","../src/experiment-tracker.ts"],"mappings":";;;;;;;;iBAWgB,mBAAmB;EACjC;EACA;EACA;EACA;;;;;;;;;;;iBAsBc,yBAAyB;EACvC;EACA;EACA;EACA;;;;;;;;iBAkBc,UAAU;EACxB;EACA;EACA;EACA;;;;;;;;;;;;;;;;iBAyBc,iBAAiB;EAC/B;EACA;EACA;EACA;EACA;;;;;;;iBAyBc,aAAa;EAC3B;EACA;EACA;EACA;EACA;;;;;;;;iBCrHc,WAAW;;;;;KCyBf;;UAGK;;EAEf;;EAEA;;EAEA;;;;UAKe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;EAEA,UAAU;;UAGK;EACf;EACA;EACA;EACA;;EAEA;;EAEA;;;EAGA;;EAEA;;EAEA;;UAGe;;EAEf;;EAEA;;EAEA,YAAY;;EAEZ;;EAEA;EACA,MAAM;EACN,OAAO;EACP,SAAS;;EAET;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;;EAGA;;UAGe;EACf,SAAS;;EAET;;EAEA;;;;;;;iBAkDc,uBACd,MAAM,iBACN,aAAa,wBACZ;;;;;;;iBAgDa,mBACd,WAAW,iBACX,QAAQ,wBACR,aAAa,wBACZ;;;KA6CS,yBAAyB,uBAAuB,QAAQ;;;UAInD;EACf,QAAQ,QAAQ;EAChB,KAAK,aAAa,eAAe;;;;iBAoBnB,wBAAwB,UAAS,eAAoB;;iBAarD,oBAAoB,eAAe;UAyBlC;EACf,QAAQ;EACR,mBAAmB;EACnB,aAAa;;EAEb;;UAGe;EACf;EACA;EACA;EACA;;EAEA,aAAa;;;;;;;;;cAUF;mBACM;mBACA;mBACA;mBACA;EAEjB,YAAY,UAAS;EAOf,OAAO,OAAO,wBAAwB,QAAQ;;;EA6B9C,OACJ,sBACA,KAAK,KAAK;IAAwC;IAAc;MAC/D,QAAQ;EAqCL,IAAI,uBAAuB,QAAQ;EAMnC,QAAQ,QAAQ;;EAKhB,WAAW,uBAAuB,QAAQ"}
1
+ {"version":3,"file":"experiment-tracker-C7PfnF4b.d.ts","names":[],"sources":["../src/statistics/power-and-mde.ts","../src/statistics/random.ts","../src/experiment-tracker.ts"],"mappings":";;;;;;;;iBAWgB,mBAAmB;EACjC;EACA;EACA;EACA;;;;;;;;;;;iBAsBc,yBAAyB;EACvC;EACA;EACA;EACA;;;;;;;;iBAkBc,UAAU;EACxB;EACA;EACA;EACA;;;;;;;;;;;;;;;;iBAyBc,iBAAiB;EAC/B;EACA;EACA;EACA;EACA;;;;;;;iBAyBc,aAAa;EAC3B;EACA;EACA;EACA;EACA;;;;;;;;iBCrHc,WAAW;;;;;KCyBf;;UAGK;;EAEf;;EAEA;;EAEA;;;;UAKe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;EAEA,UAAU;;UAGK;EACf;EACA;EACA;EACA;;EAEA;;EAEA;;;EAGA;;EAEA;;EAEA;;UAGe;;EAEf;;EAEA;;EAEA,YAAY;;EAEZ;;EAEA;EACA,MAAM;EACN,OAAO;EACP,SAAS;;EAET;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;;EAGA;;UAGe;EACf,SAAS;;EAET;;EAEA;;;;;;;iBAkDc,uBACd,MAAM,iBACN,aAAa,wBACZ;;;;;;;iBAgDa,mBACd,WAAW,iBACX,QAAQ,wBACR,aAAa,wBACZ;;;KA6CS,yBAAyB,uBAAuB,QAAQ;;;UAInD;EACf,QAAQ,QAAQ;EAChB,KAAK,aAAa,eAAe;;;;iBAoBnB,wBAAwB,UAAS,eAAoB;;iBAarD,oBAAoB,eAAe;UAyBlC;EACf,QAAQ;EACR,mBAAmB;EACnB,aAAa;;EAEb;;UAGe;EACf;EACA;EACA;EACA;;EAEA,aAAa;;;;;;;;;cAUF;mBACM;mBACA;mBACA;mBACA;EAEjB,YAAY,UAAS;EAOf,OAAO,OAAO,wBAAwB,QAAQ;;;EA6B9C,OACJ,sBACA,KAAK,KAAK;IAAwC;IAAc;MAC/D,QAAQ;EAqCL,IAAI,uBAAuB,QAAQ;EAMnC,QAAQ,QAAQ;;EAKhB,WAAW,uBAAuB,QAAQ"}
@@ -1,6 +1,6 @@
1
1
  import { n as contentHash } from "./verdict-cache-B3eCVQtY.js";
2
- import { h as tryAcquireAtomicFileLock, m as probeAtomicFileLock } from "./ledger-core-Cs9f7385.js";
3
- import { a as closeServer, c as waitForActiveHandlers, g as isRecord, h as isExternalTextCandidate, o as listenLocal, s as sendJsonIfOpen, v as resolveExternalOptimizerCallbackLimits } from "./external-optimizer-subprocess-q3VzlGAO.js";
2
+ import { h as tryAcquireAtomicFileLock, m as probeAtomicFileLock } from "./journal-Cs9f7385.js";
3
+ import { a as closeServer, c as waitForActiveHandlers, g as isRecord, h as isExternalTextCandidate, o as listenLocal, s as sendJsonIfOpen, v as resolveExternalOptimizerCallbackLimits } from "./external-optimizer-subprocess-D4dzUBZI.js";
4
4
  import { createServer } from "node:http";
5
5
  //#region src/campaign/single-run-lock.ts
6
6
  /**
@@ -291,4 +291,4 @@ function cloneCandidate(candidate) {
291
291
  //#endregion
292
292
  export { acquireSingleRunLock as n, startExternalOptimizerCallback as t };
293
293
 
294
- //# sourceMappingURL=external-optimizer-process-Dlz8YxrT.js.map
294
+ //# sourceMappingURL=external-optimizer-process-QDRURJAM.js.map