@tangle-network/agent-eval 0.129.0 → 0.130.1

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 (428) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -0
  3. package/dist/active-curriculum-C4mk67HP.js +214 -0
  4. package/dist/active-curriculum-C4mk67HP.js.map +1 -0
  5. package/dist/adversarial-smnADNFS.d.ts +21 -0
  6. package/dist/adversarial-smnADNFS.d.ts.map +1 -0
  7. package/dist/analyst/index.d.ts +81 -2872
  8. package/dist/analyst/index.d.ts.map +1 -0
  9. package/dist/analyst/index.js +319 -360
  10. package/dist/analyst/index.js.map +1 -1
  11. package/dist/analyst-BkTS3C58.d.ts +89 -0
  12. package/dist/analyst-BkTS3C58.d.ts.map +1 -0
  13. package/dist/analyst-LsnNpSkm.js +152 -0
  14. package/dist/analyst-LsnNpSkm.js.map +1 -0
  15. package/dist/analyze-runs-C1CavBMk.js +1067 -0
  16. package/dist/analyze-runs-C1CavBMk.js.map +1 -0
  17. package/dist/analyze-runs-FsgYCinh.d.ts +72 -0
  18. package/dist/analyze-runs-FsgYCinh.d.ts.map +1 -0
  19. package/dist/attribute-vocabulary-DLJ6303h.d.ts +54 -0
  20. package/dist/attribute-vocabulary-DLJ6303h.d.ts.map +1 -0
  21. package/dist/authenticity/index.d.ts +81 -79
  22. package/dist/authenticity/index.d.ts.map +1 -0
  23. package/dist/authenticity/index.js +209 -193
  24. package/dist/authenticity/index.js.map +1 -1
  25. package/dist/baseline-HsBvw_dk.js +550 -0
  26. package/dist/baseline-HsBvw_dk.js.map +1 -0
  27. package/dist/baseline-hG3K85h4.d.ts +125 -0
  28. package/dist/baseline-hG3K85h4.d.ts.map +1 -0
  29. package/dist/belief-state/index.d.ts +448 -1188
  30. package/dist/belief-state/index.d.ts.map +1 -0
  31. package/dist/belief-state/index.js +1617 -1709
  32. package/dist/belief-state/index.js.map +1 -1
  33. package/dist/benchmarks/index.d.ts +2 -891
  34. package/dist/benchmarks/index.js +2 -60
  35. package/dist/benchmarks-BJgDGkAD.js +754 -0
  36. package/dist/benchmarks-BJgDGkAD.js.map +1 -0
  37. package/dist/builder-eval/index.d.ts +150 -662
  38. package/dist/builder-eval/index.d.ts.map +1 -0
  39. package/dist/builder-eval/index.js +356 -345
  40. package/dist/builder-eval/index.js.map +1 -1
  41. package/dist/calibration-CNWWA6K8.js +94 -0
  42. package/dist/calibration-CNWWA6K8.js.map +1 -0
  43. package/dist/campaign/index.d.ts +5 -6381
  44. package/dist/campaign/index.js +3 -213
  45. package/dist/campaign-aKJt6emI.js +3886 -0
  46. package/dist/campaign-aKJt6emI.js.map +1 -0
  47. package/dist/cli.d.ts +1 -1
  48. package/dist/cli.js +164 -175
  49. package/dist/cli.js.map +1 -1
  50. package/dist/client-C97NMzqi.d.ts +581 -0
  51. package/dist/client-C97NMzqi.d.ts.map +1 -0
  52. package/dist/client-CYzbdJOZ.js +637 -0
  53. package/dist/client-CYzbdJOZ.js.map +1 -0
  54. package/dist/code-agent-session-BjkMTQ7H.js +1390 -0
  55. package/dist/code-agent-session-BjkMTQ7H.js.map +1 -0
  56. package/dist/code-agent-session-DqqgOJaz.d.ts +143 -0
  57. package/dist/code-agent-session-DqqgOJaz.d.ts.map +1 -0
  58. package/dist/concurrency-DIxRZF_J.js +85 -0
  59. package/dist/concurrency-DIxRZF_J.js.map +1 -0
  60. package/dist/contract/index.d.ts +645 -5565
  61. package/dist/contract/index.d.ts.map +1 -0
  62. package/dist/contract/index.js +1730 -1938
  63. package/dist/contract/index.js.map +1 -1
  64. package/dist/control.d.ts +3 -1030
  65. package/dist/control.js +2 -33
  66. package/dist/cost-ledger-DIgQUFZZ.js +801 -0
  67. package/dist/cost-ledger-DIgQUFZZ.js.map +1 -0
  68. package/dist/cost-ledger-Dye6jCgg.d.ts +236 -0
  69. package/dist/cost-ledger-Dye6jCgg.d.ts.map +1 -0
  70. package/dist/dataset-BvtnC8Dc.d.ts +115 -0
  71. package/dist/dataset-BvtnC8Dc.d.ts.map +1 -0
  72. package/dist/default-registry-C-vFCSEc.js +2579 -0
  73. package/dist/default-registry-C-vFCSEc.js.map +1 -0
  74. package/dist/default-registry-CNPo-Vsb.d.ts +540 -0
  75. package/dist/default-registry-CNPo-Vsb.d.ts.map +1 -0
  76. package/dist/emitter-CPBAhxum.js +266 -0
  77. package/dist/emitter-CPBAhxum.js.map +1 -0
  78. package/dist/emitter-DGQGoLyj.d.ts +113 -0
  79. package/dist/emitter-DGQGoLyj.d.ts.map +1 -0
  80. package/dist/errors-8YnH8WlF.js +64 -0
  81. package/dist/errors-8YnH8WlF.js.map +1 -0
  82. package/dist/errors-CEk209JS.d.ts +76 -0
  83. package/dist/errors-CEk209JS.d.ts.map +1 -0
  84. package/dist/eval-campaign-DEm6c8ru.js +349 -0
  85. package/dist/eval-campaign-DEm6c8ru.js.map +1 -0
  86. package/dist/execution-tracks-CpgFPpS5.js +93 -0
  87. package/dist/execution-tracks-CpgFPpS5.js.map +1 -0
  88. package/dist/exporters-q9iL-2Jf.js +148 -0
  89. package/dist/exporters-q9iL-2Jf.js.map +1 -0
  90. package/dist/extract-usage-BrQ8mCLX.js +155 -0
  91. package/dist/extract-usage-BrQ8mCLX.js.map +1 -0
  92. package/dist/failure-cluster-CqcvCcdR.d.ts +59 -0
  93. package/dist/failure-cluster-CqcvCcdR.d.ts.map +1 -0
  94. package/dist/feedback-trajectory-CVaeREXV.d.ts +340 -0
  95. package/dist/feedback-trajectory-CVaeREXV.d.ts.map +1 -0
  96. package/dist/fuzz.d.ts +320 -646
  97. package/dist/fuzz.d.ts.map +1 -0
  98. package/dist/fuzz.js +670 -618
  99. package/dist/fuzz.js.map +1 -1
  100. package/dist/hf-dataset-DBJXXoY1.js +763 -0
  101. package/dist/hf-dataset-DBJXXoY1.js.map +1 -0
  102. package/dist/hosted/index.d.ts +11 -831
  103. package/dist/hosted/index.d.ts.map +1 -0
  104. package/dist/hosted/index.js +2 -37
  105. package/dist/index-2JJSA6-r2.d.ts +926 -0
  106. package/dist/index-2JJSA6-r2.d.ts.map +1 -0
  107. package/dist/index-6N0aYmpW.d.ts +217 -0
  108. package/dist/index-6N0aYmpW.d.ts.map +1 -0
  109. package/dist/index-BAvgST_9.d.ts +131 -0
  110. package/dist/index-BAvgST_9.d.ts.map +1 -0
  111. package/dist/index-BvnJuTGD.d.ts +68 -0
  112. package/dist/index-BvnJuTGD.d.ts.map +1 -0
  113. package/dist/index-C61Wi7yg.d.ts +547 -0
  114. package/dist/index-C61Wi7yg.d.ts.map +1 -0
  115. package/dist/index-CD_WZ_Xr.d.ts +2250 -0
  116. package/dist/index-CD_WZ_Xr.d.ts.map +1 -0
  117. package/dist/index-DSC51roc.d.ts +102 -0
  118. package/dist/index-DSC51roc.d.ts.map +1 -0
  119. package/dist/index-Em67JBjs.d.ts +335 -0
  120. package/dist/index-Em67JBjs.d.ts.map +1 -0
  121. package/dist/index.d.ts +3755 -15555
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +11182 -11216
  124. package/dist/index.js.map +1 -1
  125. package/dist/integrity-BzRbCHzi.js +424 -0
  126. package/dist/integrity-BzRbCHzi.js.map +1 -0
  127. package/dist/integrity-rmVhXWA7.d.ts +61 -0
  128. package/dist/integrity-rmVhXWA7.d.ts.map +1 -0
  129. package/dist/judge-calibration-DFtEMlde.d.ts +146 -0
  130. package/dist/judge-calibration-DFtEMlde.d.ts.map +1 -0
  131. package/dist/ledger-core/index.d.ts +2 -0
  132. package/dist/ledger-core/index.js +2 -0
  133. package/dist/ledger-core-DtZz1RG0.js +388 -0
  134. package/dist/ledger-core-DtZz1RG0.js.map +1 -0
  135. package/dist/llm-client--GR4JbZE.js +687 -0
  136. package/dist/llm-client--GR4JbZE.js.map +1 -0
  137. package/dist/llm-client-B_nIBlYo.d.ts +290 -0
  138. package/dist/llm-client-B_nIBlYo.d.ts.map +1 -0
  139. package/dist/matrix/index.d.ts +3 -155
  140. package/dist/matrix/index.js +2 -8
  141. package/dist/matrix-BzQnu2S6.js +270 -0
  142. package/dist/matrix-BzQnu2S6.js.map +1 -0
  143. package/dist/meta-eval/index.d.ts +4 -1027
  144. package/dist/meta-eval/index.js +393 -390
  145. package/dist/meta-eval/index.js.map +1 -1
  146. package/dist/metrics-C9YY1OcL.js +239 -0
  147. package/dist/metrics-C9YY1OcL.js.map +1 -0
  148. package/dist/mint-yN2M2eh0.js +201 -0
  149. package/dist/mint-yN2M2eh0.js.map +1 -0
  150. package/dist/multi-layer-verifier-BHY1gWAc.d.ts +138 -0
  151. package/dist/multi-layer-verifier-BHY1gWAc.d.ts.map +1 -0
  152. package/dist/multishot/index.d.ts +273 -480
  153. package/dist/multishot/index.d.ts.map +1 -0
  154. package/dist/multishot/index.js +595 -548
  155. package/dist/multishot/index.js.map +1 -1
  156. package/dist/off-policy-DvgzvtIx.js +220 -0
  157. package/dist/off-policy-DvgzvtIx.js.map +1 -0
  158. package/dist/off-policy-mskQw8Mb.d.ts +153 -0
  159. package/dist/off-policy-mskQw8Mb.d.ts.map +1 -0
  160. package/dist/openapi.json +1 -1
  161. package/dist/opencode-sqlite-BGrHeDu3.js +318 -0
  162. package/dist/opencode-sqlite-BGrHeDu3.js.map +1 -0
  163. package/dist/outcome-store-BYHIuO0e.d.ts +65 -0
  164. package/dist/outcome-store-BYHIuO0e.d.ts.map +1 -0
  165. package/dist/outcome-store-ChBKlTd_.js +75 -0
  166. package/dist/outcome-store-ChBKlTd_.js.map +1 -0
  167. package/dist/paired-arms-D9D0wXj2.js +260 -0
  168. package/dist/paired-arms-D9D0wXj2.js.map +1 -0
  169. package/dist/pipelines/index.d.ts +95 -532
  170. package/dist/pipelines/index.d.ts.map +1 -0
  171. package/dist/pipelines/index.js +497 -478
  172. package/dist/pipelines/index.js.map +1 -1
  173. package/dist/pre-registration-DakwTRXk.js +96 -0
  174. package/dist/pre-registration-DakwTRXk.js.map +1 -0
  175. package/dist/propose-review-control-LhIWGzHl.js +1458 -0
  176. package/dist/propose-review-control-LhIWGzHl.js.map +1 -0
  177. package/dist/query-CJ_DX8vl.d.ts +28 -0
  178. package/dist/query-CJ_DX8vl.d.ts.map +1 -0
  179. package/dist/query-Di7eEQ79.js +83 -0
  180. package/dist/query-Di7eEQ79.js.map +1 -0
  181. package/dist/raw-provider-sink-BQd7mzyT.js +201 -0
  182. package/dist/raw-provider-sink-BQd7mzyT.js.map +1 -0
  183. package/dist/raw-provider-sink-BU29Sh8h.d.ts +134 -0
  184. package/dist/raw-provider-sink-BU29Sh8h.d.ts.map +1 -0
  185. package/dist/redact-7Aq1ukl-.js +107 -0
  186. package/dist/redact-7Aq1ukl-.js.map +1 -0
  187. package/dist/release-report-Cz9NKH39.js +603 -0
  188. package/dist/release-report-Cz9NKH39.js.map +1 -0
  189. package/dist/release-report-mvB2G4_J.d.ts +244 -0
  190. package/dist/release-report-mvB2G4_J.d.ts.map +1 -0
  191. package/dist/replay-GnyotH0J.js +1741 -0
  192. package/dist/replay-GnyotH0J.js.map +1 -0
  193. package/dist/replay-OoidtG1E.d.ts +749 -0
  194. package/dist/replay-OoidtG1E.d.ts.map +1 -0
  195. package/dist/reporting.d.ts +6 -1312
  196. package/dist/reporting.js +6 -51
  197. package/dist/researcher-CwTdwXG1.d.ts +314 -0
  198. package/dist/researcher-CwTdwXG1.d.ts.map +1 -0
  199. package/dist/reward-hacking-eAnOsynk.d.ts +224 -0
  200. package/dist/reward-hacking-eAnOsynk.d.ts.map +1 -0
  201. package/dist/reward-hacking-qipEpKvY.js +596 -0
  202. package/dist/reward-hacking-qipEpKvY.js.map +1 -0
  203. package/dist/reward-nw2xZGZG.js +137 -0
  204. package/dist/reward-nw2xZGZG.js.map +1 -0
  205. package/dist/rl.d.ts +760 -4010
  206. package/dist/rl.d.ts.map +1 -0
  207. package/dist/rl.js +2325 -1958
  208. package/dist/rl.js.map +1 -1
  209. package/dist/rolldown-runtime-8H4AJuhK.js +14 -0
  210. package/dist/rollout/index.d.ts +3 -2087
  211. package/dist/rollout/index.js +8 -168
  212. package/dist/rollout-BOYjemfR.js +624 -0
  213. package/dist/rollout-BOYjemfR.js.map +1 -0
  214. package/dist/rubric-predictive-validity-B3xmbmS1.js +141 -0
  215. package/dist/rubric-predictive-validity-B3xmbmS1.js.map +1 -0
  216. package/dist/rubric-predictive-validity-Ku_clp_1.d.ts +74 -0
  217. package/dist/rubric-predictive-validity-Ku_clp_1.d.ts.map +1 -0
  218. package/dist/run-evidence-ClRX_8A9.d.ts +225 -0
  219. package/dist/run-evidence-ClRX_8A9.d.ts.map +1 -0
  220. package/dist/run-record-BuoE80Dq.js +467 -0
  221. package/dist/{chunk-56TAVBOK.js.map → run-record-BuoE80Dq.js.map} +1 -1
  222. package/dist/run-record-CnZu_gjl.d.ts +357 -0
  223. package/dist/run-record-CnZu_gjl.d.ts.map +1 -0
  224. package/dist/run-score-iEEAWiBY.js +41 -0
  225. package/dist/run-score-iEEAWiBY.js.map +1 -0
  226. package/dist/runtime-trajectory-1gyaTOoC.js +93 -0
  227. package/dist/runtime-trajectory-1gyaTOoC.js.map +1 -0
  228. package/dist/runtime-trajectory-BvSZcCHD.d.ts +50 -0
  229. package/dist/runtime-trajectory-BvSZcCHD.d.ts.map +1 -0
  230. package/dist/schema-BtVldJ3T.d.ts +206 -0
  231. package/dist/schema-BtVldJ3T.d.ts.map +1 -0
  232. package/dist/schema-C6DW4ZHR.js +821 -0
  233. package/dist/schema-C6DW4ZHR.js.map +1 -0
  234. package/dist/schema-CRhEY1SO.js +69 -0
  235. package/dist/schema-CRhEY1SO.js.map +1 -0
  236. package/dist/schema-Cef2cFmb.d.ts +408 -0
  237. package/dist/schema-Cef2cFmb.d.ts.map +1 -0
  238. package/dist/semantic-concept-judge-B6cWNJ2K.js +725 -0
  239. package/dist/semantic-concept-judge-B6cWNJ2K.js.map +1 -0
  240. package/dist/sequential-Br0mAPHA.js +148 -0
  241. package/dist/sequential-Br0mAPHA.js.map +1 -0
  242. package/dist/sequential-CYwq6Ff_.d.ts +141 -0
  243. package/dist/sequential-CYwq6Ff_.d.ts.map +1 -0
  244. package/dist/series-convergence-CjO2QdRW.js +43 -0
  245. package/dist/series-convergence-CjO2QdRW.js.map +1 -0
  246. package/dist/series-convergence-ofsqPWhs.d.ts +35 -0
  247. package/dist/series-convergence-ofsqPWhs.d.ts.map +1 -0
  248. package/dist/server-m5D9cvnG.js +1040 -0
  249. package/dist/server-m5D9cvnG.js.map +1 -0
  250. package/dist/skill-usage-C_pXm7lP.d.ts +534 -0
  251. package/dist/skill-usage-C_pXm7lP.d.ts.map +1 -0
  252. package/dist/skillopt-optimization-method-CUmHkGbI.js +7718 -0
  253. package/dist/skillopt-optimization-method-CUmHkGbI.js.map +1 -0
  254. package/dist/skillopt-optimization-method-CWKVTnks.d.ts +1740 -0
  255. package/dist/skillopt-optimization-method-CWKVTnks.d.ts.map +1 -0
  256. package/dist/statistics-Cmj6nynr.d.ts +514 -0
  257. package/dist/statistics-Cmj6nynr.d.ts.map +1 -0
  258. package/dist/statistics-CnnxdpOg.js +1437 -0
  259. package/dist/statistics-CnnxdpOg.js.map +1 -0
  260. package/dist/store-CT9YIIve.d.ts +117 -0
  261. package/dist/store-CT9YIIve.d.ts.map +1 -0
  262. package/dist/store-CxJry_cs.d.ts +229 -0
  263. package/dist/store-CxJry_cs.d.ts.map +1 -0
  264. package/dist/storyboard/index.d.ts +84 -203
  265. package/dist/storyboard/index.d.ts.map +1 -0
  266. package/dist/storyboard/index.js +609 -542
  267. package/dist/storyboard/index.js.map +1 -1
  268. package/dist/summary-report-BNs5nmXI.js +862 -0
  269. package/dist/summary-report-BNs5nmXI.js.map +1 -0
  270. package/dist/summary-report-Cj9gdw4i.d.ts +407 -0
  271. package/dist/summary-report-Cj9gdw4i.d.ts.map +1 -0
  272. package/dist/supervisor-run/index.d.ts +2 -959
  273. package/dist/supervisor-run/index.js +2 -65
  274. package/dist/supervisor-run-_lnTLM3z.js +1679 -0
  275. package/dist/supervisor-run-_lnTLM3z.js.map +1 -0
  276. package/dist/task-failure-attributes-CQZlB3et.js +311 -0
  277. package/dist/task-failure-attributes-CQZlB3et.js.map +1 -0
  278. package/dist/test-graded-scenario-BsqWLmPt.js +318 -0
  279. package/dist/test-graded-scenario-BsqWLmPt.js.map +1 -0
  280. package/dist/test-graded-scenario-D1TaI2va.d.ts +141 -0
  281. package/dist/test-graded-scenario-D1TaI2va.d.ts.map +1 -0
  282. package/dist/tools-BmuN627J.js +1085 -0
  283. package/dist/tools-BmuN627J.js.map +1 -0
  284. package/dist/trace-attributes.d.ts +2 -52
  285. package/dist/trace-attributes.js +131 -61
  286. package/dist/trace-attributes.js.map +1 -1
  287. package/dist/traces.d.ts +12 -2365
  288. package/dist/traces.js +12 -252
  289. package/dist/trajectory-D_7rLrvE.js +56 -0
  290. package/dist/trajectory-D_7rLrvE.js.map +1 -0
  291. package/dist/types-DGsxbAEd.d.ts +387 -0
  292. package/dist/types-DGsxbAEd.d.ts.map +1 -0
  293. package/dist/types-k9tZGKUg.d.ts +640 -0
  294. package/dist/types-k9tZGKUg.d.ts.map +1 -0
  295. package/dist/verdict-Dps8_okt.d.ts +37 -0
  296. package/dist/verdict-Dps8_okt.d.ts.map +1 -0
  297. package/dist/wire/index.d.ts +702 -1173
  298. package/dist/wire/index.d.ts.map +1 -0
  299. package/dist/wire/index.js +2 -81
  300. package/docs/campaign-proposers.md +1 -0
  301. package/package.json +17 -9
  302. package/dist/benchmarks/index.js.map +0 -1
  303. package/dist/campaign/index.js.map +0 -1
  304. package/dist/chunk-2QU3YOPR.js +0 -7374
  305. package/dist/chunk-2QU3YOPR.js.map +0 -1
  306. package/dist/chunk-3OCR4R5I.js +0 -728
  307. package/dist/chunk-3OCR4R5I.js.map +0 -1
  308. package/dist/chunk-3RF76KTD.js +0 -84
  309. package/dist/chunk-3RF76KTD.js.map +0 -1
  310. package/dist/chunk-56TAVBOK.js +0 -698
  311. package/dist/chunk-5DTSBUL2.js +0 -159
  312. package/dist/chunk-5DTSBUL2.js.map +0 -1
  313. package/dist/chunk-7FO3TNPI.js +0 -232
  314. package/dist/chunk-7FO3TNPI.js.map +0 -1
  315. package/dist/chunk-7ZZMD7UK.js +0 -386
  316. package/dist/chunk-7ZZMD7UK.js.map +0 -1
  317. package/dist/chunk-BOD4O7OF.js +0 -40
  318. package/dist/chunk-BOD4O7OF.js.map +0 -1
  319. package/dist/chunk-BSO5JDQH.js +0 -2335
  320. package/dist/chunk-BSO5JDQH.js.map +0 -1
  321. package/dist/chunk-C6LXANRU.js +0 -1550
  322. package/dist/chunk-C6LXANRU.js.map +0 -1
  323. package/dist/chunk-DODXQREJ.js +0 -752
  324. package/dist/chunk-DODXQREJ.js.map +0 -1
  325. package/dist/chunk-DRYIUNWY.js +0 -622
  326. package/dist/chunk-DRYIUNWY.js.map +0 -1
  327. package/dist/chunk-E7QXT7SX.js +0 -183
  328. package/dist/chunk-E7QXT7SX.js.map +0 -1
  329. package/dist/chunk-EG66UGL4.js +0 -341
  330. package/dist/chunk-EG66UGL4.js.map +0 -1
  331. package/dist/chunk-FXTVJPYD.js +0 -576
  332. package/dist/chunk-FXTVJPYD.js.map +0 -1
  333. package/dist/chunk-G7MGMCZD.js +0 -153
  334. package/dist/chunk-G7MGMCZD.js.map +0 -1
  335. package/dist/chunk-GGE4NNQT.js +0 -65
  336. package/dist/chunk-GGE4NNQT.js.map +0 -1
  337. package/dist/chunk-H23X7XKK.js +0 -181
  338. package/dist/chunk-H23X7XKK.js.map +0 -1
  339. package/dist/chunk-HHWE3POT.js +0 -94
  340. package/dist/chunk-HHWE3POT.js.map +0 -1
  341. package/dist/chunk-HPWUNB47.js +0 -289
  342. package/dist/chunk-HPWUNB47.js.map +0 -1
  343. package/dist/chunk-IYCLP2N2.js +0 -766
  344. package/dist/chunk-IYCLP2N2.js.map +0 -1
  345. package/dist/chunk-JHCHEVET.js +0 -274
  346. package/dist/chunk-JHCHEVET.js.map +0 -1
  347. package/dist/chunk-JQSF5DQT.js +0 -701
  348. package/dist/chunk-JQSF5DQT.js.map +0 -1
  349. package/dist/chunk-K4DBDHLK.js +0 -158
  350. package/dist/chunk-K4DBDHLK.js.map +0 -1
  351. package/dist/chunk-K6N6XJJX.js +0 -306
  352. package/dist/chunk-K6N6XJJX.js.map +0 -1
  353. package/dist/chunk-M4YBQKIJ.js +0 -1040
  354. package/dist/chunk-M4YBQKIJ.js.map +0 -1
  355. package/dist/chunk-MA6HLL3S.js +0 -65
  356. package/dist/chunk-MA6HLL3S.js.map +0 -1
  357. package/dist/chunk-MAZ26DC7.js +0 -99
  358. package/dist/chunk-MAZ26DC7.js.map +0 -1
  359. package/dist/chunk-NPCTHQIO.js +0 -91
  360. package/dist/chunk-NPCTHQIO.js.map +0 -1
  361. package/dist/chunk-NY44NC4A.js +0 -1056
  362. package/dist/chunk-NY44NC4A.js.map +0 -1
  363. package/dist/chunk-OIUOT4QD.js +0 -44
  364. package/dist/chunk-OIUOT4QD.js.map +0 -1
  365. package/dist/chunk-ONWEPEDO.js +0 -57
  366. package/dist/chunk-ONWEPEDO.js.map +0 -1
  367. package/dist/chunk-OWN5NPMC.js +0 -152
  368. package/dist/chunk-OWN5NPMC.js.map +0 -1
  369. package/dist/chunk-P6FYH6K4.js +0 -1161
  370. package/dist/chunk-P6FYH6K4.js.map +0 -1
  371. package/dist/chunk-PC4UYEBM.js +0 -166
  372. package/dist/chunk-PC4UYEBM.js.map +0 -1
  373. package/dist/chunk-PC5DOSM7.js +0 -579
  374. package/dist/chunk-PC5DOSM7.js.map +0 -1
  375. package/dist/chunk-PXE2VKMX.js +0 -140
  376. package/dist/chunk-PXE2VKMX.js.map +0 -1
  377. package/dist/chunk-PZ5AY32C.js +0 -10
  378. package/dist/chunk-PZ5AY32C.js.map +0 -1
  379. package/dist/chunk-QB6BDBP2.js +0 -4464
  380. package/dist/chunk-QB6BDBP2.js.map +0 -1
  381. package/dist/chunk-RXHCETDZ.js +0 -536
  382. package/dist/chunk-RXHCETDZ.js.map +0 -1
  383. package/dist/chunk-RZTMDUO7.js +0 -49
  384. package/dist/chunk-RZTMDUO7.js.map +0 -1
  385. package/dist/chunk-SFLLL76A.js +0 -669
  386. package/dist/chunk-SFLLL76A.js.map +0 -1
  387. package/dist/chunk-SZLVEKMJ.js +0 -1446
  388. package/dist/chunk-SZLVEKMJ.js.map +0 -1
  389. package/dist/chunk-T4SQEITX.js +0 -95
  390. package/dist/chunk-T4SQEITX.js.map +0 -1
  391. package/dist/chunk-T6RLYGAD.js +0 -158
  392. package/dist/chunk-T6RLYGAD.js.map +0 -1
  393. package/dist/chunk-TJVT4QFF.js +0 -911
  394. package/dist/chunk-TJVT4QFF.js.map +0 -1
  395. package/dist/chunk-TQ7LNKZ3.js +0 -136
  396. package/dist/chunk-TQ7LNKZ3.js.map +0 -1
  397. package/dist/chunk-U4L7JRPZ.js +0 -1706
  398. package/dist/chunk-U4L7JRPZ.js.map +0 -1
  399. package/dist/chunk-U4PHLT2N.js +0 -419
  400. package/dist/chunk-U4PHLT2N.js.map +0 -1
  401. package/dist/chunk-VCZ5FQYW.js +0 -928
  402. package/dist/chunk-VCZ5FQYW.js.map +0 -1
  403. package/dist/chunk-VI2UW6B6.js +0 -162
  404. package/dist/chunk-VI2UW6B6.js.map +0 -1
  405. package/dist/chunk-VQMK5FMP.js +0 -247
  406. package/dist/chunk-VQMK5FMP.js.map +0 -1
  407. package/dist/chunk-WGXIEX7P.js +0 -116
  408. package/dist/chunk-WGXIEX7P.js.map +0 -1
  409. package/dist/chunk-WVATSFCP.js +0 -1553
  410. package/dist/chunk-WVATSFCP.js.map +0 -1
  411. package/dist/chunk-X4YIBDER.js +0 -1662
  412. package/dist/chunk-X4YIBDER.js.map +0 -1
  413. package/dist/chunk-YQN4ICPP.js +0 -355
  414. package/dist/chunk-YQN4ICPP.js.map +0 -1
  415. package/dist/chunk-ZET2UAYW.js +0 -89
  416. package/dist/chunk-ZET2UAYW.js.map +0 -1
  417. package/dist/chunk-ZHTZ4EYI.js +0 -1212
  418. package/dist/chunk-ZHTZ4EYI.js.map +0 -1
  419. package/dist/control.js.map +0 -1
  420. package/dist/hosted/index.js.map +0 -1
  421. package/dist/matrix/index.js.map +0 -1
  422. package/dist/reporting.js.map +0 -1
  423. package/dist/rollout/index.js.map +0 -1
  424. package/dist/run-campaign-OJJ7CZF4.js +0 -18
  425. package/dist/run-campaign-OJJ7CZF4.js.map +0 -1
  426. package/dist/supervisor-run/index.js.map +0 -1
  427. package/dist/traces.js.map +0 -1
  428. package/dist/wire/index.js.map +0 -1
