@tangle-network/agent-eval 0.150.2 → 0.161.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 (342) hide show
  1. package/CHANGELOG.md +149 -1
  2. package/README.md +7 -3
  3. package/dist/{active-curriculum-C4mk67HP.js → active-curriculum-CD5TU2yW.js} +3 -13
  4. package/dist/active-curriculum-CD5TU2yW.js.map +1 -0
  5. package/dist/{agent-profile-cell-BkcRDikH.d.ts → agent-profile-cell-CTOZJUuE.d.ts} +4 -2
  6. package/dist/agent-profile-cell-CTOZJUuE.d.ts.map +1 -0
  7. package/dist/analyst/index.d.ts +19 -36
  8. package/dist/analyst/index.d.ts.map +1 -1
  9. package/dist/analyst/index.js +8 -8
  10. package/dist/analyst/index.js.map +1 -1
  11. package/dist/{backend-integrity-DOCa_QrR.d.ts → backend-integrity-DxuQCu_A.d.ts} +4 -3
  12. package/dist/backend-integrity-DxuQCu_A.d.ts.map +1 -0
  13. package/dist/{benchmark-BtAWA8nT.d.ts → benchmark-CGPp-kDC.d.ts} +3 -3
  14. package/dist/{benchmark-BtAWA8nT.d.ts.map → benchmark-CGPp-kDC.d.ts.map} +1 -1
  15. package/dist/{benchmark-command-BU1Las59.js → benchmark-command-BVtaq_ve.js} +26 -31
  16. package/dist/benchmark-command-BVtaq_ve.js.map +1 -0
  17. package/dist/benchmarks/index.d.ts +6 -19
  18. package/dist/benchmarks/index.d.ts.map +1 -1
  19. package/dist/benchmarks/index.js +4 -4
  20. package/dist/benchmarks/index.js.map +1 -1
  21. package/dist/builder-eval/index.d.ts +3 -3
  22. package/dist/builder-eval/index.js +2 -2
  23. package/dist/campaign/index.d.ts +9 -9
  24. package/dist/campaign/index.js +7 -7
  25. package/dist/{campaign-la-gEYNz.js → campaign-BSmOwskD.js} +77 -795
  26. package/dist/campaign-BSmOwskD.js.map +1 -0
  27. package/dist/{canonical-D-XsTQ6_.js → canonical-IL-Bu-14.js} +26 -2
  28. package/dist/canonical-IL-Bu-14.js.map +1 -0
  29. package/dist/{capture-fetch-BBVFzhkk.d.ts → capture-fetch-CqwsJkkG.d.ts} +3 -3
  30. package/dist/{capture-fetch-BBVFzhkk.d.ts.map → capture-fetch-CqwsJkkG.d.ts.map} +1 -1
  31. package/dist/{chat-client-Bvmxedyv.js → chat-client-DlMlAeYI.js} +5 -55
  32. package/dist/{chat-client-Bvmxedyv.js.map → chat-client-DlMlAeYI.js.map} +1 -1
  33. package/dist/chat-json-call-6g5sJobJ.js +53 -0
  34. package/dist/chat-json-call-6g5sJobJ.js.map +1 -0
  35. package/dist/cli.js +54 -19
  36. package/dist/cli.js.map +1 -1
  37. package/dist/{client-LIuo-KPv.js → client-CX7KqIdB.js} +3 -3
  38. package/dist/client-CX7KqIdB.js.map +1 -0
  39. package/dist/{client-kPQYT_56.d.ts → client-L9VVPkim.d.ts} +4 -4
  40. package/dist/{client-kPQYT_56.d.ts.map → client-L9VVPkim.d.ts.map} +1 -1
  41. package/dist/contract/index.d.ts +13 -27
  42. package/dist/contract/index.d.ts.map +1 -1
  43. package/dist/contract/index.js +14 -17
  44. package/dist/contract/index.js.map +1 -1
  45. package/dist/{counterfactual--bpysZF0.d.ts → counterfactual-BaFUWK3H.d.ts} +4 -4
  46. package/dist/{counterfactual--bpysZF0.d.ts.map → counterfactual-BaFUWK3H.d.ts.map} +1 -1
  47. package/dist/{counterfactual-lDfCx0Uz.js → counterfactual-D_VWavVm.js} +2 -2
  48. package/dist/{counterfactual-lDfCx0Uz.js.map → counterfactual-D_VWavVm.js.map} +1 -1
  49. package/dist/{dataset-CJjKqQfA.d.ts → dataset-DQqhOCPt.d.ts} +5 -4
  50. package/dist/{dataset-CJjKqQfA.d.ts.map → dataset-DQqhOCPt.d.ts.map} +1 -1
  51. package/dist/{default-registry-Cw0Ohdoj.d.ts → default-registry-G9CKMNkc.d.ts} +7 -8
  52. package/dist/{default-registry-Cw0Ohdoj.d.ts.map → default-registry-G9CKMNkc.d.ts.map} +1 -1
  53. package/dist/{define-agent-eval-CEQWL9Hy.d.ts → define-agent-eval-Dx1JnPEa.d.ts} +26 -6
  54. package/dist/define-agent-eval-Dx1JnPEa.d.ts.map +1 -0
  55. package/dist/{define-agent-eval-C8V8sMqP.js → define-agent-eval-h-s-sI-v.js} +15 -9
  56. package/dist/define-agent-eval-h-s-sI-v.js.map +1 -0
  57. package/dist/{dspy-rlm-engine-CBYlPvNy.js → dspy-rlm-engine-DptEII26.js} +95 -15
  58. package/dist/dspy-rlm-engine-DptEII26.js.map +1 -0
  59. package/dist/{emitter-CPBAhxum.js → emitter-BpYFQPj4.js} +2 -18
  60. package/dist/emitter-BpYFQPj4.js.map +1 -0
  61. package/dist/{emitter-DGQGoLyj.d.ts → emitter-D_jYSGRd.d.ts} +4 -20
  62. package/dist/{emitter-DGQGoLyj.d.ts.map → emitter-D_jYSGRd.d.ts.map} +1 -1
  63. package/dist/{engine-BLzhNzoY.d.ts → engine-Cu5qD5Fc.d.ts} +9 -11
  64. package/dist/{engine-BLzhNzoY.d.ts.map → engine-Cu5qD5Fc.d.ts.map} +1 -1
  65. package/dist/{eval-campaign-CQuZrLR_.js → eval-campaign-BsXWL2-2.js} +17 -28
  66. package/dist/eval-campaign-BsXWL2-2.js.map +1 -0
  67. package/dist/{exact-types-ccQAyut1.d.ts → exact-types-qnexxJ1Z.d.ts} +2 -2
  68. package/dist/{exact-types-ccQAyut1.d.ts.map → exact-types-qnexxJ1Z.d.ts.map} +1 -1
  69. package/dist/{exec-y-DCLqK7.js → exec-D9WpA2p-.js} +2 -2
  70. package/dist/exec-D9WpA2p-.js.map +1 -0
  71. package/dist/experiment/index.d.ts +45 -11
  72. package/dist/experiment/index.d.ts.map +1 -1
  73. package/dist/experiment/index.js +30 -11
  74. package/dist/experiment/index.js.map +1 -1
  75. package/dist/{experiment-tracker-0MhuPArU.d.ts → experiment-tracker-DCO6Cz4s.d.ts} +2 -2
  76. package/dist/{experiment-tracker-0MhuPArU.d.ts.map → experiment-tracker-DCO6Cz4s.d.ts.map} +1 -1
  77. package/dist/{exporters-q9iL-2Jf.js → exporters-Df7TgHFv.js} +3 -3
  78. package/dist/exporters-Df7TgHFv.js.map +1 -0
  79. package/dist/{external-optimizer-contracts-DbLsm4Po.d.ts → external-optimizer-contracts-szBJ_1vh.d.ts} +2 -2
  80. package/dist/{external-optimizer-contracts-DbLsm4Po.d.ts.map → external-optimizer-contracts-szBJ_1vh.d.ts.map} +1 -1
  81. package/dist/{external-optimizer-process-x9oEXKsU.js → external-optimizer-process-WosTBChy.js} +4 -4
  82. package/dist/{external-optimizer-process-x9oEXKsU.js.map → external-optimizer-process-WosTBChy.js.map} +1 -1
  83. package/dist/{external-optimizer-subprocess-CKNb42oM.js → external-optimizer-subprocess-BIWbHpgD.js} +4 -4
  84. package/dist/{external-optimizer-subprocess-CKNb42oM.js.map → external-optimizer-subprocess-BIWbHpgD.js.map} +1 -1
  85. package/dist/{failure-cluster-BLURuWG4.d.ts → failure-cluster-CXL8NbEw.d.ts} +3 -3
  86. package/dist/{failure-cluster-BLURuWG4.d.ts.map → failure-cluster-CXL8NbEw.d.ts.map} +1 -1
  87. package/dist/{feedback-trajectory-DpTTjo0q.d.ts → feedback-trajectory-B3ZHaHV_.d.ts} +7 -7
  88. package/dist/{feedback-trajectory-DpTTjo0q.d.ts.map → feedback-trajectory-B3ZHaHV_.d.ts.map} +1 -1
  89. package/dist/fuzz.js +1 -1
  90. package/dist/{hf-dataset-XggBupCr.js → hf-dataset-D8_RNIis.js} +4 -4
  91. package/dist/{hf-dataset-XggBupCr.js.map → hf-dataset-D8_RNIis.js.map} +1 -1
  92. package/dist/hosted/index.d.ts +3 -14
  93. package/dist/hosted/index.d.ts.map +1 -1
  94. package/dist/hosted/index.js +2 -2
  95. package/dist/{index-Aj3WO3_a.d.ts → index-CGtH1piv.d.ts} +48 -26
  96. package/dist/index-CGtH1piv.d.ts.map +1 -0
  97. package/dist/{index-BNPtkBPf.d.ts → index-D-IiQIBB.d.ts} +5 -10
  98. package/dist/index-D-IiQIBB.d.ts.map +1 -0
  99. package/dist/{index-IQccV3Ou.d.ts → index-D-V8gCs_.d.ts} +13 -90
  100. package/dist/index-D-V8gCs_.d.ts.map +1 -0
  101. package/dist/{index-B8Ui1mr1.d.ts → index-lfaSeKSD.d.ts} +18 -2
  102. package/dist/index-lfaSeKSD.d.ts.map +1 -0
  103. package/dist/index-vrJugRal.d.ts +1 -0
  104. package/dist/index.d.ts +68 -56
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +59 -110
  107. package/dist/index.js.map +1 -1
  108. package/dist/{insight-report-BeT8KCgI.d.ts → insight-report-DRe8LB6d.d.ts} +4 -4
  109. package/dist/{insight-report-BeT8KCgI.d.ts.map → insight-report-DRe8LB6d.d.ts.map} +1 -1
  110. package/dist/{integrity-DL91tucI.js → integrity-CyWSSoQS.js} +2 -2
  111. package/dist/{integrity-DL91tucI.js.map → integrity-CyWSSoQS.js.map} +1 -1
  112. package/dist/{integrity-B0dZ96EO.d.ts → integrity-DUNX9Fao.d.ts} +3 -3
  113. package/dist/{integrity-B0dZ96EO.d.ts.map → integrity-DUNX9Fao.d.ts.map} +1 -1
  114. package/dist/{kind-factory-DmAa0h3K.js → kind-factory-DY8FdoXf.js} +3 -71
  115. package/dist/kind-factory-DY8FdoXf.js.map +1 -0
  116. package/dist/ledger-core/index.d.ts +2 -2
  117. package/dist/ledger-core/index.js +3 -3
  118. package/dist/{ledger-core-DTae9rv_.js → ledger-core-BOzlRygb.js} +2 -2
  119. package/dist/{ledger-core-DTae9rv_.js.map → ledger-core-BOzlRygb.js.map} +1 -1
  120. package/dist/{llm-client-Bg32RW0j.js → llm-client-hgDieDNN.js} +53 -98
  121. package/dist/llm-client-hgDieDNN.js.map +1 -0
  122. package/dist/{llm-judge-BqqMS8t7.js → llm-judge-BhasIPFT.js} +1135 -77
  123. package/dist/llm-judge-BhasIPFT.js.map +1 -0
  124. package/dist/{matrix-DrVnRp4G.d.ts → matrix-eXKRMHnL.d.ts} +74 -72
  125. package/dist/matrix-eXKRMHnL.d.ts.map +1 -0
  126. package/dist/meta-eval/index.d.ts +8 -6
  127. package/dist/meta-eval/index.d.ts.map +1 -1
  128. package/dist/meta-eval/index.js +8 -6
  129. package/dist/meta-eval/index.js.map +1 -1
  130. package/dist/{mint-BV6tLVWl.js → mint-DfODW1KW.js} +3 -3
  131. package/dist/{mint-BV6tLVWl.js.map → mint-DfODW1KW.js.map} +1 -1
  132. package/dist/multishot/golden/index.d.ts +2 -8
  133. package/dist/multishot/golden/index.d.ts.map +1 -1
  134. package/dist/multishot/golden/index.js +56 -86
  135. package/dist/multishot/golden/index.js.map +1 -1
  136. package/dist/multishot/index.d.ts +11 -46
  137. package/dist/multishot/index.d.ts.map +1 -1
  138. package/dist/multishot/index.js +30 -83
  139. package/dist/multishot/index.js.map +1 -1
  140. package/dist/openapi.json +1 -1
  141. package/dist/{opencode-sqlite-DJWAXLms.js → opencode-sqlite-eK6HW6dr.js} +2 -6
  142. package/dist/{opencode-sqlite-DJWAXLms.js.map → opencode-sqlite-eK6HW6dr.js.map} +1 -1
  143. package/dist/pipelines/index.d.ts +5 -5
  144. package/dist/pipelines/index.js +3 -3
  145. package/dist/{pre-registration-zFSLEiFU.d.ts → pre-registration-CzFCcwYk.d.ts} +55 -40
  146. package/dist/pre-registration-CzFCcwYk.d.ts.map +1 -0
  147. package/dist/pre-registration-KN9jkh58.js +110 -0
  148. package/dist/pre-registration-KN9jkh58.js.map +1 -0
  149. package/dist/{produced-state-Bnq4FaDO.js → produced-state-DZ89riy5.js} +8 -8
  150. package/dist/produced-state-DZ89riy5.js.map +1 -0
  151. package/dist/profile-cell.d.ts +1 -1
  152. package/dist/profile-cell.js +31 -5
  153. package/dist/profile-cell.js.map +1 -1
  154. package/dist/{promotion-policy-DLOUkYhI.d.ts → promotion-policy-DtnOIZvk.d.ts} +2 -2
  155. package/dist/{promotion-policy-DLOUkYhI.d.ts.map → promotion-policy-DtnOIZvk.d.ts.map} +1 -1
  156. package/dist/{query-Di7eEQ79.js → query-CHmMP42p.js} +20 -11
  157. package/dist/query-CHmMP42p.js.map +1 -0
  158. package/dist/{query-CJ_DX8vl.d.ts → query-DxPYqpmT.d.ts} +10 -4
  159. package/dist/query-DxPYqpmT.d.ts.map +1 -0
  160. package/dist/raw-provider-sink-BU29Sh8h.d.ts +134 -0
  161. package/dist/raw-provider-sink-BU29Sh8h.d.ts.map +1 -0
  162. package/dist/{registry-BQwrSYpC.d.ts → registry-8You7OK1.d.ts} +5 -7
  163. package/dist/{registry-BQwrSYpC.d.ts.map → registry-8You7OK1.d.ts.map} +1 -1
  164. package/dist/{release-confidence-BknrpBnO.js → release-confidence-DKfD2RYU.js} +28 -14
  165. package/dist/release-confidence-DKfD2RYU.js.map +1 -0
  166. package/dist/{release-confidence-4XrqlpFD.d.ts → release-confidence-Dqt0NFep.d.ts} +7 -6
  167. package/dist/release-confidence-Dqt0NFep.d.ts.map +1 -0
  168. package/dist/reporting.d.ts +3 -3
  169. package/dist/reporting.js +3 -3
  170. package/dist/{researcher-DJnoUE8c.d.ts → researcher-Cz565b7D.d.ts} +34 -21
  171. package/dist/researcher-Cz565b7D.d.ts.map +1 -0
  172. package/dist/{reward-hacking-62tojkQd.d.ts → reward-hacking-MBf7qpSB.d.ts} +2 -2
  173. package/dist/{reward-hacking-62tojkQd.d.ts.map → reward-hacking-MBf7qpSB.d.ts.map} +1 -1
  174. package/dist/{reward-hacking-C0x0xihA.js → reward-hacking-t4lB1yt8.js} +2 -2
  175. package/dist/{reward-hacking-C0x0xihA.js.map → reward-hacking-t4lB1yt8.js.map} +1 -1
  176. package/dist/rl.d.ts +11 -42
  177. package/dist/rl.d.ts.map +1 -1
  178. package/dist/rl.js +41 -24
  179. package/dist/rl.js.map +1 -1
  180. package/dist/rollout/index.d.ts +3 -3
  181. package/dist/rollout/index.js +7 -7
  182. package/dist/{rollout-ytVQ7WT8.js → rollout-Dm2tSdiQ.js} +6 -6
  183. package/dist/{rollout-ytVQ7WT8.js.map → rollout-Dm2tSdiQ.js.map} +1 -1
  184. package/dist/{rubric-predictive-validity-CzxLoZge.js → rubric-predictive-validity-CK8SCOg-.js} +5 -15
  185. package/dist/rubric-predictive-validity-CK8SCOg-.js.map +1 -0
  186. package/dist/{rubric-predictive-validity-C7LnNvF2.d.ts → rubric-predictive-validity-CxycqzX5.d.ts} +4 -3
  187. package/dist/rubric-predictive-validity-CxycqzX5.d.ts.map +1 -0
  188. package/dist/{run-record-D2lDdSAz.js → run-record-BC0ebuRP.js} +2 -2
  189. package/dist/{run-record-D2lDdSAz.js.map → run-record-BC0ebuRP.js.map} +1 -1
  190. package/dist/{run-record-DVV82Gwh.d.ts → run-record-VVy4T9OW.d.ts} +3 -3
  191. package/dist/{run-record-DVV82Gwh.d.ts.map → run-record-VVy4T9OW.d.ts.map} +1 -1
  192. package/dist/{schema-BtVldJ3T.d.ts → schema-Bjgdsn73.d.ts} +2 -4
  193. package/dist/{schema-BtVldJ3T.d.ts.map → schema-Bjgdsn73.d.ts.map} +1 -1
  194. package/dist/{schema-Cef2cFmb.d.ts → schema-BzWDXhOR.d.ts} +2 -5
  195. package/dist/schema-BzWDXhOR.d.ts.map +1 -0
  196. package/dist/{schema-C6DW4ZHR.js → schema-C1aaAxTf.js} +2 -2
  197. package/dist/schema-C1aaAxTf.js.map +1 -0
  198. package/dist/{schema-CRhEY1SO.js → schema-k6ZBftVv.js} +2 -8
  199. package/dist/{schema-CRhEY1SO.js.map → schema-k6ZBftVv.js.map} +1 -1
  200. package/dist/{semantic-concept-judge-laMCnTLn.js → semantic-concept-judge-BSkKKHeq.js} +14 -38
  201. package/dist/semantic-concept-judge-BSkKKHeq.js.map +1 -0
  202. package/dist/{sequential-eprocess-CbUt2htw.js → sequential-eprocess-D1jKoihe.js} +49 -2
  203. package/dist/sequential-eprocess-D1jKoihe.js.map +1 -0
  204. package/dist/{sequential-C458DXNf.js → sequential-rYW-Ophm.js} +41 -16
  205. package/dist/sequential-rYW-Ophm.js.map +1 -0
  206. package/dist/{series-convergence-BxKEgBwA.d.ts → series-convergence-D9WgpXGi.d.ts} +2 -2
  207. package/dist/{series-convergence-BxKEgBwA.d.ts.map → series-convergence-D9WgpXGi.d.ts.map} +1 -1
  208. package/dist/{server-dIWwF3j_.js → server-BtFd4uzB.js} +19 -42
  209. package/dist/server-BtFd4uzB.js.map +1 -0
  210. package/dist/{skillopt-optimization-method-CPBlTcj5.js → skillopt-optimization-method-DbaekMcn.js} +794 -8
  211. package/dist/skillopt-optimization-method-DbaekMcn.js.map +1 -0
  212. package/dist/{skillopt-optimization-method-BDD_o1xE.d.ts → skillopt-optimization-method-x7TTF23P.d.ts} +20 -7
  213. package/dist/{skillopt-optimization-method-BDD_o1xE.d.ts.map → skillopt-optimization-method-x7TTF23P.d.ts.map} +1 -1
  214. package/dist/{statistical-heldout-_woZ9q9j.d.ts → statistical-heldout-Cy3EhjlC.d.ts} +21 -8
  215. package/dist/statistical-heldout-Cy3EhjlC.d.ts.map +1 -0
  216. package/dist/{steps-AmkT-GIM.d.ts → steps-CiNVJry_.d.ts} +2 -17
  217. package/dist/steps-CiNVJry_.d.ts.map +1 -0
  218. package/dist/{store-CT9YIIve.d.ts → store-B06JdC56.d.ts} +2 -2
  219. package/dist/{store-CT9YIIve.d.ts.map → store-B06JdC56.d.ts.map} +1 -1
  220. package/dist/{store-otlp-CDYWW_8N.js → store-otlp-C_Rq5I4D.js} +2 -2
  221. package/dist/{store-otlp-CDYWW_8N.js.map → store-otlp-C_Rq5I4D.js.map} +1 -1
  222. package/dist/{store-tool-spans-Br2_IUhm.d.ts → store-tool-spans-DPUG7UUY.d.ts} +6 -6
  223. package/dist/{store-tool-spans-Br2_IUhm.d.ts.map → store-tool-spans-DPUG7UUY.d.ts.map} +1 -1
  224. package/dist/{store-tool-spans-CykkbOlv.js → store-tool-spans-Dlh9vkFK.js} +3 -3
  225. package/dist/{store-tool-spans-CykkbOlv.js.map → store-tool-spans-Dlh9vkFK.js.map} +1 -1
  226. package/dist/storyboard/index.d.ts +1 -1
  227. package/dist/{summary-report-DW2bEpdB.js → summary-report-BI5hUtvK.js} +6 -16
  228. package/dist/summary-report-BI5hUtvK.js.map +1 -0
  229. package/dist/{summary-report-B__Y5ub3.d.ts → summary-report-CC07PhEL.d.ts} +6 -5
  230. package/dist/summary-report-CC07PhEL.d.ts.map +1 -0
  231. package/dist/supervisor-run/index.d.ts +3 -16
  232. package/dist/supervisor-run/index.d.ts.map +1 -1
  233. package/dist/supervisor-run/index.js +3 -3
  234. package/dist/supervisor-run/index.js.map +1 -1
  235. package/dist/{task-failure-attributes--ZTP3tYO.js → task-failure-attributes-DTl-7-Kw.js} +3 -3
  236. package/dist/{task-failure-attributes--ZTP3tYO.js.map → task-failure-attributes-DTl-7-Kw.js.map} +1 -1
  237. package/dist/{tool-groups-B4tqh8jB.d.ts → tool-groups-Ci8i9ErB.d.ts} +3 -3
  238. package/dist/tool-groups-Ci8i9ErB.d.ts.map +1 -0
  239. package/dist/{tool-waste-C-VHSRwF.js → tool-waste-BqzmVdJk.js} +2 -2
  240. package/dist/{tool-waste-C-VHSRwF.js.map → tool-waste-BqzmVdJk.js.map} +1 -1
  241. package/dist/{tool-waste-DjRDEsuI.d.ts → tool-waste-Dro0gJi3.d.ts} +4 -4
  242. package/dist/{tool-waste-DjRDEsuI.d.ts.map → tool-waste-Dro0gJi3.d.ts.map} +1 -1
  243. package/dist/trace-repair/index.d.ts +4 -77
  244. package/dist/trace-repair/index.d.ts.map +1 -1
  245. package/dist/trace-repair/index.js +5 -15
  246. package/dist/trace-repair/index.js.map +1 -1
  247. package/dist/traces.d.ts +13 -23
  248. package/dist/traces.d.ts.map +1 -1
  249. package/dist/traces.js +9 -20
  250. package/dist/traces.js.map +1 -1
  251. package/dist/{trajectory-YC15QDYQ.d.ts → trajectory-Bi157Gun.d.ts} +3 -3
  252. package/dist/{trajectory-YC15QDYQ.d.ts.map → trajectory-Bi157Gun.d.ts.map} +1 -1
  253. package/dist/trajectory-replay/index.d.ts +5 -5
  254. package/dist/trajectory-replay/index.js +5 -5
  255. package/dist/{provenance-oA4-zUqm.d.ts → transient-failure-DKF5Mofa.d.ts} +468 -13
  256. package/dist/transient-failure-DKF5Mofa.d.ts.map +1 -0
  257. package/dist/types-B3jzCp0p.js.map +1 -1
  258. package/dist/{types-CLAwnY-L.d.ts → types-BPb2Kf_C2.d.ts} +3 -3
  259. package/dist/types-BPb2Kf_C2.d.ts.map +1 -0
  260. package/dist/types-Bfk0uxRj.d.ts +443 -0
  261. package/dist/types-Bfk0uxRj.d.ts.map +1 -0
  262. package/dist/{types-DdFNuyxQ.d.ts → types-D4s7Z6nq.d.ts} +30 -6
  263. package/dist/types-D4s7Z6nq.d.ts.map +1 -0
  264. package/dist/{types-B2NsbrNy.d.ts → types-D9ssmxKL.d.ts} +3 -3
  265. package/dist/{types-B2NsbrNy.d.ts.map → types-D9ssmxKL.d.ts.map} +1 -1
  266. package/dist/{types-I5WwVzQ7.d.ts → types-DeIUdzNd.d.ts} +2 -2
  267. package/dist/{types-I5WwVzQ7.d.ts.map → types-DeIUdzNd.d.ts.map} +1 -1
  268. package/dist/{verdict-BndeTAh_.js → verdict-B0xltqu6.js} +2 -2
  269. package/dist/{verdict-BndeTAh_.js.map → verdict-B0xltqu6.js.map} +1 -1
  270. package/dist/verdict-cache-CdVVTVmn.js +88 -0
  271. package/dist/verdict-cache-CdVVTVmn.js.map +1 -0
  272. package/dist/wire/index.d.ts +21 -111
  273. package/dist/wire/index.d.ts.map +1 -1
  274. package/dist/wire/index.js +2 -2
  275. package/docs/building-doctrine.md +3 -3
  276. package/docs/campaign-proposers.md +41 -10
  277. package/docs/design/statistics-decisions.md +89 -1
  278. package/docs/eval-surface-map.md +14 -0
  279. package/docs/experiment.md +19 -2
  280. package/docs/feedback-trajectories.md +1 -1
  281. package/docs/multishot-golden-records.md +4 -4
  282. package/docs/public-api.md +1616 -0
  283. package/docs/research-report-methodology.md +1 -1
  284. package/docs/search-history-receipts.md +39 -1
  285. package/docs/trace-analysis.md +1 -1
  286. package/docs/trace-repair-admission.md +1 -1
  287. package/docs/trace-repair-continuation.md +1 -1
  288. package/docs/verdicts.md +24 -0
  289. package/package.json +6 -2
  290. package/dist/active-curriculum-C4mk67HP.js.map +0 -1
  291. package/dist/agent-profile-cell-BkcRDikH.d.ts.map +0 -1
  292. package/dist/backend-integrity-DOCa_QrR.d.ts.map +0 -1
  293. package/dist/benchmark-command-BU1Las59.js.map +0 -1
  294. package/dist/campaign-la-gEYNz.js.map +0 -1
  295. package/dist/canonical-D-XsTQ6_.js.map +0 -1
  296. package/dist/client-LIuo-KPv.js.map +0 -1
  297. package/dist/define-agent-eval-C8V8sMqP.js.map +0 -1
  298. package/dist/define-agent-eval-CEQWL9Hy.d.ts.map +0 -1
  299. package/dist/dspy-rlm-engine-CBYlPvNy.js.map +0 -1
  300. package/dist/emitter-CPBAhxum.js.map +0 -1
  301. package/dist/eval-campaign-CQuZrLR_.js.map +0 -1
  302. package/dist/exec-y-DCLqK7.js.map +0 -1
  303. package/dist/exporters-q9iL-2Jf.js.map +0 -1
  304. package/dist/index-Aj3WO3_a.d.ts.map +0 -1
  305. package/dist/index-B8Ui1mr1.d.ts.map +0 -1
  306. package/dist/index-BNPtkBPf.d.ts.map +0 -1
  307. package/dist/index-C1ravkGA.d.ts +0 -1
  308. package/dist/index-IQccV3Ou.d.ts.map +0 -1
  309. package/dist/kind-factory-DmAa0h3K.js.map +0 -1
  310. package/dist/llm-client-Bg32RW0j.js.map +0 -1
  311. package/dist/llm-judge-BqqMS8t7.js.map +0 -1
  312. package/dist/matrix-DrVnRp4G.d.ts.map +0 -1
  313. package/dist/pre-registration-DakwTRXk.js +0 -96
  314. package/dist/pre-registration-DakwTRXk.js.map +0 -1
  315. package/dist/pre-registration-zFSLEiFU.d.ts.map +0 -1
  316. package/dist/produced-state-Bnq4FaDO.js.map +0 -1
  317. package/dist/provenance-oA4-zUqm.d.ts.map +0 -1
  318. package/dist/query-CJ_DX8vl.d.ts.map +0 -1
  319. package/dist/query-Di7eEQ79.js.map +0 -1
  320. package/dist/release-confidence-4XrqlpFD.d.ts.map +0 -1
  321. package/dist/release-confidence-BknrpBnO.js.map +0 -1
  322. package/dist/researcher-DJnoUE8c.d.ts.map +0 -1
  323. package/dist/rubric-predictive-validity-C7LnNvF2.d.ts.map +0 -1
  324. package/dist/rubric-predictive-validity-CzxLoZge.js.map +0 -1
  325. package/dist/schema-C6DW4ZHR.js.map +0 -1
  326. package/dist/schema-Cef2cFmb.d.ts.map +0 -1
  327. package/dist/semantic-concept-judge-laMCnTLn.js.map +0 -1
  328. package/dist/sequential-C458DXNf.js.map +0 -1
  329. package/dist/sequential-eprocess-CbUt2htw.js.map +0 -1
  330. package/dist/server-dIWwF3j_.js.map +0 -1
  331. package/dist/skillopt-optimization-method-CPBlTcj5.js.map +0 -1
  332. package/dist/statistical-heldout-_woZ9q9j.d.ts.map +0 -1
  333. package/dist/steps-AmkT-GIM.d.ts.map +0 -1
  334. package/dist/summary-report-B__Y5ub3.d.ts.map +0 -1
  335. package/dist/summary-report-DW2bEpdB.js.map +0 -1
  336. package/dist/tool-groups-B4tqh8jB.d.ts.map +0 -1
  337. package/dist/types-CLAwnY-L.d.ts.map +0 -1
  338. package/dist/types-DdFNuyxQ.d.ts.map +0 -1
  339. package/dist/types-jUBXJ7Iz.d.ts +0 -884
  340. package/dist/types-jUBXJ7Iz.d.ts.map +0 -1
  341. package/dist/verdict-cache-mZf5FEiY.js +0 -107
  342. package/dist/verdict-cache-mZf5FEiY.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-C6DW4ZHR.js","names":[],"sources":["../src/rollout/gate-checks.ts","../src/rollout/schema.ts"],"sourcesContent":["/**\n * THE canonical list of anti-Goodhart gate checks, plus the TOTAL policy every\n * entry point has to declare over it.\n *\n * Four rounds of adversarial review found the same defect four times, and it\n * was never the check itself: it was the COMPOSITION. `validateRolloutLine`\n * composed one check, `assertMinted` composed two, `assertRewardGate` composed\n * two of the three, `assertGateReport` composed its own pair — each by hand, in\n * its own file. So a check added to the package applied wherever its author\n * happened to remember, and the guard that forgot it looked exactly like the\n * guard that didn't. The last leak was literally that: `assertRewardGate`\n * composed `reward-relationship` + `gated-evidence` and not `unscreened-reward`,\n * so a never-screened positive reward that `assertMinted` correctly REFUSED\n * walked through all four waist exporters at full value.\n *\n * The fix is to make hand-composition impossible rather than to add a third\n * call to the two places that had two:\n *\n * - `GATE_CHECKS` is a TOTAL map over `GateCheckId`. A new id with no\n * implementation does not compile.\n * - `GatePolicy` is a TOTAL map over `GateCheckId`. Every entry point\n * declares one, so a new id makes EVERY entry point's policy a type error\n * until it is wired. Wiring it means writing `enforced`, `repairedBy(...)`\n * or `omittedBecause(...)` — and the last two force a written reason, so a\n * silent gap is not expressible.\n * - every check carries a `tripwire`: the minimal outcome it must refuse.\n * `gate-checks.test.ts` feeds each tripwire to every entry point that\n * declares `enforced` and requires a rejection, so wiring a check to the\n * wrong disposition is a TEST failure even when it type-checks.\n *\n * Adding a check is therefore: append the id, write the check, and the compiler\n * enumerates every place that has to decide about it.\n */\n\nimport type { GatedEvidence, RolloutOutcome, RolloutStep } from './schema'\n\n/**\n * Every gate check in the package, in the order they are applied.\n *\n * Order is load-bearing only for which message a caller sees first: a line that\n * trips two checks reports the earlier one, and `reward-relationship` is first\n * because it is the invariant the other three protect.\n */\nexport const GATE_CHECK_IDS = [\n 'reward-relationship',\n 'gated-evidence',\n 'undeclared-step-payload',\n 'unscreened-reward',\n] as const\n\nexport type GateCheckId = (typeof GATE_CHECK_IDS)[number]\n\n/**\n * An outcome as it reaches a check.\n *\n * Deliberately accepts a raw record as well as the typed shape: the checks are\n * the RUNTIME half of the gate, and the callers they exist for — JSON off a\n * ledger, a plain-JavaScript consumer of the published package — arrive with no\n * types at all. `Partial` because a tripwire states only the fields it trips on.\n */\nexport type GateCheckedOutcome = Partial<RolloutOutcome> | Readonly<Record<string, unknown>>\n\n/**\n * What a gate check reads: the reward-bearing surface of ONE LINE.\n *\n * For three rounds the subject was the OUTCOME alone, and that assumption is\n * what produced the next leak rather than any missing check: `steps[]` sits on\n * the LINE, outside `outcome`, so a per-step reward on a gated line was read by\n * no check at all while `toRewardRows` copied it out verbatim — through the\n * MINTED door, not merely the raw one. Widening the subject is what makes\n * \"somewhere else on the line\" a place the checks can see.\n *\n * `outcome` is REQUIRED, and that is the point: a bare `RolloutOutcome` is then\n * not assignable to a subject, so every call site that used to pass one is a\n * COMPILE error until it passes the line instead. A subject with an optional\n * `outcome` would have let the old call sites keep compiling while silently\n * checking nothing — the exact failure this module exists to make impossible.\n */\nexport interface GateSubject {\n outcome: GateCheckedOutcome\n /** The line's trajectory steps, when it carries any. */\n steps?: unknown\n}\n\n/** One untyped field read off the outcome, so every check narrows from the same place. */\nconst field = (subject: GateSubject, name: string): unknown =>\n (subject.outcome as Readonly<Record<string, unknown>>)?.[name]\n\nexport interface GateCheck {\n id: GateCheckId\n /** One sentence: what this check refuses. */\n refuses: string\n /** One dotted-path message per defect; `[]` when the line is clean. */\n errors: (subject: GateSubject) => string[]\n /**\n * Every minimal subject that MUST trip `errors` — the executable form of\n * `refuses`, and the reason a check cannot be added without being provable.\n * The calibration test feeds each one to every entry point declaring\n * `enforced`.\n *\n * A LIST rather than one case: a check that refuses two distinct populations\n * (a positive reward AND a reward it cannot read as a number) proved able to\n * hold for the first while silently passing the second, so each population\n * states its own tripwire and each is exercised separately.\n */\n tripwires: GateSubject[]\n}\n\n// ---------------------------------------------------------------------------\n// Total readers. Every \"is this positive?\" / \"is this populated?\" question the\n// checks ask goes through one of these.\n// ---------------------------------------------------------------------------\n\n/**\n * How the gate reads one `outcome.reward`.\n *\n * TOTAL over `unknown`, with an explicit `unreadable` case, because the\n * recurring defect across four rounds was a hand-written type test whose\n * NEGATIVE branch silently passed: `typeof reward !== 'number' || !(reward > 0)`\n * returned \"clean\" for `reward: \"0.95\"`, so a plain-JavaScript producer that\n * stringifies its numbers — the exact population the runtime backstop exists\n * for — shipped a gamed run at full value through three waist exporters.\n *\n * A value the gate cannot read as a number is not evidence the reward is\n * cleared; it is the absence of that evidence, and the gate fails closed on it.\n */\nexport type RewardReading =\n /** `null`/`undefined` — a labeled gap, which is never a positive signal. */\n | { kind: 'absent' }\n /** A number at or below zero: the gate's own verdict, applied. */\n | { kind: 'cleared' }\n /** A number above zero, `Infinity` and the 5e-324 denormal included. */\n | { kind: 'positive'; shown: string }\n /** Anything the wire format does not permit here, plus `NaN`. */\n | { kind: 'unreadable'; shown: string }\n\nexport function readReward(value: unknown): RewardReading {\n if (value === null || value === undefined) return { kind: 'absent' }\n if (typeof value === 'number') {\n if (Number.isNaN(value)) return { kind: 'unreadable', shown: 'NaN' }\n return value > 0 ? { kind: 'positive', shown: String(value) } : { kind: 'cleared' }\n }\n return {\n kind: 'unreadable',\n shown: `${JSON.stringify(value) ?? String(value)} (${typeof value})`,\n }\n}\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Whether a reward-derived field carries anything at all.\n *\n * The previous emptiness test was `Object.keys(value).length > 0`, which reads\n * `[]` for a NUMBER, a BOOLEAN and the empty string — so `metrics: 0.95` on a\n * gated line counted as empty and shipped verbatim in the verifiers format's\n * per-rubric score dict. `Object.keys` being total over primitives is not the\n * same property as being CORRECT over them.\n *\n * The rule that has no such hole: only `undefined`, `null` and a record with no\n * keys are empty. Everything else is payload, whatever its type.\n */\nexport function payloadIsPopulated(value: unknown): boolean {\n if (value === undefined || value === null) return false\n if (isPlainRecord(value)) return Object.keys(value).length > 0\n return true\n}\n\n/**\n * Every key `tangle.rollout.v1` declares on a step, as a TOTAL map over the\n * interface: a field added to `RolloutStep` and not to this list does not\n * compile, so the list cannot silently fall behind the schema it mirrors.\n *\n * This is the producer's OWN classification, which is the only partition\n * `gatedEvidenceOf` accepts — a key-name heuristic (\"strip anything matching\n * /reward|score/\") holds until someone names a field `credit` and the next\n * per-step signal ships at full value.\n */\nconst DECLARED_STEP_KEYS: { readonly [K in keyof Required<RolloutStep>]: true } = {\n kind: true,\n name: true,\n input: true,\n output: true,\n status: true,\n durationMs: true,\n llm_call_count: true,\n prompt_token_ids: true,\n completion_token_ids: true,\n logprobs: true,\n}\n\n/**\n * The part of `steps` the wire format has no name for — a per-step reward, a\n * per-step score, whatever a producer decided to hang there.\n *\n * `undefined` when the steps carry nothing undeclared.\n */\nexport function undeclaredStepPayload(steps: unknown): unknown {\n if (steps === undefined || steps === null) return undefined\n // The format says `steps` is a list. Anything else is wholly unclassified.\n if (!Array.isArray(steps)) return steps\n const extras: Array<Record<string, unknown>> = []\n let found = false\n for (const step of steps) {\n const extra: Record<string, unknown> = {}\n if (isPlainRecord(step)) {\n for (const [key, value] of Object.entries(step)) {\n if (key in DECLARED_STEP_KEYS) continue\n extra[key] = value\n found = true\n }\n } else if (step !== undefined && step !== null) {\n // A step that is not even a record carries no declared key to keep.\n extras.push({ step } as Record<string, unknown>)\n found = true\n continue\n }\n extras.push(extra)\n }\n return found ? extras : undefined\n}\n\n/** `steps` projected down to the keys the wire format declares. */\nexport function declaredSteps(steps: unknown): RolloutStep[] | undefined {\n if (!Array.isArray(steps)) return undefined\n const kept: RolloutStep[] = []\n for (const step of steps) {\n if (!isPlainRecord(step)) continue\n const projected: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(step)) {\n if (key in DECLARED_STEP_KEYS) projected[key] = value\n }\n kept.push(projected as unknown as RolloutStep)\n }\n return kept\n}\n\n/**\n * THE anti-Goodhart invariant, checked as a RELATIONSHIP between two fields\n * rather than as two independent type checks.\n *\n * Everything upstream of a training export is allowed to be wrong; this is the\n * one thing that cannot be. `realness_gated: true` means the run faked its\n * success signal, so its reward is a fabrication, and a fabrication above zero\n * is precisely what a trainer would learn to reproduce. Validating only that\n * `reward` is a number and `realness_gated` is a boolean is what let a line\n * claiming `{reward: 0.95, realness_gated: true}` validate clean and walk\n * through every exporter.\n */\nconst rewardRelationship: GateCheck = {\n id: 'reward-relationship',\n refuses: 'a positive — or unreadable — reward on a line the authenticity screen flagged as gamed',\n tripwires: [\n { outcome: { reward: 0.95, realness_gated: true } },\n // The second population, stated separately because the check held for the\n // first while passing this one for a full round.\n { outcome: { reward: '0.95' as unknown as number, realness_gated: true } },\n ],\n errors: (subject) => {\n if (field(subject, 'realness_gated') !== true) return []\n const reading = readReward(field(subject, 'reward'))\n if (reading.kind === 'absent' || reading.kind === 'cleared') return []\n if (reading.kind === 'unreadable') {\n return [\n `outcome.reward: ${reading.shown} with outcome.realness_gated: true — the wire format ` +\n 'declares this field `number | null`, so the gate cannot read this value as a number ' +\n 'and cannot establish that the reward was cleared. On a run flagged as gamed that is ' +\n 'not evidence of a zero, it is the absence of it, and a consumer that coerces the ' +\n 'value (`\"0.95\"`, `\"2\"`) reads a positive reward off a faked success. Emit a number ' +\n 'or null — `trainingReward` / `trainingScore` from `rollout/reward.ts` produce one.',\n ]\n }\n return [\n `outcome.reward: ${reading.shown} with outcome.realness_gated: true — a run flagged as ` +\n 'gamed may not carry a positive reward. The anti-Goodhart gate forces the reward to 0 (a ' +\n 'real verdict: the gate decided) before the line is written, so a fine-tune cannot learn ' +\n 'from a faked success. Derive the reward with `trainingReward` / `trainingScore` from ' +\n '`rollout/reward.ts`, or drop the line.',\n ]\n },\n}\n\n/**\n * The reward-bearing outcome fields that are NOT the scalar: the numbers the\n * reward was computed from, and the verdict record that claimed it.\n *\n * Returned as one block rather than filtered key-by-key. A key-name heuristic\n * (\"zero anything matching `layer.*` or `/score/`\") is the same defect shape as\n * the line-oriented regex the AST score guard replaced: it holds until someone\n * names a metric `pass_fraction`, and the next reward-shaped key ships at full\n * value. The producer's OWN classification — \"this is the scalar, that is\n * everything else\" — is the only partition that cannot be out-guessed.\n */\nexport function gatedEvidenceOf(subject: GateSubject): GatedEvidence | undefined {\n const evidence: GatedEvidence = {}\n // `payloadIsPopulated`, not an inline key count: a plain-JavaScript caller can\n // hand any value here, and a non-record `metrics` is still reward-derived\n // payload. See that function for the primitives an `Object.keys` test missed.\n const metrics = field(subject, 'metrics')\n if (payloadIsPopulated(metrics)) evidence.metrics = metrics as Record<string, unknown>\n const verdict = field(subject, 'verdict')\n if (verdict !== null && verdict !== undefined) evidence.verdict = verdict\n const steps = undeclaredStepPayload(subject.steps)\n if (steps !== undefined) evidence.steps = steps\n return evidence.metrics === undefined && evidence.verdict === undefined && steps === undefined\n ? undefined\n : evidence\n}\n\n/**\n * The invariant is about the OUTCOME, not about one field of it.\n *\n * `mintRolloutRows` bulk-copied `RunRecord.outcome.raw` into `outcome.metrics`\n * with no gate, so a gated run exported `reward: 0` (correct) while the\n * deterministic per-layer scores that reward was COMPUTED FROM — the `layer.*`\n * keys `rl/verifiable-reward.ts` calls the RL training signal — shipped at 1.0,\n * in the top-level `metrics` dict of the Prime Intellect verifiers format, which\n * IS that format's per-rubric score dict. `verdict` leaks the same way into\n * `toRftItem`'s `reference.verdict`, where a grader author reads\n * `resolved: true` off a run that faked it.\n */\nconst gatedEvidence: GateCheck = {\n id: 'gated-evidence',\n refuses: 'the numbers a fabricated reward was computed from, riding along at reward 0',\n tripwires: [\n { outcome: { reward: 0, realness_gated: true, metrics: { 'layer.tests': 1 } } },\n // A PRIMITIVE `metrics`: `Object.keys(0.95)` is `[]`, so the emptiness test\n // this check used to run reported it clean and the verifiers format shipped\n // it as its per-rubric score dict.\n { outcome: { reward: 0, realness_gated: true, metrics: 0.95 as unknown as never } },\n ],\n errors: (subject) => {\n if (field(subject, 'realness_gated') !== true) return []\n const evidence = gatedEvidenceOf(subject)\n if (evidence === undefined) return []\n // Each check reports only the fields it owns; `steps` is `undeclared-step-payload`.\n if (evidence.metrics === undefined && evidence.verdict === undefined) return []\n const path = evidence.metrics !== undefined ? 'outcome.metrics' : 'outcome.verdict'\n return [\n `${path} is populated with outcome.realness_gated: true — a run flagged as gamed may not ` +\n 'ship the numbers its fabricated reward was computed from, even at reward 0. The ' +\n 'per-layer scores in `metrics` ARE the reward signal in the verifiers format, and ' +\n '`verdict` is the record that claimed the success. Mint through `assertMinted`, which ' +\n 'relocates both to `provenance.gated_evidence` (see `gateGamedOutcome`), or drop the line.',\n ]\n },\n}\n\n/**\n * A reward-bearing field hung on `steps[]`, where the gate was not looking.\n *\n * The first three checks all read `outcome`, so the whole apparatus was blind to\n * anything a producer wrote elsewhere on the line — and `toRewardRows` emits\n * `steps` verbatim beside the scalar it just forced to 0. A generated corpus\n * found it in twenty cases: a gated line carrying\n * `steps: [{kind, name, reward: 0.86}]` exported `{\"reward\": 0, \"steps\":\n * [{\"reward\": 0.86}]}`, which is the per-step credit assignment of a run that\n * faked its success, at full value, through the MINTED door.\n *\n * `RolloutStep` declares ten keys and none of them is a reward, so the partition\n * needs no judgement call: whatever the format does not name is unclassified\n * payload, and on a gated line unclassified payload is exactly what the gate\n * refuses. `assertMinted` relocates it rather than rejecting, like the sibling\n * check, so an already-published ledger stays readable.\n */\nconst undeclaredStepPayloadCheck: GateCheck = {\n id: 'undeclared-step-payload',\n refuses: 'per-step reward signal hung on a gated line’s steps, outside every field the gate read',\n tripwires: [\n {\n outcome: { reward: 0, realness_gated: true },\n steps: [{ kind: 'tool', name: 'edit', reward: 0.9 }],\n },\n ],\n errors: (subject) => {\n if (field(subject, 'realness_gated') !== true) return []\n const extra = undeclaredStepPayload(subject.steps)\n if (extra === undefined) return []\n return [\n `steps[] carries fields \\`${ROLLOUT_SCHEMA_NAME}\\` does not declare (${JSON.stringify(extra).slice(0, 120)}) ` +\n 'with outcome.realness_gated: true — a per-step reward is training signal exactly like ' +\n 'the scalar, and the exporters copy `steps` through verbatim, so zeroing `outcome.reward` ' +\n 'while leaving it in place ships the gamed run’s step-level credit assignment at full ' +\n 'value. Mint through `assertMinted`, which projects the steps down to the declared keys ' +\n 'and relocates the rest to `provenance.gated_evidence.steps` (see `gateGamedOutcome`).',\n ]\n },\n}\n\n/** Named here rather than imported, so `gate-checks` stays free of schema cycles. */\nconst ROLLOUT_SCHEMA_NAME = 'tangle.rollout.v1'\n\n/**\n * A positive reward whose producer DECLARED that no authenticity screen exists.\n *\n * `realness_gated: false` is the screen's VERDICT, so writing it with no screen\n * behind it claims \"we looked and nothing fired\" about a reward nobody looked\n * at. `realness_screened: false` is the producer saying so out loud, and a\n * positive reward carrying it is exactly the signal the gate exists to qualify\n * with nothing having qualified it.\n */\nconst unscreenedReward: GateCheck = {\n id: 'unscreened-reward',\n refuses: 'a positive reward whose producer declares that no authenticity screen ever ran',\n tripwires: [\n { outcome: { reward: 1, realness_gated: false, realness_screened: false } },\n {\n outcome: {\n reward: '2' as unknown as number,\n realness_gated: false,\n realness_screened: false,\n },\n },\n ],\n errors: (subject) => {\n if (field(subject, 'realness_screened') !== false) return []\n const reading = readReward(field(subject, 'reward'))\n if (reading.kind === 'absent' || reading.kind === 'cleared') return []\n return [\n `outcome.reward: ${reading.shown} with outcome.realness_screened: false — this producer declares ` +\n 'that NO authenticity screen ran on this reward, so nothing has established the success ' +\n 'is real, and an unscreened positive reward is exactly the signal the anti-Goodhart gate ' +\n 'exists to qualify. Screen the run and write the verdict (`rolloutRewardFields` from a ' +\n '`RunRecord` carrying `outcome.realness`), or emit `reward: null` — an unqualified ' +\n 'verdict is a labeled gap, not a measured success.',\n ]\n },\n}\n\n/**\n * The registry. Total over `GateCheckId`, so an id with no check does not\n * compile, and `GATE_CHECK_IDS` stays the single enumeration everything\n * iterates.\n */\nexport const GATE_CHECKS: { readonly [K in GateCheckId]: GateCheck } = {\n 'reward-relationship': rewardRelationship,\n 'gated-evidence': gatedEvidence,\n 'undeclared-step-payload': undeclaredStepPayloadCheck,\n 'unscreened-reward': unscreenedReward,\n}\n\n/**\n * What ONE entry point does about ONE check.\n *\n * `repair` and `omit` both carry a mandatory sentence, which is the mechanism\n * that keeps a legitimate omission distinguishable from a forgotten one: you\n * cannot skip a check without writing down why, and the reasons are readable\n * side by side in `GATE_POLICIES`.\n */\nexport type GateCheckDisposition =\n | { readonly kind: 'enforce' }\n /** Resolved by TRANSFORMING the line instead of rejecting it; `by` names the function. */\n | { readonly kind: 'repair'; readonly by: string }\n /** Deliberately not applied here; `because` states the reason. */\n | { readonly kind: 'omit'; readonly because: string }\n\nexport const enforced: GateCheckDisposition = { kind: 'enforce' }\nexport const repairedBy = (by: string): GateCheckDisposition => ({ kind: 'repair', by })\nexport const omittedBecause = (because: string): GateCheckDisposition => ({\n kind: 'omit',\n because,\n})\n\n/** Total over `GateCheckId`: a new check makes every policy literal a type error. */\nexport type GatePolicy = { readonly [K in GateCheckId]: GateCheckDisposition }\n\n/**\n * Every entry point that decides about the gate, and what it decides.\n *\n * Read this as the package's gate policy in one screen. The four entry points\n * are not interchangeable — a validator that rejects, a mint funnel that\n * repairs, a runtime backstop for untyped callers, and a release certifier over\n * emitted rows — and the dispositions say which is which.\n */\nexport const GATE_POLICIES = {\n /**\n * The schema validator. Rejects the reward relationship and NOTHING ELSE, on\n * purpose: it runs on every line read off disk, and the other two conditions\n * describe artifacts that already exist.\n */\n validateRolloutLine: {\n // Stays a REJECTION rather than a transformation. A caller emitting\n // `{reward: 0.95, realness_gated: true}` is a producer defect and has to\n // fail loudly; laundering it into `reward: 0` here would hide the producer,\n // which is the actual bug.\n 'reward-relationship': enforced,\n 'gated-evidence': omittedBecause(\n 'a ledger written before the relocation existed carries `metrics` on its gated lines; ' +\n 'rejecting those would make every already-published artifact unreadable. The condition ' +\n 'is REPAIRED at `assertMinted` (`gateGamedOutcome`) instead, which is the only door into ' +\n 'the training path, so the artifact stays readable and the leak still closes.',\n ),\n 'undeclared-step-payload': omittedBecause(\n 'identical reasoning to `gated-evidence`, one field over: a foreign or pre-unification ' +\n 'ledger may carry producer-invented keys on its steps, and refusing to READ those files ' +\n 'buys nothing the relocation at `assertMinted` does not already buy. Promotion into ' +\n 'training is where it closes.',\n ),\n 'unscreened-reward': omittedBecause(\n 'supervision-journal rows legitimately carry an unscreened positive reward (there is no ' +\n '`RunRecord.outcome.realness` behind them) and must stay writable, readable and ' +\n 'reportable. Only PROMOTION into training is closed, at `assertMinted`.',\n ),\n },\n /**\n * The mint funnel — the single door every `MintedRolloutLine` passes. Validates\n * first (so the reward relationship has already been rejected), then refuses\n * what cannot be repaired, then repairs what can.\n */\n assertMinted: {\n // Re-run after `assertRolloutLine`, which already rejected it. Cheap, and it\n // makes this entry point independently complete rather than complete only\n // because of what it happens to call first.\n 'reward-relationship': enforced,\n 'gated-evidence': repairedBy('gateGamedOutcome'),\n 'undeclared-step-payload': repairedBy('gateGamedOutcome'),\n 'unscreened-reward': enforced,\n },\n /**\n * The runtime backstop, and the one entry point with no license to omit\n * anything: it exists for callers the type system never saw (plain JavaScript\n * handing an object literal to a published exporter), so a check it skips is a\n * check that does not run at all for them. This is where the fourth leak was.\n */\n assertRewardGate: {\n 'reward-relationship': enforced,\n 'gated-evidence': enforced,\n 'undeclared-step-payload': enforced,\n 'unscreened-reward': enforced,\n },\n /**\n * The release certifier. Same checks, measured over the rows a release is\n * ABOUT TO WRITE rather than over one line's outcome — see `REPORT_MEASURES`\n * in `release/gate-report.ts`, which is the second total map this policy\n * drives.\n */\n assertGateReport: {\n 'reward-relationship': enforced,\n 'gated-evidence': enforced,\n 'undeclared-step-payload': enforced,\n 'unscreened-reward': enforced,\n },\n} as const satisfies Record<string, GatePolicy>\n\n/** Every entry point that declares a gate policy. */\nexport type GateEntryPoint = keyof typeof GATE_POLICIES\n\n/**\n * Run the checks one entry point enforces. The ONLY way an entry point should\n * obtain gate errors — hand-composing two of the three is the bug this module\n * exists to remove.\n */\nexport function gateErrors(subject: GateSubject, policy: GatePolicy): string[] {\n const errors: string[] = []\n for (const id of GATE_CHECK_IDS) {\n if (policy[id].kind !== 'enforce') continue\n errors.push(...GATE_CHECKS[id].errors(subject))\n }\n return errors\n}\n","/**\n * `tangle.rollout.v1` — THE canonical rollout serialization, owned by\n * agent-eval. One JSONL line per agent invocation (a solo eval run, a\n * supervisor episode, a worker session, a proposer shot, a judge call, an\n * analyst pass), labeled with its task/split coordinates and a single\n * scalar reward, carrying the FULL message transcript inline.\n *\n * This schema is the reconciliation of two prior producers:\n * - agent-eval's RunRecord-joined rollout rows (PR #410): identity,\n * provenance hashes, the realness gate travelling into the reward,\n * trace-derived steps.\n * - the bench rollout-ledger (agent-runtime PR #591): the wire shape —\n * role, task.split/rep, parent_rollout_id, policy provenance, capture\n * provenance, inline canonical chat-with-tools messages.\n * Where the two conflicted, RunRecord-derived semantics won; the wire\n * field names follow the ledger (snake_case). See `docs/rollout.md` for\n * the field-by-field decision table.\n *\n * Messages are inlined — never referenced — because every harness store a\n * rollout can be recovered from is mutable or garbage-collected. A line\n * must stay a complete training/eval example on its own.\n *\n * `outcome.reward` is THE single scalar (null = no verdict exists — a\n * labeled gap, never 0). `outcome.realness_gated` is the anti-Goodhart\n * flag: a gated line must never export as a positive training example.\n *\n * That last sentence is enforced here, by `validateRolloutLine`, not merely\n * documented. Validating `reward` and `realness_gated` independently — each a\n * well-typed field, their COMBINATION unchecked — is what let a line claiming\n * `{reward: 0.95, realness_gated: true}` validate clean and walk into every\n * training export. The relationship between the two IS the invariant, so it is\n * checked where every other structural claim about a line is checked.\n *\n * The invariant is about the OUTCOME, not about one field of it. Zeroing\n * `reward` while `outcome.metrics` still carried the per-layer scores that\n * reward was computed from exported the gamed signal anyway, in the dict the\n * verifiers format reads as its per-rubric scores. So `gateGamedOutcome`\n * transforms the whole outcome once, at `assertMinted` — the funnel every\n * minted line passes — and the reward-bearing components are relocated to\n * `provenance.gated_evidence`, which no exporter projects.\n *\n * WHICH checks each door applies is not decided in this file. `./gate-checks`\n * owns the canonical list and the total per-entry-point policy; the three doors\n * below (`validateRolloutLine`, `assertRewardGate`, `assertMinted`) each call\n * `gateErrors` with their declared policy, so a check added to that list applies\n * here without anyone editing this file, and a check deliberately skipped has to\n * name itself there.\n */\n\nimport { declaredSteps, GATE_POLICIES, gatedEvidenceOf, gateErrors } from './gate-checks'\n\nexport const ROLLOUT_SCHEMA = 'tangle.rollout.v1'\n\n/** `agent` = a solo evaluation run (no multi-agent topology). */\nexport type RolloutRole = 'agent' | 'supervisor' | 'worker' | 'proposer' | 'judge' | 'analyst'\nexport const ROLLOUT_ROLES: readonly RolloutRole[] = [\n 'agent',\n 'supervisor',\n 'worker',\n 'proposer',\n 'judge',\n 'analyst',\n]\n\n/** Split vocabulary follows `RunRecord.splitTag`, extended with `canary`. */\nexport type RolloutSplit = 'search' | 'dev' | 'holdout' | 'canary'\nexport const ROLLOUT_SPLITS: readonly RolloutSplit[] = ['search', 'dev', 'holdout', 'canary']\n/** Splits that may ship in training exports. Everything else is fail-closed excluded. */\nexport const TRAINABLE_SPLITS: readonly RolloutSplit[] = ['search']\n\nexport function isTrainableSplit(split: RolloutSplit): boolean {\n return TRAINABLE_SPLITS.includes(split)\n}\n\n/** 'mint' = joined live from RunRecord + trace by `mintRolloutRows`. */\nexport type RolloutCapture = 'mint' | 'settle-time' | 'backfill'\nexport const ROLLOUT_CAPTURES: readonly RolloutCapture[] = ['mint', 'settle-time', 'backfill']\n\n// ---------------------------------------------------------------------------\n// Canonical message format — OpenAI chat-with-tools, full fidelity.\n// ---------------------------------------------------------------------------\n\nexport type ChatRole = 'system' | 'user' | 'assistant' | 'tool'\nexport const CHAT_ROLES: readonly ChatRole[] = ['system', 'user', 'assistant', 'tool']\n\nexport interface ChatToolCall {\n id: string\n type: 'function'\n function: {\n name: string\n /** JSON-encoded argument object, exactly as the model emitted it. */\n arguments: string\n }\n}\n\nexport interface ChatMessage {\n role: ChatRole\n content: string | null\n /** Reasoning/thinking channel where the harness captured it (full fidelity). */\n reasoning_content?: string\n tool_calls?: ChatToolCall[]\n /** Required on role:\"tool\" — the ChatToolCall this result answers. */\n tool_call_id?: string\n name?: string\n /**\n * Harbor ATIF `is_copied_context` (RFC 0001 rule 7): this turn was COPIED IN\n * from another trajectory's context, not produced by the agent on this line.\n * The RFC makes excluding it from SFT a MUST, and `toSftRows` does — training\n * on it teaches the model to author text it never authored, and credits this\n * run for another one's work. Absent = false (authored here).\n */\n is_copied_context?: boolean\n}\n\nexport interface ToolDef {\n type: 'function'\n function: {\n name: string\n description?: string\n parameters?: Record<string, unknown>\n }\n}\n\n/**\n * Compact trace-span projection (llm/tool step) carried alongside the\n * conversation when the line was minted from a trace. Optional: lines\n * recovered from harness stores have no span structure.\n */\nexport interface RolloutStep {\n kind: string\n name: string\n /** llm: last-message summary · tool: stringified args. Scrubbed. */\n input?: string\n /** llm: output text · tool: stringified result. Scrubbed. */\n output?: string\n status?: 'ok' | 'error'\n durationMs?: number\n // The four fields below are lifted verbatim from Harbor ATIF's per-step\n // `metrics` (see `interchange/harbor.ts`); the wire names stay snake_case to\n // match that spec exactly, which is why they differ from `durationMs`.\n // All optional and never back-filled: an absent field means \"not captured\",\n // which is not the same claim as an empty array.\n /**\n * LLM inferences this span represents. 0 = deterministic dispatch with no\n * model call — distinct from absent, which means the producer did not track it.\n */\n llm_call_count?: number\n /** Exact prompt tokenization. Removes the ambiguity of re-tokenizing text at train time. */\n prompt_token_ids?: number[]\n /** Exact completion tokenization; aligns index-wise with `logprobs`. */\n completion_token_ids?: number[]\n /**\n * Per-completion-token log probabilities under the sampling policy. Required\n * for off-policy correction (importance weighting) when the rollout was\n * generated by a policy other than the one being trained.\n */\n logprobs?: number[]\n}\n\n// ---------------------------------------------------------------------------\n// Ledger line sections.\n// ---------------------------------------------------------------------------\n\nexport interface RolloutTask {\n /** Benchmark/suite id (e.g. \"swe-bench-verified\") or the experiment id. */\n suite: string\n instance_id: string\n split: RolloutSplit\n /** Sampling seed the campaign pinned; null = not recorded. */\n seed: number | null\n /** Replicate index (0-based). */\n rep: number\n}\n\nexport interface RolloutPolicy {\n /** Harness that drove the invocation (e.g. \"opencode\", \"claude\", \"pi-loops\"). */\n harness: string | null\n harness_version: string | null\n model: string | null\n provider: string | null\n /** Commit of the agent profile / candidate under evaluation. */\n profile_commit: string | null\n /** sha256 of the effective prompt (post-steering), when recorded. */\n prompt_hash?: string | null\n /** sha256 of the effective run config, when recorded. */\n config_hash?: string | null\n /** Canonical agent-profile cell identity, when the run carries one. */\n agent_profile_cell_id?: string | null\n /** Sampling params (temperature, top_p, max_tokens…); null = not recorded. */\n sampling: Record<string, unknown> | null\n}\n\nexport interface RolloutOutcome {\n /**\n * THE single scalar training signal — the official verdict.\n * null = no verdict exists for this invocation (a labeled gap, never 0).\n */\n reward: number | null\n /** Where the reward came from (judge id; \"/inherited\" = parent episode's). */\n reward_source: string | null\n /** Raw judge verdict record, verbatim. */\n verdict: unknown\n /** Everything that is NOT the scalar reward. */\n metrics: Record<string, unknown>\n is_completed: boolean\n is_truncated: boolean\n error: string | null\n /**\n * Anti-Goodhart flag from `RunRecord.outcome.realness.gated`: the run faked\n * its success signal. `true` requires `reward` to be 0 or null — the\n * validator rejects the line otherwise — and the line never qualifies for\n * SFT. Required on the wire: a line that does not state the flag does not\n * validate, so no producer can dodge the gate by omitting it.\n *\n * `true` ALSO requires `metrics` to be empty and `verdict` to be null: the\n * numbers the reward was computed from are relocated to\n * `provenance.gated_evidence` by `gateGamedOutcome`. See that function for\n * why zeroing the scalar alone was not enough.\n */\n realness_gated: boolean\n /**\n * Whether an authenticity SCREEN ever RAN on this reward — a different claim\n * from `realness_gated`, which is the screen's VERDICT.\n *\n * `realness_gated: false` reads as \"we looked and nothing fired\". A producer\n * with no screen at all was emitting exactly that, so a never-screened reward\n * was indistinguishable on the wire from a screened-clean one, and the whole\n * anti-Goodhart apparatus silently treated the first as the second. The two\n * claims are now separable:\n *\n * - `true` — a screen ran; `realness_gated` is its verdict.\n * - `false` — the producer declares it HAS no screen (`unscreenedRewardFields`).\n * `assertMinted` REFUSES such a line when its reward is above\n * zero: an unscreened positive reward is precisely the signal\n * the gate exists to qualify, and nothing has qualified it.\n * - absent — not stated. Pre-unification ledgers land here, as does a\n * `RunRecord` carrying no `outcome.realness` at all. Absent is\n * read as \"unknown\", never as `false` (which would refuse most\n * of the existing corpus) and never as `true`.\n */\n realness_screened?: boolean\n}\n\nexport interface RolloutCostBlock {\n usd: number | null\n tokens_in: number | null\n tokens_out: number | null\n tokens_reasoning: number | null\n cache_read: number | null\n cache_write: number | null\n wall_s: number | null\n /**\n * Total LLM inferences across the invocation (ATIF `llm_call_count`,\n * aggregated). Optional and additive: absent = not tracked, never 0.\n */\n llm_call_count?: number | null\n}\n\nexport interface RolloutArtifacts {\n patch_path: string | null\n run_dir: string | null\n /** Source-of-truth transcript pointer (session id / jsonl path) for audit. */\n transcript_ref: string | null\n}\n\n/**\n * The reward-bearing half of a GATED line's outcome, moved off `outcome` and\n * parked here verbatim. Diagnostics, never training input — see\n * `gateGamedOutcome`.\n */\nexport interface GatedEvidence {\n /** `outcome.metrics` exactly as the producer measured it. */\n metrics?: Record<string, unknown>\n /** `outcome.verdict` verbatim — the judge record that claimed the success. */\n verdict?: unknown\n /**\n * The per-step fields `tangle.rollout.v1` does not declare, parked here when\n * the gate projected `steps[]` down to the schema's own key set.\n *\n * A per-step reward is training signal exactly like the scalar, and `steps`\n * rides through `toRewardRows` verbatim — so a gated line was shipping its\n * step-level credit assignment at full value beside a `reward` of 0.\n */\n steps?: unknown\n}\n\nexport interface RolloutProvenance {\n captured_at: string\n capture: RolloutCapture\n /**\n * Why this line is incomplete. Required when `messages` is empty (the\n * transcript could not be recovered); also set by interchange importers to\n * name a MISSING LABEL — an imported trajectory carries no verdict, so\n * `outcome.reward` is null and this says why.\n */\n gap?: string\n /**\n * Present only on a realness-gated line: the outcome fields the gate\n * relocated, kept so an auditor can still see WHY the run was gated and what\n * it claimed. Deliberately OUTSIDE `outcome`, because every training exporter\n * reads `outcome` and none reads `provenance`.\n */\n gated_evidence?: GatedEvidence\n}\n\nexport interface RolloutLine {\n schema: typeof ROLLOUT_SCHEMA\n rollout_id: string\n /** Spawning invocation within the same episode (worker → supervisor). */\n parent_rollout_id: string | null\n run_id: string\n /** Logical experiment grouping from `RunRecord.experimentId`; null = not recorded. */\n experiment_id: string | null\n /** Stable candidate identity from `RunRecord.candidateId`; null = not recorded. */\n candidate_id: string | null\n /** Improvement-loop generation (-1 = baseline); null = not an improvement loop. */\n generation: number | null\n /** Improvement-loop candidate index (-1 = baseline); null = not an improvement loop. */\n candidate_index: number | null\n role: RolloutRole\n task: RolloutTask\n policy: RolloutPolicy\n /** Full transcript, inline. [] = gap line (see provenance.gap). */\n messages: ChatMessage[]\n tool_defs: ToolDef[]\n /** Trace-span projections, when minted from a trace. */\n steps?: RolloutStep[]\n outcome: RolloutOutcome\n cost: RolloutCostBlock\n artifacts: RolloutArtifacts\n provenance: RolloutProvenance\n}\n\n// ---------------------------------------------------------------------------\n// Validation — pure TS, no runtime schema dependency, mirroring the\n// run-record validator's fail-loud discipline. Returns [] when the value\n// is a valid RolloutLine; otherwise one dotted-path error per defect.\n// ---------------------------------------------------------------------------\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\nconst isNumberOrNull = (v: unknown): boolean => v === null || typeof v === 'number'\nconst isNumberArray = (v: unknown): boolean =>\n Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isFinite(n))\nconst isIntegerArray = (v: unknown): boolean =>\n Array.isArray(v) && v.every((n) => Number.isInteger(n))\nconst isStringOrNull = (v: unknown): boolean => v === null || typeof v === 'string'\nconst isIntegerOrNull = (v: unknown): boolean => v === null || Number.isInteger(v)\n\nfunction validateChatMessage(value: unknown, path: string, errors: string[]): void {\n if (!isRecord(value)) {\n errors.push(`${path}: not an object`)\n return\n }\n if (!CHAT_ROLES.includes(value.role as ChatRole))\n errors.push(`${path}.role: invalid role ${String(value.role)}`)\n if (!isStringOrNull(value.content)) errors.push(`${path}.content: must be string|null`)\n if (value.reasoning_content !== undefined && typeof value.reasoning_content !== 'string') {\n errors.push(`${path}.reasoning_content: must be string when present`)\n }\n if (value.tool_call_id !== undefined && typeof value.tool_call_id !== 'string') {\n errors.push(`${path}.tool_call_id: must be string when present`)\n }\n if (value.role === 'tool' && typeof value.tool_call_id !== 'string') {\n errors.push(`${path}.tool_call_id: required on role:\"tool\"`)\n }\n if (value.is_copied_context !== undefined && typeof value.is_copied_context !== 'boolean') {\n errors.push(`${path}.is_copied_context: must be boolean when present`)\n }\n if (value.tool_calls !== undefined) {\n if (!Array.isArray(value.tool_calls)) {\n errors.push(`${path}.tool_calls: must be an array when present`)\n } else {\n value.tool_calls.forEach((call, i) => {\n if (!isRecord(call) || typeof call.id !== 'string' || call.type !== 'function') {\n errors.push(`${path}.tool_calls[${i}]: must be {id, type:\"function\", function}`)\n return\n }\n const fn = call.function\n if (!isRecord(fn) || typeof fn.name !== 'string' || typeof fn.arguments !== 'string') {\n errors.push(\n `${path}.tool_calls[${i}].function: must be {name: string, arguments: string}`,\n )\n }\n })\n }\n }\n}\n\nfunction validateSection(\n value: unknown,\n path: string,\n fields: Array<[name: string, check: (v: unknown) => boolean, expect: string]>,\n errors: string[],\n): void {\n if (!isRecord(value)) {\n errors.push(`${path}: not an object`)\n return\n }\n for (const [name, check, expect] of fields) {\n if (!check(value[name])) errors.push(`${path}.${name}: expected ${expect}`)\n }\n}\n\n/**\n * THE anti-Goodhart gate, applied to the WHOLE outcome as a TRANSFORMATION.\n *\n * Two prior rounds enforced the gate as a CHECK ON ONE FIELD at N call sites,\n * and each round the next reward-bearing field leaked. The one that shipped:\n * `mintRolloutRows` bulk-copied `RunRecord.outcome.raw` into `outcome.metrics`\n * with no gate, so a gated run exported `reward: 0` (correct) while the\n * deterministic per-layer scores that reward was COMPUTED FROM — the\n * `layer.*` keys `rl/verifiable-reward.ts` calls the RL training signal —\n * shipped at 1.0, in the top-level `metrics` dict of the Prime Intellect\n * verifiers format, which IS that format's per-rubric score dict. `verdict`\n * leaks the same way into `toRftItem`'s `reference.verdict`, where a grader\n * author reads `resolved: true` off a run that faked it.\n *\n * So the rule is no longer \"zero the field we remembered\". It is: if the gate\n * fired, the outcome that leaves here carries NOTHING positive that was derived\n * from the reward, whichever field a present or future exporter decides to\n * read. `reward` is already forced to 0 upstream (`trainingReward`) and\n * REJECTED here if it is not; `metrics` and `verdict` are relocated.\n *\n * WHERE they go, and why relocation rather than deletion: zeroing destroys the\n * audit trail that shows why the run was gated and what it claimed, which is\n * the row an auditor most wants and the labeled example a gaming DETECTOR\n * trains on. `provenance.gated_evidence` keeps every byte, at a path no\n * training exporter reads — all four release configs and every `rl/exporters`\n * shape project from `outcome`, `messages`, `cost` and `task`; none projects\n * `provenance`. Auditability preserved, training signal removed, and a future\n * exporter that reads a field nobody thought of is safe by construction because\n * the field is empty rather than because the exporter remembered to check.\n *\n * Idempotent: a second application finds nothing left to move and returns the\n * line unchanged, so re-minting a line read back off a ledger cannot clobber\n * the evidence it already carries.\n */\nexport function gateGamedOutcome(line: RolloutLine): RolloutLine {\n if (line.outcome.realness_gated !== true) return line\n const moved = gatedEvidenceOf(line)\n if (moved === undefined) return line\n const kept = line.provenance.gated_evidence\n const evidence: GatedEvidence = {}\n const metrics = { ...kept?.metrics, ...moved.metrics }\n if (Object.keys(metrics).length > 0) evidence.metrics = metrics\n if (moved.verdict !== undefined) evidence.verdict = moved.verdict\n else if (kept?.verdict !== undefined) evidence.verdict = kept.verdict\n if (moved.steps !== undefined) evidence.steps = moved.steps\n else if (kept?.steps !== undefined) evidence.steps = kept.steps\n // The trajectory itself STAYS: a gamed transcript is the labeled example a\n // gaming detector trains on, and the exporters are meant to ship it. Only the\n // fields the wire format does not declare come off, which is the same\n // partition `gatedEvidenceOf` applies to `metrics` — the producer's own,\n // never a key-name guess.\n const steps = moved.steps === undefined ? line.steps : declaredSteps(line.steps)\n return {\n ...line,\n ...(steps === undefined ? {} : { steps }),\n outcome: { ...line.outcome, metrics: {}, verdict: null },\n provenance: { ...line.provenance, gated_evidence: evidence },\n }\n}\n\n/**\n * EVERY gate check, for the export path — the runtime backstop.\n *\n * `validateRolloutLine` checks the reward relationship too, but an exporter\n * cannot afford to re-validate every field of every line, and more importantly\n * it is not the exporter's job to re-check the schema — it is its job never to\n * emit a signal it was told is fabricated. Thrown rather than filtered: an\n * exporter silently dropping a poisoned line would hide the producer that made\n * it, and the producer is the actual defect.\n *\n * This is the third layer, and it exists for exactly one caller: JavaScript.\n * The brand stops TypeScript callers at compile time and `assertMinted` fixes\n * data arriving from disk, but neither is present for a plain JS consumer of\n * the published package handing an object literal to `toRewardRows`. Which is\n * exactly why this entry point's policy omits nothing: a check it skips is a\n * check that never runs for those callers at all. It composed two of the three\n * for one round, and a never-screened positive reward walked through all four\n * waist exporters at full value. `GATE_POLICIES.assertRewardGate` is now the\n * only place that list is written down.\n */\nexport function assertRewardGate(line: RolloutLine, context: string): void {\n const errors = gateErrors(line, GATE_POLICIES.assertRewardGate)\n if (errors.length > 0) {\n throw new Error(`${context}: rollout ${line.rollout_id} — ${errors[0]}`)\n }\n}\n\nexport function validateRolloutLine(value: unknown): string[] {\n const errors: string[] = []\n if (!isRecord(value)) return ['line: not an object']\n\n if (value.schema !== ROLLOUT_SCHEMA) errors.push(`schema: expected \"${ROLLOUT_SCHEMA}\"`)\n if (typeof value.rollout_id !== 'string' || value.rollout_id.length === 0)\n errors.push('rollout_id: expected non-empty string')\n if (!isStringOrNull(value.parent_rollout_id))\n errors.push('parent_rollout_id: expected string|null')\n if (typeof value.run_id !== 'string' || value.run_id.length === 0)\n errors.push('run_id: expected non-empty string')\n if (!isStringOrNull(value.experiment_id)) errors.push('experiment_id: expected string|null')\n if (!isStringOrNull(value.candidate_id)) errors.push('candidate_id: expected string|null')\n if (!isIntegerOrNull(value.generation)) errors.push('generation: expected integer|null')\n if (!isIntegerOrNull(value.candidate_index)) errors.push('candidate_index: expected integer|null')\n if (!ROLLOUT_ROLES.includes(value.role as RolloutRole))\n errors.push(`role: invalid role ${String(value.role)}`)\n\n validateSection(\n value.task,\n 'task',\n [\n ['suite', (v) => typeof v === 'string' && v.length > 0, 'non-empty string'],\n ['instance_id', (v) => typeof v === 'string' && v.length > 0, 'non-empty string'],\n [\n 'split',\n (v) => ROLLOUT_SPLITS.includes(v as RolloutSplit),\n `one of ${ROLLOUT_SPLITS.join('|')}`,\n ],\n ['seed', isNumberOrNull, 'number|null'],\n ['rep', (v) => Number.isInteger(v), 'integer'],\n ],\n errors,\n )\n\n validateSection(\n value.policy,\n 'policy',\n [\n ['harness', isStringOrNull, 'string|null'],\n ['harness_version', isStringOrNull, 'string|null'],\n ['model', isStringOrNull, 'string|null'],\n ['provider', isStringOrNull, 'string|null'],\n ['profile_commit', isStringOrNull, 'string|null'],\n ['sampling', (v) => v === null || isRecord(v), 'object|null'],\n ],\n errors,\n )\n if (isRecord(value.policy)) {\n for (const key of ['prompt_hash', 'config_hash', 'agent_profile_cell_id'] as const) {\n if (value.policy[key] !== undefined && !isStringOrNull(value.policy[key])) {\n errors.push(`policy.${key}: expected string|null when present`)\n }\n }\n }\n\n if (!Array.isArray(value.messages)) {\n errors.push('messages: expected array')\n } else {\n for (const [i, m] of value.messages.entries()) validateChatMessage(m, `messages[${i}]`, errors)\n }\n\n if (!Array.isArray(value.tool_defs)) {\n errors.push('tool_defs: expected array')\n } else {\n value.tool_defs.forEach((d, i) => {\n if (\n !isRecord(d) ||\n d.type !== 'function' ||\n !isRecord(d.function) ||\n typeof d.function.name !== 'string'\n ) {\n errors.push(`tool_defs[${i}]: must be {type:\"function\", function:{name}}`)\n }\n })\n }\n\n if (value.steps !== undefined) {\n if (!Array.isArray(value.steps)) {\n errors.push('steps: expected array when present')\n } else {\n value.steps.forEach((s, i) => {\n if (!isRecord(s) || typeof s.kind !== 'string' || typeof s.name !== 'string') {\n errors.push(`steps[${i}]: must be {kind: string, name: string, …}`)\n return\n }\n // ATIF-lifted optionals: absent on every line written before they\n // existed, so they are checked only when present — old ledgers stay valid.\n if (s.llm_call_count !== undefined && !Number.isInteger(s.llm_call_count)) {\n errors.push(`steps[${i}].llm_call_count: expected integer when present`)\n }\n for (const key of ['prompt_token_ids', 'completion_token_ids'] as const) {\n if (s[key] !== undefined && !isIntegerArray(s[key])) {\n errors.push(`steps[${i}].${key}: expected integer[] when present`)\n }\n }\n if (s.logprobs !== undefined && !isNumberArray(s.logprobs)) {\n errors.push(`steps[${i}].logprobs: expected number[] when present`)\n }\n })\n }\n }\n\n validateSection(\n value.outcome,\n 'outcome',\n [\n ['reward', isNumberOrNull, 'number|null'],\n ['reward_source', isStringOrNull, 'string|null'],\n ['metrics', isRecord, 'object'],\n ['is_completed', (v) => typeof v === 'boolean', 'boolean'],\n ['is_truncated', (v) => typeof v === 'boolean', 'boolean'],\n ['error', isStringOrNull, 'string|null'],\n ],\n errors,\n )\n if (isRecord(value.outcome)) {\n if (!('verdict' in value.outcome)) errors.push('outcome.verdict: field required (may be null)')\n if (typeof value.outcome.realness_gated !== 'boolean') {\n errors.push('outcome.realness_gated: expected boolean')\n }\n if (\n value.outcome.realness_screened !== undefined &&\n typeof value.outcome.realness_screened !== 'boolean'\n ) {\n errors.push('outcome.realness_screened: expected boolean when present')\n }\n errors.push(\n ...gateErrors(\n { outcome: value.outcome, steps: value.steps },\n GATE_POLICIES.validateRolloutLine,\n ),\n )\n }\n\n validateSection(\n value.cost,\n 'cost',\n [\n ['usd', isNumberOrNull, 'number|null'],\n ['tokens_in', isNumberOrNull, 'number|null'],\n ['tokens_out', isNumberOrNull, 'number|null'],\n ['tokens_reasoning', isNumberOrNull, 'number|null'],\n ['cache_read', isNumberOrNull, 'number|null'],\n ['cache_write', isNumberOrNull, 'number|null'],\n ['wall_s', isNumberOrNull, 'number|null'],\n ],\n errors,\n )\n if (\n isRecord(value.cost) &&\n value.cost.llm_call_count !== undefined &&\n !(value.cost.llm_call_count === null || Number.isInteger(value.cost.llm_call_count))\n ) {\n errors.push('cost.llm_call_count: expected integer|null when present')\n }\n\n validateSection(\n value.artifacts,\n 'artifacts',\n [\n ['patch_path', isStringOrNull, 'string|null'],\n ['run_dir', isStringOrNull, 'string|null'],\n ['transcript_ref', isStringOrNull, 'string|null'],\n ],\n errors,\n )\n\n validateSection(\n value.provenance,\n 'provenance',\n [\n [\n 'captured_at',\n (v) => typeof v === 'string' && !Number.isNaN(Date.parse(v)),\n 'ISO-8601 timestamp',\n ],\n [\n 'capture',\n (v) => ROLLOUT_CAPTURES.includes(v as RolloutCapture),\n `one of ${ROLLOUT_CAPTURES.join('|')}`,\n ],\n ],\n errors,\n )\n if (isRecord(value.provenance)) {\n if (value.provenance.gap !== undefined && typeof value.provenance.gap !== 'string') {\n errors.push('provenance.gap: must be string when present')\n }\n const evidence = value.provenance.gated_evidence\n if (evidence !== undefined) {\n if (!isRecord(evidence)) {\n errors.push('provenance.gated_evidence: must be an object when present')\n } else if (evidence.metrics !== undefined && !isRecord(evidence.metrics)) {\n errors.push('provenance.gated_evidence.metrics: must be an object when present')\n }\n }\n }\n\n // A gap line must say WHY it is a gap; a full line must not carry a gap note.\n if (Array.isArray(value.messages) && isRecord(value.provenance)) {\n if (value.messages.length === 0 && typeof value.provenance.gap !== 'string') {\n errors.push('provenance.gap: required when messages is empty')\n }\n }\n\n return errors\n}\n\nexport function assertRolloutLine(\n value: unknown,\n context = 'rollout line',\n): asserts value is RolloutLine {\n const errors = validateRolloutLine(value)\n if (errors.length > 0) {\n throw new Error(`invalid ${context}:\\n ${errors.join('\\n ')}`)\n }\n}\n\nexport function isRolloutLine(value: unknown): value is RolloutLine {\n return validateRolloutLine(value).length === 0\n}\n\n// ---------------------------------------------------------------------------\n// The minted brand — the COMPILE-TIME half of the anti-Goodhart gate.\n// ---------------------------------------------------------------------------\n\n/**\n * Phantom property. `declare const` means it exists only in the type system:\n * nothing is written at runtime, so a branded line still serializes to exactly\n * the same JSON as a plain one.\n */\ndeclare const MINTED_ROLLOUT: unique symbol\n\n/**\n * A minted outcome states the gate verdict — it is not allowed to stay silent —\n * and, when that verdict is `true`, carries nothing else the reward was derived\n * from (`gateGamedOutcome` has run).\n */\nexport interface MintedRolloutOutcome extends RolloutOutcome {\n realness_gated: boolean\n}\n\n/**\n * A `RolloutLine` whose reward has been checked against the anti-Goodhart\n * invariant. The type every training-data exporter takes.\n *\n * Why a brand and not just the interface: `RolloutLine` is structural, so any\n * hand-built object literal of the right shape IS one — which is how a line\n * declaring `{reward: 0.95, realness_gated: true}` reached the exporters\n * despite them \"only accepting a minted line\". The phantom symbol makes the\n * type nominal: it cannot be produced by writing an object literal, only by\n * `mintRolloutRows` (which applies the gate), `readRolloutLedger` (which\n * validates every line off disk), or an explicit, greppable `assertMinted`.\n *\n * Belt and braces on purpose. The brand closes first-party call sites at\n * COMPILE time; `validateRolloutLine` closes data arriving at RUNTIME (ledger\n * files, foreign imports, JSON from another process) where types are absent.\n * Neither alone is enough.\n *\n * Assignable to `RolloutLine` in one direction only: readers, analysis, and\n * the ledger writer keep taking the plain type.\n */\nexport type MintedRolloutLine = Omit<RolloutLine, 'outcome'> & {\n readonly [MINTED_ROLLOUT]: true\n outcome: MintedRolloutOutcome\n}\n\n/**\n * Promote a line to the type the training exporters accept, applying the\n * anti-Goodhart gate to the WHOLE outcome on the way through. THE escape hatch\n * — grep `assertMinted` to enumerate every place a line enters the training\n * path without coming from mint or a ledger.\n *\n * The gate runs HERE, once, rather than at each producer, because this is the\n * single funnel every minted line passes: `mintRolloutRows` calls it,\n * `readRolloutLedger` calls it per line off disk, `scrubLines` calls it on the\n * way out of a release, and a hand-built line has no other door. One\n * transformation at the funnel means an already-published ledger holding a\n * gated line with populated `metrics` is RE-GATED when it is read, instead of\n * being rejected (which would make every such artifact unreadable) or trusted\n * (which is the leak). Three steps, in this order:\n *\n * 1. VALIDATE the schema.\n * 2. REFUSE every check `GATE_POLICIES.assertMinted` marks `enforce` — today\n * the reward relationship (which stays a REJECTION: a caller claiming\n * `{reward: 0.95, realness_gated: true}` is a producer defect and must fail\n * loudly, since laundering it into `reward: 0` here would hide the\n * producer) and a positive reward the producer declared it never screened.\n * 3. TRANSFORM the one check that policy marks `repair` — relocate the\n * reward's components off `outcome` (`gateGamedOutcome`), so no exporter\n * can leak them whichever field it reads.\n *\n * Step 2 enumerates nothing by hand: a check added to `GATE_CHECKS` is enforced\n * here the moment its disposition in that policy says so.\n *\n * Also normalizes the optional wire flag to an explicit boolean.\n * `realness_gated` is absent on pre-unification ledgers and absent means \"not\n * flagged\" per the schema, so filling it in states a claim the line was already\n * making, and makes the flag readable on every published row instead of most of\n * them. `realness_screened` is NOT filled in: absent means \"unknown\", and\n * inventing either value there would be the same overclaim this round removed.\n */\nexport function assertMinted(value: unknown, context = 'rollout line'): MintedRolloutLine {\n assertRolloutLine(value, context)\n const refused = gateErrors(value, GATE_POLICIES.assertMinted)\n if (refused.length > 0) {\n throw new Error(`invalid ${context}: rollout ${value.rollout_id} — ${refused[0]}`)\n }\n const gated = gateGamedOutcome(value)\n if (gated.outcome.realness_gated === undefined) {\n return {\n ...gated,\n outcome: { ...gated.outcome, realness_gated: false },\n } as MintedRolloutLine\n }\n return gated as MintedRolloutLine\n}\n\n/** `assertMinted` over a batch, naming the offending index in the error. */\nexport function assertMintedLines(\n values: readonly unknown[],\n context = 'rollout line',\n): MintedRolloutLine[] {\n return values.map((value, i) => assertMinted(value, `${context} [${i}]`))\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-Cef2cFmb.d.ts","names":[],"sources":["../src/rollout/schema.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmDa;;KAGD;cACC,wBAAwB;;KAUzB;cACC,yBAAyB;;cAEzB,2BAA2B;iBAExB,iBAAiB,OAAO;;KAK5B;cACC,2BAA2B;KAM5B;cACC,qBAAqB;UAEjB;EACf;EACA;EACA;IACE;;IAEA;;;UAIa;EACf,MAAM;EACN;;EAEA;EACA,aAAa;;EAEb;EACA;;;;;;;;EAQA;;UAGe;EACf;EACA;IACE;IACA;IACA,aAAa;;;;;;;;UASA;EACf;EACA;;EAEA;;EAEA;EACA;EACA;;;;;EAUA;;EAEA;;EAEA;;;;;;EAMA;;UAOe;;EAEf;EACA;EACA,OAAO;;EAEP;;EAEA;;UAGe;;EAEf;EACA;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,UAAU;;UAGK;;;;;EAKf;;EAEA;;EAEA;;EAEA,SAAS;EACT;EACA;EACA;;;;;;;;;;;;;EAaA;;;;;;;;;;;;;;;;;;;;;EAqBA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;EAKA;;UAGe;EACf;EACA;;EAEA;;;;;;;UAQe;;EAEf,UAAU;;EAEV;;;;;;;;;EASA;;UAGe;EACf;EACA,SAAS;;;;;;;EAOT;;;;;;;EAOA,iBAAiB;;UAGF;EACf,eAAe;EACf;;EAEA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;EACA,MAAM;EACN,MAAM;EACN,QAAQ;;EAER,UAAU;EACV,WAAW;;EAEX,QAAQ;EACR,SAAS;EACT,MAAM;EACN,WAAW;EACX,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6GE,iBAAiB,MAAM,cAAc;iBAqDrC,oBAAoB;iBAiNpB,kBACd,gBACA,2BACS,SAAS;iBAOJ,cAAc,iBAAiB,SAAS;;;;;;cAa1C;;;;;;UAOG,6BAA6B;EAC5C;;;;;;;;;;;;;;;;;;;;;;KAuBU,oBAAoB,KAAK;YACzB;EACV,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCK,aAAa,gBAAgB,mBAA2B;;iBAiBxD,kBACd,4BACA,mBACC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"semantic-concept-judge-laMCnTLn.js","names":[],"sources":["../src/locked-jsonl-appender.ts","../src/analyst/findings-store.ts","../src/semantic-concept-judge.ts"],"sourcesContent":["/**\n * LockedJsonlAppender — mutex-serialized JSONL append helper for arbitrary\n * payloads. The reference-replay store does the same thing for typed\n * `ReferenceReplayRun` rows; this is the generic version used by\n * `MutationTelemetry`, `TrialTelemetry`, and any other consumer that wants\n * append-only durable telemetry without rolling its own lock.\n *\n * Locks are per absolute file path (process-local). Cross-process\n * concurrency is NOT addressed — that's an fcntl/flock problem.\n */\n\nimport { appendFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { Mutex } from './concurrency'\n\nconst mutexes = new Map<string, Mutex>()\n\nfunction getMutex(path: string): Mutex {\n let m = mutexes.get(path)\n if (!m) {\n m = new Mutex()\n mutexes.set(path, m)\n }\n return m\n}\n\nexport class LockedJsonlAppender {\n private readonly mutex: Mutex\n constructor(public readonly path: string) {\n this.mutex = getMutex(path)\n if (!existsSync(dirname(path))) {\n mkdirSync(dirname(path), { recursive: true })\n }\n }\n\n async append(entry: unknown): Promise<void> {\n const line = `${JSON.stringify(entry)}\\n`\n await this.mutex.runExclusive(() => {\n appendFileSync(this.path, line)\n })\n }\n}\n\n/** Reset all internal mutex state — tests only. */\nexport function resetLockedAppendersForTesting(): void {\n mutexes.clear()\n}\n","/**\n * FindingsStore — durable persistence for AnalystFinding rows + a diff\n * helper so we can answer \"what changed since the last run?\" without\n * recomputing analysts.\n *\n * On-disk shape is JSONL: one finding per line, append-only, locked via\n * LockedJsonlAppender. Operators get crash-safety (no partial JSON),\n * cheap reads (sequential parse), and trivial backup (rsync the file).\n *\n * Reads are non-locking: a reader sees a consistent snapshot of all\n * fully-written lines and skips an incomplete trailing line if the\n * writer is mid-append. Cross-process locking is intentionally out of\n * scope (see locked-jsonl-appender.ts).\n *\n * The store is run-scoped: callers pass `runId` on append and on load,\n * which keeps multi-run files cleanly partitioned. The `diffFindings`\n * helper compares two run-id sets using stable `finding_id` semantics —\n * the diff is the cross-run signal the regression dashboard renders.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { LockedJsonlAppender } from '../locked-jsonl-appender'\nimport type { AnalystFinding } from './types'\n\n/**\n * One persisted row. We attach `run_id` on disk so a single file can\n * hold multiple runs and the diff helper can query without re-walking\n * separate files.\n */\nexport interface PersistedFinding extends AnalystFinding {\n run_id: string\n}\n\nexport class FindingsStore {\n private readonly appender: LockedJsonlAppender\n\n constructor(public readonly path: string) {\n this.appender = new LockedJsonlAppender(path)\n }\n\n async append(runId: string, findings: AnalystFinding[]): Promise<void> {\n for (const f of findings) {\n const row: PersistedFinding = { ...f, run_id: runId }\n await this.appender.append(row)\n }\n }\n\n /** Load every persisted finding. Discards malformed trailing lines silently. */\n loadAll(): PersistedFinding[] {\n if (!existsSync(this.path)) return []\n const raw = readFileSync(this.path, 'utf8')\n if (!raw) return []\n const out: PersistedFinding[] = []\n for (const line of raw.split('\\n')) {\n if (!line) continue\n try {\n out.push(JSON.parse(line) as PersistedFinding)\n } catch {\n // Skip torn trailing line — the lock guarantees no torn lines\n // mid-file, only at EOF when a writer is in-flight.\n }\n }\n return out\n }\n\n /** Filter to a single run. */\n loadRun(runId: string): PersistedFinding[] {\n return this.loadAll().filter((r) => r.run_id === runId)\n }\n}\n\n// ── Cross-run diff ──────────────────────────────────────────────────\n\nexport interface FindingsDiff {\n /** New finding ids in `current` that weren't in `previous`. */\n appeared: PersistedFinding[]\n /** Finding ids in `previous` that aren't in `current`. */\n disappeared: PersistedFinding[]\n /** Same finding id present in both runs and unchanged per the materiality test. */\n persisted: PersistedFinding[]\n /**\n * Same finding id in both runs but at least one non-identity field\n * shifted per `DiffPolicy.isMaterial`. Reported as [previous, current].\n */\n changed: Array<{ previous: PersistedFinding; current: PersistedFinding }>\n}\n\nexport interface DiffPolicy {\n /**\n * Predicate that decides whether two findings (same finding_id) count\n * as a material change. Defaults to {@link defaultIsMaterial}: severity\n * shift, confidence Δ > 0.05, or evidence count change. Compliance /\n * perf consumers MAY supply a stricter predicate (e.g. rationale text\n * diff, metric Δ thresholds).\n */\n isMaterial?: (previous: AnalystFinding, current: AnalystFinding) => boolean\n}\n\n/**\n * Default materiality test. Deliberately narrow so LLM-reword churn\n * doesn't flood the diff. Stricter tests are opt-in via DiffPolicy.\n */\nexport function defaultIsMaterial(a: AnalystFinding, b: AnalystFinding): boolean {\n if (a.severity !== b.severity) return true\n if (Math.abs((a.confidence ?? 0) - (b.confidence ?? 0)) > 0.05) return true\n if (a.evidence_refs.length !== b.evidence_refs.length) return true\n return false\n}\n\n/**\n * Diff two findings sets by stable finding_id. Callers typically load\n * the two run-id slices from the same store and pass them in.\n */\nexport function diffFindings(\n previous: PersistedFinding[],\n current: PersistedFinding[],\n policy: DiffPolicy = {},\n): FindingsDiff {\n const isMaterial = policy.isMaterial ?? defaultIsMaterial\n const prevById = new Map(previous.map((f) => [f.finding_id, f]))\n const curById = new Map(current.map((f) => [f.finding_id, f]))\n\n const appeared: PersistedFinding[] = []\n const disappeared: PersistedFinding[] = []\n const persisted: PersistedFinding[] = []\n const changed: FindingsDiff['changed'] = []\n\n for (const [id, cur] of curById) {\n const prev = prevById.get(id)\n if (!prev) {\n appeared.push(cur)\n continue\n }\n if (isMaterial(prev, cur)) {\n changed.push({ previous: prev, current: cur })\n } else {\n persisted.push(cur)\n }\n }\n for (const [id, prev] of prevById) {\n if (!curById.has(id)) disappeared.push(prev)\n }\n return { appeared, disappeared, persisted, changed }\n}\n","/**\n * Semantic concept judge — \"does the built artifact actually implement\n * the features the user asked for?\"\n *\n * Distinct from the domain/code/coherence judges in `judges.ts`:\n * - those judges score free-form conversational agent outputs along\n * quality dimensions (accuracy, depth, etc.)\n * - this judge scores a *built artifact* (served HTML + source files)\n * against an explicit list of expected concepts, returning per-concept\n * {present, score 0-10, evidence, severity}.\n *\n * The judge is strict about distinguishing (a) a working implementation\n * from (b) a keyword-present stub. \"// TODO: mint button\" is NOT present.\n * Only real, functional, wired-up code counts.\n *\n * Use via {@link createSemanticConceptJudge} or directly via\n * {@link runSemanticConceptJudge}. Soft-fails (available=false) on LLM\n * or JSON-parse errors so the caller can treat that as \"layer skipped\"\n * rather than \"layer failed\" in a multi-layer pipeline.\n */\n\nimport { CostLedger, type CostLedgerHandle, type CostReceipt } from './cost-ledger'\nimport {\n callLlmJson,\n costReceiptFromLlm,\n costReceiptFromLlmError,\n type LlmCallRequest,\n type LlmClientOptions,\n maximumChargeForLlmRequest,\n} from './llm-client'\nimport type { Severity } from './multi-layer-verifier'\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\n/**\n * Implementation complexity class for weighted scoring.\n *\n * - `render` (default): the concept is a UI surface that displays static\n * data — render a list, show a counter, lay out a button. Single-file\n * work, no external integration.\n * - `integrate`: the concept requires wiring a real external system —\n * wallet connect (wagmi + RainbowKit + chain config), payment provider\n * (Stripe Elements + intent + webhook), an API client with auth.\n * Multi-file, library-knowledge, runtime correctness matters.\n * - `compute`: the concept requires algorithmic work — solver, simulator,\n * constraint propagation, ML inference. Correctness > UI polish.\n *\n * Default weights (when applied via `weightConcepts: 'complexity'`):\n * render=1.0, integrate=2.0, compute=2.5\n *\n * Cross-vertical scoring without complexity weighting silently inflates\n * the rate of UI-heavy verticals (healthcare, fintech dashboards) vs\n * integration-heavy verticals (DeFi, wallets) — all concepts treated\n * equally even though the agent does 2-3x the work for `integrate`.\n */\nexport type ConceptComplexity = 'render' | 'integrate' | 'compute'\n\nexport interface ConceptSpec {\n name: string\n /** Short hints that help the judge; not used for matching. */\n keywords?: string[]\n /** Optional explicit weight; default 1.0. Overrides complexity-derived weight. */\n weight?: number\n /** Implementation complexity class. Default `render`. */\n complexity?: ConceptComplexity\n}\n\nexport interface ConceptFinding {\n concept: string\n present: boolean\n /** 0..10. 10 = production-ready; 7 = functional thin; 4 = partial; 0 = absent. */\n score: number\n evidence: string\n severity: Severity\n}\n\nexport interface SemanticConceptJudgeInput {\n /** Full natural-language prompt the agent was handed. */\n userRequest: string\n /** Rendered HTML the preview returns (UI artifacts). Optional. */\n servedHtml?: string\n /** Top-level source files from the agent's workdir. */\n sourceFiles: Array<{ path: string; content: string }>\n /** The expected concept list. */\n expectedConcepts: ConceptSpec[]\n /** Free-form metadata (id, difficulty) to inject into the prompt. */\n artifactLabel?: string\n artifactDescription?: string\n}\n\nexport interface SemanticConceptJudgeResult {\n kind: 'semantic-concept'\n version: string\n /** Normalized 0..1 score — mean of per-concept scores / 10. */\n score: number\n presentCount: number\n totalCount: number\n findings: ConceptFinding[]\n summary: string\n durationMs: number\n costUsd: number | null\n /** False on LLM/JSON error — treat as \"skipped / unable to judge\" in pipelines. */\n available: boolean\n error?: string\n}\n\n/**\n * Score-aggregation strategy. `mean` averages 0-10 scores uniformly.\n * `complexity` applies the default weight table (render=1, integrate=2,\n * compute=2.5) unless a concept has an explicit `weight`. `explicit`\n * honors only `weight` (defaulting to 1 for unspecified).\n */\nexport type ConceptWeightStrategy = 'mean' | 'complexity' | 'explicit'\n\nexport const DEFAULT_COMPLEXITY_WEIGHTS: Record<ConceptComplexity, number> = {\n render: 1.0,\n integrate: 2.0,\n compute: 2.5,\n}\n\nexport interface SemanticConceptJudgeOptions {\n /** Model id to call. Default 'claude-sonnet-4-6' via agent-eval defaults. */\n model?: string\n /** Per-call timeout. Default 300s. */\n timeoutMs?: number\n /** Provider-enforced output limit. Default 16000. */\n maxTokens?: number\n /** Pipeline budget for the prompt (source blob truncation). Default 45000. */\n maxSourceChars?: number\n /** Per-file cap before inclusion. Default 20000. */\n maxPerFileChars?: number\n /** HTML cap. Default 30000. */\n maxHtmlChars?: number\n /** LlmClient config (baseUrl, apiKey, authHeader, …). */\n llm?: LlmClientOptions\n costLedger?: CostLedgerHandle\n costPhase?: string\n costTags?: Record<string, string>\n signal?: AbortSignal\n /**\n * Score aggregation strategy. Default `mean` — uniform average across\n * concepts. Cross-vertical comparisons should use `complexity` to\n * neutralize the integrate-vs-render asymmetry.\n */\n weightConcepts?: ConceptWeightStrategy\n /** Override the default complexity → weight table. */\n complexityWeights?: Partial<Record<ConceptComplexity, number>>\n}\n\n// ─── Prompt assembly ────────────────────────────────────────────────────\n\nexport const SEMANTIC_CONCEPT_JUDGE_VERSION = 'semantic-concept-judge-v1-2026-04-24'\n\nconst DEFAULT_MAX_SOURCE = 45_000\nconst DEFAULT_MAX_HTML = 30_000\nconst DEFAULT_MAX_PER_FILE = 20_000\nconst DEFAULT_TIMEOUT = 300_000\nconst DEFAULT_MAX_TOKENS = 16_000\nconst DEFAULT_MODEL = 'claude-sonnet-4-6'\n\nconst SEMANTIC_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n required: ['summary', 'concepts'],\n properties: {\n summary: { type: 'string', minLength: 20, maxLength: 600 },\n concepts: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['concept', 'present', 'score', 'evidence', 'severity'],\n properties: {\n concept: { type: 'string', minLength: 1, maxLength: 120 },\n present: { type: 'boolean' },\n score: { type: 'number', minimum: 0, maximum: 10 },\n evidence: { type: 'string', minLength: 5, maxLength: 400 },\n severity: { type: 'string', enum: ['critical', 'major', 'minor', 'info'] },\n },\n },\n },\n },\n}\n\nfunction truncate(body: string, cap: number, label: string): string {\n if (body.length <= cap) return body\n return `${body.slice(0, cap)}\\n… [truncated ${body.length - cap} chars of ${label}]`\n}\n\nfunction buildPrompt(\n input: SemanticConceptJudgeInput,\n opts: Required<SemanticConceptJudgeOptions>,\n): string {\n const sourceBlob = input.sourceFiles\n .filter((f) => f.content.length <= opts.maxPerFileChars)\n .map((f) => `--- FILE: ${f.path} ---\\n${f.content}`)\n .join('\\n\\n')\n\n const html = input.servedHtml ?? ''\n\n return `You are a strict code-review judge evaluating whether an agent's 0-to-1 build actually implements the features the user asked for.\n\nYou MUST distinguish:\n (a) WORKING code that implements the concept (rendered UI, wired handler, real API call),\n (b) KEYWORD-PRESENT stub (comments mentioning the concept, variable names, TODOs),\n (c) ABSENT (concept nowhere).\n\nA comment like \"// TODO: add mint button\" is NOT present — score 2-3. Only count a concept as present if there is real functional code: a rendered component, a call handler wired to state or a network call, a computed value actually used.\n\nUSER REQUEST (what the agent was asked to build):\n${input.userRequest}\n\n${input.artifactLabel ? `ARTIFACT METADATA:\\n name: ${input.artifactLabel}\\n description: ${input.artifactDescription ?? ''}\\n\\n` : ''}EXPECTED CONCEPTS (each must be graded independently):\n${input.expectedConcepts\n .map(\n (c, i) =>\n ` ${i + 1}. \"${c.name}\"${c.keywords?.length ? ` — hints: [${c.keywords.slice(0, 6).join(' | ')}]` : ''}`,\n )\n .join('\\n')}\n\n${html ? `SERVED HTML (what the preview returns when hit):\\n${truncate(html, opts.maxHtmlChars, 'HTML')}\\n\\n` : ''}SOURCE FILES (the agent's workdir):\n${truncate(sourceBlob, opts.maxSourceChars, 'source')}\n\nFor EACH concept, return:\n - concept: the concept name as given (match exactly)\n - present: boolean — does a working implementation exist?\n - score: 0-10 — 10 = production-ready; 7 = functional but thin; 4 = partial/stubbed; 2 = keyword-only comment; 0 = absent\n - evidence: cite \"<file>:<line>\" or \"served-html:<selector>\" pointing at the strongest supporting code. If the concept is absent or stubbed, explain what's missing.\n - severity:\n \"info\" when present: true AND score >= 7\n \"minor\" when present: true AND 4 <= score < 7\n \"major\" when present: false OR score < 4\n \"critical\" when the concept is not only absent but a core user flow depends on it\n\nAlso produce a \"summary\" (one sentence, 20-600 chars): overall verdict on whether this is a shippable implementation of the user request vs a keyword-dense placeholder.\n\nBE SKEPTICAL. Keyword matching already passed — your job is to catch what keyword matching misses. If the agent shipped a working build, say so. If it shipped a stub, say so. Don't grade on effort.\n\nReturn STRICT JSON. No prose outside the JSON.`\n}\n\n// ─── Runner ─────────────────────────────────────────────────────────────\n\n/**\n * Run the semantic concept judge. Soft-fails to available=false on\n * LLM/JSON errors — callers in a MultiLayerVerifier pipeline can treat\n * that as \"skip\" rather than \"fail.\"\n */\nexport async function runSemanticConceptJudge(\n input: SemanticConceptJudgeInput,\n options: SemanticConceptJudgeOptions = {},\n): Promise<SemanticConceptJudgeResult> {\n const start = Date.now()\n const totalCount = input.expectedConcepts.length\n\n if (totalCount === 0) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount: 0,\n findings: [],\n summary: 'no expected concepts declared',\n durationMs: 0,\n costUsd: null,\n available: false,\n error: 'no expected concepts declared',\n }\n }\n\n const opts: Required<SemanticConceptJudgeOptions> = {\n model: options.model ?? DEFAULT_MODEL,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT,\n maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,\n maxSourceChars: options.maxSourceChars ?? DEFAULT_MAX_SOURCE,\n maxPerFileChars: options.maxPerFileChars ?? DEFAULT_MAX_PER_FILE,\n maxHtmlChars: options.maxHtmlChars ?? DEFAULT_MAX_HTML,\n llm: options.llm ?? {},\n costLedger: options.costLedger ?? new CostLedger(),\n costPhase: options.costPhase ?? 'judge.semantic-concept',\n costTags: options.costTags ?? {},\n signal: options.signal ?? new AbortController().signal,\n weightConcepts: options.weightConcepts ?? 'mean',\n complexityWeights: { ...DEFAULT_COMPLEXITY_WEIGHTS, ...(options.complexityWeights ?? {}) },\n }\n\n // Build a name → weight map for aggregation. Mean strategy keeps every\n // weight at 1 (uniform average). Complexity strategy reads the table\n // and lets an explicit `weight` override. Explicit strategy uses ONLY\n // the spec's `weight` (defaulting to 1).\n const weightForConcept = (spec: ConceptSpec): number => {\n if (opts.weightConcepts === 'mean') return 1\n if (spec.weight != null) return spec.weight\n if (opts.weightConcepts === 'complexity') {\n return opts.complexityWeights[spec.complexity ?? 'render'] ?? 1\n }\n return 1\n }\n const weightByName = new Map<string, number>(\n input.expectedConcepts.map((c) => [c.name, weightForConcept(c)]),\n )\n\n let receipt: CostReceipt | undefined\n try {\n const request = {\n model: opts.model,\n messages: [\n {\n role: 'system' as const,\n content:\n 'You are a strict code-review judge. Return strict JSON only. No prose outside the JSON. A keyword in a comment is NOT a working implementation.',\n },\n { role: 'user' as const, content: buildPrompt(input, opts) },\n ],\n jsonSchema: { name: 'semantic_concept_judge', schema: SEMANTIC_SCHEMA },\n temperature: 0,\n maxTokens: opts.maxTokens,\n timeoutMs: opts.timeoutMs,\n } satisfies LlmCallRequest\n const paid = await opts.costLedger.runPaidCall({\n channel: 'judge',\n phase: opts.costPhase,\n actor: 'semantic-concept',\n model: opts.model,\n ...(Object.keys(opts.costTags).length > 0 ? { tags: opts.costTags } : {}),\n maximumCharge: maximumChargeForLlmRequest(request, opts.llm),\n signal: opts.signal,\n execute: (signal, callId) =>\n callLlmJson<{ summary: string; concepts: ConceptFinding[] }>(request, {\n ...opts.llm,\n signal,\n idempotencyKey: callId,\n }),\n receipt: ({ result }) => costReceiptFromLlm(result),\n receiptFromError: costReceiptFromLlmError,\n })\n receipt = paid.receipt\n if (!paid.succeeded) throw paid.error\n const { value } = paid.value\n\n if (!value?.concepts || !Array.isArray(value.concepts)) {\n throw new Error('judge returned malformed response — expected array under \"concepts\"')\n }\n\n const findings: ConceptFinding[] = value.concepts.map((c) => ({\n concept: String(c.concept),\n present: Boolean(c.present),\n score: Math.max(0, Math.min(10, Number(c.score ?? 0))),\n evidence: String(c.evidence ?? ''),\n severity: (['critical', 'major', 'minor', 'info'] as const).includes(c.severity)\n ? c.severity\n : 'info',\n }))\n\n const presentCount = findings.filter((f) => f.present && f.score >= 7).length\n let weightSum = 0\n let weightedScoreSum = 0\n for (const f of findings) {\n const w = weightByName.get(f.concept) ?? 1\n weightSum += w\n weightedScoreSum += w * f.score\n }\n const scoreAvg =\n weightSum > 0\n ? weightedScoreSum / weightSum\n : findings.reduce((a, f) => a + f.score, 0) / Math.max(1, findings.length)\n\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: Number((scoreAvg / 10).toFixed(3)),\n presentCount,\n totalCount,\n findings,\n summary: String(value.summary ?? ''),\n durationMs: Date.now() - start,\n costUsd: paid.receipt.costUnknown ? null : paid.receipt.costUsd,\n available: true,\n }\n } catch (err) {\n return {\n kind: 'semantic-concept',\n version: SEMANTIC_CONCEPT_JUDGE_VERSION,\n score: 0,\n presentCount: 0,\n totalCount,\n findings: [],\n summary: '',\n durationMs: Date.now() - start,\n costUsd: receipt && !receipt.costUnknown ? receipt.costUsd : null,\n available: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * Factory: pin LLM options once, return a closure that accepts inputs.\n * Convenient for pipelines that want to share a single LlmClient config.\n */\nexport function createSemanticConceptJudge(\n options: SemanticConceptJudgeOptions = {},\n): (input: SemanticConceptJudgeInput) => Promise<SemanticConceptJudgeResult> {\n return (input) => runSemanticConceptJudge(input, options)\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sequential-C458DXNf.js","names":[],"sources":["../src/campaign/gates/sequential.ts"],"sourcesContent":["/**\n * Anytime-valid sequential promotion gate — an e-process (betting\n * test-martingale, see `eProcess` in `statistics.ts`) over paired\n * per-scenario deltas, so a campaign stops the MOMENT evidence decides\n * instead of burning a fixed-n budget. Decisions remain valid at any\n * data-dependent stopping time (Ville's inequality), which is exactly what\n * fixed-n machinery cannot offer: peeking at a bootstrap CI after every\n * observation and stopping on the first significant peek inflates type-I\n * error far beyond alpha.\n *\n * REPLACES, never layers on, a fixed-n gate. Running `heldoutSignificance`\n * or `paretoSignificanceGate` repeatedly on a growing sample and stopping\n * early is optional stopping no matter how it is dressed up; this gate is\n * the valid way to stop early. Use one or the other per evidence stream.\n *\n * Pre-registration binding: anytime validity holds only for the\n * PRE-REGISTERED statistic. When a `SignedManifest` is bound, the gate takes\n * alpha from `manifest.alpha`, the observation budget from\n * `manifest.preRegisteredN`, orients deltas by `manifest.direction`, and\n * shifts the null boundary by `manifest.minEffect` — re-deciding the same\n * stream under different parameters after seeing data would reopen optional\n * stopping under a fancier name. The manifest's content hash is verified at\n * construction (sync, same `sha256-content` scheme as `signManifest`).\n *\n * Non-iid caveat (stated honestly): the supermartingale guarantee needs each\n * delta's conditional mean under H0 to stay ≤ the null boundary given the\n * past — exchangeable scenario deltas suffice. Scenario streams ordered by\n * difficulty or by scenario family violate this; `decide(ctx)` therefore\n * shuffles the paired deltas with a SEEDED permutation by default (the\n * permutation is data-independent, so bet predictability is preserved).\n * Stratified betting (per-stratum λ) is future work, not implemented here.\n */\n\nimport { createHash } from 'node:crypto'\nimport { canonicalize, type SignedManifest } from '../../pre-registration'\nimport { type EProcessState, eProcess, mulberry32 } from '../../statistics'\nimport type { Gate, GateContext, GateResult, GenerationRecord, Scenario } from '../types'\nimport { pairHoldout } from './statistical-heldout'\n\nexport type SequentialDecision = 'promote' | 'continue' | 'undecided-at-maxN'\n\nexport interface SequentialObservation {\n decision: SequentialDecision\n /** Current e-value (the betting wealth) against H0. */\n eValue: number\n /** Paired deltas consumed so far. */\n n: number\n /** Names the decision basis. For 'undecided-at-maxN' it states explicitly\n * that exhausting the budget is NOT evidence of no effect. */\n reason: string\n}\n\nexport interface SequentialPairedGateOptions {\n /** Type-I budget. With `preRegistration` bound this MUST match\n * `manifest.alpha` (conflict throws). Default 0.05. */\n alpha?: number\n /** Minimum paired deltas before a promote may fire. The stopping rule is\n * \"first n ≥ minN with e-value ≥ 1/alpha\" — still a valid stopping time.\n * Default 5. */\n minN?: number\n /** Pre-registered observation budget. Required unless `preRegistration`\n * supplies it via `preRegisteredN` (conflict throws). */\n maxN?: number\n /** Bet truncation forwarded to `eProcess`. Default 0.5. */\n maxBet?: number\n /** Bound on |delta| in the judge's native scale; deltas are mapped to\n * x = (d/scale + 1)/2 ∈ [0,1]. A delta outside ±scale throws (use\n * `detectScale` to pick 1 vs 100 BEFORE streaming). Default 1. */\n scale?: number\n /** Seed for the data-independent shuffle of paired deltas in `decide(ctx)`\n * (exchangeability guard). Default 1337. */\n shuffleSeed?: number\n /** Bind the pre-registered hypothesis. Verified (content hash) at\n * construction; alpha/maxN/direction/minEffect come FROM the manifest. */\n preRegistration?: SignedManifest\n /** Override the gate name in reports. */\n name?: string\n}\n\nexport interface SequentialPairedGate<TArtifact = unknown, TScenario extends Scenario = Scenario>\n extends Gate<TArtifact, TScenario> {\n /** Streaming entry point: feed one paired per-scenario delta\n * (candidate − baseline, native scale). Each gate instance carries ONE\n * observe-stream; `decide(ctx)` runs on its own fresh stream and never\n * consumes or advances this one. 'promote' is sticky; observing past the\n * pre-registered maxN throws (extending a finished stream after seeing\n * the result reopens optional stopping — start a NEW pre-registered\n * test). */\n observe(delta: number): SequentialObservation\n /** Read-only snapshot of the observe-stream. */\n state(): EProcessState & { decision: SequentialDecision }\n}\n\ninterface ResolvedConfig {\n alpha: number\n minN: number\n maxN: number\n maxBet: number\n scale: number\n shuffleSeed: number\n /** 'decrease' negates deltas so \"better\" is always positive. */\n direction: 'increase' | 'decrease'\n /** H0 boundary in x-space: 1/2 + minEffect/(2·scale). */\n nullMean: number\n minEffect: number\n}\n\n/** Sync twin of `verifyManifest` — same `sha256-content` scheme\n * (sha256 over the canonicalized manifest minus contentHash/algo), via\n * node:crypto so gate construction can stay synchronous and fail loud\n * before any observation is consumed. */\nfunction verifyManifestSync(m: SignedManifest): boolean {\n if (m.algo !== undefined && m.algo !== 'sha256-content') {\n throw new Error(`sequentialPairedGate: unrecognized manifest hash algo '${m.algo}'`)\n }\n const { contentHash, algo: _algo, ...rest } = m\n void _algo\n const bytes = JSON.stringify(canonicalize(rest))\n const hash = createHash('sha256').update(bytes, 'utf8').digest('hex')\n return hash === contentHash\n}\n\nfunction resolveConfig(opts: SequentialPairedGateOptions): ResolvedConfig {\n const m = opts.preRegistration\n let alpha: number\n let maxN: number\n let direction: 'increase' | 'decrease'\n let minEffect: number\n if (m) {\n if (!verifyManifestSync(m)) {\n throw new Error(\n `sequentialPairedGate: pre-registration manifest '${m.id}' content hash mismatch (tampered)`,\n )\n }\n if (opts.alpha !== undefined && opts.alpha !== m.alpha) {\n throw new Error(\n `sequentialPairedGate: alpha ${opts.alpha} conflicts with pre-registered alpha ${m.alpha} — ` +\n `the registered statistic is the only one anytime validity covers`,\n )\n }\n if (opts.maxN !== undefined && opts.maxN !== m.preRegisteredN) {\n throw new Error(\n `sequentialPairedGate: maxN ${opts.maxN} conflicts with pre-registered N ${m.preRegisteredN}`,\n )\n }\n alpha = m.alpha\n maxN = m.preRegisteredN\n direction = m.direction\n minEffect = m.minEffect\n } else {\n alpha = opts.alpha ?? 0.05\n if (opts.maxN === undefined) {\n throw new Error(\n 'sequentialPairedGate: maxN is required (or bind a preRegistration manifest whose ' +\n 'preRegisteredN is the budget) — an unbounded stream has no pre-registered budget',\n )\n }\n maxN = opts.maxN\n direction = 'increase'\n minEffect = 0\n }\n const scale = opts.scale ?? 1\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`sequentialPairedGate: scale must be > 0, got ${scale}`)\n }\n if (!Number.isInteger(maxN) || maxN < 1) {\n throw new Error(`sequentialPairedGate: maxN must be a positive integer, got ${maxN}`)\n }\n const minN = opts.minN ?? 5\n if (!Number.isInteger(minN) || minN < 1 || minN > maxN) {\n throw new Error(\n `sequentialPairedGate: minN must be an integer in [1, maxN=${maxN}], got ${minN}`,\n )\n }\n if (!Number.isFinite(minEffect) || minEffect < 0 || minEffect >= scale) {\n throw new Error(\n `sequentialPairedGate: minEffect must be in [0, scale=${scale}), got ${minEffect}`,\n )\n }\n // H0: mean delta ≤ minEffect. In x = (d/scale + 1)/2 space that is\n // E[x] ≤ 1/2 + minEffect/(2·scale) — a shifted null boundary, NOT a clamp\n // of the observations (clamping is mean-distorting for skewed deltas).\n const nullMean = 0.5 + minEffect / (2 * scale)\n return {\n alpha,\n minN,\n maxN,\n maxBet: opts.maxBet ?? 0.5,\n scale,\n shuffleSeed: opts.shuffleSeed ?? 1337,\n direction,\n nullMean,\n minEffect,\n }\n}\n\ninterface SequentialStream {\n observe(delta: number): SequentialObservation\n state(): EProcessState & { decision: SequentialDecision }\n}\n\nfunction makeStream(cfg: ResolvedConfig): SequentialStream {\n const proc = eProcess({ alpha: cfg.alpha, maxBet: cfg.maxBet, nullMean: cfg.nullMean })\n const threshold = 1 / cfg.alpha\n let terminal: SequentialDecision | undefined\n return {\n observe(delta: number): SequentialObservation {\n if (terminal === 'undecided-at-maxN') {\n throw new Error(\n `sequentialPairedGate: pre-registered maxN=${cfg.maxN} exhausted — extending the ` +\n 'stream after seeing the result reopens optional stopping; start a NEW ' +\n 'pre-registered test',\n )\n }\n if (!Number.isFinite(delta) || Math.abs(delta) > cfg.scale) {\n throw new Error(\n `sequentialPairedGate: delta ${delta} outside ±scale=${cfg.scale} — pass the judge's ` +\n `native scale explicitly (detectScale helps pick 1 vs 100)`,\n )\n }\n const d = cfg.direction === 'decrease' ? -delta : delta\n const step = proc.update((d / cfg.scale + 1) / 2)\n // Stopping rule: FIRST n ≥ minN with current wealth ≥ 1/alpha — a valid\n // stopping time (measurable w.r.t. the past), sticky once latched. The\n // core's own `decided` latch ignores minN, so the gate re-derives the\n // decision from current wealth here.\n if (terminal === undefined && step.n >= cfg.minN && step.wealth >= threshold) {\n terminal = 'promote'\n }\n if (terminal === 'promote') {\n return {\n decision: 'promote',\n eValue: step.wealth,\n n: step.n,\n reason:\n `e-value ${step.wealth.toFixed(2)} ≥ 1/α=${threshold.toFixed(2)} at n=${step.n} ` +\n `(minN=${cfg.minN}): the paired improvement exceeds ${cfg.minEffect} at anytime-valid ` +\n `level α=${cfg.alpha}`,\n }\n }\n if (step.n >= cfg.maxN) {\n terminal = 'undecided-at-maxN'\n return {\n decision: 'undecided-at-maxN',\n eValue: step.wealth,\n n: step.n,\n reason:\n `undecided at pre-registered maxN=${cfg.maxN} (e-value ${step.wealth.toFixed(2)} < ` +\n `1/α=${threshold.toFixed(2)}). This is NOT evidence of no effect — the effect may be ` +\n 'real but smaller than this budget can detect; re-register with a larger N to test that',\n }\n }\n return {\n decision: 'continue',\n eValue: step.wealth,\n n: step.n,\n reason: `e-value ${step.wealth.toFixed(2)} < 1/α=${threshold.toFixed(2)} at n=${step.n}/${cfg.maxN} — keep observing`,\n }\n },\n state() {\n return { ...proc.state(), decision: terminal ?? 'continue' }\n },\n }\n}\n\n/** Data-independent in-place Fisher–Yates with a seeded PRNG — the permutation\n * depends only on the seed, never the values, so bet predictability survives. */\nfunction seededShuffle<T>(items: T[], seed: number): T[] {\n const rng = mulberry32(seed)\n for (let i = items.length - 1; i > 0; i--) {\n const j = Math.floor(rng() * (i + 1))\n const tmp = items[i]!\n items[i] = items[j]!\n items[j] = tmp\n }\n return items\n}\n\n/**\n * Anytime-valid sequential paired gate. Conforms to the existing `Gate`\n * contract (`decide(ctx)` consumes candidate vs baseline judge scores via\n * `pairHoldout` — same pairing granularity as the fixed-n gates: full cellId,\n * never scenarioId) and adds a streaming `observe(delta)` entry for campaigns\n * that score cells incrementally and want to stop mid-stream.\n *\n * Decision mapping onto the substrate's five-valued `GateDecision`:\n * - 'promote' → 'ship'\n * - 'continue' → 'need_more_work' (stream ended before maxN with\n * the e-value undecided — more reps could decide)\n * - 'undecided-at-maxN' → 'hold', with the reason stating it is NOT\n * evidence of no effect (never a silent default)\n */\nexport function sequentialPairedGate<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n options: SequentialPairedGateOptions,\n): SequentialPairedGate<TArtifact, TScenario> {\n const cfg = resolveConfig(options)\n const name = options.name ?? 'sequentialPairedGate'\n const manifest = options.preRegistration\n const observeStream = makeStream(cfg)\n\n return {\n name,\n observe(delta: number): SequentialObservation {\n return observeStream.observe(delta)\n },\n state() {\n return observeStream.state()\n },\n async decide(ctx: GateContext<TArtifact, TScenario>): Promise<GateResult> {\n if (!ctx.baselineJudgeScores) {\n throw new Error(\n `${name}: ctx.baselineJudgeScores is required — falling back to the candidate's own ` +\n 'scores would compare the candidate against itself (delta 0, silent no-op)',\n )\n }\n const scenarioIds = new Set(ctx.scenarios.map((s) => s.id))\n const paired = pairHoldout(\n ctx.judgeScores,\n ctx.baselineJudgeScores,\n scenarioIds,\n (s) => s.composite,\n )\n const deltas = paired.after.map((a, i) => a - paired.before[i]!)\n seededShuffle(deltas, cfg.shuffleSeed)\n\n const stream = makeStream(cfg)\n let last: SequentialObservation | undefined\n for (const d of deltas) {\n last = stream.observe(d)\n if (last.decision !== 'continue') break\n }\n\n const detail = {\n ...stream.state(),\n minN: cfg.minN,\n maxN: cfg.maxN,\n scale: cfg.scale,\n shuffleSeed: cfg.shuffleSeed,\n direction: cfg.direction,\n minEffect: cfg.minEffect,\n pairedN: deltas.length,\n ...(manifest ? { preRegisteredId: manifest.id, metric: manifest.metric } : {}),\n }\n const meanDelta =\n deltas.length === 0 ? undefined : deltas.reduce((s, d) => s + d, 0) / deltas.length\n\n if (last === undefined) {\n return {\n decision: 'need_more_work',\n reasons: [`${name}: no paired holdout observations — nothing to test`],\n contributingGates: [{ name, status: 'not_evaluated', detail }],\n }\n }\n const decision =\n last.decision === 'promote'\n ? 'ship'\n : last.decision === 'continue'\n ? 'need_more_work'\n : 'hold'\n return {\n decision,\n reasons: [`${name}: ${last.reason}`],\n contributingGates: [\n {\n name,\n status:\n decision === 'ship'\n ? 'pass'\n : decision === 'need_more_work'\n ? 'not_evaluated'\n : 'fail',\n detail,\n },\n ],\n delta: meanDelta,\n }\n },\n }\n}\n\nexport interface SequentialDecideOptions {\n /** Type-I budget for the early-stop evidence. Default 0.05. */\n alpha?: number\n /** Minimum paired deltas before a stop may fire. Default 5. */\n minN?: number\n /** Bet truncation forwarded to `eProcess`. Default 0.5. */\n maxBet?: number\n /** Bound on |per-scenario composite delta|. Default 1. */\n scale?: number\n}\n\nexport interface SequentialDecideFn {\n (args: { history: GenerationRecord[] }): { stop: boolean; reason?: string }\n /** Read-only snapshot of the accumulated e-process (observability + tests). */\n state(): EProcessState\n}\n\n/**\n * `SurfaceProposer.decide` adapter — stops the optimization loop the moment\n * the e-process decides the loop has produced a real improvement, instead of\n * always running `maxGenerations`.\n *\n * Stream: for each generation g ≥ 1, the per-scenario composite deltas of\n * generation g's top candidate vs the generation-0 top candidate (the\n * incumbent the loop set out to beat), paired by scenarioId. H0: no proposed\n * surface improves any scenario's expected composite over the incumbent —\n * under it every delta has conditional mean ≤ 0 and the e-process is valid.\n * Once wealth ≥ 1/alpha the loop stops and hands the winner to the promotion\n * gate (which re-scores on HELD-OUT data — this adapter only spends the\n * exploration budget, it never promotes).\n *\n * Honesty caveats: (1) the incumbent's scores are measured once and shared\n * across all generations' deltas, so type-I control is exact only insofar as\n * those scores approximate the incumbent's true per-scenario means (more reps\n * → tighter); (2) an UNDECIDED process never stops the loop — absence of a\n * crossing is NOT evidence of no effect, so the loop simply runs its normal\n * course. Calling the adapter repeatedly with a growing history consumes each\n * generation exactly once (re-feeding an already-seen record would double-count\n * evidence).\n */\nexport function sequentialDecide(options: SequentialDecideOptions = {}): SequentialDecideFn {\n const alpha = options.alpha ?? 0.05\n const minN = options.minN ?? 5\n const scale = options.scale ?? 1\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`sequentialDecide: scale must be > 0, got ${scale}`)\n }\n const proc = eProcess({ alpha, maxBet: options.maxBet ?? 0.5, nullMean: 0.5 })\n const threshold = 1 / alpha\n let processedGenerations = 0\n let reference: Map<string, number> | undefined\n let stopped: { stop: true; reason: string } | undefined\n\n const topCandidate = (record: GenerationRecord) => {\n if (record.candidates.length === 0) {\n throw new Error(\n `sequentialDecide: generation ${record.generationIndex} has no candidates — ` +\n 'cannot extract a top candidate',\n )\n }\n return record.candidates.reduce((best, candidate) => {\n if (best.composite === null) return candidate\n if (candidate.composite === null) return best\n return candidate.composite > best.composite ? candidate : best\n })\n }\n\n const decide: SequentialDecideFn = ({ history }) => {\n if (stopped) return stopped\n if (history.length === 0) return { stop: false }\n if (reference === undefined) {\n reference = new Map(\n topCandidate(history[0]!).scenarios.map((s) => [s.scenarioId, s.composite]),\n )\n }\n // Consume only generations not yet seen; start at 1 — generation 0 IS the\n // reference and would contribute all-zero deltas (pure wealth dilution).\n for (let g = Math.max(1, processedGenerations); g < history.length; g++) {\n const top = topCandidate(history[g]!)\n const byScenario = new Map(top.scenarios.map((s) => [s.scenarioId, s.composite]))\n for (const [scenarioId, refComposite] of reference) {\n const candComposite = byScenario.get(scenarioId)\n if (candComposite === undefined) {\n throw new Error(\n `sequentialDecide: generation ${history[g]!.generationIndex} top candidate is missing ` +\n `scenario '${scenarioId}' — generations must score the same scenario set to pair`,\n )\n }\n const delta = candComposite - refComposite\n if (!Number.isFinite(delta) || Math.abs(delta) > scale) {\n throw new Error(\n `sequentialDecide: paired delta ${delta} outside ±scale=${scale} on scenario ` +\n `'${scenarioId}' — pass the composite scale explicitly`,\n )\n }\n const step = proc.update((delta / scale + 1) / 2)\n if (step.n >= minN && step.wealth >= threshold) {\n stopped = {\n stop: true,\n reason:\n `sequential e-process decided at generation ${history[g]!.generationIndex}: ` +\n `e-value ${step.wealth.toFixed(2)} ≥ 1/α=${threshold.toFixed(2)} after n=${step.n} ` +\n 'paired deltas vs the generation-0 incumbent — the improvement is real at ' +\n `α=${alpha}; stop exploring and promote via the gate`,\n }\n processedGenerations = history.length\n return stopped\n }\n }\n }\n processedGenerations = history.length\n return { stop: false }\n }\n decide.state = () => proc.state()\n return decide\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+GA,SAAS,mBAAmB,GAA4B;CACtD,IAAI,EAAE,SAAS,KAAA,KAAa,EAAE,SAAS,kBACrC,MAAM,IAAI,MAAM,0DAA0D,EAAE,KAAK,EAAE;CAErF,MAAM,EAAE,aAAa,MAAM,OAAO,GAAG,SAAS;CAE9C,MAAM,QAAQ,KAAK,UAAU,aAAa,IAAI,CAAC;CAE/C,OADa,WAAW,QAAQ,CAAC,CAAC,OAAO,OAAO,MAAM,CAAC,CAAC,OAAO,KACrD,MAAM;AAClB;AAEA,SAAS,cAAc,MAAmD;CACxE,MAAM,IAAI,KAAK;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,GAAG;EACL,IAAI,CAAC,mBAAmB,CAAC,GACvB,MAAM,IAAI,MACR,oDAAoD,EAAE,GAAG,mCAC3D;EAEF,IAAI,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU,EAAE,OAC/C,MAAM,IAAI,MACR,+BAA+B,KAAK,MAAM,uCAAuC,EAAE,MAAM,oEAE3F;EAEF,IAAI,KAAK,SAAS,KAAA,KAAa,KAAK,SAAS,EAAE,gBAC7C,MAAM,IAAI,MACR,8BAA8B,KAAK,KAAK,mCAAmC,EAAE,gBAC/E;EAEF,QAAQ,EAAE;EACV,OAAO,EAAE;EACT,YAAY,EAAE;EACd,YAAY,EAAE;CAChB,OAAO;EACL,QAAQ,KAAK,SAAS;EACtB,IAAI,KAAK,SAAS,KAAA,GAChB,MAAM,IAAI,MACR,mKAEF;EAEF,OAAO,KAAK;EACZ,YAAY;EACZ,YAAY;CACd;CACA,MAAM,QAAQ,KAAK,SAAS;CAC5B,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACtC,MAAM,IAAI,MAAM,gDAAgD,OAAO;CAEzE,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,MAAM,IAAI,MAAM,8DAA8D,MAAM;CAEtF,MAAM,OAAO,KAAK,QAAQ;CAC1B,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,MAChD,MAAM,IAAI,MACR,6DAA6D,KAAK,SAAS,MAC7E;CAEF,IAAI,CAAC,OAAO,SAAS,SAAS,KAAK,YAAY,KAAK,aAAa,OAC/D,MAAM,IAAI,MACR,wDAAwD,MAAM,SAAS,WACzE;CAKF,MAAM,WAAW,KAAM,aAAa,IAAI;CACxC,OAAO;EACL;EACA;EACA;EACA,QAAQ,KAAK,UAAU;EACvB;EACA,aAAa,KAAK,eAAe;EACjC;EACA;EACA;CACF;AACF;AAOA,SAAS,WAAW,KAAuC;CACzD,MAAM,OAAO,SAAS;EAAE,OAAO,IAAI;EAAO,QAAQ,IAAI;EAAQ,UAAU,IAAI;CAAS,CAAC;CACtF,MAAM,YAAY,IAAI,IAAI;CAC1B,IAAI;CACJ,OAAO;EACL,QAAQ,OAAsC;GAC5C,IAAI,aAAa,qBACf,MAAM,IAAI,MACR,6CAA6C,IAAI,KAAK,qHAGxD;GAEF,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,OACnD,MAAM,IAAI,MACR,+BAA+B,MAAM,kBAAkB,IAAI,MAAM,8EAEnE;GAEF,MAAM,IAAI,IAAI,cAAc,aAAa,CAAC,QAAQ;GAClD,MAAM,OAAO,KAAK,QAAQ,IAAI,IAAI,QAAQ,KAAK,CAAC;GAKhD,IAAI,aAAa,KAAA,KAAa,KAAK,KAAK,IAAI,QAAQ,KAAK,UAAU,WACjE,WAAW;GAEb,IAAI,aAAa,WACf,OAAO;IACL,UAAU;IACV,QAAQ,KAAK;IACb,GAAG,KAAK;IACR,QACE,WAAW,KAAK,OAAO,QAAQ,CAAC,EAAE,SAAS,UAAU,QAAQ,CAAC,EAAE,QAAQ,KAAK,EAAE,SACtE,IAAI,KAAK,oCAAoC,IAAI,UAAU,4BACzD,IAAI;GACnB;GAEF,IAAI,KAAK,KAAK,IAAI,MAAM;IACtB,WAAW;IACX,OAAO;KACL,UAAU;KACV,QAAQ,KAAK;KACb,GAAG,KAAK;KACR,QACE,oCAAoC,IAAI,KAAK,YAAY,KAAK,OAAO,QAAQ,CAAC,EAAE,SACzE,UAAU,QAAQ,CAAC,EAAE;IAEhC;GACF;GACA,OAAO;IACL,UAAU;IACV,QAAQ,KAAK;IACb,GAAG,KAAK;IACR,QAAQ,WAAW,KAAK,OAAO,QAAQ,CAAC,EAAE,SAAS,UAAU,QAAQ,CAAC,EAAE,QAAQ,KAAK,EAAE,GAAG,IAAI,KAAK;GACrG;EACF;EACA,QAAQ;GACN,OAAO;IAAE,GAAG,KAAK,MAAM;IAAG,UAAU,YAAY;GAAW;EAC7D;CACF;AACF;;;AAIA,SAAS,cAAiB,OAAY,MAAmB;CACvD,MAAM,MAAM,WAAW,IAAI;CAC3B,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;EACzC,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI,EAAE;EACpC,MAAM,MAAM,MAAM;EAClB,MAAM,KAAK,MAAM;EACjB,MAAM,KAAK;CACb;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,qBACd,SAC4C;CAC5C,MAAM,MAAM,cAAc,OAAO;CACjC,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,WAAW,QAAQ;CACzB,MAAM,gBAAgB,WAAW,GAAG;CAEpC,OAAO;EACL;EACA,QAAQ,OAAsC;GAC5C,OAAO,cAAc,QAAQ,KAAK;EACpC;EACA,QAAQ;GACN,OAAO,cAAc,MAAM;EAC7B;EACA,MAAM,OAAO,KAA6D;GACxE,IAAI,CAAC,IAAI,qBACP,MAAM,IAAI,MACR,GAAG,KAAK,sJAEV;GAEF,MAAM,cAAc,IAAI,IAAI,IAAI,UAAU,KAAK,MAAM,EAAE,EAAE,CAAC;GAC1D,MAAM,SAAS,YACb,IAAI,aACJ,IAAI,qBACJ,cACC,MAAM,EAAE,SACX;GACA,MAAM,SAAS,OAAO,MAAM,KAAK,GAAG,MAAM,IAAI,OAAO,OAAO,EAAG;GAC/D,cAAc,QAAQ,IAAI,WAAW;GAErC,MAAM,SAAS,WAAW,GAAG;GAC7B,IAAI;GACJ,KAAK,MAAM,KAAK,QAAQ;IACtB,OAAO,OAAO,QAAQ,CAAC;IACvB,IAAI,KAAK,aAAa,YAAY;GACpC;GAEA,MAAM,SAAS;IACb,GAAG,OAAO,MAAM;IAChB,MAAM,IAAI;IACV,MAAM,IAAI;IACV,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,WAAW,IAAI;IACf,WAAW,IAAI;IACf,SAAS,OAAO;IAChB,GAAI,WAAW;KAAE,iBAAiB,SAAS;KAAI,QAAQ,SAAS;IAAO,IAAI,CAAC;GAC9E;GACA,MAAM,YACJ,OAAO,WAAW,IAAI,KAAA,IAAY,OAAO,QAAQ,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO;GAE/E,IAAI,SAAS,KAAA,GACX,OAAO;IACL,UAAU;IACV,SAAS,CAAC,GAAG,KAAK,mDAAmD;IACrE,mBAAmB,CAAC;KAAE;KAAM,QAAQ;KAAiB;IAAO,CAAC;GAC/D;GAEF,MAAM,WACJ,KAAK,aAAa,YACd,SACA,KAAK,aAAa,aAChB,mBACA;GACR,OAAO;IACL;IACA,SAAS,CAAC,GAAG,KAAK,IAAI,KAAK,QAAQ;IACnC,mBAAmB,CACjB;KACE;KACA,QACE,aAAa,SACT,SACA,aAAa,mBACX,kBACA;KACR;IACF,CACF;IACA,OAAO;GACT;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,iBAAiB,UAAmC,CAAC,GAAuB;CAC1F,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACtC,MAAM,IAAI,MAAM,4CAA4C,OAAO;CAErE,MAAM,OAAO,SAAS;EAAE;EAAO,QAAQ,QAAQ,UAAU;EAAK,UAAU;CAAI,CAAC;CAC7E,MAAM,YAAY,IAAI;CACtB,IAAI,uBAAuB;CAC3B,IAAI;CACJ,IAAI;CAEJ,MAAM,gBAAgB,WAA6B;EACjD,IAAI,OAAO,WAAW,WAAW,GAC/B,MAAM,IAAI,MACR,gCAAgC,OAAO,gBAAgB,oDAEzD;EAEF,OAAO,OAAO,WAAW,QAAQ,MAAM,cAAc;GACnD,IAAI,KAAK,cAAc,MAAM,OAAO;GACpC,IAAI,UAAU,cAAc,MAAM,OAAO;GACzC,OAAO,UAAU,YAAY,KAAK,YAAY,YAAY;EAC5D,CAAC;CACH;CAEA,MAAM,UAA8B,EAAE,cAAc;EAClD,IAAI,SAAS,OAAO;EACpB,IAAI,QAAQ,WAAW,GAAG,OAAO,EAAE,MAAM,MAAM;EAC/C,IAAI,cAAc,KAAA,GAChB,YAAY,IAAI,IACd,aAAa,QAAQ,EAAG,CAAC,CAAC,UAAU,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAC5E;EAIF,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,oBAAoB,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvE,MAAM,MAAM,aAAa,QAAQ,EAAG;GACpC,MAAM,aAAa,IAAI,IAAI,IAAI,UAAU,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;GAChF,KAAK,MAAM,CAAC,YAAY,iBAAiB,WAAW;IAClD,MAAM,gBAAgB,WAAW,IAAI,UAAU;IAC/C,IAAI,kBAAkB,KAAA,GACpB,MAAM,IAAI,MACR,gCAAgC,QAAQ,EAAE,CAAE,gBAAgB,sCAC7C,WAAW,yDAC5B;IAEF,MAAM,QAAQ,gBAAgB;IAC9B,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,OAC/C,MAAM,IAAI,MACR,kCAAkC,MAAM,kBAAkB,MAAM,gBAC1D,WAAW,wCACnB;IAEF,MAAM,OAAO,KAAK,QAAQ,QAAQ,QAAQ,KAAK,CAAC;IAChD,IAAI,KAAK,KAAK,QAAQ,KAAK,UAAU,WAAW;KAC9C,UAAU;MACR,MAAM;MACN,QACE,8CAA8C,QAAQ,EAAE,CAAE,gBAAgB,YAC/D,KAAK,OAAO,QAAQ,CAAC,EAAE,SAAS,UAAU,QAAQ,CAAC,EAAE,WAAW,KAAK,EAAE,8EAE7E,MAAM;KACf;KACA,uBAAuB,QAAQ;KAC/B,OAAO;IACT;GACF;EACF;EACA,uBAAuB,QAAQ;EAC/B,OAAO,EAAE,MAAM,MAAM;CACvB;CACA,OAAO,cAAc,KAAK,MAAM;CAChC,OAAO;AACT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sequential-eprocess-CbUt2htw.js","names":[],"sources":["../src/statistics/sequential-eprocess.ts"],"sourcesContent":["import { ValidationError } from '../errors'\n\n// ── Anytime-valid e-process (betting test-martingale) ────────────────\n\nexport interface EProcessOptions {\n /** Type-I error budget. The process decides when wealth ≥ 1/alpha\n * (Ville's inequality). Default 0.05. */\n alpha?: number\n /** Truncation bound on the predictable bet λ ∈ [0, maxBet]. Must satisfy\n * maxBet < 1/nullMean so every wealth factor stays strictly positive.\n * Default 0.5. */\n maxBet?: number\n /** The null boundary m₀ for H0: E[x] ≤ m₀ on x ∈ [0,1]. Default 0.5\n * (the paired-delta encoding x = (d+1)/2 maps \"no effect\" to 1/2).\n * A pre-registered minEffect shifts this — see `sequentialPairedGate`. */\n nullMean?: number\n}\n\nexport interface EProcessStep {\n /** Current wealth W_n — the e-value against H0 after n observations. */\n wealth: number\n /** Observations consumed so far. */\n n: number\n /** True from the first n where W_n ≥ 1/alpha onward (sticky). */\n decided: boolean\n}\n\nexport interface EProcessState extends EProcessStep {\n alpha: number\n maxBet: number\n nullMean: number\n /** The decision boundary 1/alpha. */\n threshold: number\n /** Observation count at the first threshold crossing; undefined until decided. */\n decidedAtN?: number\n}\n\nexport interface EProcess {\n /** Consume one observation x ∈ [0,1]. Throws on non-finite / out-of-range\n * input — a silent clamp would corrupt the type-I guarantee. */\n update(x: number): EProcessStep\n state(): EProcessState\n}\n\n/**\n * Betting test-martingale for bounded observations — the e-process core of\n * anytime-valid sequential testing (Waudby-Smith & Ramdas, \"Estimating means\n * of bounded random variables by betting\", JRSS-B 2024).\n *\n * Observations x_i ∈ [0,1]; H0: E[x] ≤ m₀ (`nullMean`, default 1/2). Wealth\n *\n * W_t = Π_{i≤t} (1 + λ_i (x_i − m₀)), W_0 = 1\n *\n * with the truncated GROW-style plug-in bet computed from PRIOR observations:\n *\n * λ_i = clamp((μ̂_{i−1} − m₀) / (σ̂²_{i−1} + (μ̂_{i−1} − m₀)²), 0, maxBet)\n *\n * where μ̂/σ̂² are the shrunk running estimates μ̂_t = (1/2 + Σx_i)/(t+1),\n * σ̂²_t = (1/4 + Σ(x_i − μ̂_i)²)/(t+1).\n *\n * PREDICTABILITY INVARIANT (load-bearing): λ_i is a function of x_1..x_{i−1}\n * ONLY — it may never see x_i. With λ_i ≥ 0 predictable, each factor has\n * E[1 + λ_i(x_i − m₀) | past] ≤ 1 under H0, so W is a nonnegative\n * supermartingale and Ville's inequality gives P(∃t: W_t ≥ 1/α) ≤ α — the\n * type-I guarantee holds at ANY data-dependent stopping time. λ_1 is always 0\n * (no prior evidence), so the first observation never moves wealth.\n *\n * `decided` latches at the first crossing W_t ≥ 1/α and never un-latches;\n * wealth keeps updating after the crossing (the e-process remains valid), but\n * the decision time is the first crossing.\n */\nexport function eProcess(opts: EProcessOptions = {}): EProcess {\n const alpha = opts.alpha ?? 0.05\n const maxBet = opts.maxBet ?? 0.5\n const nullMean = opts.nullMean ?? 0.5\n if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {\n throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`)\n }\n if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {\n throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`)\n }\n if (!Number.isFinite(maxBet) || maxBet <= 0 || maxBet >= 1 / nullMean) {\n throw new ValidationError(\n `eProcess: maxBet must be in (0, 1/nullMean=${(1 / nullMean).toFixed(4)}) so wealth ` +\n `factors stay positive, got ${maxBet}`,\n )\n }\n const threshold = 1 / alpha\n let wealth = 1\n let n = 0\n let decided = false\n let decidedAtN: number | undefined\n // Running sums over observations consumed so far — read BEFORE folding in\n // the next x, so every bet is predictable.\n let sumX = 0\n let varSum = 0\n return {\n update(x: number): EProcessStep {\n if (typeof x !== 'number' || !Number.isFinite(x) || x < 0 || x > 1) {\n throw new ValidationError(\n `eProcess: observation must be a finite number in [0,1], got ${x}`,\n )\n }\n // λ from prior observations ONLY — x has not touched sumX/varSum yet.\n const muPrev = (0.5 + sumX) / (n + 1)\n const varPrev = (0.25 + varSum) / (n + 1)\n const edge = muPrev - nullMean\n const lambda = Math.min(maxBet, Math.max(0, edge / (varPrev + edge * edge)))\n wealth *= 1 + lambda * (x - nullMean)\n n += 1\n sumX += x\n const muNow = (0.5 + sumX) / (n + 1)\n varSum += (x - muNow) ** 2\n if (!decided && wealth >= threshold) {\n decided = true\n decidedAtN = n\n }\n return { wealth, n, decided }\n },\n state(): EProcessState {\n return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,SAAgB,SAAS,OAAwB,CAAC,GAAa;CAC7D,MAAM,QAAQ,KAAK,SAAS;CAC5B,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,WAAW,KAAK,YAAY;CAClC,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,KAAK,SAAS,GACpD,MAAM,IAAI,gBAAgB,yCAAyC,OAAO;CAE5E,IAAI,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY,KAAK,YAAY,GAC7D,MAAM,IAAI,gBAAgB,4CAA4C,UAAU;CAElF,IAAI,CAAC,OAAO,SAAS,MAAM,KAAK,UAAU,KAAK,UAAU,IAAI,UAC3D,MAAM,IAAI,gBACR,+CAA+C,IAAI,SAAA,CAAU,QAAQ,CAAC,EAAE,yCACxC,QAClC;CAEF,MAAM,YAAY,IAAI;CACtB,IAAI,SAAS;CACb,IAAI,IAAI;CACR,IAAI,UAAU;CACd,IAAI;CAGJ,IAAI,OAAO;CACX,IAAI,SAAS;CACb,OAAO;EACL,OAAO,GAAyB;GAC9B,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,GAC/D,MAAM,IAAI,gBACR,+DAA+D,GACjE;GAGF,MAAM,UAAU,KAAM,SAAS,IAAI;GACnC,MAAM,WAAW,MAAO,WAAW,IAAI;GACvC,MAAM,OAAO,SAAS;GACtB,MAAM,SAAS,KAAK,IAAI,QAAQ,KAAK,IAAI,GAAG,QAAQ,UAAU,OAAO,KAAK,CAAC;GAC3E,UAAU,IAAI,UAAU,IAAI;GAC5B,KAAK;GACL,QAAQ;GACR,MAAM,SAAS,KAAM,SAAS,IAAI;GAClC,WAAW,IAAI,UAAU;GACzB,IAAI,CAAC,WAAW,UAAU,WAAW;IACnC,UAAU;IACV,aAAa;GACf;GACA,OAAO;IAAE;IAAQ;IAAG;GAAQ;EAC9B;EACA,QAAuB;GACrB,OAAO;IAAE;IAAQ;IAAG;IAAS;IAAO;IAAQ;IAAU;IAAW;GAAW;EAC9E;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-dIWwF3j_.js","names":[],"sources":["../src/wire/schemas.ts","../src/wire/rubrics.ts","../src/wire/handlers.ts","../src/wire/openapi.ts","../src/wire/rpc.ts","../src/wire/server.ts"],"sourcesContent":["/**\n * Wire-protocol schemas.\n *\n * These Zod schemas are the contract between the agent-eval runtime and\n * any non-TypeScript client (Python, Rust, Go, …). They get rendered to\n * OpenAPI by `wire/openapi.ts` and code-generators consume that spec to\n * produce typed clients in other languages.\n *\n * Rule: if it's not in this file, it isn't on the wire. Keep names and\n * shapes self-explanatory — every field has a `.describe()` so the\n * generated docs are useful without reading the source.\n */\nimport { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'\nimport { z } from 'zod'\n\nextendZodWithOpenApi(z)\n\n// ── Building blocks ─────────────────────────────────────────────────\n\nexport const RubricDimensionSchema = z\n .object({\n id: z\n .string()\n .min(1)\n .describe('Short stable id like \"buyer_quality\" — used as the key in scoring output.'),\n description: z\n .string()\n .min(1)\n .describe('One-line plain-English meaning. Read by humans reviewing low scores.'),\n weight: z\n .number()\n .min(0)\n .default(1)\n .describe('Relative weight in the composite score. Default 1; 0 disables.'),\n min: z.number().default(0).describe('Lower bound of valid score for this dimension.'),\n max: z.number().default(1).describe('Upper bound of valid score for this dimension.'),\n })\n .openapi('RubricDimension')\n\nexport const FailureModeSchema = z\n .object({\n id: z.string().min(1).describe('Short stable id like \"ai-cadence\" — used in detection lists.'),\n description: z.string().min(1).describe('Plain-English description of the failure pattern.'),\n })\n .openapi('FailureMode')\n\n// ── Rubric ──────────────────────────────────────────────────────────\n\nexport const RubricSchema = z\n .object({\n name: z\n .string()\n .min(1)\n .describe('Stable name like \"anti-slop\" — used by clients to invoke this rubric.'),\n description: z\n .string()\n .min(1)\n .describe('What this rubric measures. Shown in /v1/rubrics listing.'),\n systemPrompt: z\n .string()\n .min(1)\n .describe(\n 'Instructs the judging LLM. Should explain the persona (e.g. \"senior engineer reviewing voice\"), what to score on, and what to return.',\n ),\n dimensions: z\n .array(RubricDimensionSchema)\n .min(1)\n .describe('Scoring axes. The composite score is a weighted sum of these.'),\n failureModes: z\n .array(FailureModeSchema)\n .default([])\n .describe('Patterns to detect; each detected mode appears in the result.failureModes list.'),\n wins: z\n .array(FailureModeSchema)\n .default([])\n .describe('Positive patterns; each detected one appears in the result.wins list.'),\n })\n .openapi('Rubric')\n\n// ── Judge call ──────────────────────────────────────────────────────\n\nexport const JudgeRequestSchema = z\n .object({\n rubricName: z\n .string()\n .optional()\n .describe('Use a built-in rubric by name. Mutually exclusive with `rubric`.'),\n rubric: RubricSchema.optional().describe(\n 'Inline rubric definition. Mutually exclusive with `rubricName`.',\n ),\n content: z\n .string()\n .min(1)\n .describe('The text being judged — a tweet, a blog post, a code snippet, anything stringly.'),\n context: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n 'Free-form metadata for the rubric to use — analytics, source URL, author, etc. Surfaced to the LLM.',\n ),\n model: z.string().optional().describe('Override the judge model configured by the server.'),\n })\n .refine((v) => Boolean(v.rubricName) !== Boolean(v.rubric), {\n message: 'Provide exactly one of `rubricName` or `rubric`.',\n })\n .openapi('JudgeRequest')\n\nexport const JudgeResultSchema = z\n .object({\n composite: z\n .number()\n .min(0)\n .max(1)\n .describe('Weighted combination of dimension scores in 0..1. The single number to gate on.'),\n dimensions: z\n .record(z.string(), z.number())\n .describe('Per-dimension score, keyed by RubricDimension.id.'),\n failureModes: z\n .array(z.string())\n .default([])\n .describe('Failure-mode ids detected in the content (subset of rubric.failureModes ids).'),\n wins: z\n .array(z.string())\n .default([])\n .describe('Win ids detected in the content (subset of rubric.wins ids).'),\n rationale: z\n .string()\n .describe('Plain-English explanation of the score. Surfaced to the human reviewer.'),\n rubricVersion: z\n .string()\n .describe(\n 'Stable hash of the rubric used. Scores are only comparable across runs when this matches.',\n ),\n model: z.string().describe('Model that produced the judgement, for reproducibility.'),\n durationMs: z.number().int().nonnegative().describe('End-to-end wall time for this call.'),\n })\n .openapi('JudgeResult')\n\n// ── Rubric listing ──────────────────────────────────────────────────\n\nexport const RubricInfoSchema = z\n .object({\n name: z.string().describe('Pass this to /v1/judge as `rubricName`.'),\n description: z.string().describe('What this rubric measures.'),\n dimensions: z\n .array(z.object({ id: z.string(), description: z.string(), weight: z.number() }))\n .describe('The scoring axes this rubric uses, with weights.'),\n failureModes: z.array(z.string()).default([]).describe('Failure-mode ids this rubric detects.'),\n rubricVersion: z.string().describe('Stable hash — match this to compare scores across runs.'),\n })\n .openapi('RubricInfo')\n\nexport const ListRubricsResponseSchema = z\n .object({\n rubrics: z.array(RubricInfoSchema),\n })\n .openapi('ListRubricsResponse')\n\n// ── Version / health ────────────────────────────────────────────────\n\nexport const VersionResponseSchema = z\n .object({\n package: z.string().describe('Package name (always \"@tangle-network/agent-eval\").'),\n version: z.string().describe('Semver of the running server. Match your client to this.'),\n wireVersion: z\n .string()\n .describe(\n 'Wire-protocol semver. Bumps separately from package version when the schema changes.',\n ),\n apiSurface: z.array(z.string()).describe('List of supported method names.'),\n })\n .openapi('VersionResponse')\n\nexport const HealthResponseSchema = z\n .object({\n status: z.literal('ok'),\n uptimeSec: z.number(),\n })\n .openapi('HealthResponse')\n\n// ── Ingestion: production traces + user feedback ────────────────────\n\n/**\n * Minimal `TraceEvent` shape that the production runtime emits.\n * Matches `trace/schema.ts` `TraceEvent` but is duplicated here as a\n * wire schema so non-TypeScript clients can validate without depending\n * on internal types.\n */\nexport const TraceEventSchema = z\n .object({\n eventId: z.string().min(1).describe('Stable id for the event. Use ULID or UUID.'),\n runId: z.string().min(1).describe('Run this event belongs to.'),\n spanId: z.string().optional().describe('Span that emitted the event, if any.'),\n kind: z\n .enum([\n 'log',\n 'error',\n 'budget_decrement',\n 'budget_breach',\n 'state_mutation',\n 'policy_violation',\n 'redaction_applied',\n 'custom',\n ])\n .describe('Coarse event category — matches the TraceSchema v1 EventKind enum.'),\n timestamp: z\n .number()\n .int()\n .nonnegative()\n .describe('Unix millis. Must be monotonically non-decreasing within a span.'),\n payload: z\n .record(z.string(), z.unknown())\n .describe('Free-form payload — the runtime owns the shape.'),\n })\n .openapi('TraceEvent')\n\nexport const TracesIngestRequestSchema = z\n .object({\n events: z\n .array(TraceEventSchema)\n .min(1)\n .max(10_000)\n .describe('Batch of events. Max 10k per call — bigger streams should be chunked.'),\n })\n .openapi('TracesIngestRequest')\n\nexport const TracesIngestResponseSchema = z\n .object({\n accepted: z.number().int().nonnegative().describe('Number of events persisted.'),\n rejected: z\n .number()\n .int()\n .nonnegative()\n .describe('Number of events the store refused — see `errors[]` for reasons.'),\n errors: z\n .array(\n z.object({\n eventId: z.string().describe('Event id this error applies to.'),\n message: z.string().describe('Why the event was rejected.'),\n }),\n )\n .default([]),\n })\n .openapi('TracesIngestResponse')\n\nexport const FeedbackLabelSchema = z\n .object({\n id: z.string().optional(),\n source: z.enum(['user', 'judge', 'environment', 'metric', 'policy', 'system']),\n kind: z.enum([\n 'approve',\n 'reject',\n 'select',\n 'edit',\n 'rank',\n 'rate',\n 'comment',\n 'metric_outcome',\n 'policy_block',\n 'revision_request',\n ]),\n value: z.unknown(),\n reason: z.string().optional(),\n severity: z.enum(['info', 'warning', 'error', 'critical']).optional(),\n createdAt: z.string().describe('ISO-8601 UTC.'),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackLabel')\n\nexport const FeedbackAttemptSchema = z\n .object({\n id: z.string().min(1),\n stepIndex: z.number().int().nonnegative(),\n artifactType: z.enum([\n 'text',\n 'code',\n 'plan',\n 'research',\n 'action',\n 'ui',\n 'decision',\n 'data',\n 'other',\n ]),\n artifact: z.unknown(),\n options: z.array(z.unknown()).optional(),\n proposedAction: z\n .object({\n type: z.string(),\n risk: z.enum(['low', 'medium', 'high']).optional(),\n costUsd: z.number().optional(),\n externalSideEffect: z.boolean().optional(),\n requiresApproval: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n feedback: z.array(FeedbackLabelSchema).optional(),\n createdAt: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackAttempt')\n\nexport const FeedbackTrajectorySchema = z\n .object({\n id: z.string().min(1).describe('Stable id; idempotency key for the trajectory.'),\n projectId: z.string().optional(),\n scenarioId: z.string().optional(),\n task: z.object({\n intent: z.string().min(1),\n context: z.unknown().optional(),\n }),\n attempts: z.array(FeedbackAttemptSchema).default([]),\n labels: z.array(FeedbackLabelSchema).default([]),\n outcome: z\n .object({\n success: z.boolean().optional(),\n score: z.number().optional(),\n metrics: z.record(z.string(), z.number()).optional(),\n costUsd: z.number().optional(),\n detail: z.string().optional(),\n observedAt: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n split: z.enum(['train', 'dev', 'test', 'holdout']).optional(),\n tags: z.record(z.string(), z.string()).optional(),\n createdAt: z.string().describe('ISO-8601 UTC.'),\n updatedAt: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })\n .openapi('FeedbackTrajectory')\n\nexport const FeedbackIngestResponseSchema = z\n .object({\n id: z.string().describe('Trajectory id that was persisted.'),\n persisted: z.boolean().describe('True when the trajectory was saved (idempotent on id).'),\n })\n .openapi('FeedbackIngestResponse')\n\nexport type TraceEvent = z.infer<typeof TraceEventSchema>\nexport type TracesIngestRequest = z.infer<typeof TracesIngestRequestSchema>\nexport type TracesIngestResponse = z.infer<typeof TracesIngestResponseSchema>\nexport type FeedbackTrajectory = z.infer<typeof FeedbackTrajectorySchema>\nexport type FeedbackIngestResponse = z.infer<typeof FeedbackIngestResponseSchema>\n\n// ── Errors ──────────────────────────────────────────────────────────\n\nexport const ErrorResponseSchema = z\n .object({\n error: z\n .object({\n code: z\n .string()\n .describe(\n 'Machine-readable code: \"validation_error\", \"rubric_not_found\", \"judge_error\".',\n ),\n message: z.string().describe('Human-readable message.'),\n details: z.unknown().optional().describe('Optional structured detail.'),\n })\n .describe('Errors are always wrapped in this shape across all endpoints.'),\n })\n .openapi('ErrorResponse')\n\n// ── Type exports for callers in the same package ────────────────────\n\nexport type RubricDimension = z.infer<typeof RubricDimensionSchema>\nexport type FailureMode = z.infer<typeof FailureModeSchema>\nexport type Rubric = z.infer<typeof RubricSchema>\nexport type JudgeRequest = z.infer<typeof JudgeRequestSchema>\nexport type JudgeResult = z.infer<typeof JudgeResultSchema>\nexport type RubricInfo = z.infer<typeof RubricInfoSchema>\nexport type ListRubricsResponse = z.infer<typeof ListRubricsResponseSchema>\nexport type VersionResponse = z.infer<typeof VersionResponseSchema>\nexport type ErrorResponse = z.infer<typeof ErrorResponseSchema>\n\n// ── Wire-protocol version ───────────────────────────────────────────\n\n/**\n * Bump on any breaking change to a request/response schema.\n * Non-breaking (additive) changes don't require a bump.\n */\nexport const WIRE_VERSION = '1.0.0'\n\n/**\n * Stable hash of a rubric. Used to make scores comparable across runs:\n * if the rubricVersion matches, the rubric was identical.\n */\nexport function hashRubric(rubric: Rubric): string {\n const stable = stableStringify(rubric)\n let h = 5381\n for (let i = 0; i < stable.length; i++) {\n h = (h * 33) ^ stable.charCodeAt(i)\n }\n // Unsigned 32-bit hex, prefixed with rubric name + version slot\n return `${rubric.name}@${(h >>> 0).toString(16).padStart(8, '0')}`\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(',')}]`\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)\n return `{${entries.join(',')}}`\n }\n return JSON.stringify(value)\n}\n","/**\n * Built-in rubrics shipped with agent-eval.\n *\n * A rubric is a set of scoring axes plus a system prompt that tells the\n * judging LLM how to grade against those axes. Built-in rubrics are\n * curated for use cases that recur across Tangle projects — call them\n * by name from any client.\n *\n * Adding a rubric:\n * 1. Define the Rubric object below with a clear `description` and\n * named `dimensions`.\n * 2. Register it in `BUILTIN_RUBRICS` at the bottom.\n * 3. Add a test in `tests/wire/rubrics.test.ts`.\n *\n * Custom rubrics: callers pass `rubric` inline to /v1/judge instead of\n * `rubricName` — see schemas.ts.\n */\nimport type { Rubric } from './schemas'\nimport { hashRubric } from './schemas'\n\n// ── anti-slop ───────────────────────────────────────────────────────\n// Voice/style judge tuned for technical-buyer audiences. Used by the\n// Postiz autoresearch loop and any content-quality gate.\n\nconst ANTI_SLOP: Rubric = {\n name: 'anti-slop',\n description:\n 'Voice and signal quality for content aimed at senior engineers. Catches AI cadence, marketing tone, and engagement-bait shapes.',\n systemPrompt: `You are evaluating a piece of content written for senior engineers and technical founders.\n\nYou score three things:\n- buyer_quality (0..1): would a senior engineer in the target ICP find this worth their attention? High = specific, earned, technically interesting. Low = generic, hyped, off-target.\n- voice (0..1): does it read like a person who built the thing, or like AI/marketing copy?\n- signal (0..1): does it contain a non-obvious detail, constraint, or claim a reader couldn't get from the public docs?\n\nDetect failure modes (return ids matching):\n- ai-cadence: rule-of-three openings, em-dash flourish, \"Let me explain\", \"Here's the thing\", AI rhythm\n- marketing-tone: \"We're excited to announce\", \"thrilled\", \"delighted\", \"game-changer\", buzzword stack\n- vague-claim: technical claim without a specific component, file, or measurement\n- no-hook: opening doesn't earn attention from the target reader\n- engagement-bait: \"agree?\", \"thoughts?\", listicles, controversy-fishing, hook-detail-pitch\n- off-icp: content shape would attract motivational/grift/hype audiences instead of buyers\n- stale-claim: repeats a positioning line we've used many times this month\n\nDetect wins (return ids matching):\n- specific-component: names a real file, component, or measurement\n- earned-detail: shares a non-obvious detail not derivable from public docs\n- constraint-articulated: names a real tradeoff and the side chosen\n- honest-failure: describes a real failure mode and what was done about it\n\nReturn ONLY JSON matching the response schema. Be conservative — most content has 0-1 wins and 1-2 failure modes, not many of each.`,\n dimensions: [\n {\n id: 'buyer_quality',\n description: 'Would the target buyer find this worth attention?',\n weight: 0.5,\n min: 0,\n max: 1,\n },\n {\n id: 'voice',\n description: 'Does it sound like a builder, not AI or marketing?',\n weight: 0.3,\n min: 0,\n max: 1,\n },\n {\n id: 'signal',\n description: 'Non-obvious detail, constraint, or claim?',\n weight: 0.2,\n min: 0,\n max: 1,\n },\n ],\n failureModes: [\n { id: 'ai-cadence', description: 'AI-rhythm openings and transitions' },\n { id: 'marketing-tone', description: 'Buzzwords, hype, corporate-PR voice' },\n { id: 'vague-claim', description: 'Technical claim without specifics' },\n { id: 'no-hook', description: 'Opening fails to earn attention' },\n { id: 'engagement-bait', description: 'Listicle/controversy/agree-pattern' },\n { id: 'off-icp', description: 'Voice attracts the wrong audience' },\n { id: 'stale-claim', description: 'Reuses an over-used positioning line' },\n ],\n wins: [\n { id: 'specific-component', description: 'Names a real file/component/number' },\n { id: 'earned-detail', description: 'Detail not in public docs' },\n { id: 'constraint-articulated', description: 'Names a real tradeoff' },\n { id: 'honest-failure', description: 'Describes a real failure honestly' },\n ],\n}\n\n// ── Registry ────────────────────────────────────────────────────────\n\nexport const BUILTIN_RUBRICS: Record<string, Rubric> = {\n 'anti-slop': ANTI_SLOP,\n}\n\n/** Get a built-in rubric by name, or undefined. */\nexport function getBuiltinRubric(name: string): Rubric | undefined {\n return BUILTIN_RUBRICS[name]\n}\n\n/** List built-in rubrics with their stable versions. */\nexport function listBuiltinRubrics() {\n return Object.values(BUILTIN_RUBRICS).map((r) => ({\n name: r.name,\n description: r.description,\n dimensions: r.dimensions.map((d) => ({\n id: d.id,\n description: d.description,\n weight: d.weight,\n })),\n failureModes: r.failureModes.map((f) => f.id),\n rubricVersion: hashRubric(r),\n }))\n}\n","/**\n * Pure handler functions — the \"business logic\" behind every wire-protocol\n * method. The HTTP server (`server.ts`) and the stdio RPC (`rpc.ts`) both\n * call these. Tests call these directly without spinning a server.\n *\n * Each handler:\n * - Takes a parsed request (already Zod-validated by the transport).\n * - Returns a result that matches the response schema.\n * - Throws `WireError` for caller-fixable errors (404, 400, 422).\n * - Lets unexpected errors bubble — the transport maps them to 500.\n */\n\nimport { CostLedger, type CostLedgerHandle } from '../cost-ledger'\nimport type { FeedbackTrajectoryStore } from '../feedback-trajectory'\nimport {\n assertLlmRoute,\n callLlmJson,\n costReceiptFromLlm,\n costReceiptFromLlmError,\n type LlmCallRequest,\n type LlmClientOptions,\n LlmRouteAssertionError,\n type LlmRouteRequirements,\n maximumChargeForLlmRequest,\n} from '../llm-client'\nimport { packageVersion } from '../package-version'\nimport type { TraceEvent as InternalTraceEvent } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\nimport { getBuiltinRubric, listBuiltinRubrics } from './rubrics'\nimport {\n type FeedbackIngestResponse,\n hashRubric,\n type JudgeRequest,\n type JudgeResult,\n type ListRubricsResponse,\n type Rubric,\n type TracesIngestRequest,\n type TracesIngestResponse,\n type VersionResponse,\n WIRE_VERSION,\n type FeedbackTrajectory as WireFeedbackTrajectory,\n} from './schemas'\n\n/** Caller-fixable error. The transport renders this to 4xx + ErrorResponse. */\nexport class WireError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number = 400,\n public readonly details?: unknown,\n ) {\n super(message)\n this.name = 'WireError'\n }\n}\n\n// ── judge ───────────────────────────────────────────────────────────\n\n/** The JSON schema we ask the judging LLM to fill in. */\nfunction judgeOutputSchema(rubric: Rubric) {\n return {\n name: 'JudgeOutput',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n dimensions: {\n type: 'object',\n additionalProperties: false,\n properties: Object.fromEntries(\n rubric.dimensions.map((d) => [\n d.id,\n { type: 'number', minimum: d.min, maximum: d.max },\n ]),\n ),\n required: rubric.dimensions.map((d) => d.id),\n },\n failureModes: {\n type: 'array',\n items: { type: 'string', enum: rubric.failureModes.map((f) => f.id) },\n },\n wins: {\n type: 'array',\n items: { type: 'string', enum: rubric.wins.map((w) => w.id) },\n },\n rationale: { type: 'string' },\n },\n required: ['dimensions', 'rationale'],\n } as Record<string, unknown>,\n }\n}\n\ninterface JudgeOutput {\n dimensions: Record<string, number>\n failureModes?: string[]\n wins?: string[]\n rationale: string\n}\n\nfunction validateJudgeOutput(value: unknown, rubric: Rubric): JudgeOutput {\n if (!value || typeof value !== 'object') {\n throw new WireError('judge_error', 'Judge returned malformed output.', 500, value)\n }\n const raw = value as Record<string, unknown>\n const rawDimensions = raw.dimensions\n if (!rawDimensions || typeof rawDimensions !== 'object' || Array.isArray(rawDimensions)) {\n throw new WireError('judge_error', 'Judge returned malformed dimensions.', 500, value)\n }\n\n const dimensions: Record<string, number> = {}\n const dimensionRecord = rawDimensions as Record<string, unknown>\n for (const dim of rubric.dimensions) {\n const score = dimensionRecord[dim.id]\n if (\n typeof score !== 'number' ||\n !Number.isFinite(score) ||\n score < dim.min ||\n score > dim.max\n ) {\n throw new WireError(\n 'judge_error',\n `Judge returned invalid score for dimension \"${dim.id}\".`,\n 500,\n value,\n )\n }\n dimensions[dim.id] = score\n }\n\n const allowedFailures = new Set(rubric.failureModes.map((mode) => mode.id))\n const allowedWins = new Set(rubric.wins.map((win) => win.id))\n const failureModes = validateIdArray(raw.failureModes, allowedFailures, 'failureModes', value)\n const wins = validateIdArray(raw.wins, allowedWins, 'wins', value)\n if (typeof raw.rationale !== 'string' || raw.rationale.trim().length === 0) {\n throw new WireError('judge_error', 'Judge returned missing rationale.', 500, value)\n }\n\n return { dimensions, failureModes, wins, rationale: raw.rationale }\n}\n\nfunction validateIdArray(\n raw: unknown,\n allowed: Set<string>,\n field: 'failureModes' | 'wins',\n original: unknown,\n): string[] {\n if (raw === undefined) return []\n if (!Array.isArray(raw)) {\n throw new WireError('judge_error', `Judge returned non-array ${field}.`, 500, original)\n }\n const out: string[] = []\n for (const item of raw) {\n if (typeof item !== 'string' || !allowed.has(item)) {\n throw new WireError(\n 'judge_error',\n `Judge returned unknown ${field} id \"${String(item)}\".`,\n 500,\n original,\n )\n }\n out.push(item)\n }\n return out\n}\n\nfunction compositeScore(dimensions: Record<string, number>, rubric: Rubric): number {\n let weighted = 0\n let totalWeight = 0\n for (const dim of rubric.dimensions) {\n const raw = dimensions[dim.id] ?? 0\n const range = dim.max - dim.min || 1\n const normalized = Math.max(0, Math.min(1, (raw - dim.min) / range))\n weighted += normalized * dim.weight\n totalWeight += dim.weight\n }\n return totalWeight > 0 ? weighted / totalWeight : 0\n}\n\nfunction buildJudgePrompt(content: string, context: unknown): string {\n const ctx = context && Object.keys(context as object).length ? JSON.stringify(context) : ''\n return [\n `CONTENT TO JUDGE:`,\n content,\n '',\n ctx ? `CONTEXT (metadata, analytics, etc.):` : '',\n ctx ? ctx : '',\n ]\n .filter(Boolean)\n .join('\\n')\n}\n\nconst DEFAULT_JUDGE_MODEL = 'claude-sonnet-4-6'\n\nexport interface HandleJudgeOptions {\n costLedger?: CostLedgerHandle\n costPhase?: string\n llm?: LlmClientOptions\n defaultModel?: string\n routeRequirements?: LlmRouteRequirements\n signal?: AbortSignal\n}\n\nexport async function handleJudge(\n req: JudgeRequest,\n options: HandleJudgeOptions = {},\n): Promise<JudgeResult> {\n // Resolve rubric\n let rubric: Rubric\n if (req.rubricName) {\n const found = getBuiltinRubric(req.rubricName)\n if (!found) {\n throw new WireError('rubric_not_found', `No built-in rubric named \"${req.rubricName}\".`, 404)\n }\n rubric = found\n } else if (req.rubric) {\n rubric = req.rubric\n } else {\n // refine() in the schema should already have caught this — defense in depth\n throw new WireError('validation_error', 'Provide either `rubricName` or `rubric`.', 422)\n }\n\n if (options.routeRequirements) {\n try {\n assertLlmRoute(options.llm ?? {}, options.routeRequirements)\n } catch (error) {\n if (!(error instanceof LlmRouteAssertionError)) throw error\n const noEndpoint = error.reason === 'no_explicit_base_url'\n throw new WireError(\n noEndpoint ? 'llm_not_configured' : 'llm_route_rejected',\n noEndpoint\n ? 'No model endpoint is configured. Pass llm.baseUrl or configure the CLI provider environment variables.'\n : error.message,\n 503,\n { reason: error.reason },\n )\n }\n }\n\n const startedAt = Date.now()\n const model = req.model ?? options.defaultModel ?? DEFAULT_JUDGE_MODEL\n\n const request = {\n model,\n messages: [\n { role: 'system', content: rubric.systemPrompt },\n { role: 'user', content: buildJudgePrompt(req.content, req.context) },\n ],\n jsonSchema: judgeOutputSchema(rubric),\n temperature: 0.0,\n maxTokens: 4_000,\n timeoutMs: 60_000,\n } satisfies LlmCallRequest\n const ledger = options.costLedger ?? new CostLedger()\n const paid = await ledger.runPaidCall({\n channel: 'judge',\n phase: options.costPhase ?? 'wire.judge',\n actor: `wire.${req.rubricName ?? 'inline'}`,\n model,\n maximumCharge: maximumChargeForLlmRequest(request, options.llm),\n signal: options.signal,\n execute: (signal, callId) =>\n callLlmJson<JudgeOutput>(request, {\n ...options.llm,\n signal,\n idempotencyKey: callId,\n }),\n receipt: ({ result }) => costReceiptFromLlm(result),\n receiptFromError: costReceiptFromLlmError,\n })\n if (!paid.succeeded) throw paid.error\n const { value, result } = paid.value\n\n const output = validateJudgeOutput(value, rubric)\n\n const composite = compositeScore(output.dimensions, rubric)\n const durationMs = Date.now() - startedAt\n\n return {\n composite,\n dimensions: output.dimensions,\n failureModes: output.failureModes ?? [],\n wins: output.wins ?? [],\n rationale: output.rationale,\n rubricVersion: hashRubric(rubric),\n model: result.model,\n durationMs,\n }\n}\n\n// ── listRubrics ─────────────────────────────────────────────────────\n\nexport function handleListRubrics(): ListRubricsResponse {\n return { rubrics: listBuiltinRubrics() }\n}\n\n// ── version ─────────────────────────────────────────────────────────\n\nexport function handleVersion(): VersionResponse {\n return {\n package: '@tangle-network/agent-eval',\n version: packageVersion(),\n wireVersion: WIRE_VERSION,\n apiSurface: ['judge', 'listRubrics', 'version', 'feedback.ingest', 'traces.ingest'],\n }\n}\n\n// ── Ingestion handlers ───────────────────────────────────────────────\n\n/**\n * Pluggable stores the wire layer routes ingestion writes into. Both\n * are optional — when omitted, the corresponding endpoint returns 503.\n *\n * Production deployments wire a `FileSystemTraceStore` and\n * `FileSystemFeedbackTrajectoryStore` here. Tests substitute in-memory\n * stores.\n */\nexport interface IngestionStores {\n traceStore?: TraceStore\n feedbackStore?: FeedbackTrajectoryStore\n}\n\n/**\n * `POST /v1/traces/ingest` — accept a batch of `TraceEvent`s from the\n * production runtime. Best-effort: each event is appended independently;\n * one bad event does not poison the batch.\n *\n * Idempotency: the underlying store is append-only; consumers retrying\n * the same payload will get duplicate events. Consumers should\n * de-duplicate by `eventId` downstream — production traces frequently\n * land via at-least-once buses (Kafka, SQS) where dedup is unavoidable.\n */\nexport async function handleTracesIngest(\n req: TracesIngestRequest,\n stores: IngestionStores,\n): Promise<TracesIngestResponse> {\n if (!stores.traceStore) {\n throw new WireError(\n 'service_unavailable',\n 'No trace store configured on this server. Pass `traceStore` to `createApp`.',\n 503,\n )\n }\n const errors: Array<{ eventId: string; message: string }> = []\n let accepted = 0\n for (const event of req.events) {\n try {\n // The wire `TraceEvent` is structurally identical to the internal one.\n await stores.traceStore.appendEvent(event as InternalTraceEvent)\n accepted++\n } catch (err) {\n errors.push({\n eventId: event.eventId,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n return { accepted, rejected: errors.length, errors }\n}\n\n/**\n * `POST /v1/feedback` — accept a single `FeedbackTrajectory` from the\n * production runtime. Idempotent on `id`: re-posting the same trajectory\n * replaces the prior record.\n */\nexport async function handleFeedbackIngest(\n req: WireFeedbackTrajectory,\n stores: IngestionStores,\n): Promise<FeedbackIngestResponse> {\n if (!stores.feedbackStore) {\n throw new WireError(\n 'service_unavailable',\n 'No feedback store configured on this server. Pass `feedbackStore` to `createApp`.',\n 503,\n )\n }\n // The wire `FeedbackTrajectory` aligns 1:1 with the internal type;\n // cast through `unknown` since the wire schema is a Zod-inferred\n // structural type with optional fields the internal store consumes.\n await stores.feedbackStore.save(req as unknown as Parameters<FeedbackTrajectoryStore['save']>[0])\n return { id: req.id, persisted: true }\n}\n","/**\n * Build an OpenAPI spec from the wire schemas.\n *\n * The spec is the contract that other-language clients (Python, Rust,\n * Go, …) generate from. There is no hand-written client — clients are\n * derived artifacts of this file plus `schemas.ts`.\n *\n * Run `pnpm openapi` (defined in package.json) to write the spec to\n * `dist/openapi.json`. CI uses that file to regenerate the Python\n * client and gate the dual-publish workflow.\n */\nimport { OpenAPIRegistry, OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi'\nimport type { OpenAPIObject } from 'openapi3-ts/oas31'\n\nimport {\n ErrorResponseSchema,\n FeedbackIngestResponseSchema,\n FeedbackTrajectorySchema,\n HealthResponseSchema,\n JudgeRequestSchema,\n JudgeResultSchema,\n ListRubricsResponseSchema,\n TracesIngestRequestSchema,\n TracesIngestResponseSchema,\n VersionResponseSchema,\n WIRE_VERSION,\n} from './schemas'\n\nexport function buildOpenApi(packageVersion: string): OpenAPIObject {\n const registry = new OpenAPIRegistry()\n\n // Components — each schema becomes a $ref-able component\n registry.register('JudgeRequest', JudgeRequestSchema)\n registry.register('JudgeResult', JudgeResultSchema)\n registry.register('ListRubricsResponse', ListRubricsResponseSchema)\n registry.register('VersionResponse', VersionResponseSchema)\n registry.register('HealthResponse', HealthResponseSchema)\n registry.register('ErrorResponse', ErrorResponseSchema)\n registry.register('TracesIngestRequest', TracesIngestRequestSchema)\n registry.register('TracesIngestResponse', TracesIngestResponseSchema)\n registry.register('FeedbackTrajectory', FeedbackTrajectorySchema)\n registry.register('FeedbackIngestResponse', FeedbackIngestResponseSchema)\n\n // Routes\n registry.registerPath({\n method: 'post',\n path: '/v1/judge',\n summary: 'Score a piece of content against a rubric',\n description:\n 'Runs the judging LLM with the named (or inline) rubric and returns dimension scores, detected failure modes, wins, and a composite score in 0..1.',\n request: {\n body: {\n content: {\n 'application/json': { schema: JudgeRequestSchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Successful judgement',\n content: { 'application/json': { schema: JudgeResultSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 404: {\n description: 'Rubric not found',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 500: {\n description: 'Judge error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/v1/rubrics',\n summary: 'List built-in rubrics',\n description:\n 'Returns every rubric registered server-side, with their dimensions and stable rubricVersion hash.',\n responses: {\n 200: {\n description: 'Listing',\n content: { 'application/json': { schema: ListRubricsResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/v1/version',\n summary: 'Server and wire-protocol version',\n description: 'Match your client version to `version`; check `wireVersion` for compatibility.',\n responses: {\n 200: {\n description: 'Version info',\n content: { 'application/json': { schema: VersionResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'get',\n path: '/healthz',\n summary: 'Liveness check',\n responses: {\n 200: {\n description: 'OK',\n content: { 'application/json': { schema: HealthResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'post',\n path: '/v1/traces/ingest',\n summary: 'Ingest a batch of production TraceEvents',\n description:\n 'Append a batch of TraceEvents to the configured TraceStore. Accepts application/json ({events:[...]}) or application/x-ndjson (one event per line). Returns counts of accepted + rejected events.',\n request: {\n body: {\n content: {\n 'application/json': { schema: TracesIngestRequestSchema },\n 'application/x-ndjson': { schema: TracesIngestRequestSchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Ingestion summary',\n content: { 'application/json': { schema: TracesIngestResponseSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 401: {\n description: 'Unauthorized (when bearer auth is configured)',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 503: {\n description: 'No trace store configured',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n registry.registerPath({\n method: 'post',\n path: '/v1/feedback',\n summary: 'Ingest a FeedbackTrajectory from production',\n description:\n 'Persist a single FeedbackTrajectory. Idempotent on trajectory.id — re-posting replaces the prior record. Used by production runtimes to forward user 👍/👎/edits into the eval substrate.',\n request: {\n body: {\n content: {\n 'application/json': { schema: FeedbackTrajectorySchema },\n },\n },\n },\n responses: {\n 200: {\n description: 'Persisted',\n content: { 'application/json': { schema: FeedbackIngestResponseSchema } },\n },\n 400: {\n description: 'Validation error',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 401: {\n description: 'Unauthorized (when bearer auth is configured)',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n 503: {\n description: 'No feedback store configured',\n content: { 'application/json': { schema: ErrorResponseSchema } },\n },\n },\n })\n\n const generator = new OpenApiGeneratorV31(registry.definitions)\n const doc = generator.generateDocument({\n openapi: '3.1.0',\n info: {\n title: '@tangle-network/agent-eval — wire protocol',\n version: packageVersion,\n description: `HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: ${WIRE_VERSION}. Bumps on breaking changes to request/response schemas.`,\n contact: { name: 'Tangle Network', url: 'https://github.com/tangle-network/agent-eval' },\n license: { name: 'MIT' },\n },\n servers: [{ url: 'http://localhost:5005', description: 'Local agent-eval serve' }],\n })\n const rubricRef = { $ref: '#/components/schemas/Rubric' } as const\n const commonJudgeFields = {\n content: { type: 'string', minLength: 1 },\n context: { type: 'object', additionalProperties: true },\n model: { type: 'string' },\n } as const\n doc.components ??= {}\n doc.components.schemas ??= {}\n doc.components.schemas.JudgeRequest = {\n oneOf: [\n {\n type: 'object',\n additionalProperties: false,\n required: ['rubricName', 'content'],\n properties: {\n rubricName: { type: 'string', minLength: 1 },\n ...commonJudgeFields,\n },\n },\n {\n type: 'object',\n additionalProperties: false,\n required: ['rubric', 'content'],\n properties: {\n rubric: rubricRef,\n ...commonJudgeFields,\n },\n },\n ],\n description: 'Judge request. Provide exactly one of rubricName or rubric.',\n }\n return doc\n}\n","/**\n * stdio RPC transport.\n *\n * For batch / cron use without a running server. The Python client falls\n * back to this when no server is reachable.\n *\n * Protocol (line-delimited JSON over stdin/stdout):\n * IN: one JSON object on stdin: {\"method\":\"judge\",\"params\":{...}}\n * OUT: one JSON object on stdout: {\"result\":{...}} or {\"error\":{...}}\n *\n * One request per process invocation. To pipeline many calls, the client\n * writes JSONL to stdin and reads JSONL from stdout — see batch mode below.\n */\nimport type { LlmClientOptions, LlmRouteRequirements } from '../llm-client'\nimport { handleJudge, handleListRubrics, handleVersion, WireError } from './handlers'\nimport { JudgeRequestSchema } from './schemas'\n\ninterface RpcRequest {\n method: 'judge' | 'listRubrics' | 'version'\n params?: unknown\n}\n\ninterface RpcSuccess {\n result: unknown\n}\n\ninterface RpcError {\n error: { code: string; message: string; details?: unknown }\n}\n\nexport interface RpcOptions {\n llm?: LlmClientOptions\n judgeModel?: string\n llmRouteRequirements?: LlmRouteRequirements\n}\n\nexport async function dispatchRpc(\n req: RpcRequest,\n options: RpcOptions = {},\n): Promise<RpcSuccess | RpcError> {\n try {\n switch (req.method) {\n case 'judge': {\n const parsed = JudgeRequestSchema.safeParse(req.params)\n if (!parsed.success) {\n return {\n error: {\n code: 'validation_error',\n message: 'params did not match JudgeRequest schema.',\n details: parsed.error.issues,\n },\n }\n }\n return {\n result: await handleJudge(parsed.data, {\n llm: options.llm,\n defaultModel: options.judgeModel,\n routeRequirements: options.llmRouteRequirements,\n }),\n }\n }\n case 'listRubrics':\n return { result: handleListRubrics() }\n case 'version':\n return { result: handleVersion() }\n default:\n return {\n error: {\n code: 'unknown_method',\n message: `No such method: ${(req as { method: string }).method}`,\n },\n }\n }\n } catch (err) {\n if (err instanceof WireError) {\n return { error: { code: err.code, message: err.message, details: err.details } }\n }\n const message = err instanceof Error ? err.message : String(err)\n return { error: { code: 'internal_error', message } }\n }\n}\n\n// ── stdin/stdout driver ─────────────────────────────────────────────\n\nasync function readAll(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = []\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as string))\n }\n return Buffer.concat(chunks).toString('utf-8')\n}\n\n/** Read one JSON request from stdin, write one JSON response to stdout. */\nexport async function runRpcOnce(method?: string, options: RpcOptions = {}): Promise<number> {\n const raw = await readAll(process.stdin)\n let req: RpcRequest\n try {\n const body = JSON.parse(raw)\n req = method ? { method: method as RpcRequest['method'], params: body } : (body as RpcRequest)\n } catch (err) {\n process.stdout.write(\n `${JSON.stringify({\n error: {\n code: 'parse_error',\n message: `stdin was not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n },\n })}\\n`,\n )\n return 1\n }\n const out = await dispatchRpc(req, options)\n process.stdout.write(`${JSON.stringify(out)}\\n`)\n return 'error' in out ? 1 : 0\n}\n\n/** Read JSONL requests from stdin, write JSONL responses to stdout. */\nexport async function runRpcBatch(method?: string, options: RpcOptions = {}): Promise<number> {\n const raw = await readAll(process.stdin)\n const lines = raw.split('\\n').filter((l) => l.trim().length > 0)\n let exitCode = 0\n for (const line of lines) {\n let req: RpcRequest\n try {\n const body = JSON.parse(line)\n req = method ? { method: method as RpcRequest['method'], params: body } : (body as RpcRequest)\n } catch (err) {\n process.stdout.write(\n `${JSON.stringify({\n error: {\n code: 'parse_error',\n message: `line was not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n },\n })}\\n`,\n )\n exitCode = 1\n continue\n }\n const out = await dispatchRpc(req, options)\n process.stdout.write(`${JSON.stringify(out)}\\n`)\n if ('error' in out) exitCode = 1\n }\n return exitCode\n}\n","/**\n * HTTP transport for the wire protocol.\n *\n * Hono + @hono/node-server. Every endpoint:\n * 1. Validates the request against its Zod schema.\n * 2. Calls the matching handler in `handlers.ts`.\n * 3. Renders 4xx for `WireError` with structured body, 500 for unexpected.\n *\n * The server holds optional `IngestionStores` (passed to `createApp`)\n * to receive production traces and user feedback. With no stores wired,\n * the ingestion endpoints return 503 — read endpoints (`/v1/judge`,\n * `/v1/rubrics`, `/v1/version`) remain fully functional.\n *\n * Run via `agent-eval serve --port 5005`.\n */\nimport { type ServerType, serve } from '@hono/node-server'\nimport { Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport type { LlmClientOptions, LlmRouteRequirements } from '../llm-client'\nimport {\n handleFeedbackIngest,\n handleJudge,\n handleListRubrics,\n handleTracesIngest,\n handleVersion,\n type IngestionStores,\n WireError,\n} from './handlers'\nimport { buildOpenApi } from './openapi'\nimport { FeedbackTrajectorySchema, JudgeRequestSchema, TracesIngestRequestSchema } from './schemas'\n\nconst STARTED_AT = Date.now()\n\nexport interface CreateAppOptions {\n /** Stores wired to the ingestion endpoints. */\n stores?: IngestionStores\n /** Model provider used by `/v1/judge`. */\n llm?: LlmClientOptions\n /** Default judge model when a request does not provide one. */\n judgeModel?: string\n /** Model route checks applied before every judge call. */\n llmRouteRequirements?: LlmRouteRequirements\n /**\n * Bearer-token auth. When provided, every endpoint EXCEPT `/healthz`\n * and `/v1/version` requires `Authorization: Bearer <token>`. The\n * token may be a static string OR a function for time-bounded /\n * rotating tokens.\n *\n * Recommended for any server that accepts ingestion writes from the\n * public internet. Read-only deployments may omit it.\n */\n auth?: {\n bearer: string | ((token: string) => boolean | Promise<boolean>)\n }\n}\n\nconst AUTH_EXEMPT_PATHS = new Set(['/healthz', '/v1/version', '/openapi.json'])\n\nexport function createApp(opts: CreateAppOptions = {}) {\n const app = new Hono()\n\n app.use('*', cors())\n\n // Bearer-token middleware (only attached when configured).\n if (opts.auth) {\n const verify = opts.auth.bearer\n app.use('*', async (c, next) => {\n const path = new URL(c.req.url).pathname\n if (AUTH_EXEMPT_PATHS.has(path)) return next()\n const raw = c.req.header('authorization') ?? ''\n const match = raw.match(/^Bearer\\s+(.+)$/i)\n if (!match) {\n throw new WireError('unauthorized', 'Missing or malformed Authorization header.', 401)\n }\n const token = match[1] as string\n const ok = typeof verify === 'string' ? token === verify : await verify(token)\n if (!ok) {\n throw new WireError('unauthorized', 'Invalid bearer token.', 401)\n }\n return next()\n })\n }\n\n app.onError((err, c) => {\n if (err instanceof WireError) {\n const status = err.status as 400 | 401 | 404 | 422 | 500 | 503\n return c.json(\n { error: { code: err.code, message: err.message, details: err.details } },\n status,\n )\n }\n // Unexpected — log and return generic 500 without leaking internals.\n console.error('[agent-eval] unhandled error:', err)\n return c.json({ error: { code: 'internal_error', message: 'Internal server error.' } }, 500)\n })\n\n // ── Health ──\n app.get('/healthz', (c) =>\n c.json({ status: 'ok' as const, uptimeSec: (Date.now() - STARTED_AT) / 1000 }),\n )\n\n // ── Version ──\n app.get('/v1/version', (c) => c.json(handleVersion()))\n\n // ── Rubrics ──\n app.get('/v1/rubrics', (c) => c.json(handleListRubrics()))\n\n // ── Judge ──\n app.post('/v1/judge', async (c) => {\n const raw = await c.req.json().catch(() => null)\n if (raw == null) {\n throw new WireError('validation_error', 'Request body must be JSON.', 400)\n }\n const parsed = JudgeRequestSchema.safeParse(raw)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match JudgeRequest schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleJudge(parsed.data, {\n llm: opts.llm,\n defaultModel: opts.judgeModel,\n routeRequirements: opts.llmRouteRequirements,\n })\n return c.json(result)\n })\n\n // ── Traces ingest (NDJSON-friendly: accepts either {events:[...]} or NDJSON) ──\n app.post('/v1/traces/ingest', async (c) => {\n const contentType = c.req.header('content-type') ?? ''\n let payload: unknown\n if (contentType.includes('application/x-ndjson')) {\n const text = await c.req.text()\n const events = text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n try {\n return JSON.parse(line)\n } catch {\n throw new WireError(\n 'validation_error',\n 'NDJSON line did not parse as JSON.',\n 400,\n line.slice(0, 200),\n )\n }\n })\n payload = { events }\n } else {\n payload = await c.req.json().catch(() => null)\n }\n if (payload == null) {\n throw new WireError('validation_error', 'Request body must be JSON or NDJSON.', 400)\n }\n const parsed = TracesIngestRequestSchema.safeParse(payload)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match TracesIngestRequest schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleTracesIngest(parsed.data, opts.stores ?? {})\n return c.json(result)\n })\n\n // ── Feedback ingest ──\n app.post('/v1/feedback', async (c) => {\n const raw = await c.req.json().catch(() => null)\n if (raw == null) {\n throw new WireError('validation_error', 'Request body must be JSON.', 400)\n }\n const parsed = FeedbackTrajectorySchema.safeParse(raw)\n if (!parsed.success) {\n throw new WireError(\n 'validation_error',\n 'Request did not match FeedbackTrajectory schema.',\n 400,\n parsed.error.issues,\n )\n }\n const result = await handleFeedbackIngest(parsed.data, opts.stores ?? {})\n return c.json(result)\n })\n\n // ── OpenAPI spec ──\n app.get('/openapi.json', (c) => c.json(buildOpenApi(handleVersion().version)))\n\n return app\n}\n\nexport interface ServeOptions extends CreateAppOptions {\n /** Default 5005. */\n port?: number\n /** Default '127.0.0.1'. Set to '0.0.0.0' to listen on all interfaces. */\n host?: string\n}\n\nexport function startServer(opts: ServeOptions = {}): ServerType {\n const app = createApp(opts)\n const port = opts.port ?? 5005\n const host = opts.host ?? '127.0.0.1'\n return serve({ fetch: app.fetch, port, hostname: host }, ({ address, port: actualPort }) => {\n // eslint-disable-next-line no-console\n console.log(`[agent-eval] serving on http://${address}:${actualPort}`)\n })\n}\n\nexport interface StartedServer {\n server: ServerType\n /** The OS-assigned port. When opts.port was 0, this is the actual port the\n * kernel bound — callers that need to dial back (smoke tests, sidecars\n * registering with a parent) read this rather than guessing a free port. */\n port: number\n /** Resolved host the server bound to (defaults to 127.0.0.1). */\n host: string\n /** Close the server. Resolves once active connections have drained. */\n close(): Promise<void>\n}\n\n/**\n * Promise-returning variant of `startServer` that resolves once the server is\n * listening and surfaces the resolved bound port. Use this from smoke tests\n * (`startServerAsync({ port: 0 })`) and any caller that needs to dial back.\n */\nexport function startServerAsync(opts: ServeOptions = {}): Promise<StartedServer> {\n const app = createApp(opts)\n const port = opts.port ?? 5005\n const host = opts.host ?? '127.0.0.1'\n return new Promise((resolve, reject) => {\n let settled = false\n let server: ServerType | undefined\n server = serve({ fetch: app.fetch, port, hostname: host }, ({ address, port: actualPort }) => {\n if (settled) return\n settled = true\n // eslint-disable-next-line no-console\n console.log(`[agent-eval] serving on http://${address}:${actualPort}`)\n resolve({\n server: server!,\n port: actualPort,\n host: address,\n close: () =>\n new Promise<void>((res, rej) => {\n server!.close((err) => (err ? rej(err) : res()))\n }),\n })\n })\n server.on('error', (err) => {\n if (settled) return\n settled = true\n reject(err)\n })\n })\n}\n"],"mappings":"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"}