@tangle-network/agent-eval 0.221.8 → 0.222.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 (579) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/dist/adapters/http.d.ts +3 -5
  3. package/dist/adapters/http.d.ts.map +1 -1
  4. package/dist/adapters/http.js +1 -2
  5. package/dist/{adversarial-smnADNFS.d.ts → adversarial-DnQQFqTR.d.ts} +1 -3
  6. package/dist/adversarial-DnQQFqTR.d.ts.map +1 -0
  7. package/dist/{agent-profile-CNmwfaqq.d.ts → agent-profile-CoD1Dotf.d.ts} +4 -10
  8. package/dist/agent-profile-CoD1Dotf.d.ts.map +1 -0
  9. package/dist/agent-profile-Dngk3LZ0.js +153 -0
  10. package/dist/agent-profile-Dngk3LZ0.js.map +1 -0
  11. package/dist/{agent-profile-cell-BcpFbNd5.d.ts → agent-profile-cell-3kYxUsK2.d.ts} +3 -5
  12. package/dist/agent-profile-cell-3kYxUsK2.d.ts.map +1 -0
  13. package/dist/{agent-profile-cell-B1V1gUZs.js → agent-profile-cell-CT5JYueM.js} +5 -7
  14. package/dist/{agent-profile-cell-B1V1gUZs.js.map → agent-profile-cell-CT5JYueM.js.map} +1 -1
  15. package/dist/{agreement-irr-BhAqjluA.js → agreement-irr-BTjDN0i6.js} +4 -5
  16. package/dist/{agreement-irr-BhAqjluA.js.map → agreement-irr-BTjDN0i6.js.map} +1 -1
  17. package/dist/analyst/index.d.ts +95 -159
  18. package/dist/analyst/index.d.ts.map +1 -1
  19. package/dist/analyst/index.js +28 -39
  20. package/dist/analyst/index.js.map +1 -1
  21. package/dist/{analyze-runs-DfX6dHP0.d.ts → analyze-runs-C-pP1sK9.d.ts} +7 -13
  22. package/dist/analyze-runs-C-pP1sK9.d.ts.map +1 -0
  23. package/dist/{analyze-runs-CHmsykNJ.js → analyze-runs-CTheASYV.js} +23 -32
  24. package/dist/{analyze-runs-CHmsykNJ.js.map → analyze-runs-CTheASYV.js.map} +1 -1
  25. package/dist/{attribute-vocabulary-CcXqHODT.d.ts → attribute-vocabulary-5oo8ykIx.d.ts} +2 -4
  26. package/dist/attribute-vocabulary-5oo8ykIx.d.ts.map +1 -0
  27. package/dist/authenticity/index.d.ts +0 -2
  28. package/dist/authenticity/index.d.ts.map +1 -1
  29. package/dist/authenticity/index.js +1 -2
  30. package/dist/{benchmark-command-Cnjfo0Zh.js → benchmark-command-jYWR2gya.js} +61 -94
  31. package/dist/benchmark-command-jYWR2gya.js.map +1 -0
  32. package/dist/benchmarks/index.d.ts +5 -15
  33. package/dist/benchmarks/index.d.ts.map +1 -1
  34. package/dist/benchmarks/index.js +27 -38
  35. package/dist/benchmarks/index.js.map +1 -1
  36. package/dist/{bounded-process-Cj9YjXbE.js → bounded-process-BZrWXIKW.js} +2 -3
  37. package/dist/{bounded-process-Cj9YjXbE.js.map → bounded-process-BZrWXIKW.js.map} +1 -1
  38. package/dist/builder-eval/index.d.ts +5 -14
  39. package/dist/builder-eval/index.d.ts.map +1 -1
  40. package/dist/builder-eval/index.js +11 -17
  41. package/dist/builder-eval/index.js.map +1 -1
  42. package/dist/{calibration-CTwxpJ-t.js → calibration-6usfVYYo.js} +4 -5
  43. package/dist/{calibration-CTwxpJ-t.js.map → calibration-6usfVYYo.js.map} +1 -1
  44. package/dist/campaign/index.d.ts +9 -9
  45. package/dist/campaign/index.js +15 -14
  46. package/dist/{campaign-uddTlFg5.js → campaign-ddr1N3yD.js} +61 -58
  47. package/dist/campaign-ddr1N3yD.js.map +1 -0
  48. package/dist/{campaign-evidence-DunzcJGv.js → campaign-evidence-DN8rWuBj.js} +20 -322
  49. package/dist/campaign-evidence-DN8rWuBj.js.map +1 -0
  50. package/dist/{canonical-Dq2hOQ8L.js → canonical-CicJlINA.js} +3 -4
  51. package/dist/{canonical-Dq2hOQ8L.js.map → canonical-CicJlINA.js.map} +1 -1
  52. package/dist/{canonical-CFpojCN5.d.ts → canonical-gLeHiqzd.d.ts} +2 -4
  53. package/dist/canonical-gLeHiqzd.d.ts.map +1 -0
  54. package/dist/{cell-spend-DEWR3nj-.js → cell-spend-zxmzg4GH.js} +3 -4
  55. package/dist/{cell-spend-DEWR3nj-.js.map → cell-spend-zxmzg4GH.js.map} +1 -1
  56. package/dist/{chat-client-BNATB3rJ.js → chat-client-CO3uB33i.js} +3 -4
  57. package/dist/{chat-client-BNATB3rJ.js.map → chat-client-CO3uB33i.js.map} +1 -1
  58. package/dist/{chat-json-call-BzWYp18J.js → chat-json-call-8yUv4LFO.js} +4 -5
  59. package/dist/{chat-json-call-BzWYp18J.js.map → chat-json-call-8yUv4LFO.js.map} +1 -1
  60. package/dist/{claim-BPVuyHuy.js → claim-Dod_mjk3.js} +5 -6
  61. package/dist/{claim-BPVuyHuy.js.map → claim-Dod_mjk3.js.map} +1 -1
  62. package/dist/cli.js +179 -23
  63. package/dist/cli.js.map +1 -1
  64. package/dist/{client-hwo3cJjR.d.ts → client-BIFwUg7I.d.ts} +6 -12
  65. package/dist/client-BIFwUg7I.d.ts.map +1 -0
  66. package/dist/{cluster-bootstrap-DEwwhl0C.js → cluster-bootstrap-SbaeM44s.js} +4 -5
  67. package/dist/{cluster-bootstrap-DEwwhl0C.js.map → cluster-bootstrap-SbaeM44s.js.map} +1 -1
  68. package/dist/completion-verifier-7KEfroqx.d.ts +168 -0
  69. package/dist/completion-verifier-7KEfroqx.d.ts.map +1 -0
  70. package/dist/{completion-verifier-asaV1nSj.js → completion-verifier-rqbMh5-4.js} +9 -160
  71. package/dist/completion-verifier-rqbMh5-4.js.map +1 -0
  72. package/dist/contract/index.d.ts +13 -13
  73. package/dist/contract/index.js +41 -60
  74. package/dist/contract/index.js.map +1 -1
  75. package/dist/{cost-ledger-BGZB6yY2.js → cost-ledger-CS8R3IZj.js} +10 -17
  76. package/dist/{cost-ledger-BGZB6yY2.js.map → cost-ledger-CS8R3IZj.js.map} +1 -1
  77. package/dist/{cost-ledger-C1W3ICmP.d.ts → cost-ledger-Czro9wmo.d.ts} +1 -5
  78. package/dist/cost-ledger-Czro9wmo.d.ts.map +1 -0
  79. package/dist/{dataset-DQqhOCPt.d.ts → dataset-DThC1S6G.d.ts} +1 -3
  80. package/dist/dataset-DThC1S6G.d.ts.map +1 -0
  81. package/dist/{decision-point-0nJubuoM.js → decision-point-lhMgODOR.js} +14 -18
  82. package/dist/{decision-point-0nJubuoM.js.map → decision-point-lhMgODOR.js.map} +1 -1
  83. package/dist/{deep-freeze-CurcOQg3.js → deep-freeze-CK8-2W7p.js} +2 -3
  84. package/dist/{deep-freeze-CurcOQg3.js.map → deep-freeze-CK8-2W7p.js.map} +1 -1
  85. package/dist/{default-registry-CLG5YqGS.d.ts → default-registry-B1DstPYg.d.ts} +53 -61
  86. package/dist/default-registry-B1DstPYg.d.ts.map +1 -0
  87. package/dist/{default-registry-BBTDgkDM.js → default-registry-C1tPEjZ4.js} +29 -45
  88. package/dist/{default-registry-BBTDgkDM.js.map → default-registry-C1tPEjZ4.js.map} +1 -1
  89. package/dist/{define-agent-eval-CCbT7Kfr.js → define-agent-eval-BLoP4Lf9.js} +15 -18
  90. package/dist/{define-agent-eval-CCbT7Kfr.js.map → define-agent-eval-BLoP4Lf9.js.map} +1 -1
  91. package/dist/{define-agent-eval-JKt3gMQr.d.ts → define-agent-eval-CAffiFbN.d.ts} +19 -27
  92. package/dist/define-agent-eval-CAffiFbN.d.ts.map +1 -0
  93. package/dist/{descriptive-CVNy48rR.js → descriptive-cPwITVfy.js} +30 -8
  94. package/dist/descriptive-cPwITVfy.js.map +1 -0
  95. package/dist/diagnosis/index.d.ts +5 -15
  96. package/dist/diagnosis/index.d.ts.map +1 -1
  97. package/dist/diagnosis/index.js +13 -19
  98. package/dist/diagnosis/index.js.map +1 -1
  99. package/dist/{dspy-rlm-engine-DN1p_5jx.js → dspy-rlm-engine-jDiWkul6.js} +7 -10
  100. package/dist/{dspy-rlm-engine-DN1p_5jx.js.map → dspy-rlm-engine-jDiWkul6.js.map} +1 -1
  101. package/dist/{emitter-DbMXUIVP.js → emitter-DhQ65mza.js} +3 -4
  102. package/dist/{emitter-DbMXUIVP.js.map → emitter-DhQ65mza.js.map} +1 -1
  103. package/dist/{emitter-DABYYTcH.d.ts → emitter-mAXC5PSN.d.ts} +3 -5
  104. package/dist/emitter-mAXC5PSN.d.ts.map +1 -0
  105. package/dist/{engine-dtRVeuQs.d.ts → engine-CaHaCc3W.d.ts} +10 -18
  106. package/dist/engine-CaHaCc3W.d.ts.map +1 -0
  107. package/dist/{equal-terms-DbPGcVtI.js → equal-terms-K11VHmR3.js} +3 -4
  108. package/dist/{equal-terms-DbPGcVtI.js.map → equal-terms-K11VHmR3.js.map} +1 -1
  109. package/dist/{errors-BcOs5MKW.js → errors-DeEEV9Vx.js} +2 -3
  110. package/dist/{errors-BcOs5MKW.js.map → errors-DeEEV9Vx.js.map} +1 -1
  111. package/dist/{errors-DEE6u6ot.d.ts → errors-E9I2hldP.d.ts} +1 -3
  112. package/dist/errors-E9I2hldP.d.ts.map +1 -0
  113. package/dist/{eval-campaign-DoX5vz3E.js → eval-campaign-Cgixrvf7.js} +8 -9
  114. package/dist/{eval-campaign-DoX5vz3E.js.map → eval-campaign-Cgixrvf7.js.map} +1 -1
  115. package/dist/{evaluation-wdGyZ7jV.js → evaluation-B8H3GYej.js} +4 -6
  116. package/dist/{evaluation-wdGyZ7jV.js.map → evaluation-B8H3GYej.js.map} +1 -1
  117. package/dist/{evaluation-DblGquCB.d.ts → evaluation-BPqUvZ66.d.ts} +4 -6
  118. package/dist/evaluation-BPqUvZ66.d.ts.map +1 -0
  119. package/dist/evaluation.d.ts +1 -1
  120. package/dist/evaluation.js +1 -2
  121. package/dist/{exact-types-Do63KoKn.d.ts → exact-types-D98BKpxo.d.ts} +8 -10
  122. package/dist/exact-types-D98BKpxo.d.ts.map +1 -0
  123. package/dist/{exec-CpbtOXVt.js → exec-C0_AkLUv.js} +3 -5
  124. package/dist/{exec-CpbtOXVt.js.map → exec-C0_AkLUv.js.map} +1 -1
  125. package/dist/{execution-tracks-CpgFPpS5.js → execution-tracks-DaDXYwAq.js} +2 -3
  126. package/dist/{execution-tracks-CpgFPpS5.js.map → execution-tracks-DaDXYwAq.js.map} +1 -1
  127. package/dist/experiment/index.d.ts +9 -37
  128. package/dist/experiment/index.d.ts.map +1 -1
  129. package/dist/experiment/index.js +29 -40
  130. package/dist/experiment/index.js.map +1 -1
  131. package/dist/{exporters-Dk3oEbK_.d.ts → exporters-B5Ze_RKh.d.ts} +4 -4
  132. package/dist/exporters-B5Ze_RKh.d.ts.map +1 -0
  133. package/dist/{exporters-DWvM16LE.js → exporters-ByLcILYU.js} +23 -5
  134. package/dist/exporters-ByLcILYU.js.map +1 -0
  135. package/dist/{external-optimizer-process-DEzJ2CGX.js → external-optimizer-process-BRVmaDFe.js} +5 -6
  136. package/dist/{external-optimizer-process-DEzJ2CGX.js.map → external-optimizer-process-BRVmaDFe.js.map} +1 -1
  137. package/dist/{external-optimizer-subprocess-B_ukPtRD.js → external-optimizer-subprocess-U616hV_l.js} +24 -37
  138. package/dist/{external-optimizer-subprocess-B_ukPtRD.js.map → external-optimizer-subprocess-U616hV_l.js.map} +1 -1
  139. package/dist/{extract-usage-BZLU01kR.js → extract-usage-ISFqhfDz.js} +2 -3
  140. package/dist/{extract-usage-BZLU01kR.js.map → extract-usage-ISFqhfDz.js.map} +1 -1
  141. package/dist/{failure-cluster-DN0t63Z0.d.ts → failure-cluster-DOoa7CBg.d.ts} +3 -7
  142. package/dist/failure-cluster-DOoa7CBg.d.ts.map +1 -0
  143. package/dist/{failure-taxonomy-Bx5oWqaW.js → failure-taxonomy-9eQfXKoW.js} +2 -3
  144. package/dist/{failure-taxonomy-Bx5oWqaW.js.map → failure-taxonomy-9eQfXKoW.js.map} +1 -1
  145. package/dist/{feedback-trajectory-CYVJXolG.d.ts → feedback-trajectory-SBGncrCP.d.ts} +7 -13
  146. package/dist/feedback-trajectory-SBGncrCP.d.ts.map +1 -0
  147. package/dist/{finding-composition-8n0fFgVI.js → finding-composition-DlvE1Qul.js} +4 -6
  148. package/dist/{finding-composition-8n0fFgVI.js.map → finding-composition-DlvE1Qul.js.map} +1 -1
  149. package/dist/{findings-store-Bg4sdS-e.js → findings-store-B75Dspaq.js} +11 -14
  150. package/dist/{findings-store-Bg4sdS-e.js.map → findings-store-B75Dspaq.js.map} +1 -1
  151. package/dist/fuzz.d.ts +3 -17
  152. package/dist/fuzz.d.ts.map +1 -1
  153. package/dist/fuzz.js +30 -29
  154. package/dist/fuzz.js.map +1 -1
  155. package/dist/{hf-dataset-CKxIJQba.js → hf-dataset-DPVQXW5n.js} +362 -21
  156. package/dist/hf-dataset-DPVQXW5n.js.map +1 -0
  157. package/dist/hosted/index.d.ts +2 -6
  158. package/dist/hosted/index.d.ts.map +1 -1
  159. package/dist/hosted/index.js +1 -2
  160. package/dist/{index-CalAsXMR.d.ts → index-B1Bm9oJA.d.ts} +3 -15
  161. package/dist/index-B1Bm9oJA.d.ts.map +1 -0
  162. package/dist/{index-CdEVr8-O.d.ts → index-B7v2QHlD.d.ts} +24 -299
  163. package/dist/index-B7v2QHlD.d.ts.map +1 -0
  164. package/dist/{index-CTIRz-AB.d.ts → index-CUjeTDPv.d.ts} +14 -36
  165. package/dist/index-CUjeTDPv.d.ts.map +1 -0
  166. package/dist/{index-CfJULcW5.d.ts → index-DAk2quYu.d.ts} +18 -38
  167. package/dist/index-DAk2quYu.d.ts.map +1 -0
  168. package/dist/{index-D7fmC-1K.d.ts → index-DUn0GNiZ.d.ts} +183 -36
  169. package/dist/index-DUn0GNiZ.d.ts.map +1 -0
  170. package/dist/{index-CHxwfW5g.d.ts → index-DwUGehqX.d.ts} +3 -9
  171. package/dist/index-DwUGehqX.d.ts.map +1 -0
  172. package/dist/{index-jnuFLxOs.d.ts → index-aDPVYBIM.d.ts} +11 -39
  173. package/dist/index-aDPVYBIM.d.ts.map +1 -0
  174. package/dist/index.d.ts +55 -188
  175. package/dist/index.d.ts.map +1 -1
  176. package/dist/index.js +122 -195
  177. package/dist/index.js.map +1 -1
  178. package/dist/{integrity-D-s2iHiT.js → integrity-B1V6klyO.js} +12 -363
  179. package/dist/integrity-B1V6klyO.js.map +1 -0
  180. package/dist/{integrity-D9lBnv_K.d.ts → integrity-BAdVzT8u.d.ts} +4 -6
  181. package/dist/integrity-BAdVzT8u.d.ts.map +1 -0
  182. package/dist/{integrity-W4CADcFc.js → integrity-DOHt1mwU.js} +3 -4
  183. package/dist/{integrity-W4CADcFc.js.map → integrity-DOHt1mwU.js.map} +1 -1
  184. package/dist/{internal-BTK91Bqt.js → internal-v6XfOeJW.js} +6 -8
  185. package/dist/{internal-BTK91Bqt.js.map → internal-v6XfOeJW.js.map} +1 -1
  186. package/dist/{interval-Dq9gt7jx.js → interval-Bd2f4CRT.js} +6 -8
  187. package/dist/{interval-Dq9gt7jx.js.map → interval-Bd2f4CRT.js.map} +1 -1
  188. package/dist/{interval-ohuOJurX.d.ts → interval-CWyxqDpE.d.ts} +1 -5
  189. package/dist/interval-CWyxqDpE.d.ts.map +1 -0
  190. package/dist/{journal-C7om8Gum.js → journal-C1uLJi0w.js} +115 -121
  191. package/dist/{journal-C7om8Gum.js.map → journal-C1uLJi0w.js.map} +1 -1
  192. package/dist/{json-BhdsJaOQ.js → json-DtvZNAU9.js} +4 -6
  193. package/dist/{json-BhdsJaOQ.js.map → json-DtvZNAU9.js.map} +1 -1
  194. package/dist/json-recovery-DK4MDm5r.js +296 -0
  195. package/dist/json-recovery-DK4MDm5r.js.map +1 -0
  196. package/dist/{judge-calibration-BkXMIWA4.js → judge-calibration-DGqlfWW8.js} +5 -6
  197. package/dist/{judge-calibration-BkXMIWA4.js.map → judge-calibration-DGqlfWW8.js.map} +1 -1
  198. package/dist/{judge-calibration-DFtEMlde.d.ts → judge-calibration-DnrbQaXI.d.ts} +1 -3
  199. package/dist/judge-calibration-DnrbQaXI.d.ts.map +1 -0
  200. package/dist/{judge-gate-BVvmP00P.js → judge-gate-C2BCOt-M.js} +8 -12
  201. package/dist/{judge-gate-BVvmP00P.js.map → judge-gate-C2BCOt-M.js.map} +1 -1
  202. package/dist/judges-BLxg5p8E.js +20 -0
  203. package/dist/judges-BLxg5p8E.js.map +1 -0
  204. package/dist/{kind-factory-Dl0PmNQL.js → kind-factory-VKysp1ds.js} +23 -39
  205. package/dist/{kind-factory-Dl0PmNQL.js.map → kind-factory-VKysp1ds.js.map} +1 -1
  206. package/dist/ledger-core/index.d.ts +2 -2
  207. package/dist/ledger-core/index.js +3 -3
  208. package/dist/ledger-core/lock-holder.d.ts +1 -1
  209. package/dist/ledger-core/lock-holder.js +1 -2
  210. package/dist/{ledger-core-CAxUdDk0.js → ledger-core-CfT-FzPf.js} +5 -6
  211. package/dist/{ledger-core-CAxUdDk0.js.map → ledger-core-CfT-FzPf.js.map} +1 -1
  212. package/dist/{llm-client-b1ysZVIU.js → llm-client-kJ9EOqjt.js} +22 -30
  213. package/dist/{llm-client-b1ysZVIU.js.map → llm-client-kJ9EOqjt.js.map} +1 -1
  214. package/dist/{llm-judge-Cybq29bL.js → llm-judge-cgbhTKQp.js} +108 -164
  215. package/dist/llm-judge-cgbhTKQp.js.map +1 -0
  216. package/dist/{lock-holder-DaJbfpci.d.ts → lock-holder-DoxlZFkQ.d.ts} +1 -3
  217. package/dist/lock-holder-DoxlZFkQ.d.ts.map +1 -0
  218. package/dist/matrix/index.d.ts +3 -3
  219. package/dist/matrix/index.js +2 -2
  220. package/dist/{matrix-DtkZLD_3.d.ts → matrix-CBUzIZs4.d.ts} +4 -12
  221. package/dist/matrix-CBUzIZs4.d.ts.map +1 -0
  222. package/dist/{matrix-B8l-Nsxd.js → matrix-CgpX8wdm.js} +8 -13
  223. package/dist/matrix-CgpX8wdm.js.map +1 -0
  224. package/dist/{mean-BbA_JCzW.js → mean-CdDYG-us.js} +6 -9
  225. package/dist/{mean-BbA_JCzW.js.map → mean-CdDYG-us.js.map} +1 -1
  226. package/dist/meta-eval/index.d.ts +3 -3
  227. package/dist/meta-eval/index.js +17 -21
  228. package/dist/meta-eval/index.js.map +1 -1
  229. package/dist/{metrics-BKaPBtIG.js → metrics-DNCAUtuB.js} +2 -3
  230. package/dist/{metrics-BKaPBtIG.js.map → metrics-DNCAUtuB.js.map} +1 -1
  231. package/dist/{mint-CbdwjTPW.js → mint-D9ZysYtY.js} +7 -8
  232. package/dist/{mint-CbdwjTPW.js.map → mint-D9ZysYtY.js.map} +1 -1
  233. package/dist/{multi-layer-verifier-DEgMUk6v.d.ts → multi-layer-verifier-lM4aVN78.d.ts} +2 -4
  234. package/dist/multi-layer-verifier-lM4aVN78.d.ts.map +1 -0
  235. package/dist/{multiplicity-Sg0U7h8j.js → multiplicity-DAd4xaDC.js} +3 -4
  236. package/dist/{multiplicity-Sg0U7h8j.js.map → multiplicity-DAd4xaDC.js.map} +1 -1
  237. package/dist/{multiplicity-DIWHvysC.d.ts → multiplicity-D_SEsc5j.d.ts} +1 -3
  238. package/dist/multiplicity-D_SEsc5j.d.ts.map +1 -0
  239. package/dist/multishot/golden/index.d.ts +1 -17
  240. package/dist/multishot/golden/index.d.ts.map +1 -1
  241. package/dist/multishot/golden/index.js +10 -17
  242. package/dist/multishot/golden/index.js.map +1 -1
  243. package/dist/multishot/index.d.ts +2 -10
  244. package/dist/multishot/index.d.ts.map +1 -1
  245. package/dist/multishot/index.js +11 -18
  246. package/dist/multishot/index.js.map +1 -1
  247. package/dist/{nonnegative-number-DvdMxg_f.js → nonnegative-number-lEYbOsuh.js} +2 -3
  248. package/dist/{nonnegative-number-DvdMxg_f.js.map → nonnegative-number-lEYbOsuh.js.map} +1 -1
  249. package/dist/openapi.json +1 -1
  250. package/dist/{otel-spans-64hmQqON.js → otel-spans-BsGzTWIK.js} +5 -6
  251. package/dist/{otel-spans-64hmQqON.js.map → otel-spans-BsGzTWIK.js.map} +1 -1
  252. package/dist/{otlp-attributes-D9ptWaIJ.js → otlp-attributes-Boeb7gtH.js} +2 -3
  253. package/dist/{otlp-attributes-D9ptWaIJ.js.map → otlp-attributes-Boeb7gtH.js.map} +1 -1
  254. package/dist/{outcome-observations-FLmRpgYa.js → outcome-observations-D4snOtUb.js} +4 -5
  255. package/dist/{outcome-observations-FLmRpgYa.js.map → outcome-observations-D4snOtUb.js.map} +1 -1
  256. package/dist/{outcome-store-DUcMj-3D.js → outcome-store-TarrcfHG.js} +2 -3
  257. package/dist/{outcome-store-DUcMj-3D.js.map → outcome-store-TarrcfHG.js.map} +1 -1
  258. package/dist/{package-version-D7lQHt_-.js → package-version-CJl_pY9W.js} +2 -3
  259. package/dist/{package-version-D7lQHt_-.js.map → package-version-CJl_pY9W.js.map} +1 -1
  260. package/dist/{paired-arms-B2ttLc0_.js → paired-arms-D-54hO-k.js} +10 -14
  261. package/dist/{paired-arms-B2ttLc0_.js.map → paired-arms-D-54hO-k.js.map} +1 -1
  262. package/dist/{paired-binary-B_nejA44.js → paired-binary-BR0nwHOA.js} +3 -4
  263. package/dist/{paired-binary-B_nejA44.js.map → paired-binary-BR0nwHOA.js.map} +1 -1
  264. package/dist/{paired-promotion-decision-CQMJ5xGN.d.ts → paired-promotion-decision-BDnqepZ1.d.ts} +1 -5
  265. package/dist/paired-promotion-decision-BDnqepZ1.d.ts.map +1 -0
  266. package/dist/{paired-promotion-decision-D0SHb-ZL.js → paired-promotion-decision-FGvHA4p_.js} +5 -7
  267. package/dist/{paired-promotion-decision-D0SHb-ZL.js.map → paired-promotion-decision-FGvHA4p_.js.map} +1 -1
  268. package/dist/{pareto-BiBnQXAE.js → pareto-B9udAt2i.js} +28 -50
  269. package/dist/pareto-B9udAt2i.js.map +1 -0
  270. package/dist/pipelines/index.d.ts +5 -11
  271. package/dist/pipelines/index.d.ts.map +1 -1
  272. package/dist/pipelines/index.js +6 -8
  273. package/dist/pipelines/index.js.map +1 -1
  274. package/dist/{power-and-mde-CQX-0weG.js → power-and-mde-ClI6RWw4.js} +4 -5
  275. package/dist/{power-and-mde-CQX-0weG.js.map → power-and-mde-ClI6RWw4.js.map} +1 -1
  276. package/dist/{predicate-FdKmElA_.js → predicate-BYHA4MBn.js} +2 -3
  277. package/dist/{predicate-FdKmElA_.js.map → predicate-BYHA4MBn.js.map} +1 -1
  278. package/dist/{prime-bridge-transport-6feEglLf.d.ts → prime-bridge-transport-Cfqir_Im.d.ts} +1 -3
  279. package/dist/prime-bridge-transport-Cfqir_Im.d.ts.map +1 -0
  280. package/dist/{prime-bridge-transport-Z3cpKGoV.js → prime-bridge-transport-Csd5SQg7.js} +2 -3
  281. package/dist/{prime-bridge-transport-Z3cpKGoV.js.map → prime-bridge-transport-Csd5SQg7.js.map} +1 -1
  282. package/dist/{prime-protocol-BGxjfhM4.d.ts → prime-protocol-COFkxas6.d.ts} +4 -8
  283. package/dist/prime-protocol-COFkxas6.d.ts.map +1 -0
  284. package/dist/{prime-protocol-BFgGrEMP.js → prime-protocol-CrhpXRz9.js} +4 -6
  285. package/dist/{prime-protocol-BFgGrEMP.js.map → prime-protocol-CrhpXRz9.js.map} +1 -1
  286. package/dist/profile-cell.d.ts +1 -1
  287. package/dist/profile-cell.js +1 -2
  288. package/dist/{promotion-gate-CkVZHagC.d.ts → promotion-gate-CixshGI8.d.ts} +5 -11
  289. package/dist/promotion-gate-CixshGI8.d.ts.map +1 -0
  290. package/dist/{promotion-policy-6A8osGr_.js → promotion-policy-CBYeD4zi.js} +5 -6
  291. package/dist/{promotion-policy-6A8osGr_.js.map → promotion-policy-CBYeD4zi.js.map} +1 -1
  292. package/dist/{proposal-findings-DqLUWsAG.js → proposal-findings-WFQrxnfe.js} +3 -4
  293. package/dist/{proposal-findings-DqLUWsAG.js.map → proposal-findings-WFQrxnfe.js.map} +1 -1
  294. package/dist/{quantile--0yb07pD.js → quantile-CncXP-Ss.js} +2 -3
  295. package/dist/{quantile--0yb07pD.js.map → quantile-CncXP-Ss.js.map} +1 -1
  296. package/dist/{query-B_RZ36an.js → query-CGXzO9d4.js} +5 -6
  297. package/dist/{query-B_RZ36an.js.map → query-CGXzO9d4.js.map} +1 -1
  298. package/dist/{query-Cmv_U8vf.d.ts → query-UD0B08Sb.d.ts} +4 -6
  299. package/dist/query-UD0B08Sb.d.ts.map +1 -0
  300. package/dist/{random-DGEyr3zG.d.ts → random-BN150Q_X.d.ts} +1 -5
  301. package/dist/random-BN150Q_X.d.ts.map +1 -0
  302. package/dist/{random-DDDcC7YU.js → random-DrzcgC7F.js} +3 -4
  303. package/dist/{random-DDDcC7YU.js.map → random-DrzcgC7F.js.map} +1 -1
  304. package/dist/{raw-provider-sink-75w4FWBj.js → raw-provider-sink-DDLkP_eF.js} +3 -4
  305. package/dist/{raw-provider-sink-75w4FWBj.js.map → raw-provider-sink-DDLkP_eF.js.map} +1 -1
  306. package/dist/{record-id-DUgsK5qp.js → record-id-CWZXFh58.js} +2 -3
  307. package/dist/{record-id-DUgsK5qp.js.map → record-id-CWZXFh58.js.map} +1 -1
  308. package/dist/{redact-DXdlFb_U.d.ts → redact-C_wzC4c_.d.ts} +1 -3
  309. package/dist/redact-C_wzC4c_.d.ts.map +1 -0
  310. package/dist/{redact-mtkTiJVk.js → redact-D6APJS1d.js} +3 -5
  311. package/dist/{redact-mtkTiJVk.js.map → redact-D6APJS1d.js.map} +1 -1
  312. package/dist/{registry-BcdJmyoU.d.ts → registry-dhdDoAV8.d.ts} +5 -11
  313. package/dist/registry-dhdDoAV8.d.ts.map +1 -0
  314. package/dist/{release-confidence-CYIFH-fp.js → release-confidence-CTUJz5mM.js} +10 -16
  315. package/dist/release-confidence-CTUJz5mM.js.map +1 -0
  316. package/dist/{render-BhJqXoBH.js → render-pfAZ7IR4.js} +266 -33
  317. package/dist/render-pfAZ7IR4.js.map +1 -0
  318. package/dist/{reporting-html-Kvlc8oMt.js → reporting-html-DMXIjATy.js} +2 -3
  319. package/dist/{reporting-html-Kvlc8oMt.js.map → reporting-html-DMXIjATy.js.map} +1 -1
  320. package/dist/reporting.d.ts +6 -6
  321. package/dist/reporting.js +7 -7
  322. package/dist/{researcher-DKWtoMWk.d.ts → researcher-CLnNJ7Or.d.ts} +8 -12
  323. package/dist/researcher-CLnNJ7Or.d.ts.map +1 -0
  324. package/dist/{reward-nw2xZGZG.js → reward-P0VD_Aft.js} +2 -3
  325. package/dist/{reward-nw2xZGZG.js.map → reward-P0VD_Aft.js.map} +1 -1
  326. package/dist/{reward-BeUgVVC_.d.ts → reward-ST4PXNXF.d.ts} +2 -4
  327. package/dist/reward-ST4PXNXF.d.ts.map +1 -0
  328. package/dist/{reward-hacking-WTxUbtbb.d.ts → reward-hacking-C9hPVT0Q.d.ts} +4 -8
  329. package/dist/reward-hacking-C9hPVT0Q.d.ts.map +1 -0
  330. package/dist/{reward-hacking-ByuETaIb.js → reward-hacking-DZzHZlS1.js} +5 -7
  331. package/dist/{reward-hacking-ByuETaIb.js.map → reward-hacking-DZzHZlS1.js.map} +1 -1
  332. package/dist/rl.d.ts +26 -63
  333. package/dist/rl.d.ts.map +1 -1
  334. package/dist/rl.js +35 -52
  335. package/dist/rl.js.map +1 -1
  336. package/dist/{rolldown-runtime-8H4AJuhK.js → rolldown-runtime-BJohB4LM.js} +1 -2
  337. package/dist/rollout/index.d.ts +6 -6
  338. package/dist/rollout/index.js +7 -7
  339. package/dist/{rollout-Dd1ucT_M.js → rollout-BhkMpAJT.js} +279 -16
  340. package/dist/rollout-BhkMpAJT.js.map +1 -0
  341. package/dist/{terminal-record-CB9BFtjS.js → rollout-nodes-BHR9Q5jP.js} +351 -11
  342. package/dist/rollout-nodes-BHR9Q5jP.js.map +1 -0
  343. package/dist/{round-decimal-COrKglMh.js → round-decimal-ZmjAQPo1.js} +2 -3
  344. package/dist/{round-decimal-COrKglMh.js.map → round-decimal-ZmjAQPo1.js.map} +1 -1
  345. package/dist/{rubric-predictive-validity-Cd5SCtAf.d.ts → rubric-predictive-validity-B3RzbwOx.d.ts} +2 -8
  346. package/dist/rubric-predictive-validity-B3RzbwOx.d.ts.map +1 -0
  347. package/dist/{rubric-predictive-validity-CeKW2GQN.js → rubric-predictive-validity-CQp_M0vy.js} +3 -4
  348. package/dist/{rubric-predictive-validity-CeKW2GQN.js.map → rubric-predictive-validity-CQp_M0vy.js.map} +1 -1
  349. package/dist/{run-record-CysKLB93.js → run-record-CZy4-TnZ.js} +4 -5
  350. package/dist/{run-record-CysKLB93.js.map → run-record-CZy4-TnZ.js.map} +1 -1
  351. package/dist/{run-record-C3awiXPf.d.ts → run-record-D2BFMPGl.d.ts} +5 -7
  352. package/dist/run-record-D2BFMPGl.d.ts.map +1 -0
  353. package/dist/{run-record-DhEJgoPz.js → run-record-DEjx43cI.js} +6 -7
  354. package/dist/{run-record-DhEJgoPz.js.map → run-record-DEjx43cI.js.map} +1 -1
  355. package/dist/{sandbox-harness-BlSOu4LX.d.ts → sandbox-harness-B3Kx1fOA.d.ts} +1 -3
  356. package/dist/sandbox-harness-B3Kx1fOA.d.ts.map +1 -0
  357. package/dist/{schema-D6EVKzTB.d.ts → schema-CkIvnmLU.d.ts} +2 -43
  358. package/dist/schema-CkIvnmLU.d.ts.map +1 -0
  359. package/dist/{schema-Bt2vLFm3.js → schema-D-xu3MU_.js} +2 -3
  360. package/dist/{schema-Bt2vLFm3.js.map → schema-D-xu3MU_.js.map} +1 -1
  361. package/dist/{schema-C-ziyJD7.d.ts → schema-DkFJr3Y8.d.ts} +111 -48
  362. package/dist/schema-DkFJr3Y8.d.ts.map +1 -0
  363. package/dist/{schema-CvhfLjtZ.js → schema-YUIXT8iW.js} +37 -7
  364. package/dist/schema-YUIXT8iW.js.map +1 -0
  365. package/dist/search/index.d.ts +3 -35
  366. package/dist/search/index.d.ts.map +1 -1
  367. package/dist/search/index.js +4 -5
  368. package/dist/{search-kernel-CctpiDd2.d.ts → search-kernel-CBdwFZ05.d.ts} +10 -36
  369. package/dist/search-kernel-CBdwFZ05.d.ts.map +1 -0
  370. package/dist/{search-ledger-CZRqtFbW.js → search-ledger-BsVi-Ngv.js} +17 -26
  371. package/dist/{search-ledger-CZRqtFbW.js.map → search-ledger-BsVi-Ngv.js.map} +1 -1
  372. package/dist/{search-ledger-file-Bd5Tioq6.js → search-ledger-file-DTBD6X-y.js} +6 -8
  373. package/dist/{search-ledger-file-Bd5Tioq6.js.map → search-ledger-file-DTBD6X-y.js.map} +1 -1
  374. package/dist/{search-ledger-types-p2xKfiDJ.d.ts → search-ledger-types-qiYRUo_N.d.ts} +5 -9
  375. package/dist/search-ledger-types-qiYRUo_N.d.ts.map +1 -0
  376. package/dist/{search-shipper-Dn3NLsuH.js → search-shipper-pdg4viK7.js} +8 -13
  377. package/dist/{search-shipper-Dn3NLsuH.js.map → search-shipper-pdg4viK7.js.map} +1 -1
  378. package/dist/{search-summary-D4bwYnAE.js → search-summary-Ct7SrmVc.js} +6 -7
  379. package/dist/{search-summary-D4bwYnAE.js.map → search-summary-Ct7SrmVc.js.map} +1 -1
  380. package/dist/{sequential-CimQrbjv.js → sequential-B1I0tRfL.js} +6 -7
  381. package/dist/{sequential-CimQrbjv.js.map → sequential-B1I0tRfL.js.map} +1 -1
  382. package/dist/{sequential-KwGspfeR.d.ts → sequential-Bb_pdTqG.d.ts} +1 -3
  383. package/dist/sequential-Bb_pdTqG.d.ts.map +1 -0
  384. package/dist/{sequential-BVv1sjsw.js → sequential-Bjs5roiK.js} +2 -3
  385. package/dist/{sequential-BVv1sjsw.js.map → sequential-Bjs5roiK.js.map} +1 -1
  386. package/dist/{sequential-eprocess-DodI6RoF.js → sequential-eprocess-C1YLwFaz.js} +3 -4
  387. package/dist/{sequential-eprocess-DodI6RoF.js.map → sequential-eprocess-C1YLwFaz.js.map} +1 -1
  388. package/dist/{server-ChhXPCgX.js → server-DA6h3co5.js} +11 -17
  389. package/dist/{server-ChhXPCgX.js.map → server-DA6h3co5.js.map} +1 -1
  390. package/dist/{single-run-lock-Dekd8_Wv.js → single-run-lock-BGlW3OSk.js} +3 -4
  391. package/dist/{single-run-lock-Dekd8_Wv.js.map → single-run-lock-BGlW3OSk.js.map} +1 -1
  392. package/dist/{skillopt-optimization-method-sB_-yi1G.js → skillopt-optimization-method-qB1M554K.js} +38 -57
  393. package/dist/{skillopt-optimization-method-sB_-yi1G.js.map → skillopt-optimization-method-qB1M554K.js.map} +1 -1
  394. package/dist/{spans-CVngGij3.d.ts → spans-vZoW__3q.d.ts} +2 -4
  395. package/dist/spans-vZoW__3q.d.ts.map +1 -0
  396. package/dist/{statistical-heldout-BjzSOmLH.d.ts → statistical-heldout-Cei036nE.d.ts} +9 -37
  397. package/dist/statistical-heldout-Cei036nE.d.ts.map +1 -0
  398. package/dist/{statistical-heldout-Bksv92Th.js → statistical-heldout-TP6ndL0B.js} +4 -5
  399. package/dist/{statistical-heldout-Bksv92Th.js.map → statistical-heldout-TP6ndL0B.js.map} +1 -1
  400. package/dist/{steps-DlepJPwD.d.ts → steps-B8fYY_Vo.d.ts} +1 -3
  401. package/dist/steps-B8fYY_Vo.d.ts.map +1 -0
  402. package/dist/{store-B3nWRy3B.d.ts → store-CMs5wGXP.d.ts} +2 -4
  403. package/dist/store-CMs5wGXP.d.ts.map +1 -0
  404. package/dist/{store-BhNuLdJw.js → store-ZykIyQmy.js} +2 -3
  405. package/dist/{store-BhNuLdJw.js.map → store-ZykIyQmy.js.map} +1 -1
  406. package/dist/{store-otlp-CFf27E8_.js → store-otlp-DmLm65XW.js} +8 -13
  407. package/dist/{store-otlp-CFf27E8_.js.map → store-otlp-DmLm65XW.js.map} +1 -1
  408. package/dist/{store-tool-spans-DxsFwtdr.d.ts → store-tool-spans-B3i3fl0A.d.ts} +11 -29
  409. package/dist/store-tool-spans-B3i3fl0A.d.ts.map +1 -0
  410. package/dist/{store-tool-spans-BK_8FjGG.js → store-tool-spans-C2g8UYm-.js} +17 -41
  411. package/dist/{store-tool-spans-BK_8FjGG.js.map → store-tool-spans-C2g8UYm-.js.map} +1 -1
  412. package/dist/storyboard/index.d.ts +1 -5
  413. package/dist/storyboard/index.d.ts.map +1 -1
  414. package/dist/storyboard/index.js +3 -5
  415. package/dist/storyboard/index.js.map +1 -1
  416. package/dist/{summary-report-C8V49Jt3.d.ts → summary-report-0La5vejY.d.ts} +5 -13
  417. package/dist/summary-report-0La5vejY.d.ts.map +1 -0
  418. package/dist/{summary-report-DHDWxe6p.js → summary-report-CPfsrLac.js} +21 -30
  419. package/dist/summary-report-CPfsrLac.js.map +1 -0
  420. package/dist/supervisor-run/index.d.ts +30 -29
  421. package/dist/supervisor-run/index.d.ts.map +1 -1
  422. package/dist/supervisor-run/index.js +6 -7
  423. package/dist/{systemone-CHnqwmYg.d.ts → systemone-Cw2txK5m.d.ts} +12 -24
  424. package/dist/systemone-Cw2txK5m.d.ts.map +1 -0
  425. package/dist/{systemone-protocol-Bl2EI2KQ.d.ts → systemone-protocol-C4t7JH4Y.d.ts} +1 -3
  426. package/dist/systemone-protocol-C4t7JH4Y.d.ts.map +1 -0
  427. package/dist/systemone-protocol.d.ts +1 -1
  428. package/dist/systemone-protocol.js +2 -3
  429. package/dist/{systemone-review-cQ9acAsb.d.ts → systemone-review-BLgxt-4Q.d.ts} +8 -10
  430. package/dist/systemone-review-BLgxt-4Q.d.ts.map +1 -0
  431. package/dist/{systemone-review-DFGtIUcf.js → systemone-review-S49gsy_y.js} +5 -6
  432. package/dist/{systemone-review-DFGtIUcf.js.map → systemone-review-S49gsy_y.js.map} +1 -1
  433. package/dist/systemone.d.ts +4 -4
  434. package/dist/systemone.js +3 -3
  435. package/dist/{task-failure-attributes-oIK3BhCR.js → task-failure-attributes-CC6VuIpk.js} +7 -10
  436. package/dist/{task-failure-attributes-oIK3BhCR.js.map → task-failure-attributes-CC6VuIpk.js.map} +1 -1
  437. package/dist/{tool-groups-b3oU_D88.d.ts → tool-groups-C3K-d3gd.d.ts} +3 -5
  438. package/dist/tool-groups-C3K-d3gd.d.ts.map +1 -0
  439. package/dist/{tool-waste-CkjzWmeY.d.ts → tool-waste-BFG1vwTV.d.ts} +4 -16
  440. package/dist/tool-waste-BFG1vwTV.d.ts.map +1 -0
  441. package/dist/{tool-waste-DLsjS_p-.js → tool-waste-CLJ46AbT.js} +10 -26
  442. package/dist/{tool-waste-DLsjS_p-.js.map → tool-waste-CLJ46AbT.js.map} +1 -1
  443. package/dist/trace-attributes.d.ts +1 -1
  444. package/dist/trace-attributes.js +1 -2
  445. package/dist/{trace-questions-BmT8M6UQ.d.ts → trace-questions-ej5AEJ5X.d.ts} +4 -6
  446. package/dist/trace-questions-ej5AEJ5X.d.ts.map +1 -0
  447. package/dist/trace-repair/index.d.ts +46 -92
  448. package/dist/trace-repair/index.d.ts.map +1 -1
  449. package/dist/trace-repair/index.js +32 -54
  450. package/dist/trace-repair/index.js.map +1 -1
  451. package/dist/traces.d.ts +13 -29
  452. package/dist/traces.d.ts.map +1 -1
  453. package/dist/traces.js +18 -22
  454. package/dist/traces.js.map +1 -1
  455. package/dist/{trajectory-D_7rLrvE.js → trajectory-O3GDHmev.js} +2 -3
  456. package/dist/{trajectory-D_7rLrvE.js.map → trajectory-O3GDHmev.js.map} +1 -1
  457. package/dist/trajectory-replay/index.d.ts +2 -22
  458. package/dist/trajectory-replay/index.d.ts.map +1 -1
  459. package/dist/trajectory-replay/index.js +19 -30
  460. package/dist/trajectory-replay/index.js.map +1 -1
  461. package/dist/{tree-DSqwJpL9.js → tree-DrIChF4a.js} +39 -68
  462. package/dist/{tree-DSqwJpL9.js.map → tree-DrIChF4a.js.map} +1 -1
  463. package/dist/{types-B_IFcKp5.d.ts → types-0KglnQ9o.d.ts} +3 -15
  464. package/dist/types-0KglnQ9o.d.ts.map +1 -0
  465. package/dist/{types-DZ0mYVw9.d.ts → types-0oMg7zee.d.ts} +3 -5
  466. package/dist/types-0oMg7zee.d.ts.map +1 -0
  467. package/dist/{types-CnWmj8NW.js → types-BK0blWhe.js} +3 -4
  468. package/dist/{types-CnWmj8NW.js.map → types-BK0blWhe.js.map} +1 -1
  469. package/dist/{types-CmXY0PQf.d.ts → types-C-aOqgt2.d.ts} +2 -5
  470. package/dist/types-C-aOqgt2.d.ts.map +1 -0
  471. package/dist/{types-M6eF9m-r.d.ts → types-C54Uk_a1.d.ts} +84 -24
  472. package/dist/types-C54Uk_a1.d.ts.map +1 -0
  473. package/dist/{types-BXgASBCL.js → types-DK4vNv5q.js} +2 -3
  474. package/dist/{types-BXgASBCL.js.map → types-DK4vNv5q.js.map} +1 -1
  475. package/dist/{types-6Lfdlshp.d.ts → types-DzCO-S1m.d.ts} +50 -62
  476. package/dist/types-DzCO-S1m.d.ts.map +1 -0
  477. package/dist/{verdict-BGQmxQ8A.js → verdict-C8TcdwfD.js} +3 -4
  478. package/dist/{verdict-BGQmxQ8A.js.map → verdict-C8TcdwfD.js.map} +1 -1
  479. package/dist/{verdict-C24NELtN.d.ts → verdict-D_qiBQ6_.d.ts} +1 -5
  480. package/dist/verdict-D_qiBQ6_.d.ts.map +1 -0
  481. package/dist/{verdict-cache-CL_7tePD.js → verdict-cache-BVH-fl18.js} +3 -4
  482. package/dist/{verdict-cache-CL_7tePD.js.map → verdict-cache-BVH-fl18.js.map} +1 -1
  483. package/dist/wire/index.d.ts +43 -51
  484. package/dist/wire/index.d.ts.map +1 -1
  485. package/dist/wire/index.js +1 -2
  486. package/docs/eval-surface-map.md +15 -0
  487. package/docs/rollout.md +132 -6
  488. package/package.json +18 -18
  489. package/dist/adversarial-smnADNFS.d.ts.map +0 -1
  490. package/dist/agent-profile-CNmwfaqq.d.ts.map +0 -1
  491. package/dist/agent-profile-cell-BcpFbNd5.d.ts.map +0 -1
  492. package/dist/analyze-runs-DfX6dHP0.d.ts.map +0 -1
  493. package/dist/attribute-vocabulary-CcXqHODT.d.ts.map +0 -1
  494. package/dist/benchmark-command-Cnjfo0Zh.js.map +0 -1
  495. package/dist/campaign-evidence-DunzcJGv.js.map +0 -1
  496. package/dist/campaign-uddTlFg5.js.map +0 -1
  497. package/dist/canonical-CFpojCN5.d.ts.map +0 -1
  498. package/dist/client-hwo3cJjR.d.ts.map +0 -1
  499. package/dist/completion-verifier-asaV1nSj.js.map +0 -1
  500. package/dist/cost-ledger-C1W3ICmP.d.ts.map +0 -1
  501. package/dist/dataset-DQqhOCPt.d.ts.map +0 -1
  502. package/dist/default-registry-CLG5YqGS.d.ts.map +0 -1
  503. package/dist/define-agent-eval-JKt3gMQr.d.ts.map +0 -1
  504. package/dist/descriptive-B2iPaT9J.d.ts +0 -89
  505. package/dist/descriptive-B2iPaT9J.d.ts.map +0 -1
  506. package/dist/descriptive-CVNy48rR.js.map +0 -1
  507. package/dist/emitter-DABYYTcH.d.ts.map +0 -1
  508. package/dist/engine-dtRVeuQs.d.ts.map +0 -1
  509. package/dist/errors-DEE6u6ot.d.ts.map +0 -1
  510. package/dist/evaluation-DblGquCB.d.ts.map +0 -1
  511. package/dist/exact-types-Do63KoKn.d.ts.map +0 -1
  512. package/dist/exporters-DWvM16LE.js.map +0 -1
  513. package/dist/exporters-Dk3oEbK_.d.ts.map +0 -1
  514. package/dist/failure-cluster-DN0t63Z0.d.ts.map +0 -1
  515. package/dist/feedback-trajectory-CYVJXolG.d.ts.map +0 -1
  516. package/dist/hf-dataset-CKxIJQba.js.map +0 -1
  517. package/dist/index-CHxwfW5g.d.ts.map +0 -1
  518. package/dist/index-CTIRz-AB.d.ts.map +0 -1
  519. package/dist/index-CalAsXMR.d.ts.map +0 -1
  520. package/dist/index-CdEVr8-O.d.ts.map +0 -1
  521. package/dist/index-CfJULcW5.d.ts.map +0 -1
  522. package/dist/index-D7fmC-1K.d.ts.map +0 -1
  523. package/dist/index-jnuFLxOs.d.ts.map +0 -1
  524. package/dist/integrity-D-s2iHiT.js.map +0 -1
  525. package/dist/integrity-D9lBnv_K.d.ts.map +0 -1
  526. package/dist/interval-ohuOJurX.d.ts.map +0 -1
  527. package/dist/judge-calibration-DFtEMlde.d.ts.map +0 -1
  528. package/dist/llm-judge-Cybq29bL.js.map +0 -1
  529. package/dist/lock-holder-DaJbfpci.d.ts.map +0 -1
  530. package/dist/matrix-B8l-Nsxd.js.map +0 -1
  531. package/dist/matrix-DtkZLD_3.d.ts.map +0 -1
  532. package/dist/mint-CkzpVPdz.d.ts +0 -81
  533. package/dist/mint-CkzpVPdz.d.ts.map +0 -1
  534. package/dist/multi-layer-verifier-DEgMUk6v.d.ts.map +0 -1
  535. package/dist/multiplicity-DIWHvysC.d.ts.map +0 -1
  536. package/dist/paired-promotion-decision-CQMJ5xGN.d.ts.map +0 -1
  537. package/dist/pareto-BiBnQXAE.js.map +0 -1
  538. package/dist/prime-bridge-transport-6feEglLf.d.ts.map +0 -1
  539. package/dist/prime-protocol-BGxjfhM4.d.ts.map +0 -1
  540. package/dist/promotion-gate-CkVZHagC.d.ts.map +0 -1
  541. package/dist/query-Cmv_U8vf.d.ts.map +0 -1
  542. package/dist/random-DGEyr3zG.d.ts.map +0 -1
  543. package/dist/redact-DXdlFb_U.d.ts.map +0 -1
  544. package/dist/registry-BcdJmyoU.d.ts.map +0 -1
  545. package/dist/release-confidence-CYIFH-fp.js.map +0 -1
  546. package/dist/render-BhJqXoBH.js.map +0 -1
  547. package/dist/researcher-DKWtoMWk.d.ts.map +0 -1
  548. package/dist/reward-BeUgVVC_.d.ts.map +0 -1
  549. package/dist/reward-hacking-WTxUbtbb.d.ts.map +0 -1
  550. package/dist/rollout-Dd1ucT_M.js.map +0 -1
  551. package/dist/rubric-predictive-validity-Cd5SCtAf.d.ts.map +0 -1
  552. package/dist/run-record-C3awiXPf.d.ts.map +0 -1
  553. package/dist/sandbox-harness-BlSOu4LX.d.ts.map +0 -1
  554. package/dist/schema-C-ziyJD7.d.ts.map +0 -1
  555. package/dist/schema-CvhfLjtZ.js.map +0 -1
  556. package/dist/schema-D6EVKzTB.d.ts.map +0 -1
  557. package/dist/search-kernel-CctpiDd2.d.ts.map +0 -1
  558. package/dist/search-ledger-types-p2xKfiDJ.d.ts.map +0 -1
  559. package/dist/sequential-KwGspfeR.d.ts.map +0 -1
  560. package/dist/spans-CVngGij3.d.ts.map +0 -1
  561. package/dist/statistical-heldout-BjzSOmLH.d.ts.map +0 -1
  562. package/dist/steps-DlepJPwD.d.ts.map +0 -1
  563. package/dist/store-B3nWRy3B.d.ts.map +0 -1
  564. package/dist/store-tool-spans-DxsFwtdr.d.ts.map +0 -1
  565. package/dist/summary-report-C8V49Jt3.d.ts.map +0 -1
  566. package/dist/summary-report-DHDWxe6p.js.map +0 -1
  567. package/dist/systemone-CHnqwmYg.d.ts.map +0 -1
  568. package/dist/systemone-protocol-Bl2EI2KQ.d.ts.map +0 -1
  569. package/dist/systemone-review-cQ9acAsb.d.ts.map +0 -1
  570. package/dist/terminal-record-CB9BFtjS.js.map +0 -1
  571. package/dist/tool-groups-b3oU_D88.d.ts.map +0 -1
  572. package/dist/tool-waste-CkjzWmeY.d.ts.map +0 -1
  573. package/dist/trace-questions-BmT8M6UQ.d.ts.map +0 -1
  574. package/dist/types-6Lfdlshp.d.ts.map +0 -1
  575. package/dist/types-B_IFcKp5.d.ts.map +0 -1
  576. package/dist/types-CmXY0PQf.d.ts.map +0 -1
  577. package/dist/types-DZ0mYVw9.d.ts.map +0 -1
  578. package/dist/types-M6eF9m-r.d.ts.map +0 -1
  579. package/dist/verdict-C24NELtN.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bounded-process-Cj9YjXbE.js","names":[],"sources":["../src/bounded-process.ts"],"sourcesContent":["/**\n * `runBoundedProcess` — run one command under a wall-clock bound and return\n * what it produced, leaving no descendant behind.\n *\n * The child leads its own process group (`detached` on every non-win32\n * platform), so a deadline or an abort kills the group with\n * `process.kill(-pid, 'SIGKILL')` rather than only the shell that was\n * spawned. That distinction is the whole point of this module: `sh -c\n * 'solver & wait'` puts the real work in a grandchild, and a kill aimed at\n * the shell alone leaves that grandchild running, holding the stdout and\n * stderr pipes open. `close` then never fires, so the deadline produces no\n * result the caller can observe and the descendant outlives the run.\n *\n * Two further guarantees the caller depends on:\n *\n * - A killed run never reports success. A SIGKILLed child can still close\n * with exit code 0, so a run killed by the deadline or by an abort has\n * its exit code forced non-zero.\n * - A run always resolves. If a grandchild escaped the group and still\n * holds the pipes, the result is delivered {@link KILL_DRAIN_MS} after\n * the kill instead of waiting on a `close` that will not come.\n *\n * The captured output is bounded. Once the cap is reached the streams are\n * still drained — the child needs its pipes read to reach `close` — but the\n * bytes are discarded and `outputTruncated` is set.\n */\n\nimport { spawn } from 'node:child_process'\nimport { StringDecoder } from 'node:string_decoder'\n\n/** Wall-clock bound applied when the caller names none. */\nexport const DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS = 10 * 60_000\n\n/** Cap on captured stdout+stderr applied when the caller names none. */\nconst DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024\n\n/**\n * Window `close` is given after the process group is killed. A grandchild\n * that escaped the group can hold the pipes open indefinitely; the caller\n * receives its result at the end of this window rather than hanging.\n */\nconst KILL_DRAIN_MS = 2000\n\n/** Exit code reported for a run the wall-clock bound killed (GNU `timeout`). */\nconst TIMEOUT_EXIT_CODE = 124\n\n/** Exit code reported for a run an `AbortSignal` killed (128 + SIGKILL). */\nconst ABORT_EXIT_CODE = 137\n\n/** Exit code reported when the process could not be spawned at all. */\nconst SPAWN_FAILURE_EXIT_CODE = 127\n\n/** Exit code reported when a process closed with no code and was not killed. */\nconst UNKNOWN_EXIT_CODE = 1\n\nexport interface BoundedProcessInput {\n /**\n * The command line, interpreted by a shell unless `shell` is `false`. When\n * {@link BoundedProcessInput.args} is present this is a program path\n * instead, and no shell reads it.\n */\n command: string\n /**\n * Argument vector for `command`, delivered to the program as separate\n * argv entries with no shell between them.\n *\n * This is the form to use whenever an argument carries text the caller did\n * not author — a script body, a path, a pattern. Without it, `interpreter\n * -flag <script>` can only be expressed by quoting the script into a\n * shell string, and a quoting bug there is a command injection rather than\n * a wrong answer. Each entry arrives verbatim, so there is nothing to\n * quote: `{ command: 'bash', args: ['-n', '-c', body] }` parses `body`\n * whatever shell metacharacters it holds.\n *\n * Two limits are the platform's, not this module's. A NUL byte in an entry\n * cannot be passed to a process at all, and is reported as a `runnerError`\n * rather than thrown. A lone surrogate is encoded to UTF-8 as U+FFFD, and a\n * non-string entry from an untypechecked caller is coerced with `String()`,\n * so an entry is verbatim exactly when it is a string a UTF-8 argv can hold.\n *\n * A shell cannot interpret an argument vector, so `args` and a truthy\n * `shell` are contradictory. Passing both spawns nothing and reports\n * `runnerError`.\n */\n args?: string[]\n /**\n * Text written to the child's standard input. The stream is closed after\n * the write, so a command that reads until end-of-file sees exactly this\n * payload and then EOF.\n *\n * The child's stdin is closed whether or not this field is present. A pipe\n * nobody closes is a hang: a command that reads stdin waits for bytes that\n * never arrive until the deadline kills it, which reads downstream as a\n * slow command rather than as a caller that forgot to send input.\n *\n * The payload is written as UTF-8 and is otherwise verbatim: a NUL byte,\n * a newline, a quote and a backslash all arrive as themselves, because\n * nothing parses this text. The one platform limit is the one `args`\n * already states — a lone surrogate is encoded as U+FFFD, since no UTF-8\n * stream can carry it.\n *\n * A child that exits before reading breaks the pipe. That is the child's\n * behaviour, not a runner failure, so the run still settles on the child's\n * own exit code, and the undelivered payload is reported in `runnerError`\n * with the `stdin not delivered:` prefix. Whether a SMALL payload to a\n * command that ignores stdin reports this is a race — the write may land in\n * the pipe buffer before the child exits — so the flag is a statement about\n * delivery, never about the command. It is not a race for the case that\n * matters: a payload larger than the pipe buffer that the child never\n * drains cannot be delivered, and reports every time.\n */\n stdin?: string\n /**\n * Shell that interprets `command`. `true` (the default) uses the platform\n * default — `/bin/sh` on POSIX, `cmd.exe` on Windows. A string names the\n * shell binary, e.g. `'bash'`, which is required for a bash-only construct\n * such as `[[ ]]` or `$BASH_VERSION`. `false` executes `command` directly\n * as a program path with no arguments. Ignored — and refused when truthy —\n * once {@link BoundedProcessInput.args} is present.\n */\n shell?: boolean | string\n /** Working directory. The parent's cwd is inherited when omitted. */\n cwd?: string\n /**\n * Environment for the child. How it combines with the parent environment\n * is decided by {@link BoundedProcessInput.envMode}.\n */\n env?: NodeJS.ProcessEnv\n /**\n * `'merge'` (the default) layers `env` on top of `process.env`, so the\n * child sees every variable this process has plus the named ones.\n * `'replace'` passes exactly `env` and nothing else, which is what a\n * grader needs when the claim under test is about the variables the\n * command could read. `PATH` is not re-added under `'replace'`, and a\n * command that must find a binary on `PATH` names `PATH` itself.\n *\n * With no `PATH` in the child environment the two forms do NOT search the\n * same directories, so a caller under `'replace'` that names no `PATH` gets\n * a resolution that depends on which form it picked. The shell form execs\n * the shell, which applies its own compiled-in default; the argv form\n * reaches `execvp`, which falls back to `confstr(_CS_PATH)`. Measured on\n * Linux/glibc: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`\n * against `/bin:/usr/bin`, so a binary in `/usr/local/bin` resolves on the\n * shell form and reports ENOENT on the argv form. Name `PATH` and both\n * forms search exactly what was named.\n */\n envMode?: 'merge' | 'replace'\n /** Wall-clock bound in ms. Defaults to 10 minutes. */\n timeoutMs?: number\n /**\n * Cap on captured stdout+stderr. Reaching it truncates the captured text\n * and sets `outputTruncated`; it never kills the process. Defaults to\n * 16 MiB.\n */\n maxOutputBytes?: number\n /**\n * Kills the process group when it aborts, the same way the deadline does.\n * A signal that is already aborted when `runBoundedProcess` is called\n * prevents the spawn entirely — nothing runs.\n */\n signal?: AbortSignal\n}\n\nexport interface BoundedProcessResult {\n /**\n * The process actually started. False when nothing ran at all: an\n * already-aborted signal, `args` with a truthy `shell`, an argument the\n * platform refuses, or a program that does not exist.\n *\n * This is the field to branch on, never the text of `runnerError`. A caller\n * deciding whether a run produced an outcome at all is asking exactly this,\n * and asking it here is type-checked rather than held by a wording\n * convention.\n */\n spawned: boolean\n /**\n * The `stdin` payload reached the child in full. True whenever the caller\n * supplied none, because nothing could fail to arrive.\n *\n * False means the command ran on partial input, which is a fact about the\n * answer it produced: a checksum over a truncated payload is a wrong answer,\n * not a failed run. `spawned` stays true and `exitCode` stays the child's.\n */\n stdinDelivered: boolean\n /**\n * Exit code. Forced non-zero whenever `killedByTimeout` or\n * `killedBySignal` is set, because a SIGKILLed child can close with 0 and\n * a killed run must never read as a pass.\n */\n exitCode: number\n /** Captured stdout, truncated at `maxOutputBytes`. */\n stdout: string\n /**\n * Captured stderr, truncated at `maxOutputBytes`. A runner-side failure is\n * reported in `runnerError`, not appended here; the caller decides whether\n * the command's own stderr and the runner's diagnosis belong together.\n */\n stderr: string\n /** Wall-clock duration in ms, measured across the whole call. */\n wallMs: number\n /** The wall-clock bound was reached and the process group was killed. */\n killedByTimeout: boolean\n /** `signal` aborted and the process group was killed. */\n killedBySignal: boolean\n /** `maxOutputBytes` was reached and later output was discarded. */\n outputTruncated: boolean\n /**\n * Human-readable diagnosis of a runner-side failure, in one of three shapes:\n *\n * - `not spawned:` — the caller's own bug, such as `args` with a truthy\n * `shell`, or an already-aborted signal. No retry helps.\n * - `stdin not delivered:` — the command ran and exited on its own, and\n * the stdin payload did not reach it in full because the child closed\n * the pipe first.\n * - anything else — the process could not be spawned (a missing binary, a\n * NUL byte in an argument).\n *\n * Absent when the command ran and read everything it was sent, however it\n * exited. The prefixes are for a person reading a log; code reads `spawned`\n * and `stdinDelivered`, which say the same things and are type-checked.\n */\n runnerError?: string\n}\n\nexport async function runBoundedProcess(input: BoundedProcessInput): Promise<BoundedProcessResult> {\n const start = Date.now()\n const maxOutputBytes = input.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES\n const timeoutMs = input.timeoutMs ?? DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS\n const envMode = input.envMode ?? 'merge'\n const env =\n input.env === undefined && envMode === 'merge'\n ? undefined\n : envMode === 'replace'\n ? { ...input.env }\n : { ...process.env, ...input.env }\n\n if (input.signal?.aborted) {\n return {\n spawned: false,\n stdinDelivered: true,\n exitCode: ABORT_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: true,\n outputTruncated: false,\n runnerError: 'aborted before spawn: the AbortSignal was already aborted',\n }\n }\n\n // Reported rather than thrown, because this module's contract is that a\n // call always resolves. A caller bug still reads as a failure and never as\n // a pass: the exit code is non-zero and `runnerError` names the cause.\n if (input.args !== undefined && input.shell) {\n return {\n spawned: false,\n stdinDelivered: true,\n exitCode: SPAWN_FAILURE_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: false,\n outputTruncated: false,\n // Shares `SPAWN_FAILURE_EXIT_CODE` with a program that does not exist,\n // because both mean nothing ran. The `not spawned:` prefix is the stable\n // discriminator: it marks the caller's own bug, which no retry fixes.\n runnerError:\n 'not spawned: `args` passes an argument vector directly to the program, so a shell ' +\n 'cannot interpret it — pass `args` or a truthy `shell`, never both',\n }\n }\n\n return await new Promise<BoundedProcessResult>((resolve) => {\n const spawnOptions = {\n cwd: input.cwd,\n env,\n // Own process group so a kill reaches the whole tree, not just the\n // shell — otherwise a runaway grandchild keeps the pipes open and\n // `close` never fires.\n detached: process.platform !== 'win32',\n }\n // The argv form takes the same bounds, the same group and the same kill\n // path. Two things differ, and both are stated where they are decided:\n // no shell reads the command, and executable lookup falls back to a\n // different default `PATH` when the caller names none (see `envMode`).\n //\n // `spawn` validates its arguments and THROWS synchronously — a NUL byte in\n // `command` or in an `args` entry, or an `args` that is not an array from\n // an untypechecked caller. A throw inside this executor would reject, and\n // this module's contract is that a call always resolves. A caller that\n // grades untrusted text must be able to score that text as failed rather\n // than die on it.\n let child: ReturnType<typeof spawn>\n try {\n child =\n input.args === undefined\n ? spawn(input.command, { ...spawnOptions, shell: input.shell ?? true })\n : spawn(input.command, input.args, { ...spawnOptions, shell: false })\n } catch (err) {\n resolve({\n spawned: false,\n stdinDelivered: true,\n exitCode: SPAWN_FAILURE_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: false,\n outputTruncated: false,\n runnerError: String(err),\n })\n return\n }\n // A pipe nobody closes is a hang, so stdin is always ended — after the\n // payload when there is one, immediately when there is not. A write that\n // fails is recorded and never thrown: the child already ran, and this\n // module's contract is that a call always resolves.\n let stdinError: string | undefined\n const childStdin = child.stdin\n if (childStdin) {\n childStdin.on('error', (err) => {\n // Closing an unused pipe races a command that exits at once, and that\n // broken pipe says nothing about a caller who sent nothing. Only a\n // payload the caller supplied can fail to be delivered.\n if (input.stdin !== undefined) stdinError ??= `stdin not delivered: ${String(err)}`\n })\n if (input.stdin === undefined) childStdin.end()\n else childStdin.end(input.stdin, 'utf8')\n } else if (input.stdin !== undefined) {\n stdinError = 'stdin not delivered: the child was spawned with no stdin pipe'\n }\n\n let stdout = ''\n let stderr = ''\n let outputBytes = 0\n let outputTruncated = false\n let killedByTimeout = false\n let killedBySignal = false\n let settled = false\n\n // Bound the in-memory buffer so a runaway process can't OOM the caller.\n // Once the cap is hit the streams are still drained (the child needs them\n // read to reach `close`) but the bytes are discarded.\n function capture(s: string): string {\n if (outputBytes >= maxOutputBytes) {\n outputTruncated = true\n return ''\n }\n const room = maxOutputBytes - outputBytes\n if (s.length > room) {\n outputBytes = maxOutputBytes\n outputTruncated = true\n return s.slice(0, room)\n }\n outputBytes += s.length\n return s\n }\n\n // Decoded across chunk boundaries. A stream arrives as Buffers split at\n // arbitrary byte offsets, so decoding each chunk on its own replaces any\n // multi-byte character that straddles a boundary with U+FFFD — the output\n // is then corrupted at every 64 KiB of non-ASCII text. The decoder holds\n // the partial sequence until its remaining bytes arrive.\n const stdoutDecoder = new StringDecoder('utf8')\n const stderrDecoder = new StringDecoder('utf8')\n const decode = (decoder: StringDecoder, d: unknown): string =>\n Buffer.isBuffer(d) ? decoder.write(d) : String(d)\n\n const onStdout = (d: unknown) => {\n const chunk = capture(decode(stdoutDecoder, d))\n if (chunk) stdout += chunk\n }\n const onStderr = (d: unknown) => {\n const chunk = capture(decode(stderrDecoder, d))\n if (chunk) stderr += chunk\n }\n\n child.stdout?.on('data', onStdout)\n child.stderr?.on('data', onStderr)\n\n let forceResolve: ReturnType<typeof setTimeout> | undefined\n\n const cleanup = () => {\n clearTimeout(timeout)\n if (forceResolve) clearTimeout(forceResolve)\n input.signal?.removeEventListener('abort', onAbort)\n child.stdout?.off('data', onStdout)\n child.stderr?.off('data', onStderr)\n // The stdin `error` listener stays attached on purpose: a stream that\n // emits `error` with no listener throws, and a late EPIPE after the run\n // has settled must not take the process down.\n child.removeAllListeners('close')\n child.removeAllListeners('error')\n }\n\n // Resolve exactly once. `code` comes from `close`; on a kill path the\n // exit code is forced non-zero so a SIGKILLed child that reports 0 can\n // never read as a clean pass downstream.\n const finish = (outcome: { code: number | null; spawned?: boolean; runnerError?: string }) => {\n if (settled) return\n settled = true\n cleanup()\n const spawned = outcome.spawned ?? true\n resolve({\n spawned,\n // A program that never started was sent nothing, whatever the write to\n // its doomed pipe reported.\n stdinDelivered: spawned ? stdinError === undefined : true,\n exitCode: exitCodeFor(outcome.code, killedByTimeout, killedBySignal),\n stdout,\n stderr,\n wallMs: Date.now() - start,\n killedByTimeout,\n killedBySignal,\n outputTruncated,\n runnerError: outcome.runnerError ?? stdinError,\n })\n }\n\n // SIGKILL the whole process group (we spawned detached). On a clean close\n // this never runs.\n const killTree = () => {\n try {\n if (process.platform !== 'win32' && typeof child.pid === 'number') {\n process.kill(-child.pid, 'SIGKILL')\n } else {\n child.kill('SIGKILL')\n }\n } catch (err) {\n // ESRCH means the group exited between the decision to kill and the\n // signal, which `close` reports on its own. Anything else means the\n // group may still be running, which the caller must hear about.\n if ((err as NodeJS.ErrnoException)?.code !== 'ESRCH') {\n console.warn('[bounded-process] SIGKILL of the process group failed:', err)\n }\n }\n }\n\n // Give `close` a brief window to fire (flushing any final output) after\n // the group dies; if an orphaned grandchild keeps the pipes open, resolve\n // anyway so the caller can't hang on a runaway. The deadline and an abort\n // can both fire, so the kill happens at most once and the drain window is\n // not restarted by the second one.\n let killed = false\n const killAndDrain = () => {\n if (killed) return\n killed = true\n killTree()\n forceResolve = setTimeout(() => finish({ code: null }), KILL_DRAIN_MS)\n }\n\n function onAbort() {\n if (settled) return\n killedBySignal = true\n killAndDrain()\n }\n\n const timeout = setTimeout(() => {\n killedByTimeout = true\n killAndDrain()\n }, timeoutMs)\n\n input.signal?.addEventListener('abort', onAbort, { once: true })\n\n child.on('close', (code) => {\n if (forceResolve) clearTimeout(forceResolve)\n finish({ code })\n })\n child.on('error', (err) => {\n if (forceResolve) clearTimeout(forceResolve)\n // `error` on a child means the program never started — a missing binary,\n // a refused argument. Nothing ran, whatever the stdin write did.\n finish({ code: SPAWN_FAILURE_EXIT_CODE, spawned: false, runnerError: String(err) })\n })\n })\n}\n\n/**\n * A killed run reports the code the child closed with only when that code is\n * already non-zero; otherwise it reports the conventional code for the kind\n * of kill. A run that closed on its own with no code at all reports 1.\n */\nfunction exitCodeFor(\n code: number | null,\n killedByTimeout: boolean,\n killedBySignal: boolean,\n): number {\n if (code !== null && code !== 0) return code\n if (killedByTimeout) return TIMEOUT_EXIT_CODE\n if (killedBySignal) return ABORT_EXIT_CODE\n return code ?? UNKNOWN_EXIT_CODE\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bounded-process-BZrWXIKW.js","names":[],"sources":["../src/bounded-process.ts"],"sourcesContent":["/**\n * `runBoundedProcess` — run one command under a wall-clock bound and return\n * what it produced, leaving no descendant behind.\n *\n * The child leads its own process group (`detached` on every non-win32\n * platform), so a deadline or an abort kills the group with\n * `process.kill(-pid, 'SIGKILL')` rather than only the shell that was\n * spawned. That distinction is the whole point of this module: `sh -c\n * 'solver & wait'` puts the real work in a grandchild, and a kill aimed at\n * the shell alone leaves that grandchild running, holding the stdout and\n * stderr pipes open. `close` then never fires, so the deadline produces no\n * result the caller can observe and the descendant outlives the run.\n *\n * Two further guarantees the caller depends on:\n *\n * - A killed run never reports success. A SIGKILLed child can still close\n * with exit code 0, so a run killed by the deadline or by an abort has\n * its exit code forced non-zero.\n * - A run always resolves. If a grandchild escaped the group and still\n * holds the pipes, the result is delivered {@link KILL_DRAIN_MS} after\n * the kill instead of waiting on a `close` that will not come.\n *\n * The captured output is bounded. Once the cap is reached the streams are\n * still drained — the child needs its pipes read to reach `close` — but the\n * bytes are discarded and `outputTruncated` is set.\n */\n\nimport { spawn } from 'node:child_process'\nimport { StringDecoder } from 'node:string_decoder'\n\n/** Wall-clock bound applied when the caller names none. */\nexport const DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS = 10 * 60_000\n\n/** Cap on captured stdout+stderr applied when the caller names none. */\nconst DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024\n\n/**\n * Window `close` is given after the process group is killed. A grandchild\n * that escaped the group can hold the pipes open indefinitely; the caller\n * receives its result at the end of this window rather than hanging.\n */\nconst KILL_DRAIN_MS = 2000\n\n/** Exit code reported for a run the wall-clock bound killed (GNU `timeout`). */\nconst TIMEOUT_EXIT_CODE = 124\n\n/** Exit code reported for a run an `AbortSignal` killed (128 + SIGKILL). */\nconst ABORT_EXIT_CODE = 137\n\n/** Exit code reported when the process could not be spawned at all. */\nconst SPAWN_FAILURE_EXIT_CODE = 127\n\n/** Exit code reported when a process closed with no code and was not killed. */\nconst UNKNOWN_EXIT_CODE = 1\n\nexport interface BoundedProcessInput {\n /**\n * The command line, interpreted by a shell unless `shell` is `false`. When\n * {@link BoundedProcessInput.args} is present this is a program path\n * instead, and no shell reads it.\n */\n command: string\n /**\n * Argument vector for `command`, delivered to the program as separate\n * argv entries with no shell between them.\n *\n * This is the form to use whenever an argument carries text the caller did\n * not author — a script body, a path, a pattern. Without it, `interpreter\n * -flag <script>` can only be expressed by quoting the script into a\n * shell string, and a quoting bug there is a command injection rather than\n * a wrong answer. Each entry arrives verbatim, so there is nothing to\n * quote: `{ command: 'bash', args: ['-n', '-c', body] }` parses `body`\n * whatever shell metacharacters it holds.\n *\n * Two limits are the platform's, not this module's. A NUL byte in an entry\n * cannot be passed to a process at all, and is reported as a `runnerError`\n * rather than thrown. A lone surrogate is encoded to UTF-8 as U+FFFD, and a\n * non-string entry from an untypechecked caller is coerced with `String()`,\n * so an entry is verbatim exactly when it is a string a UTF-8 argv can hold.\n *\n * A shell cannot interpret an argument vector, so `args` and a truthy\n * `shell` are contradictory. Passing both spawns nothing and reports\n * `runnerError`.\n */\n args?: string[]\n /**\n * Text written to the child's standard input. The stream is closed after\n * the write, so a command that reads until end-of-file sees exactly this\n * payload and then EOF.\n *\n * The child's stdin is closed whether or not this field is present. A pipe\n * nobody closes is a hang: a command that reads stdin waits for bytes that\n * never arrive until the deadline kills it, which reads downstream as a\n * slow command rather than as a caller that forgot to send input.\n *\n * The payload is written as UTF-8 and is otherwise verbatim: a NUL byte,\n * a newline, a quote and a backslash all arrive as themselves, because\n * nothing parses this text. The one platform limit is the one `args`\n * already states — a lone surrogate is encoded as U+FFFD, since no UTF-8\n * stream can carry it.\n *\n * A child that exits before reading breaks the pipe. That is the child's\n * behaviour, not a runner failure, so the run still settles on the child's\n * own exit code, and the undelivered payload is reported in `runnerError`\n * with the `stdin not delivered:` prefix. Whether a SMALL payload to a\n * command that ignores stdin reports this is a race — the write may land in\n * the pipe buffer before the child exits — so the flag is a statement about\n * delivery, never about the command. It is not a race for the case that\n * matters: a payload larger than the pipe buffer that the child never\n * drains cannot be delivered, and reports every time.\n */\n stdin?: string\n /**\n * Shell that interprets `command`. `true` (the default) uses the platform\n * default — `/bin/sh` on POSIX, `cmd.exe` on Windows. A string names the\n * shell binary, e.g. `'bash'`, which is required for a bash-only construct\n * such as `[[ ]]` or `$BASH_VERSION`. `false` executes `command` directly\n * as a program path with no arguments. Ignored — and refused when truthy —\n * once {@link BoundedProcessInput.args} is present.\n */\n shell?: boolean | string\n /** Working directory. The parent's cwd is inherited when omitted. */\n cwd?: string\n /**\n * Environment for the child. How it combines with the parent environment\n * is decided by {@link BoundedProcessInput.envMode}.\n */\n env?: NodeJS.ProcessEnv\n /**\n * `'merge'` (the default) layers `env` on top of `process.env`, so the\n * child sees every variable this process has plus the named ones.\n * `'replace'` passes exactly `env` and nothing else, which is what a\n * grader needs when the claim under test is about the variables the\n * command could read. `PATH` is not re-added under `'replace'`, and a\n * command that must find a binary on `PATH` names `PATH` itself.\n *\n * With no `PATH` in the child environment the two forms do NOT search the\n * same directories, so a caller under `'replace'` that names no `PATH` gets\n * a resolution that depends on which form it picked. The shell form execs\n * the shell, which applies its own compiled-in default; the argv form\n * reaches `execvp`, which falls back to `confstr(_CS_PATH)`. Measured on\n * Linux/glibc: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`\n * against `/bin:/usr/bin`, so a binary in `/usr/local/bin` resolves on the\n * shell form and reports ENOENT on the argv form. Name `PATH` and both\n * forms search exactly what was named.\n */\n envMode?: 'merge' | 'replace'\n /** Wall-clock bound in ms. Defaults to 10 minutes. */\n timeoutMs?: number\n /**\n * Cap on captured stdout+stderr. Reaching it truncates the captured text\n * and sets `outputTruncated`; it never kills the process. Defaults to\n * 16 MiB.\n */\n maxOutputBytes?: number\n /**\n * Kills the process group when it aborts, the same way the deadline does.\n * A signal that is already aborted when `runBoundedProcess` is called\n * prevents the spawn entirely — nothing runs.\n */\n signal?: AbortSignal\n}\n\nexport interface BoundedProcessResult {\n /**\n * The process actually started. False when nothing ran at all: an\n * already-aborted signal, `args` with a truthy `shell`, an argument the\n * platform refuses, or a program that does not exist.\n *\n * This is the field to branch on, never the text of `runnerError`. A caller\n * deciding whether a run produced an outcome at all is asking exactly this,\n * and asking it here is type-checked rather than held by a wording\n * convention.\n */\n spawned: boolean\n /**\n * The `stdin` payload reached the child in full. True whenever the caller\n * supplied none, because nothing could fail to arrive.\n *\n * False means the command ran on partial input, which is a fact about the\n * answer it produced: a checksum over a truncated payload is a wrong answer,\n * not a failed run. `spawned` stays true and `exitCode` stays the child's.\n */\n stdinDelivered: boolean\n /**\n * Exit code. Forced non-zero whenever `killedByTimeout` or\n * `killedBySignal` is set, because a SIGKILLed child can close with 0 and\n * a killed run must never read as a pass.\n */\n exitCode: number\n /** Captured stdout, truncated at `maxOutputBytes`. */\n stdout: string\n /**\n * Captured stderr, truncated at `maxOutputBytes`. A runner-side failure is\n * reported in `runnerError`, not appended here; the caller decides whether\n * the command's own stderr and the runner's diagnosis belong together.\n */\n stderr: string\n /** Wall-clock duration in ms, measured across the whole call. */\n wallMs: number\n /** The wall-clock bound was reached and the process group was killed. */\n killedByTimeout: boolean\n /** `signal` aborted and the process group was killed. */\n killedBySignal: boolean\n /** `maxOutputBytes` was reached and later output was discarded. */\n outputTruncated: boolean\n /**\n * Human-readable diagnosis of a runner-side failure, in one of three shapes:\n *\n * - `not spawned:` — the caller's own bug, such as `args` with a truthy\n * `shell`, or an already-aborted signal. No retry helps.\n * - `stdin not delivered:` — the command ran and exited on its own, and\n * the stdin payload did not reach it in full because the child closed\n * the pipe first.\n * - anything else — the process could not be spawned (a missing binary, a\n * NUL byte in an argument).\n *\n * Absent when the command ran and read everything it was sent, however it\n * exited. The prefixes are for a person reading a log; code reads `spawned`\n * and `stdinDelivered`, which say the same things and are type-checked.\n */\n runnerError?: string\n}\n\nexport async function runBoundedProcess(input: BoundedProcessInput): Promise<BoundedProcessResult> {\n const start = Date.now()\n const maxOutputBytes = input.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES\n const timeoutMs = input.timeoutMs ?? DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS\n const envMode = input.envMode ?? 'merge'\n const env =\n input.env === undefined && envMode === 'merge'\n ? undefined\n : envMode === 'replace'\n ? { ...input.env }\n : { ...process.env, ...input.env }\n\n if (input.signal?.aborted) {\n return {\n spawned: false,\n stdinDelivered: true,\n exitCode: ABORT_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: true,\n outputTruncated: false,\n runnerError: 'aborted before spawn: the AbortSignal was already aborted',\n }\n }\n\n // Reported rather than thrown, because this module's contract is that a\n // call always resolves. A caller bug still reads as a failure and never as\n // a pass: the exit code is non-zero and `runnerError` names the cause.\n if (input.args !== undefined && input.shell) {\n return {\n spawned: false,\n stdinDelivered: true,\n exitCode: SPAWN_FAILURE_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: false,\n outputTruncated: false,\n // Shares `SPAWN_FAILURE_EXIT_CODE` with a program that does not exist,\n // because both mean nothing ran. The `not spawned:` prefix is the stable\n // discriminator: it marks the caller's own bug, which no retry fixes.\n runnerError:\n 'not spawned: `args` passes an argument vector directly to the program, so a shell ' +\n 'cannot interpret it — pass `args` or a truthy `shell`, never both',\n }\n }\n\n return await new Promise<BoundedProcessResult>((resolve) => {\n const spawnOptions = {\n cwd: input.cwd,\n env,\n // Own process group so a kill reaches the whole tree, not just the\n // shell — otherwise a runaway grandchild keeps the pipes open and\n // `close` never fires.\n detached: process.platform !== 'win32',\n }\n // The argv form takes the same bounds, the same group and the same kill\n // path. Two things differ, and both are stated where they are decided:\n // no shell reads the command, and executable lookup falls back to a\n // different default `PATH` when the caller names none (see `envMode`).\n //\n // `spawn` validates its arguments and THROWS synchronously — a NUL byte in\n // `command` or in an `args` entry, or an `args` that is not an array from\n // an untypechecked caller. A throw inside this executor would reject, and\n // this module's contract is that a call always resolves. A caller that\n // grades untrusted text must be able to score that text as failed rather\n // than die on it.\n let child: ReturnType<typeof spawn>\n try {\n child =\n input.args === undefined\n ? spawn(input.command, { ...spawnOptions, shell: input.shell ?? true })\n : spawn(input.command, input.args, { ...spawnOptions, shell: false })\n } catch (err) {\n resolve({\n spawned: false,\n stdinDelivered: true,\n exitCode: SPAWN_FAILURE_EXIT_CODE,\n stdout: '',\n stderr: '',\n wallMs: Date.now() - start,\n killedByTimeout: false,\n killedBySignal: false,\n outputTruncated: false,\n runnerError: String(err),\n })\n return\n }\n // A pipe nobody closes is a hang, so stdin is always ended — after the\n // payload when there is one, immediately when there is not. A write that\n // fails is recorded and never thrown: the child already ran, and this\n // module's contract is that a call always resolves.\n let stdinError: string | undefined\n const childStdin = child.stdin\n if (childStdin) {\n childStdin.on('error', (err) => {\n // Closing an unused pipe races a command that exits at once, and that\n // broken pipe says nothing about a caller who sent nothing. Only a\n // payload the caller supplied can fail to be delivered.\n if (input.stdin !== undefined) stdinError ??= `stdin not delivered: ${String(err)}`\n })\n if (input.stdin === undefined) childStdin.end()\n else childStdin.end(input.stdin, 'utf8')\n } else if (input.stdin !== undefined) {\n stdinError = 'stdin not delivered: the child was spawned with no stdin pipe'\n }\n\n let stdout = ''\n let stderr = ''\n let outputBytes = 0\n let outputTruncated = false\n let killedByTimeout = false\n let killedBySignal = false\n let settled = false\n\n // Bound the in-memory buffer so a runaway process can't OOM the caller.\n // Once the cap is hit the streams are still drained (the child needs them\n // read to reach `close`) but the bytes are discarded.\n function capture(s: string): string {\n if (outputBytes >= maxOutputBytes) {\n outputTruncated = true\n return ''\n }\n const room = maxOutputBytes - outputBytes\n if (s.length > room) {\n outputBytes = maxOutputBytes\n outputTruncated = true\n return s.slice(0, room)\n }\n outputBytes += s.length\n return s\n }\n\n // Decoded across chunk boundaries. A stream arrives as Buffers split at\n // arbitrary byte offsets, so decoding each chunk on its own replaces any\n // multi-byte character that straddles a boundary with U+FFFD — the output\n // is then corrupted at every 64 KiB of non-ASCII text. The decoder holds\n // the partial sequence until its remaining bytes arrive.\n const stdoutDecoder = new StringDecoder('utf8')\n const stderrDecoder = new StringDecoder('utf8')\n const decode = (decoder: StringDecoder, d: unknown): string =>\n Buffer.isBuffer(d) ? decoder.write(d) : String(d)\n\n const onStdout = (d: unknown) => {\n const chunk = capture(decode(stdoutDecoder, d))\n if (chunk) stdout += chunk\n }\n const onStderr = (d: unknown) => {\n const chunk = capture(decode(stderrDecoder, d))\n if (chunk) stderr += chunk\n }\n\n child.stdout?.on('data', onStdout)\n child.stderr?.on('data', onStderr)\n\n let forceResolve: ReturnType<typeof setTimeout> | undefined\n\n const cleanup = () => {\n clearTimeout(timeout)\n if (forceResolve) clearTimeout(forceResolve)\n input.signal?.removeEventListener('abort', onAbort)\n child.stdout?.off('data', onStdout)\n child.stderr?.off('data', onStderr)\n // The stdin `error` listener stays attached on purpose: a stream that\n // emits `error` with no listener throws, and a late EPIPE after the run\n // has settled must not take the process down.\n child.removeAllListeners('close')\n child.removeAllListeners('error')\n }\n\n // Resolve exactly once. `code` comes from `close`; on a kill path the\n // exit code is forced non-zero so a SIGKILLed child that reports 0 can\n // never read as a clean pass downstream.\n const finish = (outcome: { code: number | null; spawned?: boolean; runnerError?: string }) => {\n if (settled) return\n settled = true\n cleanup()\n const spawned = outcome.spawned ?? true\n resolve({\n spawned,\n // A program that never started was sent nothing, whatever the write to\n // its doomed pipe reported.\n stdinDelivered: spawned ? stdinError === undefined : true,\n exitCode: exitCodeFor(outcome.code, killedByTimeout, killedBySignal),\n stdout,\n stderr,\n wallMs: Date.now() - start,\n killedByTimeout,\n killedBySignal,\n outputTruncated,\n runnerError: outcome.runnerError ?? stdinError,\n })\n }\n\n // SIGKILL the whole process group (we spawned detached). On a clean close\n // this never runs.\n const killTree = () => {\n try {\n if (process.platform !== 'win32' && typeof child.pid === 'number') {\n process.kill(-child.pid, 'SIGKILL')\n } else {\n child.kill('SIGKILL')\n }\n } catch (err) {\n // ESRCH means the group exited between the decision to kill and the\n // signal, which `close` reports on its own. Anything else means the\n // group may still be running, which the caller must hear about.\n if ((err as NodeJS.ErrnoException)?.code !== 'ESRCH') {\n console.warn('[bounded-process] SIGKILL of the process group failed:', err)\n }\n }\n }\n\n // Give `close` a brief window to fire (flushing any final output) after\n // the group dies; if an orphaned grandchild keeps the pipes open, resolve\n // anyway so the caller can't hang on a runaway. The deadline and an abort\n // can both fire, so the kill happens at most once and the drain window is\n // not restarted by the second one.\n let killed = false\n const killAndDrain = () => {\n if (killed) return\n killed = true\n killTree()\n forceResolve = setTimeout(() => finish({ code: null }), KILL_DRAIN_MS)\n }\n\n function onAbort() {\n if (settled) return\n killedBySignal = true\n killAndDrain()\n }\n\n const timeout = setTimeout(() => {\n killedByTimeout = true\n killAndDrain()\n }, timeoutMs)\n\n input.signal?.addEventListener('abort', onAbort, { once: true })\n\n child.on('close', (code) => {\n if (forceResolve) clearTimeout(forceResolve)\n finish({ code })\n })\n child.on('error', (err) => {\n if (forceResolve) clearTimeout(forceResolve)\n // `error` on a child means the program never started — a missing binary,\n // a refused argument. Nothing ran, whatever the stdin write did.\n finish({ code: SPAWN_FAILURE_EXIT_CODE, spawned: false, runnerError: String(err) })\n })\n })\n}\n\n/**\n * A killed run reports the code the child closed with only when that code is\n * already non-zero; otherwise it reports the conventional code for the kind\n * of kill. A run that closed on its own with no code at all reports 1.\n */\nfunction exitCodeFor(\n code: number | null,\n killedByTimeout: boolean,\n killedBySignal: boolean,\n): number {\n if (code !== null && code !== 0) return code\n if (killedByTimeout) return TIMEOUT_EXIT_CODE\n if (killedBySignal) return ABORT_EXIT_CODE\n return code ?? UNKNOWN_EXIT_CODE\n}\n"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
- import { f as Run, o as FailureClass } from "../schema-D6EVKzTB.js";
2
- import { s as TraceStore } from "../store-B3nWRy3B.js";
3
- import { o as TraceEmitter } from "../emitter-DABYYTcH.js";
4
- import { n as SandboxDriver, r as SandboxHarnessResult, t as HarnessConfig } from "../sandbox-harness-BlSOu4LX.js";
5
- //#region src/test-graded-scenario.d.ts
1
+ import { f as Run, o as FailureClass } from "../schema-CkIvnmLU.js";
2
+ import { s as TraceStore } from "../store-CMs5wGXP.js";
3
+ import { o as TraceEmitter } from "../emitter-mAXC5PSN.js";
4
+ import { n as SandboxDriver, r as SandboxHarnessResult, t as HarnessConfig } from "../sandbox-harness-B3Kx1fOA.js";
6
5
  interface TestGradedScenario {
7
6
  id: string;
8
7
  description?: string;
@@ -22,8 +21,6 @@ interface TestGradedRunResult {
22
21
  score: number;
23
22
  failureClass?: FailureClass;
24
23
  }
25
- //#endregion
26
- //#region src/builder-eval/builder-session.d.ts
27
24
  export interface BuilderSessionInit {
28
25
  projectId: string;
29
26
  chatId?: string;
@@ -112,8 +109,6 @@ export declare function resumeBuilderSession(store: TraceStore, projectId: strin
112
109
  lastBuildRun?: Run;
113
110
  lastAppRuntimeRuns: Run[];
114
111
  }>;
115
- //#endregion
116
- //#region src/builder-eval/three-layer-eval.d.ts
117
112
  export type ProjectKind = 'full' | 'scaffold-only';
118
113
  export interface ThreeLayerProjectReport {
119
114
  projectId: string;
@@ -144,8 +139,6 @@ export interface ThreeLayerProjectReport {
144
139
  export declare function scoreProject(store: TraceStore, projectId: string): Promise<ThreeLayerProjectReport>;
145
140
  /** Aggregate scoring across every project in a corpus. */
146
141
  export declare function scoreAllProjects(store: TraceStore): Promise<ThreeLayerProjectReport[]>;
147
- //#endregion
148
- //#region src/builder-eval/correlation.d.ts
149
142
  export interface LayerCorrelation {
150
143
  n: number;
151
144
  pearson: number;
@@ -160,8 +153,6 @@ export interface CorrelationReport {
160
153
  completeProjects: number;
161
154
  }
162
155
  export declare function correlateLayers(reports: ThreeLayerProjectReport[]): CorrelationReport;
163
- //#endregion
164
- //#region src/builder-eval/project-registry.d.ts
165
156
  export interface ProjectSummary {
166
157
  projectId: string;
167
158
  chatCount: number;
@@ -199,5 +190,5 @@ export declare class ProjectRegistry {
199
190
  projectTimeline(projectId: string): Promise<ProjectTimelineEntry[]>;
200
191
  projectChats(projectId: string): Promise<ChatSummary[]>;
201
192
  }
202
- //#endregion
193
+ export {};
203
194
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/test-graded-scenario.ts","../../src/builder-eval/builder-session.ts","../../src/builder-eval/three-layer-eval.ts","../../src/builder-eval/correlation.ts","../../src/builder-eval/project-registry.ts"],"mappings":";;;;;UAmBiB;EACf;EACA;EACA,SAAS;;EAET;;EAEA;;EAEA,OAAO;;UAUQ;EACf;EACA,UAAU;EACV,SAAS;EACT;EACA;EACA,eAAe;;;;iBCjBA;EACf;EACA;;EAEA,OAAO;;iBAGQ;EACf,SAAS;EACT,SAAS;;EAET;;iBAGe;EACf,UAAU;;EAEV,SAAS;;qBAGE;UACH;UACA;WACC;WACA;UACD;UACA;UACA;EAER,YAAY,OAAO,YAAY,MAAM,oBAAoB,SAAS;;EAS5D,UAAU,sBAAwC;;MAYpD,WAAW;;;;;EAST,KAAK,SAAS,cAAc;IAAU;IAAe,QAAQ;;;;;;;;EA2B7D,eAAe,SAAS,wBAAwB,QAAQ;;;EAqBxD,gBAAgB,eAAe,qBAAqB;;EAcpD,QAAQ;IAAW;IAAe;IAAgB;MAAmB;;;;;;;;EAerE,gBAAgB,qBAAqB,QAAQ;;;;;;EAsB7C,iBAAiB;IACrB;IACA;IACA;IACA;MACE;MAqBA;MAGA;;;;;;;wBAUgB,qBACpB,OAAO,YACP,oBACC;EACD;EACA,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,oBAAoB;;;;YC5MV;iBAEK;EACf;;;;;;;EAOA,MAAM;EACN;;EAEA;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;EAMA;;wBAGoB,aACpB,OAAO,YACP,oBACC,QAAQ;;wBAuCW,iBAAiB,OAAO,aAAa,QAAQ;;;iBC/ElD;EACf;EACA;EACA;;iBAGe;;EAEf,cAAc;EACd,gBAAgB;EAChB,iBAAiB;;EAEjB;;wBAGc,gBAAgB,SAAS,4BAA4B;;;iBCpBpD;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAkB;IAAe;;;iBAGlB;EACf;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,UAAU;;EAEV;EACA;EACA;EACA;;iBAGe;EACf,KAAK;EACL;;qBAGW;UACS;EAApB,YAAoB,OAAO;EAErB,gBAAgB,QAAQ;EAgCxB,gBAAgB,oBAAoB,QAAQ;EAgB5C,aAAa,oBAAoB,QAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/test-graded-scenario.ts","../../src/builder-eval/builder-session.ts","../../src/builder-eval/three-layer-eval.ts","../../src/builder-eval/correlation.ts","../../src/builder-eval/project-registry.ts"],"mappings":";;;;UAmBiB;EACf;EACA;EACA,SAAS;;EAET;;EAEA;;EAEA,OAAO;;UAUQ;EACf;EACA,UAAU;EACV,SAAS;EACT;EACA;EACA,eAAe;;iBCjBA;EACf;EACA;;EAEA,OAAO;;iBAGQ;EACf,SAAS;EACT,SAAS;;EAET;;iBAGe;EACf,UAAU;;EAEV,SAAS;;qBAGE;UACH;UACA;WACC;WACA;UACD;UACA;UACA;EAEI,YAAA,OAAO,YAAY,MAAM,oBAAoB,SAAS;;EAS5D,UAAU,sBAAwC;;MAYpD,WAAW;;;;;EAST,KAAK,SAAS,cAAc;IAAU;IAAe,QAAQ;;;;;;;;EA2B7D,eAAe,SAAS,wBAAwB,QAAQ;;;EAqBxD,gBAAgB,eAAe,qBAAqB;;EAcpD,QAAQ;IAAW;IAAe;IAAgB;MAAmB;;;;;;;;EAerE,gBAAgB,qBAAqB,QAAQ;;;;;;EAsB7C,iBAAiB;IACrB;IACA;IACA;IACA;MACE;MAqBA;MAGA;;;;;;;wBAUgB,qBACpB,OAAO,YACP,oBACC;EACD;EACA,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,oBAAoB;;YC5MV;iBAEK;EACf;;;;;;;EAOA,MAAM;EACN;;EAEA;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;EAMA;;wBAGoB,aACpB,OAAO,YACP,oBACC,QAAQ;;wBAuCW,iBAAiB,OAAO,aAAa,QAAQ;iBC/ElD;EACf;EACA;EACA;;iBAGe;;EAEf,cAAc;EACd,gBAAgB;EAChB,iBAAiB;;EAEjB;;wBAGc,gBAAgB,SAAS,4BAA4B;iBCpBpD;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAkB;IAAe;;;iBAGlB;EACf;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,UAAU;;EAEV;EACA;EACA;EACA;;iBAGe;EACf,KAAK;EACL;;qBAGW;UACS;EAAA,YAAA,OAAO;EAErB,gBAAgB,QAAQ;EAgCxB,gBAAgB,oBAAoB,QAAQ;EAgB5C,aAAa,oBAAoB,QAAQ"}
@@ -1,9 +1,9 @@
1
- import { a as spearmanR, r as pearsonR } from "../descriptive-CVNy48rR.js";
2
- import { i as judgeSpans } from "../query-B_RZ36an.js";
3
- import { t as newRecordId } from "../record-id-DUgsK5qp.js";
4
- import { t as TraceEmitter } from "../emitter-DbMXUIVP.js";
5
- import { n as runBoundedProcess } from "../bounded-process-Cj9YjXbE.js";
6
- //#region src/sandbox-harness.ts
1
+ import { a as spearmanR, r as pearsonR } from "../descriptive-cPwITVfy.js";
2
+ import { i as judgeSpans } from "../query-CGXzO9d4.js";
3
+ import { t as newRecordId } from "../record-id-CWZXFh58.js";
4
+ import { t as TraceEmitter } from "../emitter-DhQ65mza.js";
5
+ import { n as runBoundedProcess } from "../bounded-process-BZrWXIKW.js";
6
+ // src/sandbox-harness.ts
7
7
  /**
8
8
  * SandboxHarness — executes a scenario in an isolated environment and
9
9
  * emits a rich SandboxSpan into the trace.
@@ -127,8 +127,7 @@ var SandboxHarness = class {
127
127
  return result;
128
128
  }
129
129
  };
130
- //#endregion
131
- //#region src/test-graded-scenario.ts
130
+ // src/test-graded-scenario.ts
132
131
  async function runTestGradedScenario(scenario, store, options = {}) {
133
132
  const emitter = new TraceEmitter(store);
134
133
  await emitter.startRun({
@@ -169,8 +168,7 @@ function reasonForFailure(result) {
169
168
  }
170
169
  return "no test command";
171
170
  }
172
- //#endregion
173
- //#region src/builder-eval/builder-session.ts
171
+ // src/builder-eval/builder-session.ts
174
172
  /**
175
173
  * BuilderSession — ties a builder-of-builders workflow together.
176
174
  *
@@ -361,8 +359,7 @@ async function resumeBuilderSession(store, projectId) {
361
359
  lastAppRuntimeRuns: appRuntimeRuns
362
360
  };
363
361
  }
364
- //#endregion
365
- //#region src/builder-eval/correlation.ts
362
+ // src/builder-eval/correlation.ts
366
363
  /**
367
364
  * Meta-eval correlation — the highest-leverage signal in the framework.
368
365
  *
@@ -406,8 +403,7 @@ function pairwise(reports, a, b) {
406
403
  spearman: spearmanR(xs, ys)
407
404
  };
408
405
  }
409
- //#endregion
410
- //#region src/builder-eval/project-registry.ts
406
+ // src/builder-eval/project-registry.ts
411
407
  var ProjectRegistry = class {
412
408
  store;
413
409
  constructor(store) {
@@ -485,8 +481,7 @@ var ProjectRegistry = class {
485
481
  return out;
486
482
  }
487
483
  };
488
- //#endregion
489
- //#region src/builder-eval/three-layer-eval.ts
484
+ // src/builder-eval/three-layer-eval.ts
490
485
  /**
491
486
  * Three-layer evaluation — the canonical scoring breakdown for
492
487
  * builder-of-builders workflows.
@@ -552,7 +547,6 @@ async function extractMetaScore(store, builderRunId) {
552
547
  if (meta.score >= 0 && meta.score <= 10) return meta.score / 10;
553
548
  return null;
554
549
  }
555
- //#endregion
556
550
  export { BuilderSession, ProjectRegistry, correlateLayers, resumeBuilderSession, scoreAllProjects, scoreProject };
557
551
 
558
552
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/sandbox-harness.ts","../../src/test-graded-scenario.ts","../../src/builder-eval/builder-session.ts","../../src/builder-eval/correlation.ts","../../src/builder-eval/project-registry.ts","../../src/builder-eval/three-layer-eval.ts"],"sourcesContent":["/**\n * SandboxHarness — executes a scenario in an isolated environment and\n * emits a rich SandboxSpan into the trace.\n *\n * Two built-in drivers:\n * - `SubprocessSandboxDriver` — runs the phase in a local cwd with env\n * vars, through `runBoundedProcess` (deadline, process-group kill,\n * output cap). Fast, no dependencies, fine for unit tests and CI gates.\n * - `DockerSandboxDriver` — lifted from tangle-router's sandbox path;\n * shells out to `docker run`. Stronger isolation, slower startup.\n *\n * Consumers implement `SandboxDriver` for custom backends (Firecracker,\n * Cloudflare sandbox product, etc.). The harness doesn't care which.\n */\n\nimport { runBoundedProcess } from './bounded-process'\n\nimport type { TraceEmitter } from './trace/emitter'\nimport type { SandboxSpan } from './trace/schema'\n\nexport interface HarnessConfig {\n /** Setup command (e.g. \"pnpm install\"). Non-zero exit fails the run. */\n setupCommand?: string\n /** Run command (e.g. \"pnpm build\"). */\n runCommand?: string\n /** Test command (e.g. \"pnpm test --run\"). Drives the test count + pass count. */\n testCommand?: string\n /** Absolute cwd for the subprocess driver. Ignored by docker driver. */\n cwd?: string\n /** Max wall-clock per phase in ms. Default 10 minutes. */\n timeoutMs?: number\n /**\n * Cap on captured stdout+stderr bytes per phase. A runaway process can\n * otherwise grow the in-memory buffer without bound. Once hit, further\n * output is dropped and `outputTruncated` is set. Default 16 MiB.\n */\n maxOutputBytes?: number\n /** Image for the docker driver. */\n image?: string\n /** Extra env vars (validated; shell-escaped). */\n env?: Record<string, string>\n /** Parser for the test output — maps stdout/stderr/exit code → pass count. */\n testParser?: TestOutputParser\n}\n\nexport interface TestOutputParser {\n id: string\n parse(\n stdout: string,\n stderr: string,\n exitCode: number,\n ): { testsTotal: number; testsPassed: number } | undefined\n}\n\nexport interface SandboxResult {\n phase: 'setup' | 'run' | 'test'\n exitCode: number\n stdout: string\n stderr: string\n wallMs: number\n testsTotal?: number\n testsPassed?: number\n /**\n * True when the process was killed because it exceeded `timeoutMs`. A\n * SIGKILLed child can still close with exit code 0; callers MUST treat\n * a timed-out phase as a hard failure regardless of `exitCode`, never\n * as a pass. `undefined`/`false` means the process completed on its own.\n */\n killedByTimeout?: boolean\n /**\n * True when captured stdout/stderr hit `maxOutputBytes` and further\n * output was dropped. The result is still returned (the process was\n * not killed for this), but downstream parsers see truncated text.\n */\n outputTruncated?: boolean\n}\n\nexport interface SandboxDriver {\n id: string\n exec(\n phase: SandboxResult['phase'],\n command: string,\n config: HarnessConfig,\n ): Promise<SandboxResult>\n}\n\n// ── Parsers ──────────────────────────────────────────────────────────\n\n/** Vitest default summary line: \"Tests X passed | Y failed\". */\nexport const vitestTestParser: TestOutputParser = {\n id: 'vitest',\n parse(stdout) {\n const m = stdout.match(/Tests\\s+(\\d+)\\s+(passed|failed)(?:\\s*\\|\\s*(\\d+)\\s+(passed|failed))?/i)\n if (!m) return undefined\n let passed = 0\n let failed = 0\n const a = parseInt(m[1]!, 10)\n const aLabel = m[2]!.toLowerCase()\n if (aLabel === 'passed') passed += a\n else failed += a\n if (m[3] && m[4]) {\n const b = parseInt(m[3], 10)\n if (m[4].toLowerCase() === 'passed') passed += b\n else failed += b\n }\n return { testsTotal: passed + failed, testsPassed: passed }\n },\n}\n\n/** Pytest default: \"collected N items\" + \" X passed, Y failed\". */\nexport const pytestTestParser: TestOutputParser = {\n id: 'pytest',\n parse(stdout) {\n const total = stdout.match(/collected\\s+(\\d+)\\s+items?/i)\n const passed = stdout.match(/(\\d+)\\s+passed/)\n if (!total || !passed) return undefined\n return { testsTotal: parseInt(total[1]!, 10), testsPassed: parseInt(passed[1]!, 10) }\n },\n}\n\n/** Jest: \"Tests: X passed, Y total\" (and optional failed). */\nexport const jestTestParser: TestOutputParser = {\n id: 'jest',\n parse(stdout) {\n const m = stdout.match(/Tests:\\s+(?:(\\d+)\\s+failed[^,]*,\\s*)?(\\d+)\\s+passed,\\s+(\\d+)\\s+total/i)\n if (!m) return undefined\n return { testsTotal: parseInt(m[3]!, 10), testsPassed: parseInt(m[2]!, 10) }\n },\n}\n\n/** Composite parser — tries a list of parsers in order. */\nexport function composeParsers(...parsers: TestOutputParser[]): TestOutputParser {\n return {\n id: parsers.map((p) => p.id).join('|'),\n parse(stdout, stderr, exitCode) {\n for (const p of parsers) {\n const res = p.parse(stdout, stderr, exitCode)\n if (res) return res\n }\n return undefined\n },\n }\n}\n\n// ── Drivers ──────────────────────────────────────────────────────────\n\ninterface SubprocessSandboxDriverOptions {\n /**\n * Default cwd for all `exec` calls. Used when the per-call `HarnessConfig`\n * does not set its own `cwd`. Lets callers bind the driver to a working\n * directory once instead of spreading cwd into every harness config —\n * useful when the harness config is constructed far from the call site\n * (e.g. starter-foundry's promoter passes a static HarnessConfig per\n * family taxonomy but needs a per-run composed-scaffold cwd).\n */\n cwd?: string\n /**\n * Default env merged into every `exec` call's env (per-call `HarnessConfig.env`\n * still wins on key collision). Same ergonomic rationale as `cwd` above.\n */\n env?: Record<string, string>\n}\n\nexport class SubprocessSandboxDriver implements SandboxDriver {\n id = 'subprocess'\n private defaultCwd?: string\n private defaultEnv?: Record<string, string>\n\n constructor(options: SubprocessSandboxDriverOptions = {}) {\n this.defaultCwd = options.cwd\n this.defaultEnv = options.env\n }\n\n async exec(\n phase: SandboxResult['phase'],\n command: string,\n config: HarnessConfig,\n ): Promise<SandboxResult> {\n // Per-call config wins; fall back to constructor defaults. Honoring\n // the constructor `cwd` keeps the subprocess from inheriting Node's\n // cwd when only the constructor arg is supplied.\n const effectiveCwd = config.cwd ?? this.defaultCwd\n // The parent environment is merged here, so the runner is handed the\n // complete environment and passes it through unchanged.\n const effectiveEnv = { ...process.env, ...(this.defaultEnv ?? {}), ...(config.env ?? {}) }\n const result = await runBoundedProcess({\n command,\n shell: true,\n cwd: effectiveCwd,\n env: effectiveEnv,\n envMode: 'replace',\n timeoutMs: config.timeoutMs ?? 10 * 60_000,\n maxOutputBytes: config.maxOutputBytes ?? 16 * 1024 * 1024,\n })\n // A timed-out phase never reaches the parser: the output of a killed\n // process is a fragment, and a fragment that happens to parse would\n // report a pass for a run that never finished.\n const parsed =\n !result.killedByTimeout && phase === 'test' && config.testParser\n ? config.testParser.parse(result.stdout, result.stderr, result.exitCode)\n : undefined\n return {\n phase,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.runnerError ? result.stderr + result.runnerError : result.stderr,\n wallMs: result.wallMs,\n testsTotal: parsed?.testsTotal,\n testsPassed: parsed?.testsPassed,\n killedByTimeout: result.killedByTimeout || undefined,\n outputTruncated: result.outputTruncated || undefined,\n }\n }\n}\n\n\n\n\n\n// ── Harness orchestration ────────────────────────────────────────────\n\nexport interface SandboxHarnessResult {\n passed: boolean\n setup?: SandboxResult\n run?: SandboxResult\n test?: SandboxResult\n totalWallMs: number\n /** Final score — 0 when no tests; otherwise testsPassed/testsTotal. */\n score: number\n}\n\nexport class SandboxHarness {\n private driver: SandboxDriver\n constructor(driver: SandboxDriver = new SubprocessSandboxDriver()) {\n this.driver = driver\n }\n\n async run(config: HarnessConfig, emitter: TraceEmitter): Promise<SandboxHarnessResult> {\n const handle = await emitter.sandbox({\n name: `sandbox(${this.driver.id})`,\n image: config.image,\n command: [config.setupCommand, config.runCommand, config.testCommand]\n .filter(Boolean)\n .join(' && '),\n })\n const result: SandboxHarnessResult = { passed: false, totalWallMs: 0, score: 0 }\n try {\n if (config.setupCommand) {\n result.setup = await this.driver.exec('setup', config.setupCommand, config)\n result.totalWallMs += result.setup.wallMs\n if (result.setup.killedByTimeout || result.setup.exitCode !== 0) {\n const reason = result.setup.killedByTimeout\n ? `setup timed out after ${result.setup.wallMs}ms`\n : `setup failed (exit ${result.setup.exitCode})`\n await handle.fail(reason, {\n exitCode: result.setup.exitCode,\n wallMs: result.totalWallMs,\n } as Partial<SandboxSpan>)\n return result\n }\n }\n if (config.runCommand) {\n result.run = await this.driver.exec('run', config.runCommand, config)\n result.totalWallMs += result.run.wallMs\n if (result.run.killedByTimeout || result.run.exitCode !== 0) {\n const reason = result.run.killedByTimeout\n ? `run timed out after ${result.run.wallMs}ms`\n : `run failed (exit ${result.run.exitCode})`\n await handle.fail(reason, {\n exitCode: result.run.exitCode,\n wallMs: result.totalWallMs,\n } as Partial<SandboxSpan>)\n return result\n }\n }\n if (config.testCommand) {\n result.test = await this.driver.exec('test', config.testCommand, config)\n result.totalWallMs += result.test.wallMs\n // A timed-out test phase is a hard fail regardless of the exit code\n // a SIGKILLed child happens to report — never let it score as a pass.\n const passed = !result.test.killedByTimeout && result.test.exitCode === 0\n result.passed = passed\n if (result.test.testsTotal !== undefined && result.test.testsTotal > 0) {\n result.score = (result.test.testsPassed ?? 0) / result.test.testsTotal\n } else {\n result.score = passed ? 1 : 0\n }\n await handle.end({\n exitCode: result.test.exitCode,\n testsTotal: result.test.testsTotal,\n testsPassed: result.test.testsPassed,\n wallMs: result.totalWallMs,\n status: passed ? 'ok' : 'error',\n } as Partial<SandboxSpan>)\n } else {\n result.passed = true\n result.score = 1\n await handle.end({ wallMs: result.totalWallMs } as Partial<SandboxSpan>)\n }\n } catch (err) {\n await handle.fail(err instanceof Error ? err : String(err))\n throw err\n }\n return result\n }\n}\n","/**\n * TestGradedScenario — a scenario whose score comes from a test suite.\n *\n * This is the SWE-bench pattern generalized. The scenario ships:\n * - fixture data (setup instructions)\n * - a test command the harness runs\n * - optional assertion overrides\n *\n * The runner emits a run, delegates to SandboxHarness, records the\n * outcome, and returns a structured verdict. Consumers bind their own\n * agent execution to this contract.\n */\n\nimport type { HarnessConfig, SandboxDriver, SandboxHarnessResult } from './sandbox-harness'\nimport { SandboxHarness } from './sandbox-harness'\nimport { TraceEmitter } from './trace/emitter'\nimport type { FailureClass, Run } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\nexport interface TestGradedScenario {\n id: string\n description?: string\n harness: HarnessConfig\n /** Optional pass threshold in 0..1 (default 1.0 = all tests must pass). */\n passThreshold?: number\n /** Provenance for dataset tracking. */\n datasetVersion?: string\n /** Free-form tags (difficulty, category, etc.). */\n tags?: Record<string, string>\n}\n\ninterface TestGradedRunOptions {\n variantId?: string\n driver?: SandboxDriver\n /** Metadata recorded on the Run (codeSha, promptSha, modelFingerprint, seed). */\n provenance?: Pick<Run, 'codeSha' | 'promptSha' | 'modelFingerprint' | 'seed' | 'envFingerprint'>\n}\n\nexport interface TestGradedRunResult {\n runId: string\n scenario: TestGradedScenario\n harness: SandboxHarnessResult\n pass: boolean\n score: number\n failureClass?: FailureClass\n}\n\nexport async function runTestGradedScenario(\n scenario: TestGradedScenario,\n store: TraceStore,\n options: TestGradedRunOptions = {},\n): Promise<TestGradedRunResult> {\n const emitter = new TraceEmitter(store)\n await emitter.startRun({\n scenarioId: scenario.id,\n variantId: options.variantId,\n datasetVersion: scenario.datasetVersion,\n tags: scenario.tags,\n ...options.provenance,\n })\n const harness = new SandboxHarness(options.driver)\n const result = await harness.run(scenario.harness, emitter)\n const threshold = scenario.passThreshold ?? 1.0\n const pass = result.passed && result.score >= threshold\n const setupFailed = result.setup !== undefined && result.setup.exitCode !== 0\n const runFailed = result.run !== undefined && result.run.exitCode !== 0\n const testFailed = result.test !== undefined && result.test.exitCode !== 0\n const failureClass: FailureClass | undefined = pass\n ? 'success'\n : setupFailed || runFailed\n ? 'sandbox_failure'\n : testFailed\n ? 'format_drift'\n : 'unknown'\n await emitter.endRun({\n pass,\n score: result.score,\n failureClass,\n notes: pass ? undefined : reasonForFailure(result),\n })\n return {\n runId: emitter.runId,\n scenario,\n harness: result,\n pass,\n score: result.score,\n failureClass,\n }\n}\n\nfunction reasonForFailure(result: SandboxHarnessResult): string {\n if (result.setup && result.setup.exitCode !== 0)\n return `setup failed: exit ${result.setup.exitCode}`\n if (result.run && result.run.exitCode !== 0) return `run failed: exit ${result.run.exitCode}`\n if (result.test) {\n if (result.test.testsTotal !== undefined) {\n return `tests: ${result.test.testsPassed ?? 0}/${result.test.testsTotal}`\n }\n return `test exit ${result.test.exitCode}`\n }\n return 'no test command'\n}\n","/**\n * BuilderSession — ties a builder-of-builders workflow together.\n *\n * Models agent-builder's shape: Project → Chat → Edit → Ship → App →\n * AppAgent. Each layer is a Run (linked via parentRunId). The\n * framework-enforced invariants:\n *\n * - One Project → many Chats; chatId scopes runs within a project.\n * - One Chat = one builder Run with `layer='builder'`.\n * - One Ship = one child Run with `layer='app-build'` + SandboxHarness.\n * - One AppScenario = one grandchild Run with `layer='app-runtime'`.\n *\n * Consumers obtain a BuilderSession, call `startChat`, drive the\n * builder agent (emitting spans), and call `ship` / `runAppScenario`\n * as the workflow progresses. The session reconstructs itself from\n * trace data via `resume(store, projectId)`.\n */\n\nimport { newRecordId } from '../record-id'\nimport type { HarnessConfig, SandboxDriver, SandboxHarnessResult } from '../sandbox-harness'\nimport { SandboxHarness } from '../sandbox-harness'\nimport type { TestGradedRunResult, TestGradedScenario } from '../test-graded-scenario'\nimport { runTestGradedScenario } from '../test-graded-scenario'\nimport { TraceEmitter } from '../trace/emitter'\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface BuilderSessionInit {\n projectId: string\n chatId?: string\n /** Free-form: user's task description, project name, etc. Stored on the builder Run. */\n tags?: Record<string, string>\n}\n\nexport interface ShipOptions {\n harness: HarnessConfig\n driver?: SandboxDriver\n /** scenarioId of this app-build run. Defaults to `${projectId}/build`. */\n scenarioId?: string\n}\n\nexport interface RunAppScenarioOptions {\n scenario: TestGradedScenario\n /** Harness driver override; defaults to the one the session was created with. */\n driver?: SandboxDriver\n}\n\nexport class BuilderSession {\n private store: TraceStore\n private builderEmitter: TraceEmitter\n readonly projectId: string\n readonly chatId: string\n private builderRunId?: string\n private lastBuildRunId?: string\n private defaultDriver?: SandboxDriver\n\n constructor(store: TraceStore, init: BuilderSessionInit, driver?: SandboxDriver) {\n this.store = store\n this.projectId = init.projectId\n this.chatId = init.chatId ?? newRecordId()\n this.defaultDriver = driver\n this.builderEmitter = new TraceEmitter(store)\n }\n\n /** Start the builder (L0) run for this chat. Returns the runId. */\n async startChat(scenarioId = `${this.projectId}/chat`): Promise<string> {\n await this.builderEmitter.startRun({\n scenarioId,\n projectId: this.projectId,\n chatId: this.chatId,\n layer: 'builder',\n })\n this.builderRunId = this.builderEmitter.runId\n return this.builderRunId\n }\n\n /** The emitter for builder-level spans (edits, LLM calls, tool invocations). */\n get emitter(): TraceEmitter {\n if (!this.builderRunId) throw new Error('BuilderSession.emitter: call startChat() first')\n return this.builderEmitter\n }\n\n /**\n * Ship the project's generated app: run the sandbox harness as a child\n * Run (`layer='app-build'`). Returns the build result + runId.\n */\n async ship(options: ShipOptions): Promise<{ runId: string; result: SandboxHarnessResult }> {\n if (!this.builderRunId) throw new Error('BuilderSession.ship: call startChat() first')\n const buildEmitter = new TraceEmitter(this.store)\n await buildEmitter.startRun({\n scenarioId: options.scenarioId ?? `${this.projectId}/build`,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId: this.builderRunId,\n layer: 'app-build',\n })\n const harness = new SandboxHarness(options.driver ?? this.defaultDriver)\n const result = await harness.run(options.harness, buildEmitter)\n await buildEmitter.endRun({\n pass: result.passed,\n score: result.score,\n failureClass: result.passed ? 'success' : 'sandbox_failure',\n })\n this.lastBuildRunId = buildEmitter.runId\n return { runId: buildEmitter.runId, result }\n }\n\n /**\n * Run a domain scenario against the just-built app as a grandchild Run\n * (`layer='app-runtime'`). The `ship` call must precede this so the\n * parent is set correctly; if no build exists yet the session attaches\n * directly to the builder run (useful for prototypes).\n */\n async runAppScenario(options: RunAppScenarioOptions): Promise<TestGradedRunResult> {\n const parentRunId = this.lastBuildRunId ?? this.builderRunId\n if (!parentRunId)\n throw new Error('BuilderSession.runAppScenario: call startChat() + ship() first')\n const { scenario, driver } = options\n const result = await runTestGradedScenario(scenario, this.store, {\n driver: driver ?? this.defaultDriver,\n provenance: { codeSha: undefined, promptSha: undefined, modelFingerprint: undefined },\n })\n // Attach to the parent chain by updating the stored Run in place.\n await this.store.updateRun(result.runId, {\n parentRunId,\n projectId: this.projectId,\n chatId: this.chatId,\n layer: 'app-runtime',\n })\n return result\n }\n\n /** Record an end-of-chat meta score (judge verdict on whether the builder\n * served the user's intent). Accepts a numeric score + optional rationale. */\n async recordMetaScore(score: number, rationale?: string): Promise<void> {\n if (!this.builderRunId)\n throw new Error('BuilderSession.recordMetaScore: call startChat() first')\n await this.builderEmitter.recordJudge({\n judgeId: 'builder-meta',\n targetSpanId: this.builderRunId, // attach to the builder run itself\n dimension: 'user_intent_satisfaction',\n score,\n rationale,\n name: 'builder-meta',\n })\n }\n\n /** Close the builder Run with a final outcome. */\n async endChat(outcome: { pass: boolean; score?: number; notes?: string }): Promise<void> {\n await this.builderEmitter.endRun({\n pass: outcome.pass,\n score: outcome.score,\n notes: outcome.notes,\n })\n }\n\n /**\n * Inline app-runtime run — for cases where the \"scenario\" isn't a\n * SWE-bench-style test suite but a live agent interaction (LLM chat,\n * domain flow). Returns an emitter bound to a fresh Run in the\n * `app-runtime` layer; caller emits spans inside and calls\n * `.endRun()` with the final verdict.\n */\n async startAppRuntime(scenarioId: string): Promise<TraceEmitter> {\n const parentRunId = this.lastBuildRunId ?? this.builderRunId\n if (!parentRunId)\n throw new Error(\n 'BuilderSession.startAppRuntime: call startChat() + (optionally) ship() first',\n )\n const emitter = new TraceEmitter(this.store)\n await emitter.startRun({\n scenarioId,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId,\n layer: 'app-runtime',\n })\n return emitter\n }\n\n /**\n * Lightweight \"ship marker\" — record an app-build Run with a caller-\n * provided verdict. Use when there isn't a sandbox harness to run but\n * you still want to mark the build state at publish time.\n */\n async recordShipMarker(args: {\n pass: boolean\n score: number\n scenarioId?: string\n notes?: string\n }): Promise<string> {\n if (!this.builderRunId)\n throw new Error('BuilderSession.recordShipMarker: call startChat() first')\n const emitter = new TraceEmitter(this.store)\n await emitter.startRun({\n scenarioId: args.scenarioId ?? `${this.projectId}/ship`,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId: this.builderRunId,\n layer: 'app-build',\n })\n await emitter.endRun({\n pass: args.pass,\n score: args.score,\n failureClass: args.pass ? 'success' : 'sandbox_failure',\n notes: args.notes,\n })\n this.lastBuildRunId = emitter.runId\n return emitter.runId\n }\n\n get lastBuildRunIdValue(): string | undefined {\n return this.lastBuildRunId\n }\n get builderRunIdValue(): string | undefined {\n return this.builderRunId\n }\n}\n\n/**\n * Reconstruct the most recent BuilderSession state for a given project —\n * returns { builderRunId, lastBuildRunId, chatRuns }. For chat-first UIs\n * this is how a resumed session finds its place in the edit history.\n */\nexport async function resumeBuilderSession(\n store: TraceStore,\n projectId: string,\n): Promise<{\n projectId: string\n chatRuns: Run[]\n lastBuilderRun?: Run\n lastBuildRun?: Run\n lastAppRuntimeRuns: Run[]\n}> {\n const runs = await store.listRuns({ projectId })\n const chatRuns = runs\n .filter((r) => r.layer === 'builder')\n .sort((a, b) => b.startedAt - a.startedAt)\n const buildRuns = runs\n .filter((r) => r.layer === 'app-build')\n .sort((a, b) => b.startedAt - a.startedAt)\n const appRuntimeRuns = runs\n .filter((r) => r.layer === 'app-runtime')\n .sort((a, b) => b.startedAt - a.startedAt)\n return {\n projectId,\n chatRuns,\n lastBuilderRun: chatRuns[0],\n lastBuildRun: buildRuns[0],\n lastAppRuntimeRuns: appRuntimeRuns,\n }\n}\n","/**\n * Meta-eval correlation — the highest-leverage signal in the framework.\n *\n * Given a corpus of three-layer project reports, compute how well each\n * pair of layers correlates. The question we care about most:\n *\n * Does `metaScore` (what the builder thinks it did) predict\n * `runtimeScore` (what the user actually gets)?\n *\n * If r < ~0.4, the builder's self-scoring is broken — it's optimizing\n * for something other than real-world success. If r > 0.7, meta_score\n * is a usable proxy and can drive CI gates cheaply.\n *\n * Non-parametric rank correlation (Spearman) is also reported because\n * meta scores are often ordinal-ish.\n */\n\nimport { pearsonR, spearmanR } from '../statistics'\nimport type { ThreeLayerProjectReport } from './three-layer-eval'\n\nexport interface LayerCorrelation {\n n: number\n pearson: number\n spearman: number\n}\n\nexport interface CorrelationReport {\n /** Pairs present in the corpus (layers with ≥ 2 matched data points). */\n metaVsBuild?: LayerCorrelation\n metaVsRuntime?: LayerCorrelation\n buildVsRuntime?: LayerCorrelation\n /** Number of complete projects (all 3 scores present). */\n completeProjects: number\n}\n\nexport function correlateLayers(reports: ThreeLayerProjectReport[]): CorrelationReport {\n const completeProjects = reports.filter((r) => r.complete).length\n return {\n metaVsBuild: pairwise(\n reports,\n (r) => r.metaScore,\n (r) => r.buildScore,\n ),\n metaVsRuntime: pairwise(\n reports,\n (r) => r.metaScore,\n (r) => r.runtimeScore,\n ),\n buildVsRuntime: pairwise(\n reports,\n (r) => r.buildScore,\n (r) => r.runtimeScore,\n ),\n completeProjects,\n }\n}\n\nfunction pairwise(\n reports: ThreeLayerProjectReport[],\n a: (r: ThreeLayerProjectReport) => number | null,\n b: (r: ThreeLayerProjectReport) => number | null,\n): LayerCorrelation | undefined {\n const xs: number[] = []\n const ys: number[] = []\n for (const r of reports) {\n const x = a(r)\n const y = b(r)\n if (x !== null && y !== null && Number.isFinite(x) && Number.isFinite(y)) {\n xs.push(x)\n ys.push(y)\n }\n }\n if (xs.length < 2) return undefined\n return {\n n: xs.length,\n pearson: pearsonR(xs, ys),\n spearman: spearmanR(xs, ys),\n }\n}\n","/**\n * ProjectRegistry — project-level aggregation over the trace corpus.\n *\n * Thin reader over TraceStore that answers the questions a chat-first,\n * resumable UI needs:\n * - listProjects() → project IDs with latest activity\n * - projectTimeline(id) → chats + builds + runtime runs, chronological\n * - projectChats(id) → chat-level summaries (turn count, outcome)\n *\n * All queries are pure reads; no state duplication.\n */\n\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface ProjectSummary {\n projectId: string\n chatCount: number\n buildCount: number\n appRuntimeCount: number\n lastActivityAt: number\n latestChatId?: string\n latestOutcome?: { pass: boolean; score?: number }\n}\n\nexport interface ChatSummary {\n chatId: string\n projectId: string\n builderRunId: string\n startedAt: number\n endedAt?: number\n status: Run['status']\n outcome?: Run['outcome']\n /** Counts of spans emitted during the chat. */\n llmTurns?: number\n toolCalls?: number\n buildRunId?: string\n appRuntimeRunIds: string[]\n}\n\nexport interface ProjectTimelineEntry {\n run: Run\n layerBucket: 'chat' | 'build' | 'runtime' | 'other'\n}\n\nexport class ProjectRegistry {\n constructor(private store: TraceStore) {}\n\n async listProjects(): Promise<ProjectSummary[]> {\n const runs = await this.store.listRuns()\n const byProject = new Map<string, Run[]>()\n for (const r of runs) {\n if (!r.projectId) continue\n const arr = byProject.get(r.projectId) ?? []\n arr.push(r)\n byProject.set(r.projectId, arr)\n }\n const summaries: ProjectSummary[] = []\n for (const [projectId, projectRuns] of byProject) {\n const sorted = projectRuns.slice().sort((a, b) => b.startedAt - a.startedAt)\n const chats = projectRuns.filter((r) => r.layer === 'builder')\n const builds = projectRuns.filter((r) => r.layer === 'app-build')\n const runtimes = projectRuns.filter((r) => r.layer === 'app-runtime')\n const latest = sorted[0]\n if (!latest) continue\n summaries.push({\n projectId,\n chatCount: chats.length,\n buildCount: builds.length,\n appRuntimeCount: runtimes.length,\n lastActivityAt: latest.startedAt,\n latestChatId: chats[0]?.chatId,\n latestOutcome: latest.outcome\n ? { pass: latest.outcome.pass ?? false, score: latest.outcome.score }\n : undefined,\n })\n }\n return summaries.sort((a, b) => b.lastActivityAt - a.lastActivityAt)\n }\n\n async projectTimeline(projectId: string): Promise<ProjectTimelineEntry[]> {\n const runs = await this.store.listRuns({ projectId })\n const ordered = runs.slice().sort((a, b) => a.startedAt - b.startedAt)\n return ordered.map((run) => ({\n run,\n layerBucket:\n run.layer === 'builder'\n ? 'chat'\n : run.layer === 'app-build'\n ? 'build'\n : run.layer === 'app-runtime'\n ? 'runtime'\n : 'other',\n }))\n }\n\n async projectChats(projectId: string): Promise<ChatSummary[]> {\n const builderRuns = (await this.store.listRuns({ projectId, layer: 'builder' })).sort(\n (a, b) => b.startedAt - a.startedAt,\n )\n const childrenFor = async (runId: string) => this.store.listRuns({ parentRunId: runId })\n const out: ChatSummary[] = []\n for (const run of builderRuns) {\n const spans = await this.store.spans({ runId: run.runId })\n const children = await childrenFor(run.runId)\n const build = children.find((c) => c.layer === 'app-build')\n const runtime: string[] = []\n // Runtime runs can be grandchildren (attached to the build) or siblings\n // when shipped skipped.\n if (build) {\n const grands = await childrenFor(build.runId)\n for (const g of grands) if (g.layer === 'app-runtime') runtime.push(g.runId)\n }\n for (const c of children) if (c.layer === 'app-runtime') runtime.push(c.runId)\n out.push({\n chatId: run.chatId ?? run.runId,\n projectId,\n builderRunId: run.runId,\n startedAt: run.startedAt,\n endedAt: run.endedAt,\n status: run.status,\n outcome: run.outcome,\n llmTurns: spans.filter((s) => s.kind === 'llm').length,\n toolCalls: spans.filter((s) => s.kind === 'tool').length,\n buildRunId: build?.runId,\n appRuntimeRunIds: runtime,\n })\n }\n return out\n }\n}\n","/**\n * Three-layer evaluation — the canonical scoring breakdown for\n * builder-of-builders workflows.\n *\n * meta_score: did the builder understand + satisfy user intent?\n * (judge verdict attached to the builder run)\n * build_score: did the generated scaffold build + pass its own tests?\n * (outcome.score on the app-build child run)\n * runtime_score: did the generated agent pass its domain scenarios?\n * (mean outcome.score over app-runtime grandchild runs)\n *\n * Returns a structured report per project. The cross-layer correlation\n * is the highest-leverage signal the framework computes — if\n * meta_score doesn't predict runtime_score, the builder's self-scoring\n * is broken.\n *\n * Scaffold-only mode: when a project has no `app-runtime` runs (e.g. a\n * scaffold-builder eval that grades compose + build without driving a\n * runtime scenario), `kind` is `'scaffold-only'` and `complete` measures\n * meta + build only. Consumers can tell the two apart without having to\n * interpret null-runtime as either \"not yet computed\" or \"N/A for this\n * project shape\".\n */\n\nimport { judgeSpans } from '../trace/query'\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport type ProjectKind = 'full' | 'scaffold-only'\n\nexport interface ThreeLayerProjectReport {\n projectId: string\n /**\n * `'full'` when the project has at least one `app-runtime` run;\n * `'scaffold-only'` when it only has meta + build layers. Lets\n * downstream consumers treat a null runtime score as expected\n * (scaffold-only) vs. missing (full, pipeline broke).\n */\n kind: ProjectKind\n builderRunId?: string\n /** Judge-verdict score on the builder run (0..1 after normalization). */\n metaScore: number | null\n buildRunId?: string\n /** 0..1 from the sandbox harness (testsPassed / testsTotal). */\n buildScore: number | null\n appRuntimeRunIds: string[]\n /** Mean of outcome.score over app-runtime runs, 0..1. Always null in scaffold-only mode. */\n runtimeScore: number | null\n runtimePassRate: number | null\n /**\n * Layer-aware completeness:\n * - `kind='full'`: all three layers scored\n * - `kind='scaffold-only'`: meta + build scored (runtime not applicable)\n */\n complete: boolean\n}\n\nexport async function scoreProject(\n store: TraceStore,\n projectId: string,\n): Promise<ThreeLayerProjectReport> {\n const allRuns = await store.listRuns({ projectId })\n const builder = latestByLayer(allRuns, 'builder')\n const build = latestByLayer(allRuns, 'app-build')\n const runtime = allRuns.filter((r) => r.layer === 'app-runtime')\n\n const metaScore = builder ? await extractMetaScore(store, builder.runId) : null\n const buildScore = build?.outcome?.score ?? null\n const runtimeScores = runtime\n .map((r) => r.outcome?.score)\n .filter((s): s is number => typeof s === 'number')\n const runtimeScore =\n runtimeScores.length > 0\n ? runtimeScores.reduce((a, b) => a + b, 0) / runtimeScores.length\n : null\n const runtimePassed = runtime.filter((r) => r.outcome?.pass === true).length\n const runtimePassRate = runtime.length > 0 ? runtimePassed / runtime.length : null\n\n const kind: ProjectKind = runtime.length === 0 ? 'scaffold-only' : 'full'\n const complete =\n kind === 'scaffold-only'\n ? metaScore !== null && buildScore !== null\n : metaScore !== null && buildScore !== null && runtimeScore !== null\n\n return {\n projectId,\n kind,\n builderRunId: builder?.runId,\n metaScore,\n buildRunId: build?.runId,\n buildScore,\n appRuntimeRunIds: runtime.map((r) => r.runId),\n runtimeScore,\n runtimePassRate,\n complete,\n }\n}\n\n/** Aggregate scoring across every project in a corpus. */\nexport async function scoreAllProjects(store: TraceStore): Promise<ThreeLayerProjectReport[]> {\n const runs = await store.listRuns()\n const projectIds = [...new Set(runs.map((r) => r.projectId).filter((p): p is string => !!p))]\n return Promise.all(projectIds.map((p) => scoreProject(store, p)))\n}\n\nfunction latestByLayer(runs: Run[], layer: Run['layer']): Run | undefined {\n const filtered = runs.filter((r) => r.layer === layer).sort((a, b) => b.startedAt - a.startedAt)\n return filtered[0]\n}\n\nasync function extractMetaScore(store: TraceStore, builderRunId: string): Promise<number | null> {\n const js = await judgeSpans(store, builderRunId)\n const meta = js.find(\n (s) => s.judgeId === 'builder-meta' && s.dimension === 'user_intent_satisfaction',\n )\n if (!meta) return null\n // Normalize score to 0..1. Accept 0-1 natively; 0-10 scale is also common.\n if (meta.score >= 0 && meta.score <= 1) return meta.score\n if (meta.score >= 0 && meta.score <= 10) return meta.score / 10\n return null\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/sandbox-harness.ts","../../src/test-graded-scenario.ts","../../src/builder-eval/builder-session.ts","../../src/builder-eval/correlation.ts","../../src/builder-eval/project-registry.ts","../../src/builder-eval/three-layer-eval.ts"],"sourcesContent":["/**\n * SandboxHarness — executes a scenario in an isolated environment and\n * emits a rich SandboxSpan into the trace.\n *\n * Two built-in drivers:\n * - `SubprocessSandboxDriver` — runs the phase in a local cwd with env\n * vars, through `runBoundedProcess` (deadline, process-group kill,\n * output cap). Fast, no dependencies, fine for unit tests and CI gates.\n * - `DockerSandboxDriver` — lifted from tangle-router's sandbox path;\n * shells out to `docker run`. Stronger isolation, slower startup.\n *\n * Consumers implement `SandboxDriver` for custom backends (Firecracker,\n * Cloudflare sandbox product, etc.). The harness doesn't care which.\n */\n\nimport { runBoundedProcess } from './bounded-process'\n\nimport type { TraceEmitter } from './trace/emitter'\nimport type { SandboxSpan } from './trace/schema'\n\nexport interface HarnessConfig {\n /** Setup command (e.g. \"pnpm install\"). Non-zero exit fails the run. */\n setupCommand?: string\n /** Run command (e.g. \"pnpm build\"). */\n runCommand?: string\n /** Test command (e.g. \"pnpm test --run\"). Drives the test count + pass count. */\n testCommand?: string\n /** Absolute cwd for the subprocess driver. Ignored by docker driver. */\n cwd?: string\n /** Max wall-clock per phase in ms. Default 10 minutes. */\n timeoutMs?: number\n /**\n * Cap on captured stdout+stderr bytes per phase. A runaway process can\n * otherwise grow the in-memory buffer without bound. Once hit, further\n * output is dropped and `outputTruncated` is set. Default 16 MiB.\n */\n maxOutputBytes?: number\n /** Image for the docker driver. */\n image?: string\n /** Extra env vars (validated; shell-escaped). */\n env?: Record<string, string>\n /** Parser for the test output — maps stdout/stderr/exit code → pass count. */\n testParser?: TestOutputParser\n}\n\nexport interface TestOutputParser {\n id: string\n parse(\n stdout: string,\n stderr: string,\n exitCode: number,\n ): { testsTotal: number; testsPassed: number } | undefined\n}\n\nexport interface SandboxResult {\n phase: 'setup' | 'run' | 'test'\n exitCode: number\n stdout: string\n stderr: string\n wallMs: number\n testsTotal?: number\n testsPassed?: number\n /**\n * True when the process was killed because it exceeded `timeoutMs`. A\n * SIGKILLed child can still close with exit code 0; callers MUST treat\n * a timed-out phase as a hard failure regardless of `exitCode`, never\n * as a pass. `undefined`/`false` means the process completed on its own.\n */\n killedByTimeout?: boolean\n /**\n * True when captured stdout/stderr hit `maxOutputBytes` and further\n * output was dropped. The result is still returned (the process was\n * not killed for this), but downstream parsers see truncated text.\n */\n outputTruncated?: boolean\n}\n\nexport interface SandboxDriver {\n id: string\n exec(\n phase: SandboxResult['phase'],\n command: string,\n config: HarnessConfig,\n ): Promise<SandboxResult>\n}\n\n// ── Parsers ──────────────────────────────────────────────────────────\n\n/** Vitest default summary line: \"Tests X passed | Y failed\". */\nexport const vitestTestParser: TestOutputParser = {\n id: 'vitest',\n parse(stdout) {\n const m = stdout.match(/Tests\\s+(\\d+)\\s+(passed|failed)(?:\\s*\\|\\s*(\\d+)\\s+(passed|failed))?/i)\n if (!m) return undefined\n let passed = 0\n let failed = 0\n const a = parseInt(m[1]!, 10)\n const aLabel = m[2]!.toLowerCase()\n if (aLabel === 'passed') passed += a\n else failed += a\n if (m[3] && m[4]) {\n const b = parseInt(m[3], 10)\n if (m[4].toLowerCase() === 'passed') passed += b\n else failed += b\n }\n return { testsTotal: passed + failed, testsPassed: passed }\n },\n}\n\n/** Pytest default: \"collected N items\" + \" X passed, Y failed\". */\nexport const pytestTestParser: TestOutputParser = {\n id: 'pytest',\n parse(stdout) {\n const total = stdout.match(/collected\\s+(\\d+)\\s+items?/i)\n const passed = stdout.match(/(\\d+)\\s+passed/)\n if (!total || !passed) return undefined\n return { testsTotal: parseInt(total[1]!, 10), testsPassed: parseInt(passed[1]!, 10) }\n },\n}\n\n/** Jest: \"Tests: X passed, Y total\" (and optional failed). */\nexport const jestTestParser: TestOutputParser = {\n id: 'jest',\n parse(stdout) {\n const m = stdout.match(/Tests:\\s+(?:(\\d+)\\s+failed[^,]*,\\s*)?(\\d+)\\s+passed,\\s+(\\d+)\\s+total/i)\n if (!m) return undefined\n return { testsTotal: parseInt(m[3]!, 10), testsPassed: parseInt(m[2]!, 10) }\n },\n}\n\n/** Composite parser — tries a list of parsers in order. */\nexport function composeParsers(...parsers: TestOutputParser[]): TestOutputParser {\n return {\n id: parsers.map((p) => p.id).join('|'),\n parse(stdout, stderr, exitCode) {\n for (const p of parsers) {\n const res = p.parse(stdout, stderr, exitCode)\n if (res) return res\n }\n return undefined\n },\n }\n}\n\n// ── Drivers ──────────────────────────────────────────────────────────\n\ninterface SubprocessSandboxDriverOptions {\n /**\n * Default cwd for all `exec` calls. Used when the per-call `HarnessConfig`\n * does not set its own `cwd`. Lets callers bind the driver to a working\n * directory once instead of spreading cwd into every harness config —\n * useful when the harness config is constructed far from the call site\n * (e.g. starter-foundry's promoter passes a static HarnessConfig per\n * family taxonomy but needs a per-run composed-scaffold cwd).\n */\n cwd?: string\n /**\n * Default env merged into every `exec` call's env (per-call `HarnessConfig.env`\n * still wins on key collision). Same ergonomic rationale as `cwd` above.\n */\n env?: Record<string, string>\n}\n\nexport class SubprocessSandboxDriver implements SandboxDriver {\n id = 'subprocess'\n private defaultCwd?: string\n private defaultEnv?: Record<string, string>\n\n constructor(options: SubprocessSandboxDriverOptions = {}) {\n this.defaultCwd = options.cwd\n this.defaultEnv = options.env\n }\n\n async exec(\n phase: SandboxResult['phase'],\n command: string,\n config: HarnessConfig,\n ): Promise<SandboxResult> {\n // Per-call config wins; fall back to constructor defaults. Honoring\n // the constructor `cwd` keeps the subprocess from inheriting Node's\n // cwd when only the constructor arg is supplied.\n const effectiveCwd = config.cwd ?? this.defaultCwd\n // The parent environment is merged here, so the runner is handed the\n // complete environment and passes it through unchanged.\n const effectiveEnv = { ...process.env, ...(this.defaultEnv ?? {}), ...(config.env ?? {}) }\n const result = await runBoundedProcess({\n command,\n shell: true,\n cwd: effectiveCwd,\n env: effectiveEnv,\n envMode: 'replace',\n timeoutMs: config.timeoutMs ?? 10 * 60_000,\n maxOutputBytes: config.maxOutputBytes ?? 16 * 1024 * 1024,\n })\n // A timed-out phase never reaches the parser: the output of a killed\n // process is a fragment, and a fragment that happens to parse would\n // report a pass for a run that never finished.\n const parsed =\n !result.killedByTimeout && phase === 'test' && config.testParser\n ? config.testParser.parse(result.stdout, result.stderr, result.exitCode)\n : undefined\n return {\n phase,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.runnerError ? result.stderr + result.runnerError : result.stderr,\n wallMs: result.wallMs,\n testsTotal: parsed?.testsTotal,\n testsPassed: parsed?.testsPassed,\n killedByTimeout: result.killedByTimeout || undefined,\n outputTruncated: result.outputTruncated || undefined,\n }\n }\n}\n\n\n\n\n\n// ── Harness orchestration ────────────────────────────────────────────\n\nexport interface SandboxHarnessResult {\n passed: boolean\n setup?: SandboxResult\n run?: SandboxResult\n test?: SandboxResult\n totalWallMs: number\n /** Final score — 0 when no tests; otherwise testsPassed/testsTotal. */\n score: number\n}\n\nexport class SandboxHarness {\n private driver: SandboxDriver\n constructor(driver: SandboxDriver = new SubprocessSandboxDriver()) {\n this.driver = driver\n }\n\n async run(config: HarnessConfig, emitter: TraceEmitter): Promise<SandboxHarnessResult> {\n const handle = await emitter.sandbox({\n name: `sandbox(${this.driver.id})`,\n image: config.image,\n command: [config.setupCommand, config.runCommand, config.testCommand]\n .filter(Boolean)\n .join(' && '),\n })\n const result: SandboxHarnessResult = { passed: false, totalWallMs: 0, score: 0 }\n try {\n if (config.setupCommand) {\n result.setup = await this.driver.exec('setup', config.setupCommand, config)\n result.totalWallMs += result.setup.wallMs\n if (result.setup.killedByTimeout || result.setup.exitCode !== 0) {\n const reason = result.setup.killedByTimeout\n ? `setup timed out after ${result.setup.wallMs}ms`\n : `setup failed (exit ${result.setup.exitCode})`\n await handle.fail(reason, {\n exitCode: result.setup.exitCode,\n wallMs: result.totalWallMs,\n } as Partial<SandboxSpan>)\n return result\n }\n }\n if (config.runCommand) {\n result.run = await this.driver.exec('run', config.runCommand, config)\n result.totalWallMs += result.run.wallMs\n if (result.run.killedByTimeout || result.run.exitCode !== 0) {\n const reason = result.run.killedByTimeout\n ? `run timed out after ${result.run.wallMs}ms`\n : `run failed (exit ${result.run.exitCode})`\n await handle.fail(reason, {\n exitCode: result.run.exitCode,\n wallMs: result.totalWallMs,\n } as Partial<SandboxSpan>)\n return result\n }\n }\n if (config.testCommand) {\n result.test = await this.driver.exec('test', config.testCommand, config)\n result.totalWallMs += result.test.wallMs\n // A timed-out test phase is a hard fail regardless of the exit code\n // a SIGKILLed child happens to report — never let it score as a pass.\n const passed = !result.test.killedByTimeout && result.test.exitCode === 0\n result.passed = passed\n if (result.test.testsTotal !== undefined && result.test.testsTotal > 0) {\n result.score = (result.test.testsPassed ?? 0) / result.test.testsTotal\n } else {\n result.score = passed ? 1 : 0\n }\n await handle.end({\n exitCode: result.test.exitCode,\n testsTotal: result.test.testsTotal,\n testsPassed: result.test.testsPassed,\n wallMs: result.totalWallMs,\n status: passed ? 'ok' : 'error',\n } as Partial<SandboxSpan>)\n } else {\n result.passed = true\n result.score = 1\n await handle.end({ wallMs: result.totalWallMs } as Partial<SandboxSpan>)\n }\n } catch (err) {\n await handle.fail(err instanceof Error ? err : String(err))\n throw err\n }\n return result\n }\n}\n","/**\n * TestGradedScenario — a scenario whose score comes from a test suite.\n *\n * This is the SWE-bench pattern generalized. The scenario ships:\n * - fixture data (setup instructions)\n * - a test command the harness runs\n * - optional assertion overrides\n *\n * The runner emits a run, delegates to SandboxHarness, records the\n * outcome, and returns a structured verdict. Consumers bind their own\n * agent execution to this contract.\n */\n\nimport type { HarnessConfig, SandboxDriver, SandboxHarnessResult } from './sandbox-harness'\nimport { SandboxHarness } from './sandbox-harness'\nimport { TraceEmitter } from './trace/emitter'\nimport type { FailureClass, Run } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\nexport interface TestGradedScenario {\n id: string\n description?: string\n harness: HarnessConfig\n /** Optional pass threshold in 0..1 (default 1.0 = all tests must pass). */\n passThreshold?: number\n /** Provenance for dataset tracking. */\n datasetVersion?: string\n /** Free-form tags (difficulty, category, etc.). */\n tags?: Record<string, string>\n}\n\ninterface TestGradedRunOptions {\n variantId?: string\n driver?: SandboxDriver\n /** Metadata recorded on the Run (codeSha, promptSha, modelFingerprint, seed). */\n provenance?: Pick<Run, 'codeSha' | 'promptSha' | 'modelFingerprint' | 'seed' | 'envFingerprint'>\n}\n\nexport interface TestGradedRunResult {\n runId: string\n scenario: TestGradedScenario\n harness: SandboxHarnessResult\n pass: boolean\n score: number\n failureClass?: FailureClass\n}\n\nexport async function runTestGradedScenario(\n scenario: TestGradedScenario,\n store: TraceStore,\n options: TestGradedRunOptions = {},\n): Promise<TestGradedRunResult> {\n const emitter = new TraceEmitter(store)\n await emitter.startRun({\n scenarioId: scenario.id,\n variantId: options.variantId,\n datasetVersion: scenario.datasetVersion,\n tags: scenario.tags,\n ...options.provenance,\n })\n const harness = new SandboxHarness(options.driver)\n const result = await harness.run(scenario.harness, emitter)\n const threshold = scenario.passThreshold ?? 1.0\n const pass = result.passed && result.score >= threshold\n const setupFailed = result.setup !== undefined && result.setup.exitCode !== 0\n const runFailed = result.run !== undefined && result.run.exitCode !== 0\n const testFailed = result.test !== undefined && result.test.exitCode !== 0\n const failureClass: FailureClass | undefined = pass\n ? 'success'\n : setupFailed || runFailed\n ? 'sandbox_failure'\n : testFailed\n ? 'format_drift'\n : 'unknown'\n await emitter.endRun({\n pass,\n score: result.score,\n failureClass,\n notes: pass ? undefined : reasonForFailure(result),\n })\n return {\n runId: emitter.runId,\n scenario,\n harness: result,\n pass,\n score: result.score,\n failureClass,\n }\n}\n\nfunction reasonForFailure(result: SandboxHarnessResult): string {\n if (result.setup && result.setup.exitCode !== 0)\n return `setup failed: exit ${result.setup.exitCode}`\n if (result.run && result.run.exitCode !== 0) return `run failed: exit ${result.run.exitCode}`\n if (result.test) {\n if (result.test.testsTotal !== undefined) {\n return `tests: ${result.test.testsPassed ?? 0}/${result.test.testsTotal}`\n }\n return `test exit ${result.test.exitCode}`\n }\n return 'no test command'\n}\n","/**\n * BuilderSession — ties a builder-of-builders workflow together.\n *\n * Models agent-builder's shape: Project → Chat → Edit → Ship → App →\n * AppAgent. Each layer is a Run (linked via parentRunId). The\n * framework-enforced invariants:\n *\n * - One Project → many Chats; chatId scopes runs within a project.\n * - One Chat = one builder Run with `layer='builder'`.\n * - One Ship = one child Run with `layer='app-build'` + SandboxHarness.\n * - One AppScenario = one grandchild Run with `layer='app-runtime'`.\n *\n * Consumers obtain a BuilderSession, call `startChat`, drive the\n * builder agent (emitting spans), and call `ship` / `runAppScenario`\n * as the workflow progresses. The session reconstructs itself from\n * trace data via `resume(store, projectId)`.\n */\n\nimport { newRecordId } from '../record-id'\nimport type { HarnessConfig, SandboxDriver, SandboxHarnessResult } from '../sandbox-harness'\nimport { SandboxHarness } from '../sandbox-harness'\nimport type { TestGradedRunResult, TestGradedScenario } from '../test-graded-scenario'\nimport { runTestGradedScenario } from '../test-graded-scenario'\nimport { TraceEmitter } from '../trace/emitter'\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface BuilderSessionInit {\n projectId: string\n chatId?: string\n /** Free-form: user's task description, project name, etc. Stored on the builder Run. */\n tags?: Record<string, string>\n}\n\nexport interface ShipOptions {\n harness: HarnessConfig\n driver?: SandboxDriver\n /** scenarioId of this app-build run. Defaults to `${projectId}/build`. */\n scenarioId?: string\n}\n\nexport interface RunAppScenarioOptions {\n scenario: TestGradedScenario\n /** Harness driver override; defaults to the one the session was created with. */\n driver?: SandboxDriver\n}\n\nexport class BuilderSession {\n private store: TraceStore\n private builderEmitter: TraceEmitter\n readonly projectId: string\n readonly chatId: string\n private builderRunId?: string\n private lastBuildRunId?: string\n private defaultDriver?: SandboxDriver\n\n constructor(store: TraceStore, init: BuilderSessionInit, driver?: SandboxDriver) {\n this.store = store\n this.projectId = init.projectId\n this.chatId = init.chatId ?? newRecordId()\n this.defaultDriver = driver\n this.builderEmitter = new TraceEmitter(store)\n }\n\n /** Start the builder (L0) run for this chat. Returns the runId. */\n async startChat(scenarioId = `${this.projectId}/chat`): Promise<string> {\n await this.builderEmitter.startRun({\n scenarioId,\n projectId: this.projectId,\n chatId: this.chatId,\n layer: 'builder',\n })\n this.builderRunId = this.builderEmitter.runId\n return this.builderRunId\n }\n\n /** The emitter for builder-level spans (edits, LLM calls, tool invocations). */\n get emitter(): TraceEmitter {\n if (!this.builderRunId) throw new Error('BuilderSession.emitter: call startChat() first')\n return this.builderEmitter\n }\n\n /**\n * Ship the project's generated app: run the sandbox harness as a child\n * Run (`layer='app-build'`). Returns the build result + runId.\n */\n async ship(options: ShipOptions): Promise<{ runId: string; result: SandboxHarnessResult }> {\n if (!this.builderRunId) throw new Error('BuilderSession.ship: call startChat() first')\n const buildEmitter = new TraceEmitter(this.store)\n await buildEmitter.startRun({\n scenarioId: options.scenarioId ?? `${this.projectId}/build`,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId: this.builderRunId,\n layer: 'app-build',\n })\n const harness = new SandboxHarness(options.driver ?? this.defaultDriver)\n const result = await harness.run(options.harness, buildEmitter)\n await buildEmitter.endRun({\n pass: result.passed,\n score: result.score,\n failureClass: result.passed ? 'success' : 'sandbox_failure',\n })\n this.lastBuildRunId = buildEmitter.runId\n return { runId: buildEmitter.runId, result }\n }\n\n /**\n * Run a domain scenario against the just-built app as a grandchild Run\n * (`layer='app-runtime'`). The `ship` call must precede this so the\n * parent is set correctly; if no build exists yet the session attaches\n * directly to the builder run (useful for prototypes).\n */\n async runAppScenario(options: RunAppScenarioOptions): Promise<TestGradedRunResult> {\n const parentRunId = this.lastBuildRunId ?? this.builderRunId\n if (!parentRunId)\n throw new Error('BuilderSession.runAppScenario: call startChat() + ship() first')\n const { scenario, driver } = options\n const result = await runTestGradedScenario(scenario, this.store, {\n driver: driver ?? this.defaultDriver,\n provenance: { codeSha: undefined, promptSha: undefined, modelFingerprint: undefined },\n })\n // Attach to the parent chain by updating the stored Run in place.\n await this.store.updateRun(result.runId, {\n parentRunId,\n projectId: this.projectId,\n chatId: this.chatId,\n layer: 'app-runtime',\n })\n return result\n }\n\n /** Record an end-of-chat meta score (judge verdict on whether the builder\n * served the user's intent). Accepts a numeric score + optional rationale. */\n async recordMetaScore(score: number, rationale?: string): Promise<void> {\n if (!this.builderRunId)\n throw new Error('BuilderSession.recordMetaScore: call startChat() first')\n await this.builderEmitter.recordJudge({\n judgeId: 'builder-meta',\n targetSpanId: this.builderRunId, // attach to the builder run itself\n dimension: 'user_intent_satisfaction',\n score,\n rationale,\n name: 'builder-meta',\n })\n }\n\n /** Close the builder Run with a final outcome. */\n async endChat(outcome: { pass: boolean; score?: number; notes?: string }): Promise<void> {\n await this.builderEmitter.endRun({\n pass: outcome.pass,\n score: outcome.score,\n notes: outcome.notes,\n })\n }\n\n /**\n * Inline app-runtime run — for cases where the \"scenario\" isn't a\n * SWE-bench-style test suite but a live agent interaction (LLM chat,\n * domain flow). Returns an emitter bound to a fresh Run in the\n * `app-runtime` layer; caller emits spans inside and calls\n * `.endRun()` with the final verdict.\n */\n async startAppRuntime(scenarioId: string): Promise<TraceEmitter> {\n const parentRunId = this.lastBuildRunId ?? this.builderRunId\n if (!parentRunId)\n throw new Error(\n 'BuilderSession.startAppRuntime: call startChat() + (optionally) ship() first',\n )\n const emitter = new TraceEmitter(this.store)\n await emitter.startRun({\n scenarioId,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId,\n layer: 'app-runtime',\n })\n return emitter\n }\n\n /**\n * Lightweight \"ship marker\" — record an app-build Run with a caller-\n * provided verdict. Use when there isn't a sandbox harness to run but\n * you still want to mark the build state at publish time.\n */\n async recordShipMarker(args: {\n pass: boolean\n score: number\n scenarioId?: string\n notes?: string\n }): Promise<string> {\n if (!this.builderRunId)\n throw new Error('BuilderSession.recordShipMarker: call startChat() first')\n const emitter = new TraceEmitter(this.store)\n await emitter.startRun({\n scenarioId: args.scenarioId ?? `${this.projectId}/ship`,\n projectId: this.projectId,\n chatId: this.chatId,\n parentRunId: this.builderRunId,\n layer: 'app-build',\n })\n await emitter.endRun({\n pass: args.pass,\n score: args.score,\n failureClass: args.pass ? 'success' : 'sandbox_failure',\n notes: args.notes,\n })\n this.lastBuildRunId = emitter.runId\n return emitter.runId\n }\n\n get lastBuildRunIdValue(): string | undefined {\n return this.lastBuildRunId\n }\n get builderRunIdValue(): string | undefined {\n return this.builderRunId\n }\n}\n\n/**\n * Reconstruct the most recent BuilderSession state for a given project —\n * returns { builderRunId, lastBuildRunId, chatRuns }. For chat-first UIs\n * this is how a resumed session finds its place in the edit history.\n */\nexport async function resumeBuilderSession(\n store: TraceStore,\n projectId: string,\n): Promise<{\n projectId: string\n chatRuns: Run[]\n lastBuilderRun?: Run\n lastBuildRun?: Run\n lastAppRuntimeRuns: Run[]\n}> {\n const runs = await store.listRuns({ projectId })\n const chatRuns = runs\n .filter((r) => r.layer === 'builder')\n .sort((a, b) => b.startedAt - a.startedAt)\n const buildRuns = runs\n .filter((r) => r.layer === 'app-build')\n .sort((a, b) => b.startedAt - a.startedAt)\n const appRuntimeRuns = runs\n .filter((r) => r.layer === 'app-runtime')\n .sort((a, b) => b.startedAt - a.startedAt)\n return {\n projectId,\n chatRuns,\n lastBuilderRun: chatRuns[0],\n lastBuildRun: buildRuns[0],\n lastAppRuntimeRuns: appRuntimeRuns,\n }\n}\n","/**\n * Meta-eval correlation — the highest-leverage signal in the framework.\n *\n * Given a corpus of three-layer project reports, compute how well each\n * pair of layers correlates. The question we care about most:\n *\n * Does `metaScore` (what the builder thinks it did) predict\n * `runtimeScore` (what the user actually gets)?\n *\n * If r < ~0.4, the builder's self-scoring is broken — it's optimizing\n * for something other than real-world success. If r > 0.7, meta_score\n * is a usable proxy and can drive CI gates cheaply.\n *\n * Non-parametric rank correlation (Spearman) is also reported because\n * meta scores are often ordinal-ish.\n */\n\nimport { pearsonR, spearmanR } from '../statistics'\nimport type { ThreeLayerProjectReport } from './three-layer-eval'\n\nexport interface LayerCorrelation {\n n: number\n pearson: number\n spearman: number\n}\n\nexport interface CorrelationReport {\n /** Pairs present in the corpus (layers with ≥ 2 matched data points). */\n metaVsBuild?: LayerCorrelation\n metaVsRuntime?: LayerCorrelation\n buildVsRuntime?: LayerCorrelation\n /** Number of complete projects (all 3 scores present). */\n completeProjects: number\n}\n\nexport function correlateLayers(reports: ThreeLayerProjectReport[]): CorrelationReport {\n const completeProjects = reports.filter((r) => r.complete).length\n return {\n metaVsBuild: pairwise(\n reports,\n (r) => r.metaScore,\n (r) => r.buildScore,\n ),\n metaVsRuntime: pairwise(\n reports,\n (r) => r.metaScore,\n (r) => r.runtimeScore,\n ),\n buildVsRuntime: pairwise(\n reports,\n (r) => r.buildScore,\n (r) => r.runtimeScore,\n ),\n completeProjects,\n }\n}\n\nfunction pairwise(\n reports: ThreeLayerProjectReport[],\n a: (r: ThreeLayerProjectReport) => number | null,\n b: (r: ThreeLayerProjectReport) => number | null,\n): LayerCorrelation | undefined {\n const xs: number[] = []\n const ys: number[] = []\n for (const r of reports) {\n const x = a(r)\n const y = b(r)\n if (x !== null && y !== null && Number.isFinite(x) && Number.isFinite(y)) {\n xs.push(x)\n ys.push(y)\n }\n }\n if (xs.length < 2) return undefined\n return {\n n: xs.length,\n pearson: pearsonR(xs, ys),\n spearman: spearmanR(xs, ys),\n }\n}\n","/**\n * ProjectRegistry — project-level aggregation over the trace corpus.\n *\n * Thin reader over TraceStore that answers the questions a chat-first,\n * resumable UI needs:\n * - listProjects() → project IDs with latest activity\n * - projectTimeline(id) → chats + builds + runtime runs, chronological\n * - projectChats(id) → chat-level summaries (turn count, outcome)\n *\n * All queries are pure reads; no state duplication.\n */\n\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface ProjectSummary {\n projectId: string\n chatCount: number\n buildCount: number\n appRuntimeCount: number\n lastActivityAt: number\n latestChatId?: string\n latestOutcome?: { pass: boolean; score?: number }\n}\n\nexport interface ChatSummary {\n chatId: string\n projectId: string\n builderRunId: string\n startedAt: number\n endedAt?: number\n status: Run['status']\n outcome?: Run['outcome']\n /** Counts of spans emitted during the chat. */\n llmTurns?: number\n toolCalls?: number\n buildRunId?: string\n appRuntimeRunIds: string[]\n}\n\nexport interface ProjectTimelineEntry {\n run: Run\n layerBucket: 'chat' | 'build' | 'runtime' | 'other'\n}\n\nexport class ProjectRegistry {\n constructor(private store: TraceStore) {}\n\n async listProjects(): Promise<ProjectSummary[]> {\n const runs = await this.store.listRuns()\n const byProject = new Map<string, Run[]>()\n for (const r of runs) {\n if (!r.projectId) continue\n const arr = byProject.get(r.projectId) ?? []\n arr.push(r)\n byProject.set(r.projectId, arr)\n }\n const summaries: ProjectSummary[] = []\n for (const [projectId, projectRuns] of byProject) {\n const sorted = projectRuns.slice().sort((a, b) => b.startedAt - a.startedAt)\n const chats = projectRuns.filter((r) => r.layer === 'builder')\n const builds = projectRuns.filter((r) => r.layer === 'app-build')\n const runtimes = projectRuns.filter((r) => r.layer === 'app-runtime')\n const latest = sorted[0]\n if (!latest) continue\n summaries.push({\n projectId,\n chatCount: chats.length,\n buildCount: builds.length,\n appRuntimeCount: runtimes.length,\n lastActivityAt: latest.startedAt,\n latestChatId: chats[0]?.chatId,\n latestOutcome: latest.outcome\n ? { pass: latest.outcome.pass ?? false, score: latest.outcome.score }\n : undefined,\n })\n }\n return summaries.sort((a, b) => b.lastActivityAt - a.lastActivityAt)\n }\n\n async projectTimeline(projectId: string): Promise<ProjectTimelineEntry[]> {\n const runs = await this.store.listRuns({ projectId })\n const ordered = runs.slice().sort((a, b) => a.startedAt - b.startedAt)\n return ordered.map((run) => ({\n run,\n layerBucket:\n run.layer === 'builder'\n ? 'chat'\n : run.layer === 'app-build'\n ? 'build'\n : run.layer === 'app-runtime'\n ? 'runtime'\n : 'other',\n }))\n }\n\n async projectChats(projectId: string): Promise<ChatSummary[]> {\n const builderRuns = (await this.store.listRuns({ projectId, layer: 'builder' })).sort(\n (a, b) => b.startedAt - a.startedAt,\n )\n const childrenFor = async (runId: string) => this.store.listRuns({ parentRunId: runId })\n const out: ChatSummary[] = []\n for (const run of builderRuns) {\n const spans = await this.store.spans({ runId: run.runId })\n const children = await childrenFor(run.runId)\n const build = children.find((c) => c.layer === 'app-build')\n const runtime: string[] = []\n // Runtime runs can be grandchildren (attached to the build) or siblings\n // when shipped skipped.\n if (build) {\n const grands = await childrenFor(build.runId)\n for (const g of grands) if (g.layer === 'app-runtime') runtime.push(g.runId)\n }\n for (const c of children) if (c.layer === 'app-runtime') runtime.push(c.runId)\n out.push({\n chatId: run.chatId ?? run.runId,\n projectId,\n builderRunId: run.runId,\n startedAt: run.startedAt,\n endedAt: run.endedAt,\n status: run.status,\n outcome: run.outcome,\n llmTurns: spans.filter((s) => s.kind === 'llm').length,\n toolCalls: spans.filter((s) => s.kind === 'tool').length,\n buildRunId: build?.runId,\n appRuntimeRunIds: runtime,\n })\n }\n return out\n }\n}\n","/**\n * Three-layer evaluation — the canonical scoring breakdown for\n * builder-of-builders workflows.\n *\n * meta_score: did the builder understand + satisfy user intent?\n * (judge verdict attached to the builder run)\n * build_score: did the generated scaffold build + pass its own tests?\n * (outcome.score on the app-build child run)\n * runtime_score: did the generated agent pass its domain scenarios?\n * (mean outcome.score over app-runtime grandchild runs)\n *\n * Returns a structured report per project. The cross-layer correlation\n * is the highest-leverage signal the framework computes — if\n * meta_score doesn't predict runtime_score, the builder's self-scoring\n * is broken.\n *\n * Scaffold-only mode: when a project has no `app-runtime` runs (e.g. a\n * scaffold-builder eval that grades compose + build without driving a\n * runtime scenario), `kind` is `'scaffold-only'` and `complete` measures\n * meta + build only. Consumers can tell the two apart without having to\n * interpret null-runtime as either \"not yet computed\" or \"N/A for this\n * project shape\".\n */\n\nimport { judgeSpans } from '../trace/query'\nimport type { Run } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport type ProjectKind = 'full' | 'scaffold-only'\n\nexport interface ThreeLayerProjectReport {\n projectId: string\n /**\n * `'full'` when the project has at least one `app-runtime` run;\n * `'scaffold-only'` when it only has meta + build layers. Lets\n * downstream consumers treat a null runtime score as expected\n * (scaffold-only) vs. missing (full, pipeline broke).\n */\n kind: ProjectKind\n builderRunId?: string\n /** Judge-verdict score on the builder run (0..1 after normalization). */\n metaScore: number | null\n buildRunId?: string\n /** 0..1 from the sandbox harness (testsPassed / testsTotal). */\n buildScore: number | null\n appRuntimeRunIds: string[]\n /** Mean of outcome.score over app-runtime runs, 0..1. Always null in scaffold-only mode. */\n runtimeScore: number | null\n runtimePassRate: number | null\n /**\n * Layer-aware completeness:\n * - `kind='full'`: all three layers scored\n * - `kind='scaffold-only'`: meta + build scored (runtime not applicable)\n */\n complete: boolean\n}\n\nexport async function scoreProject(\n store: TraceStore,\n projectId: string,\n): Promise<ThreeLayerProjectReport> {\n const allRuns = await store.listRuns({ projectId })\n const builder = latestByLayer(allRuns, 'builder')\n const build = latestByLayer(allRuns, 'app-build')\n const runtime = allRuns.filter((r) => r.layer === 'app-runtime')\n\n const metaScore = builder ? await extractMetaScore(store, builder.runId) : null\n const buildScore = build?.outcome?.score ?? null\n const runtimeScores = runtime\n .map((r) => r.outcome?.score)\n .filter((s): s is number => typeof s === 'number')\n const runtimeScore =\n runtimeScores.length > 0\n ? runtimeScores.reduce((a, b) => a + b, 0) / runtimeScores.length\n : null\n const runtimePassed = runtime.filter((r) => r.outcome?.pass === true).length\n const runtimePassRate = runtime.length > 0 ? runtimePassed / runtime.length : null\n\n const kind: ProjectKind = runtime.length === 0 ? 'scaffold-only' : 'full'\n const complete =\n kind === 'scaffold-only'\n ? metaScore !== null && buildScore !== null\n : metaScore !== null && buildScore !== null && runtimeScore !== null\n\n return {\n projectId,\n kind,\n builderRunId: builder?.runId,\n metaScore,\n buildRunId: build?.runId,\n buildScore,\n appRuntimeRunIds: runtime.map((r) => r.runId),\n runtimeScore,\n runtimePassRate,\n complete,\n }\n}\n\n/** Aggregate scoring across every project in a corpus. */\nexport async function scoreAllProjects(store: TraceStore): Promise<ThreeLayerProjectReport[]> {\n const runs = await store.listRuns()\n const projectIds = [...new Set(runs.map((r) => r.projectId).filter((p): p is string => !!p))]\n return Promise.all(projectIds.map((p) => scoreProject(store, p)))\n}\n\nfunction latestByLayer(runs: Run[], layer: Run['layer']): Run | undefined {\n const filtered = runs.filter((r) => r.layer === layer).sort((a, b) => b.startedAt - a.startedAt)\n return filtered[0]\n}\n\nasync function extractMetaScore(store: TraceStore, builderRunId: string): Promise<number | null> {\n const js = await judgeSpans(store, builderRunId)\n const meta = js.find(\n (s) => s.judgeId === 'builder-meta' && s.dimension === 'user_intent_satisfaction',\n )\n if (!meta) return null\n // Normalize score to 0..1. Accept 0-1 natively; 0-10 scale is also common.\n if (meta.score >= 0 && meta.score <= 1) return meta.score\n if (meta.score >= 0 && meta.score <= 10) return meta.score / 10\n return null\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { s as runMetricExtractor } from "./query-B_RZ36an.js";
2
- import { i as reduceOutcomeMetric, t as assertUniqueObservationIds } from "./outcome-observations-FLmRpgYa.js";
3
- //#region src/meta-eval/calibration.ts
1
+ import { s as runMetricExtractor } from "./query-CGXzO9d4.js";
2
+ import { i as reduceOutcomeMetric, t as assertUniqueObservationIds } from "./outcome-observations-D4snOtUb.js";
3
+ // src/meta-eval/calibration.ts
4
4
  /**
5
5
  * Calibration curve — binned "if eval says X, what does reality show?"
6
6
  *
@@ -191,7 +191,6 @@ function validateCalibrationRequest(evalMetric, outcomeMetric, options) {
191
191
  if (options.binning !== void 0 && !["equal-width", "equal-frequency"].includes(options.binning)) throw new Error("calibration binning must be equal-width or equal-frequency");
192
192
  if (options.range !== void 0 && (!Number.isFinite(options.range.lo) || !Number.isFinite(options.range.hi) || !Number.isFinite(options.range.hi - options.range.lo) || options.range.hi < options.range.lo)) throw new Error("calibration range must have finite ordered bounds");
193
193
  }
194
- //#endregion
195
194
  export { rankedProbabilityScore as a, multiclassBrierScore as i, calibrationCurve as n, calibrationFromPairs as r, brierScore as t };
196
195
 
197
- //# sourceMappingURL=calibration-CTwxpJ-t.js.map
196
+ //# sourceMappingURL=calibration-6usfVYYo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"calibration-CTwxpJ-t.js","names":[],"sources":["../src/meta-eval/calibration.ts"],"sourcesContent":["/**\n * Calibration curve — binned \"if eval says X, what does reality show?\"\n *\n * Companion to correlationStudy. Raw correlation is a single number;\n * the calibration curve shows *where* the eval is well-calibrated vs\n * overconfident / underconfident. Buckets the eval metric, computes\n * mean outcome per bucket, reports expected-calibration-error (ECE).\n */\n\nimport { runMetricExtractor } from '../trace/query'\nimport type { TraceStore } from '../trace/store'\nimport type { EvalMetricSpec } from './correlation-study'\nimport { assertUniqueObservationIds, reduceOutcomeMetric } from './outcome-observations'\nimport type { DeploymentOutcome, OutcomeStore } from './outcome-store'\n\nexport interface CalibrationBin {\n lower: number\n upper: number\n n: number\n evalMean: number\n outcomeMean: number\n /** |outcomeMean − evalMean|; contributes to ECE weighted by n/total. */\n gap: number\n}\n\nexport interface CalibrationReport {\n evalMetric: string\n outcomeMetric: string\n n: number\n bins: CalibrationBin[]\n /** Expected Calibration Error — Σ (n_i/N) × |outcomeMean_i − evalMean_i|. */\n ece: number\n /** Largest observed difference between a bin's mean score and mean outcome. */\n maxGap: number\n}\n\nexport interface CalibrationOptions {\n /** Positive integer; empty bins are omitted. Default 10. */\n bins?: number\n /** Equal-width (fixed bin edges) or equal-frequency (quantile bins). */\n binning?: 'equal-width' | 'equal-frequency'\n /** Clip eval values to [lo, hi] before binning. */\n range?: { lo: number; hi: number }\n}\n\nexport interface CalibrationPair {\n evalScore: number\n outcome: number\n}\n\nexport async function calibrationCurve(\n traceStore: TraceStore,\n outcomeStore: OutcomeStore,\n evalMetric: EvalMetricSpec,\n outcomeMetric: string,\n options: CalibrationOptions = {},\n): Promise<CalibrationReport | null> {\n const settings = {\n ...options,\n range: options.range === undefined ? undefined : { ...options.range },\n }\n validateCalibrationRequest(evalMetric.id, outcomeMetric, settings)\n const extract = evalMetric.extract ?? runMetricExtractor(evalMetric.id)\n const metricId = evalMetric.id\n const runs = await traceStore.listRuns()\n assertUniqueObservationIds(\n runs.map((run) => run.runId),\n 'runId',\n )\n const outcomes = await outcomeStore.list()\n const byRun = new Map<string, DeploymentOutcome[]>()\n for (const o of outcomes) {\n const arr = byRun.get(o.runId) ?? []\n arr.push(o)\n byRun.set(o.runId, arr)\n }\n\n const pairs: Array<{ x: number; y: number }> = []\n for (const run of runs) {\n const os = byRun.get(run.runId)\n if (!os?.length) continue\n const x = await extract(run, traceStore)\n if (x === null || !Number.isFinite(x)) continue\n const y = reduceOutcomeMetric(os, outcomeMetric, 'latest')\n if (y === null) continue\n pairs.push({ x, y })\n }\n if (pairs.length < 2) return null\n\n return calibrationFromPairs(\n pairs.map((p) => ({ evalScore: p.x, outcome: p.y })),\n metricId,\n outcomeMetric,\n settings,\n )\n}\n\n/** Measure already joined observations without constructing trace and outcome stores. */\nexport function calibrationFromPairs(\n inputPairs: readonly CalibrationPair[],\n evalMetric: string,\n outcomeMetric: string,\n options: CalibrationOptions = {},\n): CalibrationReport | null {\n validateCalibrationRequest(evalMetric, outcomeMetric, options)\n for (const [index, pair] of inputPairs.entries()) {\n if (\n pair === null ||\n typeof pair !== 'object' ||\n !Number.isFinite(pair.evalScore) ||\n !Number.isFinite(pair.outcome)\n ) {\n throw new Error(`calibration pair ${index} must contain finite evalScore and outcome values`)\n }\n }\n const pairs = inputPairs\n if (pairs.length < 2) return null\n\n const numBins = options.bins ?? 10\n const binning = options.binning ?? 'equal-width'\n const xs = pairs.map((p) => p.evalScore)\n const lo = options.range?.lo ?? Math.min(...xs)\n const hi = options.range?.hi ?? Math.max(...xs)\n const span = hi - lo\n if (!Number.isFinite(span)) throw new Error('calibration range span must be finite')\n const clipped = pairs.map((pair) => ({\n ...pair,\n evalScore: Math.min(hi, Math.max(lo, pair.evalScore)),\n }))\n\n const bins: CalibrationBin[] = []\n if (span === 0 || clipped.every((pair) => pair.evalScore === clipped[0]!.evalScore)) {\n bins.push(toBin(clipped))\n } else if (binning === 'equal-frequency') {\n const sorted = [...clipped].sort((a, b) => a.evalScore - b.evalScore)\n const count = Math.min(numBins, sorted.length)\n for (let i = 0; i < count; i++) {\n const start = Math.floor((i * sorted.length) / count)\n const end = Math.floor(((i + 1) * sorted.length) / count)\n bins.push(toBin(sorted.slice(start, end)))\n }\n } else {\n const groups = new Map<number, CalibrationPair[]>()\n for (const pair of clipped) {\n const index = Math.min(numBins - 1, Math.floor(((pair.evalScore - lo) / span) * numBins))\n const group = groups.get(index) ?? []\n group.push(pair)\n groups.set(index, group)\n }\n for (const [index, chunk] of [...groups].sort(([a], [b]) => a - b)) {\n bins.push(toBin(chunk, lo + span * (index / numBins), lo + span * ((index + 1) / numBins)))\n }\n }\n\n const total = bins.reduce((a, b) => a + b.n, 0)\n const ece = bins.reduce((a, b) => a + (b.n / total) * b.gap, 0)\n const maxGap = bins.reduce((a, b) => Math.max(a, b.gap), 0)\n\n return { evalMetric, outcomeMetric, n: pairs.length, bins, ece, maxGap }\n}\n\n/**\n * Mean squared error of probability forecasts against binary outcomes, Σ(p − y)²/N; always\n * forecasting 0.5 scores 0.25. For the reliability table and ECE use `calibrationFromPairs`\n * with `range: { lo: 0, hi: 1 }` (`binning: 'equal-frequency'` gives equal-mass bins).\n */\nexport function brierScore(pairs: readonly CalibrationPair[]): number {\n if (!pairs.length) throw new Error('Brier score requires at least one pair')\n let total = 0\n for (const [index, pair] of pairs.entries()) {\n if (\n pair === null ||\n typeof pair !== 'object' ||\n !(pair.evalScore >= 0 && pair.evalScore <= 1) ||\n (pair.outcome !== 0 && pair.outcome !== 1)\n ) {\n throw new Error(`Brier pair ${index} needs a probability in [0, 1] and an outcome of 0 or 1`)\n }\n total += (pair.evalScore - pair.outcome) ** 2\n }\n return total / pairs.length\n}\n\n/** One categorical forecast: a distribution over named outcomes and the outcome that occurred. */\nexport interface CategoricalForecast {\n /** Probability per outcome name. Must sum to 1 within 1e-6 and include `outcome`. */\n probabilities: Readonly<Record<string, number>>\n outcome: string\n}\n\n/**\n * Multiclass Brier score in its sum form, mean over forecasts of Σₖ(pₖ − yₖ)², range [0, 2].\n * With two outcomes it is twice the binary `brierScore`. A uniform forecast over K outcomes\n * scores 1 − 1/K. The distribution is not renormalized here: repair provider rounding before\n * scoring (`normalizeSystemOneResult` in `/systemone/protocol`), so a defective answer stays\n * visible instead of being scored as if it were valid.\n */\nexport function multiclassBrierScore(forecasts: readonly CategoricalForecast[]): number {\n if (!forecasts.length) throw new Error('multiclass Brier score requires at least one forecast')\n let total = 0\n for (const [index, forecast] of forecasts.entries()) {\n const entries = categoricalEntries(forecast, index, 'multiclass Brier')\n for (const [name, probability] of entries) {\n total += (probability - (name === forecast.outcome ? 1 : 0)) ** 2\n }\n }\n return total / forecasts.length\n}\n\n/** One ordinal forecast: probabilities in level order, lowest level first. */\nexport interface OrdinalForecast {\n probabilities: readonly number[]\n /** Index into `probabilities` of the level that occurred. */\n outcome: number\n}\n\n/**\n * Ranked probability score, mean over forecasts of Σₖ₌₁ᴷ⁻¹(Fₖ − Oₖ)² / (K − 1), where F and O are\n * the cumulative forecast and observation, range [0, 1]. Unlike multiclass Brier it charges\n * less for mass on a level next to the outcome than for mass far from it, which is the right\n * penalty for score questions. With two levels it equals the binary Brier score.\n */\nexport function rankedProbabilityScore(forecasts: readonly OrdinalForecast[]): number {\n if (!forecasts.length) throw new Error('ranked probability score requires at least one forecast')\n let total = 0\n for (const [index, forecast] of forecasts.entries()) {\n const probabilities = forecast?.probabilities\n if (!Array.isArray(probabilities) || probabilities.length < 2) {\n throw new Error(`RPS forecast ${index} needs at least two level probabilities`)\n }\n assertDistribution(probabilities, `RPS forecast ${index}`)\n if (\n !Number.isInteger(forecast.outcome) ||\n forecast.outcome < 0 ||\n forecast.outcome >= probabilities.length\n ) {\n throw new Error(\n `RPS forecast ${index} outcome must index one of its ${probabilities.length} levels`,\n )\n }\n let cumulative = 0\n let sum = 0\n for (let level = 0; level < probabilities.length - 1; level++) {\n cumulative += probabilities[level]!\n sum += (cumulative - (level >= forecast.outcome ? 1 : 0)) ** 2\n }\n total += sum / (probabilities.length - 1)\n }\n return total / forecasts.length\n}\n\nfunction categoricalEntries(\n forecast: CategoricalForecast,\n index: number,\n label: string,\n): [string, number][] {\n if (forecast === null || typeof forecast !== 'object' || typeof forecast.outcome !== 'string') {\n throw new Error(`${label} forecast ${index} needs probabilities and a string outcome`)\n }\n const probabilities = forecast.probabilities\n if (probabilities === null || typeof probabilities !== 'object' || Array.isArray(probabilities)) {\n throw new Error(`${label} forecast ${index} probabilities must be an object keyed by outcome`)\n }\n const entries = Object.entries(probabilities)\n if (entries.length < 2) throw new Error(`${label} forecast ${index} needs at least two outcomes`)\n if (!entries.some(([name]) => name === forecast.outcome)) {\n throw new Error(\n `${label} forecast ${index} has no probability for outcome ${JSON.stringify(forecast.outcome)}`,\n )\n }\n assertDistribution(\n entries.map(([, probability]) => probability),\n `${label} forecast ${index}`,\n )\n return entries\n}\n\nfunction assertDistribution(probabilities: readonly number[], label: string): void {\n let sum = 0\n for (const probability of probabilities) {\n if (!(probability >= 0 && probability <= 1)) {\n throw new Error(`${label} has a probability outside [0, 1]: ${probability}`)\n }\n sum += probability\n }\n if (Math.abs(sum - 1) > 1e-6) throw new Error(`${label} probabilities sum to ${sum}, not 1`)\n}\n\nfunction toBin(chunk: CalibrationPair[], lower?: number, upper?: number): CalibrationBin {\n const xs = chunk.map((c) => c.evalScore)\n const ys = chunk.map((c) => c.outcome)\n const evalMean = mean(xs)\n const outcomeMean = mean(ys)\n return {\n lower: lower ?? Math.min(...xs),\n upper: upper ?? Math.max(...xs),\n n: chunk.length,\n evalMean,\n outcomeMean,\n gap: Math.abs(outcomeMean - evalMean),\n }\n}\n\nfunction mean(xs: number[]): number {\n return xs.reduce((sum, value) => sum + value / xs.length, 0)\n}\n\nfunction validateCalibrationRequest(\n evalMetric: string,\n outcomeMetric: string,\n options: CalibrationOptions,\n): void {\n assertUniqueObservationIds([evalMetric], 'eval metric')\n assertUniqueObservationIds([outcomeMetric], 'outcome metric')\n if (evalMetric.trim() !== evalMetric || outcomeMetric.trim() !== outcomeMetric) {\n throw new Error('calibration metric identities must not have surrounding whitespace')\n }\n if (options.bins !== undefined && (!Number.isSafeInteger(options.bins) || options.bins < 1)) {\n throw new Error('calibration bins must be a positive safe integer')\n }\n if (\n options.binning !== undefined &&\n !['equal-width', 'equal-frequency'].includes(options.binning)\n ) {\n throw new Error('calibration binning must be equal-width or equal-frequency')\n }\n if (\n options.range !== undefined &&\n (!Number.isFinite(options.range.lo) ||\n !Number.isFinite(options.range.hi) ||\n !Number.isFinite(options.range.hi - options.range.lo) ||\n options.range.hi < options.range.lo)\n ) {\n throw new Error('calibration range must have finite ordered bounds')\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"calibration-6usfVYYo.js","names":[],"sources":["../src/meta-eval/calibration.ts"],"sourcesContent":["/**\n * Calibration curve — binned \"if eval says X, what does reality show?\"\n *\n * Companion to correlationStudy. Raw correlation is a single number;\n * the calibration curve shows *where* the eval is well-calibrated vs\n * overconfident / underconfident. Buckets the eval metric, computes\n * mean outcome per bucket, reports expected-calibration-error (ECE).\n */\n\nimport { runMetricExtractor } from '../trace/query'\nimport type { TraceStore } from '../trace/store'\nimport type { EvalMetricSpec } from './correlation-study'\nimport { assertUniqueObservationIds, reduceOutcomeMetric } from './outcome-observations'\nimport type { DeploymentOutcome, OutcomeStore } from './outcome-store'\n\nexport interface CalibrationBin {\n lower: number\n upper: number\n n: number\n evalMean: number\n outcomeMean: number\n /** |outcomeMean − evalMean|; contributes to ECE weighted by n/total. */\n gap: number\n}\n\nexport interface CalibrationReport {\n evalMetric: string\n outcomeMetric: string\n n: number\n bins: CalibrationBin[]\n /** Expected Calibration Error — Σ (n_i/N) × |outcomeMean_i − evalMean_i|. */\n ece: number\n /** Largest observed difference between a bin's mean score and mean outcome. */\n maxGap: number\n}\n\nexport interface CalibrationOptions {\n /** Positive integer; empty bins are omitted. Default 10. */\n bins?: number\n /** Equal-width (fixed bin edges) or equal-frequency (quantile bins). */\n binning?: 'equal-width' | 'equal-frequency'\n /** Clip eval values to [lo, hi] before binning. */\n range?: { lo: number; hi: number }\n}\n\nexport interface CalibrationPair {\n evalScore: number\n outcome: number\n}\n\nexport async function calibrationCurve(\n traceStore: TraceStore,\n outcomeStore: OutcomeStore,\n evalMetric: EvalMetricSpec,\n outcomeMetric: string,\n options: CalibrationOptions = {},\n): Promise<CalibrationReport | null> {\n const settings = {\n ...options,\n range: options.range === undefined ? undefined : { ...options.range },\n }\n validateCalibrationRequest(evalMetric.id, outcomeMetric, settings)\n const extract = evalMetric.extract ?? runMetricExtractor(evalMetric.id)\n const metricId = evalMetric.id\n const runs = await traceStore.listRuns()\n assertUniqueObservationIds(\n runs.map((run) => run.runId),\n 'runId',\n )\n const outcomes = await outcomeStore.list()\n const byRun = new Map<string, DeploymentOutcome[]>()\n for (const o of outcomes) {\n const arr = byRun.get(o.runId) ?? []\n arr.push(o)\n byRun.set(o.runId, arr)\n }\n\n const pairs: Array<{ x: number; y: number }> = []\n for (const run of runs) {\n const os = byRun.get(run.runId)\n if (!os?.length) continue\n const x = await extract(run, traceStore)\n if (x === null || !Number.isFinite(x)) continue\n const y = reduceOutcomeMetric(os, outcomeMetric, 'latest')\n if (y === null) continue\n pairs.push({ x, y })\n }\n if (pairs.length < 2) return null\n\n return calibrationFromPairs(\n pairs.map((p) => ({ evalScore: p.x, outcome: p.y })),\n metricId,\n outcomeMetric,\n settings,\n )\n}\n\n/** Measure already joined observations without constructing trace and outcome stores. */\nexport function calibrationFromPairs(\n inputPairs: readonly CalibrationPair[],\n evalMetric: string,\n outcomeMetric: string,\n options: CalibrationOptions = {},\n): CalibrationReport | null {\n validateCalibrationRequest(evalMetric, outcomeMetric, options)\n for (const [index, pair] of inputPairs.entries()) {\n if (\n pair === null ||\n typeof pair !== 'object' ||\n !Number.isFinite(pair.evalScore) ||\n !Number.isFinite(pair.outcome)\n ) {\n throw new Error(`calibration pair ${index} must contain finite evalScore and outcome values`)\n }\n }\n const pairs = inputPairs\n if (pairs.length < 2) return null\n\n const numBins = options.bins ?? 10\n const binning = options.binning ?? 'equal-width'\n const xs = pairs.map((p) => p.evalScore)\n const lo = options.range?.lo ?? Math.min(...xs)\n const hi = options.range?.hi ?? Math.max(...xs)\n const span = hi - lo\n if (!Number.isFinite(span)) throw new Error('calibration range span must be finite')\n const clipped = pairs.map((pair) => ({\n ...pair,\n evalScore: Math.min(hi, Math.max(lo, pair.evalScore)),\n }))\n\n const bins: CalibrationBin[] = []\n if (span === 0 || clipped.every((pair) => pair.evalScore === clipped[0]!.evalScore)) {\n bins.push(toBin(clipped))\n } else if (binning === 'equal-frequency') {\n const sorted = [...clipped].sort((a, b) => a.evalScore - b.evalScore)\n const count = Math.min(numBins, sorted.length)\n for (let i = 0; i < count; i++) {\n const start = Math.floor((i * sorted.length) / count)\n const end = Math.floor(((i + 1) * sorted.length) / count)\n bins.push(toBin(sorted.slice(start, end)))\n }\n } else {\n const groups = new Map<number, CalibrationPair[]>()\n for (const pair of clipped) {\n const index = Math.min(numBins - 1, Math.floor(((pair.evalScore - lo) / span) * numBins))\n const group = groups.get(index) ?? []\n group.push(pair)\n groups.set(index, group)\n }\n for (const [index, chunk] of [...groups].sort(([a], [b]) => a - b)) {\n bins.push(toBin(chunk, lo + span * (index / numBins), lo + span * ((index + 1) / numBins)))\n }\n }\n\n const total = bins.reduce((a, b) => a + b.n, 0)\n const ece = bins.reduce((a, b) => a + (b.n / total) * b.gap, 0)\n const maxGap = bins.reduce((a, b) => Math.max(a, b.gap), 0)\n\n return { evalMetric, outcomeMetric, n: pairs.length, bins, ece, maxGap }\n}\n\n/**\n * Mean squared error of probability forecasts against binary outcomes, Σ(p − y)²/N; always\n * forecasting 0.5 scores 0.25. For the reliability table and ECE use `calibrationFromPairs`\n * with `range: { lo: 0, hi: 1 }` (`binning: 'equal-frequency'` gives equal-mass bins).\n */\nexport function brierScore(pairs: readonly CalibrationPair[]): number {\n if (!pairs.length) throw new Error('Brier score requires at least one pair')\n let total = 0\n for (const [index, pair] of pairs.entries()) {\n if (\n pair === null ||\n typeof pair !== 'object' ||\n !(pair.evalScore >= 0 && pair.evalScore <= 1) ||\n (pair.outcome !== 0 && pair.outcome !== 1)\n ) {\n throw new Error(`Brier pair ${index} needs a probability in [0, 1] and an outcome of 0 or 1`)\n }\n total += (pair.evalScore - pair.outcome) ** 2\n }\n return total / pairs.length\n}\n\n/** One categorical forecast: a distribution over named outcomes and the outcome that occurred. */\nexport interface CategoricalForecast {\n /** Probability per outcome name. Must sum to 1 within 1e-6 and include `outcome`. */\n probabilities: Readonly<Record<string, number>>\n outcome: string\n}\n\n/**\n * Multiclass Brier score in its sum form, mean over forecasts of Σₖ(pₖ − yₖ)², range [0, 2].\n * With two outcomes it is twice the binary `brierScore`. A uniform forecast over K outcomes\n * scores 1 − 1/K. The distribution is not renormalized here: repair provider rounding before\n * scoring (`normalizeSystemOneResult` in `/systemone/protocol`), so a defective answer stays\n * visible instead of being scored as if it were valid.\n */\nexport function multiclassBrierScore(forecasts: readonly CategoricalForecast[]): number {\n if (!forecasts.length) throw new Error('multiclass Brier score requires at least one forecast')\n let total = 0\n for (const [index, forecast] of forecasts.entries()) {\n const entries = categoricalEntries(forecast, index, 'multiclass Brier')\n for (const [name, probability] of entries) {\n total += (probability - (name === forecast.outcome ? 1 : 0)) ** 2\n }\n }\n return total / forecasts.length\n}\n\n/** One ordinal forecast: probabilities in level order, lowest level first. */\nexport interface OrdinalForecast {\n probabilities: readonly number[]\n /** Index into `probabilities` of the level that occurred. */\n outcome: number\n}\n\n/**\n * Ranked probability score, mean over forecasts of Σₖ₌₁ᴷ⁻¹(Fₖ − Oₖ)² / (K − 1), where F and O are\n * the cumulative forecast and observation, range [0, 1]. Unlike multiclass Brier it charges\n * less for mass on a level next to the outcome than for mass far from it, which is the right\n * penalty for score questions. With two levels it equals the binary Brier score.\n */\nexport function rankedProbabilityScore(forecasts: readonly OrdinalForecast[]): number {\n if (!forecasts.length) throw new Error('ranked probability score requires at least one forecast')\n let total = 0\n for (const [index, forecast] of forecasts.entries()) {\n const probabilities = forecast?.probabilities\n if (!Array.isArray(probabilities) || probabilities.length < 2) {\n throw new Error(`RPS forecast ${index} needs at least two level probabilities`)\n }\n assertDistribution(probabilities, `RPS forecast ${index}`)\n if (\n !Number.isInteger(forecast.outcome) ||\n forecast.outcome < 0 ||\n forecast.outcome >= probabilities.length\n ) {\n throw new Error(\n `RPS forecast ${index} outcome must index one of its ${probabilities.length} levels`,\n )\n }\n let cumulative = 0\n let sum = 0\n for (let level = 0; level < probabilities.length - 1; level++) {\n cumulative += probabilities[level]!\n sum += (cumulative - (level >= forecast.outcome ? 1 : 0)) ** 2\n }\n total += sum / (probabilities.length - 1)\n }\n return total / forecasts.length\n}\n\nfunction categoricalEntries(\n forecast: CategoricalForecast,\n index: number,\n label: string,\n): [string, number][] {\n if (forecast === null || typeof forecast !== 'object' || typeof forecast.outcome !== 'string') {\n throw new Error(`${label} forecast ${index} needs probabilities and a string outcome`)\n }\n const probabilities = forecast.probabilities\n if (probabilities === null || typeof probabilities !== 'object' || Array.isArray(probabilities)) {\n throw new Error(`${label} forecast ${index} probabilities must be an object keyed by outcome`)\n }\n const entries = Object.entries(probabilities)\n if (entries.length < 2) throw new Error(`${label} forecast ${index} needs at least two outcomes`)\n if (!entries.some(([name]) => name === forecast.outcome)) {\n throw new Error(\n `${label} forecast ${index} has no probability for outcome ${JSON.stringify(forecast.outcome)}`,\n )\n }\n assertDistribution(\n entries.map(([, probability]) => probability),\n `${label} forecast ${index}`,\n )\n return entries\n}\n\nfunction assertDistribution(probabilities: readonly number[], label: string): void {\n let sum = 0\n for (const probability of probabilities) {\n if (!(probability >= 0 && probability <= 1)) {\n throw new Error(`${label} has a probability outside [0, 1]: ${probability}`)\n }\n sum += probability\n }\n if (Math.abs(sum - 1) > 1e-6) throw new Error(`${label} probabilities sum to ${sum}, not 1`)\n}\n\nfunction toBin(chunk: CalibrationPair[], lower?: number, upper?: number): CalibrationBin {\n const xs = chunk.map((c) => c.evalScore)\n const ys = chunk.map((c) => c.outcome)\n const evalMean = mean(xs)\n const outcomeMean = mean(ys)\n return {\n lower: lower ?? Math.min(...xs),\n upper: upper ?? Math.max(...xs),\n n: chunk.length,\n evalMean,\n outcomeMean,\n gap: Math.abs(outcomeMean - evalMean),\n }\n}\n\nfunction mean(xs: number[]): number {\n return xs.reduce((sum, value) => sum + value / xs.length, 0)\n}\n\nfunction validateCalibrationRequest(\n evalMetric: string,\n outcomeMetric: string,\n options: CalibrationOptions,\n): void {\n assertUniqueObservationIds([evalMetric], 'eval metric')\n assertUniqueObservationIds([outcomeMetric], 'outcome metric')\n if (evalMetric.trim() !== evalMetric || outcomeMetric.trim() !== outcomeMetric) {\n throw new Error('calibration metric identities must not have surrounding whitespace')\n }\n if (options.bins !== undefined && (!Number.isSafeInteger(options.bins) || options.bins < 1)) {\n throw new Error('calibration bins must be a positive safe integer')\n }\n if (\n options.binning !== undefined &&\n !['equal-width', 'equal-frequency'].includes(options.binning)\n ) {\n throw new Error('calibration binning must be equal-width or equal-frequency')\n }\n if (\n options.range !== undefined &&\n (!Number.isFinite(options.range.lo) ||\n !Number.isFinite(options.range.hi) ||\n !Number.isFinite(options.range.hi - options.range.lo) ||\n options.range.hi < options.range.lo)\n ) {\n throw new Error('calibration range must have finite ordered bounds')\n }\n}\n"],"mappings":";;;;;;;;;;;AAkDA,eAAsB,iBACpB,YACA,cACA,YACA,eACA,UAA8B,CAAC,GACI;CACnC,MAAM,WAAW;EACf,GAAG;EACH,OAAO,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,GAAG,QAAQ,MAAM;CACtE;CACA,2BAA2B,WAAW,IAAI,eAAe,QAAQ;CACjE,MAAM,UAAU,WAAW,WAAW,mBAAmB,WAAW,EAAE;CACtE,MAAM,WAAW,WAAW;CAC5B,MAAM,OAAO,MAAM,WAAW,SAAS;CACvC,2BACE,KAAK,KAAK,QAAQ,IAAI,KAAK,GAC3B,OACF;CACA,MAAM,WAAW,MAAM,aAAa,KAAK;CACzC,MAAM,wBAAQ,IAAI,IAAiC;CACnD,KAAK,MAAM,KAAK,UAAU;EACxB,MAAM,MAAM,MAAM,IAAI,EAAE,KAAK,KAAK,CAAC;EACnC,IAAI,KAAK,CAAC;EACV,MAAM,IAAI,EAAE,OAAO,GAAG;CACxB;CAEA,MAAM,QAAyC,CAAC;CAChD,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,KAAK,MAAM,IAAI,IAAI,KAAK;EAC9B,IAAI,CAAC,IAAI,QAAQ;EACjB,MAAM,IAAI,MAAM,QAAQ,KAAK,UAAU;EACvC,IAAI,MAAM,QAAQ,CAAC,OAAO,SAAS,CAAC,GAAG;EACvC,MAAM,IAAI,oBAAoB,IAAI,eAAe,QAAQ;EACzD,IAAI,MAAM,MAAM;EAChB,MAAM,KAAK;GAAE;GAAG;EAAE,CAAC;CACrB;CACA,IAAI,MAAM,SAAS,GAAG,OAAO;CAE7B,OAAO,qBACL,MAAM,KAAK,OAAO;EAAE,WAAW,EAAE;EAAG,SAAS,EAAE;CAAE,EAAE,GACnD,UACA,eACA,QACF;AACF;;AAGA,SAAgB,qBACd,YACA,YACA,eACA,UAA8B,CAAC,GACL;CAC1B,2BAA2B,YAAY,eAAe,OAAO;CAC7D,KAAK,MAAM,CAAC,OAAO,SAAS,WAAW,QAAQ,GAC7C,IACE,SAAS,QACT,OAAO,SAAS,YAChB,CAAC,OAAO,SAAS,KAAK,SAAS,KAC/B,CAAC,OAAO,SAAS,KAAK,OAAO,GAE7B,MAAM,IAAI,MAAM,oBAAoB,MAAM,kDAAkD;CAGhG,MAAM,QAAQ;CACd,IAAI,MAAM,SAAS,GAAG,OAAO;CAE7B,MAAM,UAAU,QAAQ,QAAQ;CAChC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,SAAS;CACvC,MAAM,KAAK,QAAQ,OAAO,MAAM,KAAK,IAAI,GAAG,EAAE;CAC9C,MAAM,KAAK,QAAQ,OAAO,MAAM,KAAK,IAAI,GAAG,EAAE;CAC9C,MAAM,OAAO,KAAK;CAClB,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG,MAAM,IAAI,MAAM,uCAAuC;CACnF,MAAM,UAAU,MAAM,KAAK,UAAU;EACnC,GAAG;EACH,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,SAAS,CAAC;CACtD,EAAE;CAEF,MAAM,OAAyB,CAAC;CAChC,IAAI,SAAS,KAAK,QAAQ,OAAO,SAAS,KAAK,cAAc,QAAQ,EAAE,CAAE,SAAS,GAChF,KAAK,KAAK,MAAM,OAAO,CAAC;MACnB,IAAI,YAAY,mBAAmB;EACxC,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;EACpE,MAAM,QAAQ,KAAK,IAAI,SAAS,OAAO,MAAM;EAC7C,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;GAC9B,MAAM,QAAQ,KAAK,MAAO,IAAI,OAAO,SAAU,KAAK;GACpD,MAAM,MAAM,KAAK,OAAQ,IAAI,KAAK,OAAO,SAAU,KAAK;GACxD,KAAK,KAAK,MAAM,OAAO,MAAM,OAAO,GAAG,CAAC,CAAC;EAC3C;CACF,OAAO;EACL,MAAM,yBAAS,IAAI,IAA+B;EAClD,KAAK,MAAM,QAAQ,SAAS;GAC1B,MAAM,QAAQ,KAAK,IAAI,UAAU,GAAG,KAAK,OAAQ,KAAK,YAAY,MAAM,OAAQ,OAAO,CAAC;GACxF,MAAM,QAAQ,OAAO,IAAI,KAAK,KAAK,CAAC;GACpC,MAAM,KAAK,IAAI;GACf,OAAO,IAAI,OAAO,KAAK;EACzB;EACA,KAAK,MAAM,CAAC,OAAO,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,GAC/D,KAAK,KAAK,MAAM,OAAO,KAAK,QAAQ,QAAQ,UAAU,KAAK,SAAS,QAAQ,KAAK,QAAQ,CAAC;CAE9F;CAEA,MAAM,QAAQ,KAAK,QAAQ,GAAG,MAAM,IAAI,EAAE,GAAG,CAAC;CAC9C,MAAM,MAAM,KAAK,QAAQ,GAAG,MAAM,IAAK,EAAE,IAAI,QAAS,EAAE,KAAK,CAAC;CAC9D,MAAM,SAAS,KAAK,QAAQ,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;CAE1D,OAAO;EAAE;EAAY;EAAe,GAAG,MAAM;EAAQ;EAAM;EAAK;CAAO;AACzE;;;;;;AAOA,SAAgB,WAAW,OAA2C;CACpE,IAAI,CAAC,MAAM,QAAQ,MAAM,IAAI,MAAM,wCAAwC;CAC3E,IAAI,QAAQ;CACZ,KAAK,MAAM,CAAC,OAAO,SAAS,MAAM,QAAQ,GAAG;EAC3C,IACE,SAAS,QACT,OAAO,SAAS,YAChB,EAAE,KAAK,aAAa,KAAK,KAAK,aAAa,MAC1C,KAAK,YAAY,KAAK,KAAK,YAAY,GAExC,MAAM,IAAI,MAAM,cAAc,MAAM,wDAAwD;EAE9F,UAAU,KAAK,YAAY,KAAK,YAAY;CAC9C;CACA,OAAO,QAAQ,MAAM;AACvB;;;;;;;;AAgBA,SAAgB,qBAAqB,WAAmD;CACtF,IAAI,CAAC,UAAU,QAAQ,MAAM,IAAI,MAAM,uDAAuD;CAC9F,IAAI,QAAQ;CACZ,KAAK,MAAM,CAAC,OAAO,aAAa,UAAU,QAAQ,GAAG;EACnD,MAAM,UAAU,mBAAmB,UAAU,OAAO,kBAAkB;EACtE,KAAK,MAAM,CAAC,MAAM,gBAAgB,SAChC,UAAU,eAAe,SAAS,SAAS,UAAU,IAAI,OAAO;CAEpE;CACA,OAAO,QAAQ,UAAU;AAC3B;;;;;;;AAeA,SAAgB,uBAAuB,WAA+C;CACpF,IAAI,CAAC,UAAU,QAAQ,MAAM,IAAI,MAAM,yDAAyD;CAChG,IAAI,QAAQ;CACZ,KAAK,MAAM,CAAC,OAAO,aAAa,UAAU,QAAQ,GAAG;EACnD,MAAM,gBAAgB,UAAU;EAChC,IAAI,CAAC,MAAM,QAAQ,aAAa,KAAK,cAAc,SAAS,GAC1D,MAAM,IAAI,MAAM,gBAAgB,MAAM,wCAAwC;EAEhF,mBAAmB,eAAe,gBAAgB,OAAO;EACzD,IACE,CAAC,OAAO,UAAU,SAAS,OAAO,KAClC,SAAS,UAAU,KACnB,SAAS,WAAW,cAAc,QAElC,MAAM,IAAI,MACR,gBAAgB,MAAM,iCAAiC,cAAc,OAAO,QAC9E;EAEF,IAAI,aAAa;EACjB,IAAI,MAAM;EACV,KAAK,IAAI,QAAQ,GAAG,QAAQ,cAAc,SAAS,GAAG,SAAS;GAC7D,cAAc,cAAc;GAC5B,QAAQ,cAAc,SAAS,SAAS,UAAU,IAAI,OAAO;EAC/D;EACA,SAAS,OAAO,cAAc,SAAS;CACzC;CACA,OAAO,QAAQ,UAAU;AAC3B;AAEA,SAAS,mBACP,UACA,OACA,OACoB;CACpB,IAAI,aAAa,QAAQ,OAAO,aAAa,YAAY,OAAO,SAAS,YAAY,UACnF,MAAM,IAAI,MAAM,GAAG,MAAM,YAAY,MAAM,0CAA0C;CAEvF,MAAM,gBAAgB,SAAS;CAC/B,IAAI,kBAAkB,QAAQ,OAAO,kBAAkB,YAAY,MAAM,QAAQ,aAAa,GAC5F,MAAM,IAAI,MAAM,GAAG,MAAM,YAAY,MAAM,kDAAkD;CAE/F,MAAM,UAAU,OAAO,QAAQ,aAAa;CAC5C,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,YAAY,MAAM,6BAA6B;CAChG,IAAI,CAAC,QAAQ,MAAM,CAAC,UAAU,SAAS,SAAS,OAAO,GACrD,MAAM,IAAI,MACR,GAAG,MAAM,YAAY,MAAM,kCAAkC,KAAK,UAAU,SAAS,OAAO,GAC9F;CAEF,mBACE,QAAQ,KAAK,GAAG,iBAAiB,WAAW,GAC5C,GAAG,MAAM,YAAY,OACvB;CACA,OAAO;AACT;AAEA,SAAS,mBAAmB,eAAkC,OAAqB;CACjF,IAAI,MAAM;CACV,KAAK,MAAM,eAAe,eAAe;EACvC,IAAI,EAAE,eAAe,KAAK,eAAe,IACvC,MAAM,IAAI,MAAM,GAAG,MAAM,qCAAqC,aAAa;EAE7E,OAAO;CACT;CACA,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,MAAM,MAAM,IAAI,MAAM,GAAG,MAAM,wBAAwB,IAAI,QAAQ;AAC7F;AAEA,SAAS,MAAM,OAA0B,OAAgB,OAAgC;CACvF,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,SAAS;CACvC,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,OAAO;CACrC,MAAM,WAAW,KAAK,EAAE;CACxB,MAAM,cAAc,KAAK,EAAE;CAC3B,OAAO;EACL,OAAO,SAAS,KAAK,IAAI,GAAG,EAAE;EAC9B,OAAO,SAAS,KAAK,IAAI,GAAG,EAAE;EAC9B,GAAG,MAAM;EACT;EACA;EACA,KAAK,KAAK,IAAI,cAAc,QAAQ;CACtC;AACF;AAEA,SAAS,KAAK,IAAsB;CAClC,OAAO,GAAG,QAAQ,KAAK,UAAU,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAC7D;AAEA,SAAS,2BACP,YACA,eACA,SACM;CACN,2BAA2B,CAAC,UAAU,GAAG,aAAa;CACtD,2BAA2B,CAAC,aAAa,GAAG,gBAAgB;CAC5D,IAAI,WAAW,KAAK,MAAM,cAAc,cAAc,KAAK,MAAM,eAC/D,MAAM,IAAI,MAAM,oEAAoE;CAEtF,IAAI,QAAQ,SAAS,KAAA,MAAc,CAAC,OAAO,cAAc,QAAQ,IAAI,KAAK,QAAQ,OAAO,IACvF,MAAM,IAAI,MAAM,kDAAkD;CAEpE,IACE,QAAQ,YAAY,KAAA,KACpB,CAAC,CAAC,eAAe,iBAAiB,CAAC,CAAC,SAAS,QAAQ,OAAO,GAE5D,MAAM,IAAI,MAAM,4DAA4D;CAE9E,IACE,QAAQ,UAAU,KAAA,MACjB,CAAC,OAAO,SAAS,QAAQ,MAAM,EAAE,KAChC,CAAC,OAAO,SAAS,QAAQ,MAAM,EAAE,KACjC,CAAC,OAAO,SAAS,QAAQ,MAAM,KAAK,QAAQ,MAAM,EAAE,KACpD,QAAQ,MAAM,KAAK,QAAQ,MAAM,KAEnC,MAAM,IAAI,MAAM,mDAAmD;AAEvE"}