@@ -0,0 +1,862 @@
1
+ import { r as hashJson, t as canonicalize } from "./pre-registration-DakwTRXk.js";
2
+ import { N as wilcoxonSignedRank, a as confidenceInterval, b as pairedMde, t as benjaminiHochberg, v as pairedBootstrap, y as pairedCohensDz } from "./statistics-CnnxdpOg.js";
3
+ import { r as pairRunRecords } from "./paired-arms-D9D0wXj2.js";
4
+ import { r as observedSplitScore } from "./reward-nw2xZGZG.js";
5
+ //#region src/summary-report.ts
6
+ /**
7
+ * Table 1 helper. Buckets runs by `candidateId`, computes mean +
8
+ * bootstrap CI on the chosen split, and (when a comparator is given)
9
+ * BH-adjusted Wilcoxon p + paired Cohen's dz versus that comparator.
10
+ */
11
+ function summaryTable(runs, opts = {}) {
12
+ const split = opts.split ?? "holdout";
13
+ const confidence = opts.confidence ?? .95;
14
+ const fdr = opts.fdr ?? .05;
15
+ const comparator = opts.comparator ?? null;
16
+ const byCandidate = /* @__PURE__ */ new Map();
17
+ for (const r of runs) {
18
+ if (r.splitTag !== split) continue;
19
+ const v = observedSplitScore(r, split);
20
+ if (typeof v !== "number" || !Number.isFinite(v)) continue;
21
+ const bucket = byCandidate.get(r.candidateId) ?? {
22
+ runs: [],
23
+ scores: []
24
+ };
25
+ bucket.runs.push(r);
26
+ bucket.scores.push(v);
27
+ byCandidate.set(r.candidateId, bucket);
28
+ }
29
+ const candidateIds = [...byCandidate.keys()].sort();
30
+ const compRuns = comparator ? byCandidate.get(comparator) : void 0;
31
+ const tentative = [];
32
+ for (const id of candidateIds) {
33
+ const bucket = byCandidate.get(id);
34
+ const ci = confidenceInterval(bucket.scores, confidence);
35
+ let rawP = null;
36
+ let d = null;
37
+ let pairedN = null;
38
+ let unpairedCandidateN = null;
39
+ let unpairedComparatorN = null;
40
+ if (comparator && compRuns && id !== comparator) {
41
+ const paired = pairScoresByKey(bucket.runs, compRuns.runs, split);
42
+ pairedN = paired.before.length;
43
+ unpairedCandidateN = paired.unpairedCandidateN;
44
+ unpairedComparatorN = paired.unpairedComparatorN;
45
+ if (paired.before.length >= 6) rawP = wilcoxonSignedRank(paired.before, paired.after).p;
46
+ d = pairedCohensDz(paired.before, paired.after);
47
+ }
48
+ tentative.push({
49
+ candidateId: id,
50
+ n: bucket.scores.length,
51
+ mean: ci.mean,
52
+ ciLow: ci.lower,
53
+ ciHigh: ci.upper,
54
+ qValue: rawP,
55
+ cohensD: d,
56
+ pairedN,
57
+ unpairedCandidateN,
58
+ unpairedComparatorN,
59
+ rawP
60
+ });
61
+ }
62
+ if (comparator) {
63
+ const idxs = [];
64
+ const ps = [];
65
+ for (let i = 0; i < tentative.length; i++) {
66
+ const r = tentative[i];
67
+ if (r.candidateId === comparator) continue;
68
+ if (r.rawP === null || !Number.isFinite(r.rawP)) continue;
69
+ idxs.push(i);
70
+ ps.push(r.rawP);
71
+ }
72
+ if (ps.length > 0) {
73
+ const { qValues } = benjaminiHochberg(ps, fdr);
74
+ for (let k = 0; k < idxs.length; k++) tentative[idxs[k]].qValue = qValues[k];
75
+ }
76
+ }
77
+ const rows = tentative.map(({ rawP: _rawP, ...rest }) => rest);
78
+ return {
79
+ rows,
80
+ comparator,
81
+ split,
82
+ markdown: renderSummaryTableMarkdown(rows, comparator, split)
83
+ };
84
+ }
85
+ function pairScoresByKey(candidate, baseline, split) {
86
+ const scoreOf = (run) => {
87
+ const v = observedSplitScore(run, split);
88
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
89
+ };
90
+ const scoredCandidate = candidate.filter((run) => scoreOf(run) !== void 0);
91
+ const pairing = pairRunRecords(baseline.filter((run) => scoreOf(run) !== void 0), scoredCandidate);
92
+ return {
93
+ before: pairing.pairs.map((pair) => scoreOf(pair.baseline)),
94
+ after: pairing.pairs.map((pair) => scoreOf(pair.treatment)),
95
+ unpairedCandidateN: pairing.unpairedTreatment.length,
96
+ unpairedComparatorN: pairing.unpairedBaseline.length
97
+ };
98
+ }
99
+ function renderSummaryTableMarkdown(rows, comparator, split) {
100
+ const lines = [];
101
+ const cmpLabel = comparator ? ` (vs ${comparator})` : "";
102
+ lines.push(`Summary Table — ${split} split${cmpLabel}`);
103
+ lines.push("");
104
+ lines.push("| Candidate | N | Pairs | Unpaired | Mean | 95% CI | q (BH) | Cohen's dz |");
105
+ lines.push("|---|---:|---:|---:|---:|---|---:|---:|");
106
+ for (const r of rows) {
107
+ const ci = `[${fmt(r.ciLow)}, ${fmt(r.ciHigh)}]`;
108
+ const q = r.qValue !== null ? r.qValue.toFixed(4) : "—";
109
+ const d = r.cohensD !== null ? r.cohensD.toFixed(3) : "—";
110
+ const paired = r.pairedN ?? "—";
111
+ const unpaired = r.unpairedCandidateN === null || r.unpairedComparatorN === null ? "—" : `${r.unpairedCandidateN}/${r.unpairedComparatorN}`;
112
+ lines.push(`| ${r.candidateId} | ${r.n} | ${paired} | ${unpaired} | ${fmt(r.mean)} | ${ci} | ${q} | ${d} |`);
113
+ }
114
+ return lines.join("\n");
115
+ }
116
+ /**
117
+ * Cost vs quality scatter spec. `gateDecisions` is keyed by
118
+ * candidate id; if present, every point picks up the gate verdict
119
+ * for overlay.
120
+ */
121
+ function paretoChart(runs, opts = {}) {
122
+ const split = opts.split ?? "holdout";
123
+ const buckets = /* @__PURE__ */ new Map();
124
+ for (const r of runs) {
125
+ if (r.splitTag !== split) continue;
126
+ const v = observedSplitScore(r, split);
127
+ if (typeof v !== "number" || !Number.isFinite(v)) continue;
128
+ if (r.costUsd === null) continue;
129
+ const bucket = buckets.get(r.candidateId) ?? {
130
+ cost: [],
131
+ quality: []
132
+ };
133
+ bucket.cost.push(r.costUsd);
134
+ bucket.quality.push(v);
135
+ buckets.set(r.candidateId, bucket);
136
+ }
137
+ const points = [];
138
+ for (const [candidateId, bucket] of buckets.entries()) points.push({
139
+ candidateId,
140
+ cost: avg(bucket.cost),
141
+ quality: avg(bucket.quality),
142
+ n: bucket.cost.length,
143
+ onFrontier: false,
144
+ gate: opts.gateDecisions?.[candidateId] ? gateLabel(opts.gateDecisions[candidateId]) : void 0
145
+ });
146
+ for (const p of points) p.onFrontier = !points.some((q) => q !== p && dominates(q, p));
147
+ return {
148
+ kind: "pareto-cost-quality",
149
+ split,
150
+ axes: {
151
+ x: "costUsd",
152
+ y: "score"
153
+ },
154
+ points
155
+ };
156
+ }
157
+ function dominates(a, b) {
158
+ return a.cost <= b.cost && a.quality >= b.quality && (a.cost < b.cost || a.quality > b.quality);
159
+ }
160
+ function gateLabel(d) {
161
+ return d.promote ? "promote" : "reject";
162
+ }
163
+ /**
164
+ * Held-out improvement distribution: per-pair delta (candidate −
165
+ * comparator), histogrammed. Includes the bootstrap CI on the median
166
+ * delta — same primitive the promotion gate uses.
167
+ */
168
+ function gainHistogram(runs, candidateId, comparator, opts = {}) {
169
+ const split = opts.split ?? "holdout";
170
+ const binCount = opts.bins ?? 11;
171
+ if (binCount < 1) throw new Error("gainHistogram: bins must be ≥ 1");
172
+ const { before, after, unpairedCandidateN, unpairedComparatorN } = pairScoresByKey(runs.filter((r) => r.candidateId === candidateId && r.splitTag === split), runs.filter((r) => r.candidateId === comparator && r.splitTag === split), split);
173
+ const n = before.length;
174
+ if (n === 0) return {
175
+ kind: "gain-distribution",
176
+ candidateId,
177
+ comparator,
178
+ split,
179
+ n: 0,
180
+ unpairedCandidateN,
181
+ unpairedComparatorN,
182
+ bins: [],
183
+ median: null,
184
+ ci: null
185
+ };
186
+ const deltas = before.map((b, i) => after[i] - b);
187
+ const sortedDeltas = [...deltas].sort((a, b) => a - b);
188
+ const median = medianOfSorted(sortedDeltas);
189
+ const min = sortedDeltas[0];
190
+ const max = sortedDeltas[sortedDeltas.length - 1];
191
+ const bound = Math.max(Math.abs(min), Math.abs(max), 1e-6);
192
+ const lo = -bound;
193
+ const width = (bound - lo) / binCount;
194
+ const bins = [];
195
+ for (let i = 0; i < binCount; i++) bins.push({
196
+ lo: lo + i * width,
197
+ hi: lo + (i + 1) * width,
198
+ count: 0
199
+ });
200
+ for (const d of deltas) {
201
+ let idx = Math.floor((d - lo) / width);
202
+ if (idx < 0) idx = 0;
203
+ if (idx >= binCount) idx = binCount - 1;
204
+ bins[idx].count += 1;
205
+ }
206
+ const ci = pairedBootstrap(before, after, {
207
+ confidence: opts.confidence ?? .95,
208
+ resamples: opts.resamples ?? 2e3,
209
+ statistic: "median",
210
+ seed: opts.seed
211
+ });
212
+ return {
213
+ kind: "gain-distribution",
214
+ candidateId,
215
+ comparator,
216
+ split,
217
+ n,
218
+ unpairedCandidateN,
219
+ unpairedComparatorN,
220
+ bins,
221
+ median,
222
+ ci: {
223
+ low: ci.low,
224
+ high: ci.high
225
+ }
226
+ };
227
+ }
228
+ /**
229
+ * Hard floor below which a paired comparison is treated as uninformative
230
+ * regardless of `minPairs`. Mirrors the lower limit on Wilcoxon signed-rank
231
+ * exact tables; below this the test has no power to separate effect sizes.
232
+ */
233
+ const RESEARCH_REPORT_HARD_PAIR_FLOOR = 6;
234
+ /**
235
+ * Internal: paired posterior summary on (candidate − comparator) deltas.
236
+ *
237
+ * Returns the bootstrap CI on the median (matching `gainHistogram`) plus
238
+ * Bayesian-bootstrap posterior summaries Pr(Δ>0) and Pr(Δ∈ROPE) computed
239
+ * from Dirichlet(1, ..., 1) weights on the observed paired deltas
240
+ * (Rubin 1981), and the
241
+ * minimum detectable paired effect at the configured power and α.
242
+ *
243
+ * `null` is returned when no paired observations exist; callers must
244
+ * gate on `n` before consuming the bootstrap statistics.
245
+ */
246
+ function pairedPosterior(runs, candidateId, comparator, opts) {
247
+ const { before, after } = pairScoresByKey(runs.filter((r) => r.candidateId === candidateId && r.splitTag === opts.split), runs.filter((r) => r.candidateId === comparator && r.splitTag === opts.split), opts.split);
248
+ const n = before.length;
249
+ if (n === 0) return null;
250
+ const deltas = before.map((b, i) => after[i] - b);
251
+ const meanDelta = deltas.reduce((s, x) => s + x, 0) / n;
252
+ const medianDelta = medianOfSorted([...deltas].sort((a, b) => a - b));
253
+ const sdDelta = stdev(deltas, meanDelta);
254
+ const ci = pairedBootstrap(before, after, {
255
+ confidence: opts.confidence,
256
+ resamples: 2e3,
257
+ statistic: "median",
258
+ seed: opts.seed
259
+ });
260
+ const meanSamples = bayesianBootstrapMeanSamples(deltas, 2e3, opts.seed);
261
+ const prGreaterThanZero = meanSamples.length === 0 ? 0 : meanSamples.filter((s) => s > 0).length / meanSamples.length;
262
+ const prInRope = opts.rope === null || meanSamples.length === 0 ? null : meanSamples.filter((s) => s >= opts.rope.low && s <= opts.rope.high).length / meanSamples.length;
263
+ const dStandardised = pairedMde({
264
+ nPaired: n,
265
+ alpha: opts.mdeAlpha,
266
+ power: opts.mdePower
267
+ });
268
+ const mde = sdDelta === 0 ? 0 : dStandardised * sdDelta;
269
+ return {
270
+ n,
271
+ meanDelta,
272
+ medianDelta,
273
+ sdDelta,
274
+ ci: {
275
+ low: ci.low,
276
+ high: ci.high
277
+ },
278
+ prGreaterThanZero,
279
+ prInRope,
280
+ mde
281
+ };
282
+ }
283
+ function bayesianBootstrapMeanSamples(deltas, resamples, seed) {
284
+ const n = deltas.length;
285
+ if (n === 0) return [];
286
+ if (n === 1) return new Array(resamples).fill(deltas[0]);
287
+ const rng = seedRng(seed);
288
+ const samples = new Array(resamples);
289
+ for (let b = 0; b < resamples; b++) {
290
+ let weightedSum = 0;
291
+ let weightSum = 0;
292
+ for (let k = 0; k < n; k++) {
293
+ const weight = -Math.log(Math.max(Number.MIN_VALUE, rng()));
294
+ weightedSum += deltas[k] * weight;
295
+ weightSum += weight;
296
+ }
297
+ samples[b] = weightedSum / weightSum;
298
+ }
299
+ return samples;
300
+ }
301
+ function seedRng(seed) {
302
+ if (seed === void 0) return Math.random;
303
+ let s = seed >>> 0;
304
+ return () => {
305
+ s = s + 1831565813 >>> 0;
306
+ let t = s;
307
+ t = Math.imul(t ^ t >>> 15, t | 1);
308
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
309
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
310
+ };
311
+ }
312
+ function stdev(xs, mean) {
313
+ if (xs.length < 2) return 0;
314
+ let sse = 0;
315
+ for (const x of xs) sse += (x - mean) ** 2;
316
+ return Math.sqrt(sse / (xs.length - 1));
317
+ }
318
+ /**
319
+ * Executive research report for CPO / AI-lead / launch-review consumption.
320
+ *
321
+ * Composes:
322
+ * - `summaryTable` marginal stats with BH-FDR-adjusted q-values
323
+ * - `paretoChart` cost-vs-quality frontier with gate overlay
324
+ * - `gainHistogram` per-candidate paired-delta distribution
325
+ * - paired posterior (this file): bootstrap CI on median, Bayesian-bootstrap Pr(Δ>0),
326
+ * Pr(Δ∈ROPE), MDE at the configured power
327
+ *
328
+ * Decisions are made on paired evidence — never on marginal means alone —
329
+ * and respect any held-out gate decision the caller passes through. The
330
+ * report embeds a SHA-256 fingerprint of the input run set and, optionally,
331
+ * the hash of a preregistered protocol so a downstream reader can verify
332
+ * provenance and that the analysis was the preregistered one.
333
+ *
334
+ * Async because the fingerprint uses Web Crypto via `hashJson`; deterministic
335
+ * for any fixed `runs`, `seed`, and ROPE.
336
+ */
337
+ async function researchReport(runs, opts = {}) {
338
+ const split = opts.split ?? "holdout";
339
+ const comparator = opts.comparator ?? null;
340
+ const confidence = opts.confidence ?? .95;
341
+ const fdr = opts.fdr ?? .05;
342
+ const minPairs = Math.max(opts.minPairs ?? 20, 6);
343
+ const rope = opts.rope ?? null;
344
+ const mdePower = opts.mdePower ?? .8;
345
+ const mdeAlpha = opts.mdeAlpha ?? fdr;
346
+ const title = opts.title ?? "Agent Evaluation Research Report";
347
+ const generatedAt = opts.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
348
+ const preregistrationHash = opts.preregistrationHash ?? null;
349
+ if (rope && !(Number.isFinite(rope.low) && Number.isFinite(rope.high) && rope.low <= rope.high)) throw new Error(`researchReport: rope must satisfy low ≤ high with finite bounds, got ${JSON.stringify(rope)}`);
350
+ const summary = summaryTable(runs, {
351
+ comparator: comparator ?? void 0,
352
+ split,
353
+ confidence,
354
+ fdr
355
+ });
356
+ const pareto = paretoChart(runs, {
357
+ split,
358
+ gateDecisions: opts.gateDecisions
359
+ });
360
+ const candidateIds = opts.candidateIds ?? summary.rows.map((r) => r.candidateId).filter((id) => id !== comparator);
361
+ const gains = comparator ? candidateIds.map((id) => gainHistogram(runs, id, comparator, {
362
+ split,
363
+ confidence,
364
+ seed: opts.seed
365
+ })) : [];
366
+ const gainByCandidate = new Map(gains.map((g) => [g.candidateId, g]));
367
+ const paretoByCandidate = new Map(pareto.points.map((p) => [p.candidateId, p]));
368
+ const posteriorByCandidate = /* @__PURE__ */ new Map();
369
+ if (comparator) for (const id of candidateIds) posteriorByCandidate.set(id, pairedPosterior(runs, id, comparator, {
370
+ split,
371
+ confidence,
372
+ seed: opts.seed,
373
+ rope,
374
+ mdePower,
375
+ mdeAlpha
376
+ }));
377
+ const candidates = summary.rows.map((row) => {
378
+ const gain = gainByCandidate.get(row.candidateId);
379
+ const point = paretoByCandidate.get(row.candidateId);
380
+ const posterior = posteriorByCandidate.get(row.candidateId) ?? null;
381
+ const gateDecision = opts.gateDecisions?.[row.candidateId];
382
+ const classified = classifyCandidate(row, {
383
+ comparator,
384
+ posterior,
385
+ point,
386
+ gateDecision,
387
+ split,
388
+ fdr,
389
+ minPairs,
390
+ rope
391
+ });
392
+ return {
393
+ candidateId: row.candidateId,
394
+ n: row.n,
395
+ mean: row.mean,
396
+ ciLow: row.ciLow,
397
+ ciHigh: row.ciHigh,
398
+ qValue: row.qValue,
399
+ cohensD: row.cohensD,
400
+ meanDeltaVsComparator: posterior ? posterior.meanDelta : null,
401
+ pairedN: posterior?.n ?? gain?.n ?? 0,
402
+ medianGain: posterior ? posterior.medianDelta : gain ? gain.median : null,
403
+ meanGain: posterior ? posterior.meanDelta : null,
404
+ gainCi: posterior ? posterior.ci : gain ? gain.ci : null,
405
+ prGreaterThanZero: posterior ? posterior.prGreaterThanZero : null,
406
+ prInRope: posterior ? posterior.prInRope : null,
407
+ mde: posterior ? posterior.mde : null,
408
+ onParetoFrontier: point?.onFrontier ?? false,
409
+ gate: gateDecision ? gateLabel(gateDecision) : void 0,
410
+ decision: classified.decision,
411
+ decisionReason: classified.reason
412
+ };
413
+ }).sort((a, b) => {
414
+ const decisionRank = decisionWeight(b.decision) - decisionWeight(a.decision);
415
+ if (decisionRank !== 0) return decisionRank;
416
+ return b.mean - a.mean;
417
+ });
418
+ const recommendation = buildRecommendation(candidates, {
419
+ comparator,
420
+ failureClusters: opts.failureClusters,
421
+ rope,
422
+ minPairs,
423
+ preregistrationHash
424
+ });
425
+ const executiveSummary = buildExecutiveSummary(candidates, recommendation, {
426
+ comparator,
427
+ split,
428
+ failureClusters: opts.failureClusters,
429
+ preregistrationHash
430
+ });
431
+ const methodology = buildMethodology({
432
+ split,
433
+ comparator,
434
+ fdr,
435
+ minPairs,
436
+ rope,
437
+ confidence,
438
+ mdePower,
439
+ mdeAlpha
440
+ });
441
+ const runFingerprint = await hashJson(canonicalize({
442
+ triples: runs.filter((r) => r.splitTag === split).map((r) => ({
443
+ runId: r.runId,
444
+ candidateId: r.candidateId,
445
+ splitTag: r.splitTag
446
+ })).sort((a, b) => a.runId.localeCompare(b.runId)),
447
+ comparator,
448
+ split
449
+ }));
450
+ const markdown = renderResearchMarkdown({
451
+ title,
452
+ generatedAt,
453
+ split,
454
+ comparator,
455
+ rope,
456
+ runFingerprint,
457
+ preregistrationHash,
458
+ executiveSummary,
459
+ recommendation,
460
+ candidates,
461
+ summary,
462
+ pareto,
463
+ gains,
464
+ methodology,
465
+ failureClusters: opts.failureClusters
466
+ });
467
+ const html = renderResearchHtml(markdown, title);
468
+ return {
469
+ kind: "agent-eval-research-report",
470
+ title,
471
+ generatedAt,
472
+ split,
473
+ comparator,
474
+ runFingerprint,
475
+ preregistrationHash,
476
+ rope,
477
+ executiveSummary,
478
+ recommendation,
479
+ candidates,
480
+ summary,
481
+ charts: {
482
+ pareto,
483
+ gains
484
+ },
485
+ methodology,
486
+ failureClusters: opts.failureClusters,
487
+ markdown,
488
+ html
489
+ };
490
+ }
491
+ function buildMethodology(ctx) {
492
+ const assumptions = [
493
+ "Pairs are matched by (experimentId, scenarioId, seed); input order does not affect the comparison.",
494
+ "Paired deltas are exchangeable conditional on the matched scenario — no mid-run distribution shift.",
495
+ `Decisions are pre-specified at fdr=${ctx.fdr}, minPairs=${ctx.minPairs}, confidence=${ctx.confidence}; deviating from these post-hoc invalidates the false-discovery control.`
496
+ ];
497
+ if (ctx.rope) assumptions.push(`The Region of Practical Equivalence ${formatRope(ctx.rope)} is supplied by the domain owner; equivalent verdicts are only meaningful if that range is treated as the standing definition of "no material difference."`);
498
+ if (ctx.comparator === null) assumptions.push("No comparator was configured; this run is descriptive, not causal.");
499
+ return {
500
+ assumptions,
501
+ methods: [
502
+ "Marginal scores summarised with BH-FDR-adjusted Wilcoxon signed-rank q-values and paired Cohen's dz via summaryTable.",
503
+ "Paired evidence summarised with a frequentist bootstrap CI on the median delta and a Dirichlet-weight Bayesian bootstrap for Pr(Δ>0) and Pr(Δ∈ROPE) on the mean delta.",
504
+ `Minimum detectable effect reported per candidate at α=${ctx.mdeAlpha} (two-sided), power=${ctx.mdePower}, standardised by the observed paired-delta SD.`,
505
+ "Pareto frontier flagged as a separate axis (cost vs quality); a candidate can be on-frontier without winning the paired test.",
506
+ "Held-out gate decisions, when supplied, override the statistical verdict in the reject direction."
507
+ ],
508
+ alternatives: [
509
+ "Paired t-test rejected: not robust to the heavy-tailed score distributions common in agent benchmarks.",
510
+ "Unpaired Mann–Whitney rejected: matched scenarios make pairing free; unpaired throws away that variance reduction.",
511
+ "Sequential / always-valid inference (e-values, mSPRT) is the right tool for iterative sweeps and is out of scope for this single-look report — preregister and run once, or wrap this report in an alpha-spending schedule.",
512
+ "Hierarchical Bayesian shrinkage across many candidates is future work; the current ranking uses raw paired statistics."
513
+ ],
514
+ whenNotToApply: [
515
+ `Paired N below 6 on any candidate — the bootstrap CI is degenerate.`,
516
+ "Comparator chosen post-hoc by inspecting the same data; q-values are no longer false-discovery-controlled.",
517
+ "Scenarios not drawn under a stable preregistered protocol; the report can describe the data but cannot anchor a launch decision.",
518
+ "Score distributions with mid-run shift (judge model swap, rubric change, infra outage) — pair exchangeability is violated."
519
+ ],
520
+ citations: [
521
+ "Benjamini, Y. & Hochberg, Y. (1995). Controlling the false discovery rate: a practical and powerful approach to multiple testing. JRSS B, 57(1), 289–300.",
522
+ "Wilcoxon, F. (1945). Individual comparisons by ranking methods. Biometrics Bulletin, 1(6), 80–83.",
523
+ "Efron, B. (1979). Bootstrap methods: another look at the jackknife. Annals of Statistics, 7(1), 1–26.",
524
+ "Rubin, D. B. (1981). The Bayesian bootstrap. Annals of Statistics, 9(1), 130–134.",
525
+ "Kruschke, J. K. (2018). Rejecting or accepting parameter values in Bayesian estimation. Advances in Methods and Practices in Psychological Science, 1(2), 270–280. (ROPE.)"
526
+ ]
527
+ };
528
+ }
529
+ function formatRope(rope) {
530
+ return `[${fmt(rope.low)}, ${fmt(rope.high)}]`;
531
+ }
532
+ function classifyCandidate(row, ctx) {
533
+ if (ctx.comparator && row.candidateId === ctx.comparator) return {
534
+ decision: "hold",
535
+ reason: "Comparator baseline."
536
+ };
537
+ if (ctx.gateDecision && !ctx.gateDecision.promote) return {
538
+ decision: "reject",
539
+ reason: `Held-out gate returned ${ctx.gateDecision.rejectionCode ?? "rejected"}: ${ctx.gateDecision.reason}`
540
+ };
541
+ if (!ctx.comparator) return {
542
+ decision: ctx.point?.onFrontier ? "hold" : "needs_more_data",
543
+ reason: "No comparator configured; report ranks candidates but cannot anchor a promotion call."
544
+ };
545
+ if (!ctx.posterior || ctx.posterior.n < 6) return {
546
+ decision: "needs_more_data",
547
+ reason: `Only ${ctx.posterior?.n ?? 0} paired observations; below hard floor of 6 for any paired inference.`
548
+ };
549
+ const ci = ctx.posterior.ci;
550
+ if (ctx.split === "search") return {
551
+ decision: "hold",
552
+ reason: "Search-split evidence is descriptive; release decisions require matched holdout runs."
553
+ };
554
+ if (ctx.rope && ci.low >= ctx.rope.low && ci.high <= ctx.rope.high) return {
555
+ decision: "equivalent",
556
+ reason: `Paired-delta CI [${fmt(ci.low)}, ${fmt(ci.high)}] is fully inside ROPE ${formatRope(ctx.rope)}; candidate is practically equivalent to comparator.`
557
+ };
558
+ const gainPositive = ci.low > 0;
559
+ if (ci.high < 0) return {
560
+ decision: "reject",
561
+ reason: `Paired-delta CI [${fmt(ci.low)}, ${fmt(ci.high)}] lies entirely below zero.`
562
+ };
563
+ if (ctx.posterior.n < ctx.minPairs) return {
564
+ decision: "needs_more_data",
565
+ reason: `Only ${ctx.posterior.n} paired observations; minimum detectable effect at this N is ${fmt(ctx.posterior.mde)} score units (need ≥ ${ctx.minPairs} pairs to issue a directional verdict).`
566
+ };
567
+ if (row.qValue !== null && row.qValue <= ctx.fdr && gainPositive) return {
568
+ decision: "promote",
569
+ reason: `BH-adjusted q=${fmt(row.qValue)} ≤ ${ctx.fdr} and paired-delta CI [${fmt(ci.low)}, ${fmt(ci.high)}] excludes zero; Pr(Δ>0)=${fmt(ctx.posterior.prGreaterThanZero)}.`
570
+ };
571
+ return {
572
+ decision: "hold",
573
+ reason: `Pr(Δ>0)=${fmt(ctx.posterior.prGreaterThanZero)} but CI [${fmt(ci.low)}, ${fmt(ci.high)}] crosses zero; effect not decisive at fdr=${ctx.fdr}.`
574
+ };
575
+ }
576
+ function buildRecommendation(candidates, ctx) {
577
+ const nonComparator = candidates.filter((c) => c.candidateId !== ctx.comparator);
578
+ const bestPromote = nonComparator.find((c) => c.decision === "promote");
579
+ const bestEquivalent = nonComparator.find((c) => c.decision === "equivalent");
580
+ const chosen = bestPromote ?? bestEquivalent ?? nonComparator[0] ?? null;
581
+ const decision = bestPromote ? "promote" : nonComparator.some((c) => c.decision === "needs_more_data") ? "needs_more_data" : bestEquivalent ? "equivalent" : nonComparator.some((c) => c.decision === "hold") ? "hold" : "reject";
582
+ const rationale = [];
583
+ const risks = [];
584
+ const nextActions = [];
585
+ if (chosen) {
586
+ rationale.push(`${chosen.candidateId}: ${chosen.decisionReason}`);
587
+ if (chosen.gainCi) {
588
+ const probSummary = chosen.prGreaterThanZero !== null ? `, Pr(Δ>0)=${fmt(chosen.prGreaterThanZero)}` : "";
589
+ rationale.push(`Median paired gain CI: [${fmt(chosen.gainCi.low)}, ${fmt(chosen.gainCi.high)}]${probSummary}.`);
590
+ }
591
+ if (chosen.mde !== null && Number.isFinite(chosen.mde)) rationale.push(`MDE at current paired N=${chosen.pairedN}: ${fmt(chosen.mde)} score units.`);
592
+ }
593
+ if (!ctx.comparator) {
594
+ risks.push("No comparator was configured; verdict is descriptive, not causal.");
595
+ nextActions.push("Re-run with a stable comparator candidate for paired inference.");
596
+ }
597
+ if (!ctx.preregistrationHash) {
598
+ risks.push("No preregistration hash supplied; readers cannot verify the analysis was specified before data inspection.");
599
+ nextActions.push("Sign a HypothesisManifest before the next sweep and pass `preregistrationHash` so the report cites it.");
600
+ }
601
+ if (ctx.rope === null && nonComparator.length > 0) {
602
+ risks.push("No ROPE configured; the report cannot distinguish \"equivalent\" from \"inconclusive\".");
603
+ nextActions.push("Define a domain-specific Region of Practical Equivalence and pass it to lock in the equivalence threshold.");
604
+ }
605
+ const inconclusive = nonComparator.filter((c) => c.decision === "needs_more_data");
606
+ if (inconclusive.length > 0) {
607
+ const worst = inconclusive.reduce((a, b) => b.pairedN < a.pairedN ? b : a);
608
+ risks.push(`${inconclusive.length} candidate(s) below soft floor (${ctx.minPairs} pairs); thinnest is ${worst.candidateId} with ${worst.pairedN}.`);
609
+ nextActions.push(`Collect at least ${ctx.minPairs - worst.pairedN} more matched holdout runs for ${worst.candidateId}.`);
610
+ }
611
+ const rejected = nonComparator.filter((c) => c.decision === "reject");
612
+ if (rejected.length > 0) risks.push(`${rejected.length} candidate(s) failed the paired test or held-out gate; do not ship those variants.`);
613
+ if (ctx.failureClusters && ctx.failureClusters.clusters.length > 0) {
614
+ const top = ctx.failureClusters.clusters[0];
615
+ risks.push(`Top failure cluster: ${top.failureClass} across ${top.runCount} run(s).`);
616
+ nextActions.push("Prioritize the largest failure cluster before broad rollout.");
617
+ }
618
+ if (decision === "promote") nextActions.push("Ship behind the existing promotion gate and monitor canaries.");
619
+ else if (decision === "hold") nextActions.push("Keep current production candidate while expanding holdout evidence.");
620
+ else if (decision === "equivalent") nextActions.push("Either keep the comparator (no quality regression) or promote on cost/latency grounds — equivalence does not justify either; the choice is a product decision, not a stats one.");
621
+ else if (decision === "reject") nextActions.push("Do not promote this sweep; inspect failures and generate a revised candidate.");
622
+ return {
623
+ decision,
624
+ candidateId: chosen?.candidateId ?? null,
625
+ rationale,
626
+ risks,
627
+ nextActions
628
+ };
629
+ }
630
+ function buildExecutiveSummary(candidates, recommendation, ctx) {
631
+ const lines = [];
632
+ const nonComparator = candidates.filter((c) => c.candidateId !== ctx.comparator);
633
+ lines.push(`Evaluated ${nonComparator.length} candidate(s) on the ${ctx.split} split${ctx.comparator ? ` against ${ctx.comparator}` : ""}.`);
634
+ lines.push(`Recommendation: ${recommendation.decision}${recommendation.candidateId ? ` ${recommendation.candidateId}` : ""}.`);
635
+ const promoted = nonComparator.filter((c) => c.decision === "promote").length;
636
+ const held = nonComparator.filter((c) => c.decision === "hold").length;
637
+ const equivalent = nonComparator.filter((c) => c.decision === "equivalent").length;
638
+ const rejected = nonComparator.filter((c) => c.decision === "reject").length;
639
+ const more = nonComparator.filter((c) => c.decision === "needs_more_data").length;
640
+ lines.push(`Decision mix: ${promoted} promote, ${equivalent} equivalent, ${held} hold, ${rejected} reject, ${more} need more data.`);
641
+ const frontier = nonComparator.filter((c) => c.onParetoFrontier).map((c) => c.candidateId);
642
+ if (frontier.length > 0) lines.push(`Pareto-frontier candidates: ${frontier.join(", ")}.`);
643
+ if (ctx.failureClusters) lines.push(`Failure clustering found ${ctx.failureClusters.totalFailures}/${ctx.failureClusters.totalRuns} failed runs across ${ctx.failureClusters.clusters.length} reportable cluster(s).`);
644
+ lines.push(ctx.preregistrationHash ? `Preregistered analysis: ${ctx.preregistrationHash.slice(0, 12)}…` : "Analysis is post-hoc — no preregistration hash supplied.");
645
+ return lines;
646
+ }
647
+ function renderResearchMarkdown(report) {
648
+ const lines = [];
649
+ lines.push(`# ${report.title}`);
650
+ lines.push("");
651
+ lines.push(`**Generated:** ${report.generatedAt}`);
652
+ lines.push(`**Primary split:** ${report.split}`);
653
+ lines.push(`**Comparator:** ${report.comparator ?? "not configured"}`);
654
+ lines.push(`**ROPE:** ${report.rope ? formatRope(report.rope) : "not configured"}`);
655
+ lines.push(`**Run fingerprint:** \`${report.runFingerprint}\``);
656
+ lines.push(`**Preregistration:** ${report.preregistrationHash ? `\`${report.preregistrationHash}\`` : "none"}`);
657
+ lines.push("");
658
+ lines.push("## Executive Summary");
659
+ lines.push("");
660
+ for (const item of report.executiveSummary) lines.push(`- ${item}`);
661
+ lines.push("");
662
+ lines.push("## Recommendation");
663
+ lines.push("");
664
+ lines.push(`**Decision:** ${report.recommendation.decision}`);
665
+ lines.push(`**Candidate:** ${report.recommendation.candidateId ?? "N/A"}`);
666
+ lines.push("");
667
+ lines.push("### Rationale");
668
+ lines.push("");
669
+ for (const item of report.recommendation.rationale) lines.push(`- ${item}`);
670
+ lines.push("");
671
+ lines.push("### Risks");
672
+ lines.push("");
673
+ for (const item of report.recommendation.risks.length ? report.recommendation.risks : ["No material report-level risks detected."]) lines.push(`- ${item}`);
674
+ lines.push("");
675
+ lines.push("### Next Actions");
676
+ lines.push("");
677
+ for (const item of report.recommendation.nextActions) lines.push(`- ${item}`);
678
+ lines.push("");
679
+ lines.push("## Candidate Decision Table");
680
+ lines.push("");
681
+ lines.push("| Candidate | Decision | Mean | Δ̄ | Pr(Δ>0) | q | dz | Paired N | Median Gain CI | MDE | Pareto | Gate |");
682
+ lines.push("|---|---|---:|---:|---:|---:|---:|---:|---|---:|---|---|");
683
+ for (const c of report.candidates) {
684
+ const delta = c.meanDeltaVsComparator === null ? "-" : signed(c.meanDeltaVsComparator);
685
+ const prGt = c.prGreaterThanZero === null ? "-" : c.prGreaterThanZero.toFixed(3);
686
+ const q = c.qValue !== null ? c.qValue.toFixed(4) : "-";
687
+ const d = c.cohensD !== null ? c.cohensD.toFixed(3) : "-";
688
+ const gain = c.gainCi ? `[${fmt(c.gainCi.low)}, ${fmt(c.gainCi.high)}]` : "-";
689
+ const mde = c.mde === null || !Number.isFinite(c.mde) ? "-" : fmt(c.mde);
690
+ lines.push(`| ${c.candidateId} | ${c.decision} | ${fmt(c.mean)} | ${delta} | ${prGt} | ${q} | ${d} | ${c.pairedN} | ${gain} | ${mde} | ${c.onParetoFrontier ? "yes" : "no"} | ${c.gate ?? "-"} |`);
691
+ }
692
+ lines.push("");
693
+ lines.push("## Statistical Summary");
694
+ lines.push("");
695
+ lines.push(report.summary.markdown);
696
+ lines.push("");
697
+ lines.push("## Methodology");
698
+ lines.push("");
699
+ lines.push("### Assumptions");
700
+ lines.push("");
701
+ for (const item of report.methodology.assumptions) lines.push(`- ${item}`);
702
+ lines.push("");
703
+ lines.push("### Methods");
704
+ lines.push("");
705
+ for (const item of report.methodology.methods) lines.push(`- ${item}`);
706
+ lines.push("");
707
+ lines.push("### Alternatives Considered");
708
+ lines.push("");
709
+ for (const item of report.methodology.alternatives) lines.push(`- ${item}`);
710
+ lines.push("");
711
+ lines.push("### When NOT To Apply");
712
+ lines.push("");
713
+ for (const item of report.methodology.whenNotToApply) lines.push(`- ${item}`);
714
+ lines.push("");
715
+ lines.push("### Citations");
716
+ lines.push("");
717
+ for (const item of report.methodology.citations) lines.push(`- ${item}`);
718
+ lines.push("");
719
+ lines.push("## Chart Specs");
720
+ lines.push("");
721
+ lines.push("The report carries JSON chart specs for Pareto cost/quality and paired gain histograms.");
722
+ lines.push("");
723
+ lines.push("```json");
724
+ lines.push(JSON.stringify({
725
+ pareto: report.pareto,
726
+ gains: report.gains
727
+ }, null, 2));
728
+ lines.push("```");
729
+ if (report.failureClusters) {
730
+ lines.push("");
731
+ lines.push("## Failure Clusters");
732
+ lines.push("");
733
+ lines.push("| Failure Class | Runs | Scenarios | Tool | Example |");
734
+ lines.push("|---|---:|---:|---|---|");
735
+ for (const c of report.failureClusters.clusters.slice(0, 10)) lines.push(`| ${c.failureClass} | ${c.runCount} | ${c.scenarioIds.length} | ${c.toolName ?? "-"} | ${escapePipes(c.exampleError ?? c.exampleRunId)} |`);
736
+ }
737
+ return lines.join("\n");
738
+ }
739
+ function renderResearchHtml(markdown, title) {
740
+ const body = markdownToHtml(markdown);
741
+ return [
742
+ "<!doctype html>",
743
+ "<html lang=\"en\">",
744
+ "<head>",
745
+ "<meta charset=\"utf-8\">",
746
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">",
747
+ `<title>${escapeHtml(title)}</title>`,
748
+ "<style>",
749
+ "body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;margin:0;color:#172026;background:#f7f8f8;}",
750
+ "main{max-width:1080px;margin:0 auto;padding:40px 24px 64px;background:#fff;min-height:100vh;}",
751
+ "h1{font-size:34px;line-height:1.15;margin:0 0 20px;}h2{margin-top:34px;border-top:1px solid #d9dfdf;padding-top:22px;}h3{margin-top:22px;}",
752
+ "p,li{line-height:1.55;}table{border-collapse:collapse;width:100%;margin:16px 0;font-size:14px;}th,td{border:1px solid #d9dfdf;padding:8px;text-align:left;}th{background:#eef2f2;}",
753
+ "code,pre{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}pre{overflow:auto;background:#111827;color:#f9fafb;padding:16px;border-radius:6px;}",
754
+ "</style>",
755
+ "</head>",
756
+ "<body><main>",
757
+ body,
758
+ "</main></body></html>"
759
+ ].join("\n");
760
+ }
761
+ function markdownToHtml(markdown) {
762
+ const lines = markdown.split("\n");
763
+ const html = [];
764
+ let inList = false;
765
+ let inCode = false;
766
+ let code = [];
767
+ let table = [];
768
+ const flushList = () => {
769
+ if (inList) {
770
+ html.push("</ul>");
771
+ inList = false;
772
+ }
773
+ };
774
+ const flushTable = () => {
775
+ if (table.length === 0) return;
776
+ html.push(renderMarkdownTable(table));
777
+ table = [];
778
+ };
779
+ for (const line of lines) {
780
+ if (line.startsWith("```")) {
781
+ if (inCode) {
782
+ html.push(`<pre><code>${escapeHtml(code.join("\n"))}</code></pre>`);
783
+ code = [];
784
+ inCode = false;
785
+ } else {
786
+ flushList();
787
+ flushTable();
788
+ inCode = true;
789
+ }
790
+ continue;
791
+ }
792
+ if (inCode) {
793
+ code.push(line);
794
+ continue;
795
+ }
796
+ if (line.startsWith("|")) {
797
+ flushList();
798
+ table.push(line);
799
+ continue;
800
+ }
801
+ flushTable();
802
+ if (line.startsWith("- ")) {
803
+ if (!inList) {
804
+ html.push("<ul>");
805
+ inList = true;
806
+ }
807
+ html.push(`<li>${inlineMarkdown(line.slice(2))}</li>`);
808
+ continue;
809
+ }
810
+ flushList();
811
+ if (line.startsWith("# ")) html.push(`<h1>${inlineMarkdown(line.slice(2))}</h1>`);
812
+ else if (line.startsWith("## ")) html.push(`<h2>${inlineMarkdown(line.slice(3))}</h2>`);
813
+ else if (line.startsWith("### ")) html.push(`<h3>${inlineMarkdown(line.slice(4))}</h3>`);
814
+ else if (line.trim() === "") html.push("");
815
+ else html.push(`<p>${inlineMarkdown(line)}</p>`);
816
+ }
817
+ flushList();
818
+ flushTable();
819
+ return html.join("\n");
820
+ }
821
+ function renderMarkdownTable(lines) {
822
+ const rows = lines.filter((line) => !/^\|[-:\s|]+\|$/.test(line)).map((line) => line.slice(1, -1).split("|").map((cell) => inlineMarkdown(cell.trim())));
823
+ if (rows.length === 0) return "";
824
+ const [head, ...body] = rows;
825
+ return `<table><thead><tr>${head.map((cell) => `<th>${cell}</th>`).join("")}</tr></thead><tbody>${body.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("\n")}</tbody></table>`;
826
+ }
827
+ function inlineMarkdown(s) {
828
+ return escapeHtml(s).replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
829
+ }
830
+ function escapeHtml(s) {
831
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
832
+ }
833
+ function escapePipes(s) {
834
+ return s.replace(/\|/g, "\\|");
835
+ }
836
+ function decisionWeight(decision) {
837
+ if (decision === "promote") return 5;
838
+ if (decision === "equivalent") return 4;
839
+ if (decision === "hold") return 3;
840
+ if (decision === "needs_more_data") return 2;
841
+ return 1;
842
+ }
843
+ function signed(x) {
844
+ return `${x >= 0 ? "+" : ""}${fmt(x)}`;
845
+ }
846
+ function avg(xs) {
847
+ if (xs.length === 0) return NaN;
848
+ return xs.reduce((s, x) => s + x, 0) / xs.length;
849
+ }
850
+ function medianOfSorted(sorted) {
851
+ if (sorted.length === 0) return 0;
852
+ const mid = Math.floor(sorted.length / 2);
853
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
854
+ }
855
+ function fmt(x) {
856
+ if (!Number.isFinite(x)) return String(x);
857
+ return x.toFixed(4);
858
+ }
859
+ //#endregion
860
+ export { summaryTable as a, researchReport as i, gainHistogram as n, paretoChart as r, RESEARCH_REPORT_HARD_PAIR_FLOOR as t };
861
+
862
+ //# sourceMappingURL=summary-report-BNs5nmXI.js.map