@tangle-network/agent-eval 0.128.2 → 0.130.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 (424) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/README.md +19 -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 +83 -2932
  8. package/dist/analyst/index.d.ts.map +1 -0
  9. package/dist/analyst/index.js +319 -364
  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 -1205
  30. package/dist/belief-state/index.d.ts.map +1 -0
  31. package/dist/belief-state/index.js +1617 -1710
  32. package/dist/belief-state/index.js.map +1 -1
  33. package/dist/benchmarks/index.d.ts +2 -894
  34. package/dist/benchmarks/index.js +2 -59
  35. package/dist/benchmarks-DviOvUNr.js +754 -0
  36. package/dist/benchmarks-DviOvUNr.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 -6390
  44. package/dist/campaign/index.js +3 -212
  45. package/dist/campaign-CBKZvQ1H.js +3885 -0
  46. package/dist/campaign-CBKZvQ1H.js.map +1 -0
  47. package/dist/cli.d.ts +1 -1
  48. package/dist/cli.js +164 -174
  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 -5605
  61. package/dist/contract/index.d.ts.map +1 -0
  62. package/dist/contract/index.js +1730 -1937
  63. package/dist/contract/index.js.map +1 -1
  64. package/dist/control.d.ts +3 -1030
  65. package/dist/control.js +2 -32
  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 -617
  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-CAPUUKaM.d.ts +335 -0
  116. package/dist/index-CAPUUKaM.d.ts.map +1 -0
  117. package/dist/index-DE5fb3EC.d.ts +2244 -0
  118. package/dist/index-DE5fb3EC.d.ts.map +1 -0
  119. package/dist/index-DSC51roc.d.ts +102 -0
  120. package/dist/index-DSC51roc.d.ts.map +1 -0
  121. package/dist/index.d.ts +3776 -15120
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +11185 -11191
  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 -481
  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 -1298
  196. package/dist/reporting.js +6 -50
  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 +916 -3596
  206. package/dist/rl.d.ts.map +1 -0
  207. package/dist/rl.js +2362 -1751
  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 -1048
  211. package/dist/rollout/index.js +8 -110
  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/run-record-BuoE80Dq.js.map +1 -0
  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-B7wX7XkF.d.ts +1739 -0
  253. package/dist/skillopt-optimization-method-B7wX7XkF.d.ts.map +1 -0
  254. package/dist/skillopt-optimization-method-D4ODwFVV.js +7712 -0
  255. package/dist/skillopt-optimization-method-D4ODwFVV.js.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 -849
  273. package/dist/supervisor-run/index.js +2 -64
  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 -251
  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 -1174
  298. package/dist/wire/index.d.ts.map +1 -0
  299. package/dist/wire/index.js +2 -81
  300. package/docs/feature-guide.md +1 -1
  301. package/docs/rollout.md +116 -2
  302. package/package.json +18 -10
  303. package/dist/benchmarks/index.js.map +0 -1
  304. package/dist/campaign/index.js.map +0 -1
  305. package/dist/chunk-2JX3CFMB.js +0 -695
  306. package/dist/chunk-2JX3CFMB.js.map +0 -1
  307. package/dist/chunk-2MKQIFS4.js +0 -183
  308. package/dist/chunk-2MKQIFS4.js.map +0 -1
  309. package/dist/chunk-3RF76KTD.js +0 -84
  310. package/dist/chunk-3RF76KTD.js.map +0 -1
  311. package/dist/chunk-5DTSBUL2.js +0 -159
  312. package/dist/chunk-5DTSBUL2.js.map +0 -1
  313. package/dist/chunk-7ZZMD7UK.js +0 -386
  314. package/dist/chunk-7ZZMD7UK.js.map +0 -1
  315. package/dist/chunk-BOD4O7OF.js +0 -40
  316. package/dist/chunk-BOD4O7OF.js.map +0 -1
  317. package/dist/chunk-BYT7ELPS.js +0 -1553
  318. package/dist/chunk-BYT7ELPS.js.map +0 -1
  319. package/dist/chunk-DJKY2TSY.js +0 -2428
  320. package/dist/chunk-DJKY2TSY.js.map +0 -1
  321. package/dist/chunk-DPUHNQLN.js +0 -232
  322. package/dist/chunk-DPUHNQLN.js.map +0 -1
  323. package/dist/chunk-DRYIUNWY.js +0 -622
  324. package/dist/chunk-DRYIUNWY.js.map +0 -1
  325. package/dist/chunk-EJGRPCO3.js +0 -617
  326. package/dist/chunk-EJGRPCO3.js.map +0 -1
  327. package/dist/chunk-EOSZT7PL.js +0 -2001
  328. package/dist/chunk-EOSZT7PL.js.map +0 -1
  329. package/dist/chunk-EZJEIH2R.js +0 -1559
  330. package/dist/chunk-EZJEIH2R.js.map +0 -1
  331. package/dist/chunk-GGE4NNQT.js +0 -65
  332. package/dist/chunk-GGE4NNQT.js.map +0 -1
  333. package/dist/chunk-HHWE3POT.js +0 -94
  334. package/dist/chunk-HHWE3POT.js.map +0 -1
  335. package/dist/chunk-IHQDPH7D.js +0 -171
  336. package/dist/chunk-IHQDPH7D.js.map +0 -1
  337. package/dist/chunk-JHCHEVET.js +0 -274
  338. package/dist/chunk-JHCHEVET.js.map +0 -1
  339. package/dist/chunk-K4DBDHLK.js +0 -158
  340. package/dist/chunk-K4DBDHLK.js.map +0 -1
  341. package/dist/chunk-K6N6XJJX.js +0 -306
  342. package/dist/chunk-K6N6XJJX.js.map +0 -1
  343. package/dist/chunk-MA6HLL3S.js +0 -65
  344. package/dist/chunk-MA6HLL3S.js.map +0 -1
  345. package/dist/chunk-MAZ26DC7.js +0 -99
  346. package/dist/chunk-MAZ26DC7.js.map +0 -1
  347. package/dist/chunk-MHELPNRP.js +0 -1212
  348. package/dist/chunk-MHELPNRP.js.map +0 -1
  349. package/dist/chunk-NACAGYSY.js +0 -1040
  350. package/dist/chunk-NACAGYSY.js.map +0 -1
  351. package/dist/chunk-NKAGIDE2.js +0 -7633
  352. package/dist/chunk-NKAGIDE2.js.map +0 -1
  353. package/dist/chunk-NPCTHQIO.js +0 -91
  354. package/dist/chunk-NPCTHQIO.js.map +0 -1
  355. package/dist/chunk-NYLOYM6N.js +0 -332
  356. package/dist/chunk-NYLOYM6N.js.map +0 -1
  357. package/dist/chunk-ONWEPEDO.js +0 -57
  358. package/dist/chunk-ONWEPEDO.js.map +0 -1
  359. package/dist/chunk-P5W7RQKK.js +0 -576
  360. package/dist/chunk-P5W7RQKK.js.map +0 -1
  361. package/dist/chunk-P6FYH6K4.js +0 -1161
  362. package/dist/chunk-P6FYH6K4.js.map +0 -1
  363. package/dist/chunk-PBE2LOSS.js +0 -669
  364. package/dist/chunk-PBE2LOSS.js.map +0 -1
  365. package/dist/chunk-PC4UYEBM.js +0 -166
  366. package/dist/chunk-PC4UYEBM.js.map +0 -1
  367. package/dist/chunk-PXE2VKMX.js +0 -140
  368. package/dist/chunk-PXE2VKMX.js.map +0 -1
  369. package/dist/chunk-PZ5AY32C.js +0 -10
  370. package/dist/chunk-PZ5AY32C.js.map +0 -1
  371. package/dist/chunk-RZTMDUO7.js +0 -49
  372. package/dist/chunk-RZTMDUO7.js.map +0 -1
  373. package/dist/chunk-S5YLIBFX.js +0 -136
  374. package/dist/chunk-S5YLIBFX.js.map +0 -1
  375. package/dist/chunk-SZLVEKMJ.js +0 -1446
  376. package/dist/chunk-SZLVEKMJ.js.map +0 -1
  377. package/dist/chunk-T4SQEITX.js +0 -95
  378. package/dist/chunk-T4SQEITX.js.map +0 -1
  379. package/dist/chunk-TBL77AUT.js +0 -355
  380. package/dist/chunk-TBL77AUT.js.map +0 -1
  381. package/dist/chunk-TSN7JT6D.js +0 -1646
  382. package/dist/chunk-TSN7JT6D.js.map +0 -1
  383. package/dist/chunk-TT4KNT67.js +0 -124
  384. package/dist/chunk-TT4KNT67.js.map +0 -1
  385. package/dist/chunk-UB2LOJ6Q.js +0 -4461
  386. package/dist/chunk-UB2LOJ6Q.js.map +0 -1
  387. package/dist/chunk-UWZZKKU7.js +0 -237
  388. package/dist/chunk-UWZZKKU7.js.map +0 -1
  389. package/dist/chunk-VBQ3CRKH.js +0 -291
  390. package/dist/chunk-VBQ3CRKH.js.map +0 -1
  391. package/dist/chunk-VGRCHJON.js +0 -163
  392. package/dist/chunk-VGRCHJON.js.map +0 -1
  393. package/dist/chunk-VI2UW6B6.js +0 -162
  394. package/dist/chunk-VI2UW6B6.js.map +0 -1
  395. package/dist/chunk-VLOATJQ2.js +0 -908
  396. package/dist/chunk-VLOATJQ2.js.map +0 -1
  397. package/dist/chunk-VQMK5FMP.js +0 -247
  398. package/dist/chunk-VQMK5FMP.js.map +0 -1
  399. package/dist/chunk-VZSRQ272.js +0 -149
  400. package/dist/chunk-VZSRQ272.js.map +0 -1
  401. package/dist/chunk-WGXIEX7P.js +0 -116
  402. package/dist/chunk-WGXIEX7P.js.map +0 -1
  403. package/dist/chunk-WS3NZZQQ.js +0 -929
  404. package/dist/chunk-WS3NZZQQ.js.map +0 -1
  405. package/dist/chunk-XDWDC2MP.js +0 -695
  406. package/dist/chunk-XDWDC2MP.js.map +0 -1
  407. package/dist/chunk-XPRT64IE.js +0 -766
  408. package/dist/chunk-XPRT64IE.js.map +0 -1
  409. package/dist/chunk-YJBNWCAA.js +0 -1056
  410. package/dist/chunk-YJBNWCAA.js.map +0 -1
  411. package/dist/chunk-ZET2UAYW.js +0 -89
  412. package/dist/chunk-ZET2UAYW.js.map +0 -1
  413. package/dist/chunk-ZUUWPZCV.js +0 -752
  414. package/dist/chunk-ZUUWPZCV.js.map +0 -1
  415. package/dist/control.js.map +0 -1
  416. package/dist/hosted/index.js.map +0 -1
  417. package/dist/matrix/index.js.map +0 -1
  418. package/dist/reporting.js.map +0 -1
  419. package/dist/rollout/index.js.map +0 -1
  420. package/dist/run-campaign-ISHFZ7FJ.js +0 -17
  421. package/dist/run-campaign-ISHFZ7FJ.js.map +0 -1
  422. package/dist/supervisor-run/index.js.map +0 -1
  423. package/dist/traces.js.map +0 -1
  424. package/dist/wire/index.js.map +0 -1
@@ -0,0 +1,1679 @@
1
+ import { c as unscreenedRewardFields } from "./reward-nw2xZGZG.js";
2
+ import { f as isRolloutLine, i as ROLLOUT_SCHEMA } from "./schema-C6DW4ZHR.js";
3
+ import { d as transcriptFromEntries, i as openOpencodeDb, l as parseClaudeEntries, r as findOpencodeSessionsByDirectory, t as DEFAULT_OPENCODE_DB } from "./opencode-sqlite-BGrHeDu3.js";
4
+ import { basename, dirname, join } from "node:path";
5
+ import { appendFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
6
+ //#region src/supervisor-run/types.ts
7
+ function unavailable(reason) {
8
+ return { unavailable: reason };
9
+ }
10
+ function isUnavailable(v) {
11
+ return typeof v === "object" && v !== null && typeof v.unavailable === "string";
12
+ }
13
+ /** Render a measured scalar for the markdown/headline: `0` and `unavailable` stay distinct. */
14
+ function showMeasured(v) {
15
+ if (isUnavailable(v)) return `unavailable — ${v.unavailable}`;
16
+ if (v === null) return "null";
17
+ return String(v);
18
+ }
19
+ /** A source that carries every fact the analyzer can use. */
20
+ const NO_SOURCE_LIMITS = {
21
+ spendUsd: null,
22
+ workerVerdicts: null,
23
+ deliverables: null
24
+ };
25
+ const SUPERVISOR_RUN_SCHEMA = "tangle.supervisor-run@1";
26
+ const SUPERVISOR_RUN_ROLLUP_SCHEMA = "tangle.supervisor-run-rollup@1";
27
+ //#endregion
28
+ //#region src/supervisor-run/analyze.ts
29
+ /**
30
+ * The pure analyzer. Takes already-read bytes (`SupervisorRunSources`) and
31
+ * returns the report — every metric derivable from a synthetic journal string
32
+ * with no filesystem, no process, and no network. All I/O lives in a reader
33
+ * (`loops-reader.ts` is one).
34
+ */
35
+ function asRecord(v) {
36
+ return typeof v === "object" && v !== null ? v : {};
37
+ }
38
+ function num(v) {
39
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
40
+ }
41
+ function readSpend(v) {
42
+ const rec = asRecord(v);
43
+ const tok = asRecord(rec.tokens);
44
+ const cacheRead = tok.cacheRead ?? tok.cache_read;
45
+ const cacheWrite = tok.cacheWrite ?? tok.cache_write;
46
+ return {
47
+ tokens: {
48
+ input: num(tok.input),
49
+ output: num(tok.output),
50
+ cacheRead: num(cacheRead),
51
+ cacheWrite: num(cacheWrite),
52
+ hasCache: cacheRead !== void 0 || cacheWrite !== void 0
53
+ },
54
+ usd: num(rec.usd)
55
+ };
56
+ }
57
+ const NO_CACHE_COUNTERS = "the journal carries no cache-token counters for this role";
58
+ function parseJsonl(text) {
59
+ if (text === null) return [];
60
+ const out = [];
61
+ for (const line of text.split("\n")) {
62
+ const trimmed = line.trim();
63
+ if (!trimmed) continue;
64
+ try {
65
+ const parsed = JSON.parse(trimmed);
66
+ if (typeof parsed === "object" && parsed !== null) out.push(parsed);
67
+ } catch {}
68
+ }
69
+ return out;
70
+ }
71
+ function parseJson(text) {
72
+ if (text === null) return null;
73
+ try {
74
+ const parsed = JSON.parse(text);
75
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+ function ms(at) {
81
+ if (typeof at !== "string") return null;
82
+ const t = Date.parse(at);
83
+ return Number.isFinite(t) ? t : null;
84
+ }
85
+ function parseSupervisorTree(src) {
86
+ const events = parseJsonl(src.journal);
87
+ const state = parseJson(src.state);
88
+ const spawns = [];
89
+ const closes = [];
90
+ let brainIn = 0;
91
+ let brainOut = 0;
92
+ let brainCacheRead = 0;
93
+ let brainCacheWrite = 0;
94
+ let brainHasCache = false;
95
+ let brainUsd = 0;
96
+ let meteredCount = 0;
97
+ let rootId = null;
98
+ for (const ev of events) {
99
+ const kind = typeof ev.kind === "string" ? ev.kind : "";
100
+ const id = typeof ev.id === "string" ? ev.id : "";
101
+ if (kind === "spawned") {
102
+ const parent = typeof ev.parent === "string" ? ev.parent : null;
103
+ const label = typeof ev.label === "string" ? ev.label : "";
104
+ if (parent === null && rootId === null) rootId = id;
105
+ spawns.push({
106
+ id,
107
+ parent,
108
+ label,
109
+ at: ms(ev.at)
110
+ });
111
+ } else if (kind === "settled") closes.push({
112
+ id,
113
+ kind: "settled",
114
+ status: typeof ev.status === "string" ? ev.status : null,
115
+ verdict: typeof ev.verdict === "string" ? ev.verdict : null,
116
+ at: ms(ev.at),
117
+ spend: readSpend(ev.spent),
118
+ hasSpend: asRecord(ev.spent).tokens !== void 0
119
+ });
120
+ else if (kind === "cancelled") closes.push({
121
+ id,
122
+ kind: "cancelled",
123
+ status: "cancelled",
124
+ verdict: typeof ev.reason === "string" ? ev.reason : null,
125
+ at: ms(ev.at),
126
+ spend: {
127
+ tokens: {
128
+ input: 0,
129
+ output: 0,
130
+ cacheRead: 0,
131
+ cacheWrite: 0,
132
+ hasCache: false
133
+ },
134
+ usd: 0
135
+ },
136
+ hasSpend: false
137
+ });
138
+ else if (kind === "metered") {
139
+ const s = readSpend(ev.spend);
140
+ brainIn += s.tokens.input;
141
+ brainOut += s.tokens.output;
142
+ brainCacheRead += s.tokens.cacheRead;
143
+ brainCacheWrite += s.tokens.cacheWrite;
144
+ brainHasCache = brainHasCache || s.tokens.hasCache;
145
+ brainUsd += s.usd;
146
+ meteredCount += 1;
147
+ }
148
+ }
149
+ const workerSpawns = spawns.filter((s) => s.id !== rootId);
150
+ const workerIds = new Set(workerSpawns.map((s) => s.id));
151
+ const workerCloses = closes.filter((c) => workerIds.has(c.id));
152
+ const workerLogs = /* @__PURE__ */ new Map();
153
+ for (const w of src.workers ?? []) {
154
+ const facts = {
155
+ started: null,
156
+ finished: false,
157
+ finishedAt: null,
158
+ passed: null,
159
+ finishedPatchBytes: null,
160
+ evidenceBytes: 0,
161
+ steersQueued: 0,
162
+ steersDelivered: 0,
163
+ questions: 0
164
+ };
165
+ for (const req of parseJsonl(w.inbox)) if (typeof req.message === "string" && req.message.trim().length > 0) facts.steersQueued += 1;
166
+ for (const ev of parseJsonl(w.events)) {
167
+ const kind = ev.kind;
168
+ if (kind === "message") {
169
+ if (ev.direction === "up") {
170
+ facts.questions += 1;
171
+ continue;
172
+ }
173
+ if (typeof ev.requestId !== "string") facts.steersQueued += 1;
174
+ if (ev.delivered === true) facts.steersDelivered += 1;
175
+ } else if (kind === "started") facts.started = ms(ev.at);
176
+ else if (kind === "finished") {
177
+ facts.finished = true;
178
+ facts.finishedAt = ms(ev.at);
179
+ facts.passed = typeof ev.passed === "boolean" ? ev.passed : null;
180
+ facts.finishedPatchBytes = typeof ev.patchBytes === "number" ? ev.patchBytes : null;
181
+ facts.evidenceBytes = typeof ev.evidence === "string" ? ev.evidence.length : 0;
182
+ }
183
+ }
184
+ workerLogs.set(w.label, facts);
185
+ }
186
+ const startedAt = ms(state?.startedAt) ?? spawns[0]?.at ?? null;
187
+ const completedAt = ms(state?.completedAt) ?? [...spawns.map((s) => s.at), ...closes.map((c) => c.at)].reduce((acc, t) => t === null ? acc : acc === null ? t : Math.max(acc, t), null);
188
+ return {
189
+ rootId,
190
+ spawns,
191
+ closes,
192
+ workerSpawns,
193
+ workerCloses,
194
+ brain: {
195
+ tokensIn: brainIn,
196
+ tokensOut: brainOut,
197
+ cacheRead: brainCacheRead,
198
+ cacheWrite: brainCacheWrite,
199
+ hasCache: brainHasCache,
200
+ usd: brainUsd,
201
+ meteredCount
202
+ },
203
+ workerLogs,
204
+ startedAt,
205
+ completedAt
206
+ };
207
+ }
208
+ /**
209
+ * Analyze already-read supervisor-run bytes. Pure and synchronous: same bytes
210
+ * in, same report out (modulo `generatedAt`, which `now` pins in tests).
211
+ */
212
+ function analyzeSupervisorRunSources(src, now = Date.now) {
213
+ const gaps = [];
214
+ const gap = (what, reason) => {
215
+ gaps.push(`${what}: ${reason}`);
216
+ return unavailable(reason);
217
+ };
218
+ const journalMissing = src.supRunDir === null ? "no supervisor run dir under <ws>/.loops/supervisor" : "journal.jsonl absent";
219
+ const haveJournal = src.journal !== null;
220
+ const state = parseJson(src.state);
221
+ const result = parseJson(src.result);
222
+ const judge = parseJson(src.judge);
223
+ const tree = parseSupervisorTree(src);
224
+ const { rootId, workerSpawns, workerCloses, startedAt, completedAt } = tree;
225
+ const supervisorWallMs = startedAt !== null && completedAt !== null && completedAt >= startedAt ? completedAt - startedAt : !haveJournal ? gap("supervisorWallMs", journalMissing) : gap("supervisorWallMs", "no parseable start/complete timestamps in state.json or journal");
226
+ const steerRows = [];
227
+ let steerQueuedTotal = 0;
228
+ let steerDeliveredTotal = 0;
229
+ let upLegMessages = 0;
230
+ if (src.workers !== null) for (const w of src.workers) {
231
+ const facts = tree.workerLogs.get(w.label);
232
+ const queued = facts?.steersQueued ?? 0;
233
+ const delivered = facts?.steersDelivered ?? 0;
234
+ upLegMessages += facts?.questions ?? 0;
235
+ steerRows.push({
236
+ worker: w.label,
237
+ queued,
238
+ delivered
239
+ });
240
+ steerQueuedTotal += queued;
241
+ steerDeliveredTotal += delivered;
242
+ }
243
+ const workersGapReason = src.workersMissingReason ?? "workers/ directory absent";
244
+ const steers = src.workers === null ? gap("steers", workersGapReason) : steerQueuedTotal;
245
+ const steersDelivered = src.workers === null ? unavailable(workersGapReason) : steerDeliveredTotal;
246
+ const steersByWorker = src.workers === null ? unavailable(workersGapReason) : steerRows;
247
+ const driverSteerCalls = src.driverLog === null ? gap("driverSteerCalls", "driver.log absent") : Math.max(0, (src.driverLog.match(/supervisor_steer/g) ?? []).length - registrationMentions(src.driverLog));
248
+ const timeline = [];
249
+ for (const s of workerSpawns) if (s.at !== null) timeline.push({
250
+ at: s.at,
251
+ delta: 1
252
+ });
253
+ for (const c of workerCloses) if (c.at !== null) timeline.push({
254
+ at: c.at,
255
+ delta: -1
256
+ });
257
+ timeline.sort((a, b) => a.at - b.at || a.delta - b.delta);
258
+ let waves = 0;
259
+ const waveSizes = [];
260
+ let closedSinceWaveStart = true;
261
+ for (const step of timeline) if (step.delta === 1) {
262
+ if (closedSinceWaveStart) {
263
+ waves += 1;
264
+ waveSizes.push(0);
265
+ closedSinceWaveStart = false;
266
+ }
267
+ waveSizes[waveSizes.length - 1] = (waveSizes[waveSizes.length - 1] ?? 0) + 1;
268
+ } else closedSinceWaveStart = true;
269
+ let live = 0;
270
+ let maxConcurrency = 0;
271
+ let idleMs = 0;
272
+ let sumWorkerWallMs = 0;
273
+ let prev = startedAt;
274
+ for (const step of timeline) {
275
+ if (prev !== null && step.at >= prev) {
276
+ const span = step.at - prev;
277
+ if (live === 0) idleMs += span;
278
+ sumWorkerWallMs += span * live;
279
+ }
280
+ live += step.delta;
281
+ if (live > maxConcurrency) maxConcurrency = live;
282
+ prev = step.at;
283
+ }
284
+ if (prev !== null && completedAt !== null && completedAt >= prev) {
285
+ const span = completedAt - prev;
286
+ if (live === 0) idleMs += span;
287
+ sumWorkerWallMs += span * live;
288
+ }
289
+ const firstWorkerSpawnAt = workerSpawns.reduce((acc, s) => s.at === null ? acc : acc === null ? s.at : Math.min(acc, s.at), null);
290
+ const firstSettleAt = workerCloses.reduce((acc, c) => c.at === null ? acc : acc === null ? c.at : Math.min(acc, c.at), null);
291
+ const respawns = firstSettleAt === null ? 0 : workerSpawns.filter((s) => s.at !== null && s.at > firstSettleAt).length;
292
+ const labelCounts = /* @__PURE__ */ new Map();
293
+ for (const s of workerSpawns) labelCounts.set(s.label, (labelCounts.get(s.label) ?? 0) + 1);
294
+ const repeatedLabels = [...labelCounts.entries()].filter(([, n]) => n > 1).map(([l]) => l);
295
+ const parentOf = new Map(tree.spawns.map((s) => [s.id, s.parent]));
296
+ let delegationDepth = 0;
297
+ for (const s of workerSpawns) {
298
+ let d = 0;
299
+ let cur = s.id;
300
+ const seen = /* @__PURE__ */ new Set();
301
+ while (cur !== null && cur !== rootId && !seen.has(cur)) {
302
+ seen.add(cur);
303
+ d += 1;
304
+ cur = parentOf.get(cur) ?? null;
305
+ }
306
+ if (d > delegationDepth) delegationDepth = d;
307
+ }
308
+ const orchestration = {
309
+ workersSpawned: haveJournal ? workerSpawns.length : gap("workersSpawned", journalMissing),
310
+ workersSettled: haveJournal ? workerCloses.filter((c) => c.kind === "settled").length : unavailable(journalMissing),
311
+ workersCancelled: haveJournal ? workerCloses.filter((c) => c.kind === "cancelled").length : unavailable(journalMissing),
312
+ steers,
313
+ steersDelivered,
314
+ steersByWorker,
315
+ driverSteerCalls,
316
+ waves: haveJournal ? waves : unavailable(journalMissing),
317
+ waveSizes: haveJournal ? waveSizes : unavailable(journalMissing),
318
+ maxConcurrency: haveJournal ? maxConcurrency : unavailable(journalMissing),
319
+ respawns: haveJournal ? respawns : unavailable(journalMissing),
320
+ repeatedLabels: haveJournal ? repeatedLabels : unavailable(journalMissing),
321
+ delegationDepth: haveJournal ? delegationDepth : unavailable(journalMissing),
322
+ timeToFirstSpawnMs: startedAt !== null && firstWorkerSpawnAt !== null ? firstWorkerSpawnAt - startedAt : haveJournal ? unavailable("no worker spawn timestamps") : unavailable(journalMissing),
323
+ supervisorWallMs,
324
+ idleMs: isUnavailable(supervisorWallMs) ? unavailable(supervisorWallMs.unavailable) : idleMs,
325
+ idlePct: isUnavailable(supervisorWallMs) || supervisorWallMs === 0 ? isUnavailable(supervisorWallMs) ? unavailable(supervisorWallMs.unavailable) : unavailable("supervisor wall is 0ms") : round(idleMs / supervisorWallMs * 100, 1),
326
+ workerUtilization: isUnavailable(supervisorWallMs) || supervisorWallMs === 0 ? isUnavailable(supervisorWallMs) ? unavailable(supervisorWallMs.unavailable) : unavailable("supervisor wall is 0ms") : round(sumWorkerWallMs / supervisorWallMs, 3)
327
+ };
328
+ const settledByStatus = {};
329
+ const settledVerdicts = {};
330
+ for (const c of workerCloses) {
331
+ const key = c.status ?? "unknown";
332
+ settledByStatus[key] = (settledByStatus[key] ?? 0) + 1;
333
+ if (c.verdict !== null) settledVerdicts[c.verdict] = (settledVerdicts[c.verdict] ?? 0) + 1;
334
+ }
335
+ const verdictLimit = src.limits.workerVerdicts;
336
+ let accepted = 0;
337
+ let rejected = 0;
338
+ let emptyPass = 0;
339
+ let evidenceBytes = 0;
340
+ for (const w of src.workers ?? []) {
341
+ const f = tree.workerLogs.get(w.label);
342
+ if (f === void 0 || !f.finished) continue;
343
+ evidenceBytes += f.evidenceBytes;
344
+ if (f.passed === true) if ((f.finishedPatchBytes ?? 0) > 0) accepted += 1;
345
+ else emptyPass += 1;
346
+ else if (f.passed === false) rejected += 1;
347
+ }
348
+ let observeThenRespawn = 0;
349
+ let respawnWithoutEvidence = 0;
350
+ const spawnTimes = workerSpawns.map((s) => s.at).filter((t) => t !== null).sort((a, b) => a - b);
351
+ const closeTimes = workerCloses.map((c) => c.at).filter((t) => t !== null).sort((a, b) => a - b);
352
+ for (let i = 1; i < spawnTimes.length; i += 1) {
353
+ const prevSpawn = spawnTimes[i - 1];
354
+ const thisSpawn = spawnTimes[i];
355
+ const sawEvidence = closeTimes.some((t) => t >= prevSpawn && t <= thisSpawn);
356
+ if (firstSettleAt !== null && thisSpawn > firstSettleAt) if (sawEvidence) observeThenRespawn += 1;
357
+ else respawnWithoutEvidence += 1;
358
+ }
359
+ const decision = {
360
+ settledByStatus: haveJournal ? settledByStatus : gap("settledByStatus", journalMissing),
361
+ settledVerdicts: verdictLimit !== null ? unavailable(verdictLimit) : haveJournal ? settledVerdicts : unavailable(journalMissing),
362
+ accepted: verdictLimit !== null ? gap("accepted", verdictLimit) : src.workers === null ? unavailable(workersGapReason) : accepted,
363
+ rejected: verdictLimit !== null ? unavailable(verdictLimit) : src.workers === null ? unavailable(workersGapReason) : rejected,
364
+ emptyPass: verdictLimit !== null || src.limits.deliverables !== null ? unavailable(verdictLimit ?? src.limits.deliverables) : src.workers === null ? unavailable(workersGapReason) : emptyPass,
365
+ observeThenRespawn: haveJournal ? observeThenRespawn : unavailable(journalMissing),
366
+ respawnWithoutEvidence: haveJournal ? respawnWithoutEvidence : unavailable(journalMissing),
367
+ reviewActions: src.workers === null ? unavailable(workersGapReason) : steerQueuedTotal + upLegMessages,
368
+ workerEvidenceBytes: src.workers === null ? unavailable(workersGapReason) : evidenceBytes
369
+ };
370
+ const journalWorkerIn = workerCloses.reduce((a, c) => a + c.spend.tokens.input, 0);
371
+ const journalWorkerOut = workerCloses.reduce((a, c) => a + c.spend.tokens.output, 0);
372
+ const journalWorkerUsd = workerCloses.reduce((a, c) => a + c.spend.usd, 0);
373
+ const labelById = new Map(tree.workerSpawns.map((s) => [s.id, s.label]));
374
+ const workerUsdByLabel = /* @__PURE__ */ new Map();
375
+ for (const c of workerCloses) {
376
+ const label = labelById.get(c.id);
377
+ if (label === void 0) continue;
378
+ workerUsdByLabel.set(label, (workerUsdByLabel.get(label) ?? 0) + c.spend.usd);
379
+ }
380
+ const sq = src.harnessWorkerTokens;
381
+ const harnessGapReason = src.harnessMissingReason ?? "harness session store unavailable and journal settled spend is 0";
382
+ const workerIn = sq !== null ? journalWorkerIn + sq.input : journalWorkerIn > 0 ? journalWorkerIn : gap("workers.tokensIn", harnessGapReason);
383
+ const workerOut = sq !== null ? journalWorkerOut + sq.output : journalWorkerOut > 0 ? journalWorkerOut : unavailable(harnessGapReason);
384
+ const stateResult = asRecord(state?.result);
385
+ const stateUsd = typeof stateResult.spentUsd === "number" ? stateResult.spentUsd : null;
386
+ const usdLimit = src.limits.spendUsd;
387
+ const totalUsd = usdLimit !== null ? gap("totalUsd", usdLimit) : stateUsd !== null ? round(stateUsd, 6) : haveJournal ? round(tree.brain.usd + journalWorkerUsd, 6) : gap("totalUsd", journalMissing);
388
+ const perWorker = (src.workers ?? []).map((w) => {
389
+ const f = tree.workerLogs.get(w.label);
390
+ return {
391
+ worker: w.label,
392
+ wallMs: f?.started != null && f.finishedAt != null ? f.finishedAt - f.started : null,
393
+ tokensIn: w.tokensIn ?? null,
394
+ tokensOut: w.tokensOut ?? null,
395
+ usd: usdLimit !== null ? null : workerUsdByLabel.get(w.label) ?? null,
396
+ patchBytes: w.patchBytes ?? f?.finishedPatchBytes ?? null,
397
+ passed: f?.passed ?? null
398
+ };
399
+ });
400
+ const walls = perWorker.map((w) => w.wallMs).filter((w) => w !== null).sort((a, b) => a - b);
401
+ const brainCalls = parseJsonl(src.brainLog);
402
+ const economics = {
403
+ brain: {
404
+ tokensIn: haveJournal ? tree.brain.tokensIn : gap("brain.tokensIn", journalMissing),
405
+ tokensOut: haveJournal ? tree.brain.tokensOut : unavailable(journalMissing),
406
+ usd: usdLimit !== null ? unavailable(usdLimit) : haveJournal ? round(tree.brain.usd, 6) : unavailable(journalMissing),
407
+ cacheRead: !haveJournal ? unavailable(journalMissing) : tree.brain.hasCache ? tree.brain.cacheRead : unavailable(NO_CACHE_COUNTERS),
408
+ cacheWrite: !haveJournal ? unavailable(journalMissing) : tree.brain.hasCache ? tree.brain.cacheWrite : unavailable(NO_CACHE_COUNTERS),
409
+ source: haveJournal ? `journal metered events (n=${tree.brain.meteredCount})` : journalMissing
410
+ },
411
+ brainTruncations: src.brainLog === null ? gap("brain.brainTruncations", src.supRunDir === null ? "no supervisor run dir under <ws>/.loops/supervisor" : "brain.jsonl absent — loops predates the brain-call tap, so truncation cannot be ruled out") : brainCalls.filter((c) => c.finish_reason === "length").length,
412
+ workers: {
413
+ tokensIn: workerIn,
414
+ tokensOut: workerOut,
415
+ cacheRead: sq?.cacheRead !== void 0 ? sq.cacheRead : unavailable(NO_CACHE_COUNTERS),
416
+ cacheWrite: sq?.cacheWrite !== void 0 ? sq.cacheWrite : unavailable(NO_CACHE_COUNTERS),
417
+ usd: usdLimit !== null ? unavailable(usdLimit) : haveJournal ? round(journalWorkerUsd, 6) : unavailable(journalMissing),
418
+ source: sq !== null ? `journal settled spend + ${sq.store} sessions (n=${sq.sessions})` : `journal settled spend only — ${src.harnessMissingReason ?? "harness session store unavailable"}`
419
+ },
420
+ totalUsd,
421
+ totalUsdSource: usdLimit !== null ? usdLimit : stateUsd !== null ? `state.json result.spentUsd${journalWorkerUsd === 0 ? " — brain-priced only; worker CLI inference is unpriced (see worker token counts)" : ""}` : haveJournal ? "journal metered + settled usd" : journalMissing,
422
+ costPerAcceptedPatchUsd: isUnavailable(totalUsd) ? unavailable(totalUsd.unavailable) : isUnavailable(decision.accepted) ? unavailable(decision.accepted.unavailable) : decision.accepted === 0 ? unavailable("no accepted worker patch (cost has no denominator)") : round(totalUsd / decision.accepted, 6),
423
+ workerWallMsDistribution: walls.length === 0 ? unavailable(src.workers === null ? workersGapReason : "no worker start/finish pairs captured") : {
424
+ n: walls.length,
425
+ min: walls[0],
426
+ p50: quantile(walls, .5),
427
+ p90: quantile(walls, .9),
428
+ max: walls[walls.length - 1],
429
+ sum: walls.reduce((a, b) => a + b, 0)
430
+ },
431
+ perWorker: src.workers === null ? unavailable(workersGapReason) : perWorker
432
+ };
433
+ const patchStats = src.patch === null ? gap("patch", src.limits.deliverables ?? "delivered patch file absent") : parsePatch(src.patch);
434
+ const outcome = {
435
+ supStatus: pickString(state, "status") ?? pickString(result, "sup_status") ?? gap("supStatus", "no state.json / result.json status"),
436
+ supVerdict: pickString(state, "verdict") ?? pickString(result, "sup_verdict") ?? unavailable("no state.json / result.json verdict"),
437
+ delivered: typeof stateResult.delivered === "boolean" ? stateResult.delivered : typeof result?.delivered === "boolean" ? result.delivered : unavailable("no delivered flag in state.json or result.json"),
438
+ judgeResolved: judge === null ? gap("judge", "judge.json absent") : typeof judge.resolved === "boolean" ? judge.resolved : null,
439
+ judgeScore: judge === null ? unavailable("judge.json absent") : typeof judge.score === "number" ? judge.score : null,
440
+ judgePassed: judge === null ? unavailable("judge.json absent") : typeof judge.passed === "number" ? judge.passed : null,
441
+ judgeTotal: judge === null ? unavailable("judge.json absent") : typeof judge.total === "number" ? judge.total : null,
442
+ verifyPass: typeof result?.verify_pass === "boolean" ? result.verify_pass : gap("verifyPass", "result.json absent or has no verify_pass"),
443
+ verifyRc: typeof result?.verify_rc === "number" ? result.verify_rc : unavailable("result.json absent or has no verify_rc"),
444
+ patch: patchStats,
445
+ judgeSource: src.judgeSource
446
+ };
447
+ return {
448
+ schema: SUPERVISOR_RUN_SCHEMA,
449
+ runRef: src.runRef,
450
+ instanceId: src.instanceId,
451
+ arm: src.arm,
452
+ supervisorId: rootId !== null ? rootId : unavailable(journalMissing),
453
+ generatedAt: new Date(now()).toISOString(),
454
+ orchestration,
455
+ decision,
456
+ economics,
457
+ outcome,
458
+ gaps,
459
+ traceCommand: src.traceCommand ?? "npx --yes @tangle-network/traces@latest analyze --harness opencode --cwd <worker-clone-cwd>"
460
+ };
461
+ }
462
+ /** `[driver] registered tools: …supervisor_steer…` is a banner, not an invocation. */
463
+ function registrationMentions(driverLog) {
464
+ let n = 0;
465
+ for (const line of driverLog.split("\n")) if (line.includes("registered tools:") && line.includes("supervisor_steer")) n += 1;
466
+ return n;
467
+ }
468
+ function pickString(rec, key) {
469
+ const v = rec?.[key];
470
+ return typeof v === "string" ? v : null;
471
+ }
472
+ function round(v, digits) {
473
+ const f = 10 ** digits;
474
+ return Math.round(v * f) / f;
475
+ }
476
+ function quantile(sorted, q) {
477
+ if (sorted.length === 0) return 0;
478
+ return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(q * sorted.length) - 1))];
479
+ }
480
+ /** Unified-diff stats. Counts `+++ b/<path>` targets, body +/- lines, and test-file touches. */
481
+ function parsePatch(text) {
482
+ const files = /* @__PURE__ */ new Set();
483
+ const testFiles = /* @__PURE__ */ new Set();
484
+ let added = 0;
485
+ let removed = 0;
486
+ for (const line of text.split("\n")) {
487
+ if (line.startsWith("+++ ")) {
488
+ const p = line.slice(4).trim().replace(/^b\//, "");
489
+ if (p !== "/dev/null") {
490
+ files.add(p);
491
+ if (isTestPath(p)) testFiles.add(p);
492
+ }
493
+ continue;
494
+ }
495
+ if (line.startsWith("--- ") || line.startsWith("diff --git") || line.startsWith("index ")) continue;
496
+ if (line.startsWith("+")) added += 1;
497
+ else if (line.startsWith("-")) removed += 1;
498
+ }
499
+ return {
500
+ files: files.size,
501
+ linesAdded: added,
502
+ linesRemoved: removed,
503
+ testFilesTouched: [...testFiles].sort()
504
+ };
505
+ }
506
+ function isTestPath(p) {
507
+ const base = p.split("/").pop() ?? p;
508
+ return /(^|\/)(tests?|__tests__|testing|spec)(\/|$)/.test(p) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(base) || /^test_.*\.py$/.test(base) || /_test\.py$/.test(base);
509
+ }
510
+ /**
511
+ * Aggregate many supervisor-run reports. A metric no run could measure stays
512
+ * `unavailable` rather than becoming a 0-valued mean, and cells whose steer
513
+ * count was unavailable are counted separately from cells that measured zero.
514
+ */
515
+ function rollupSupervisorRuns(reports) {
516
+ const known = (vals) => vals.filter((v) => !isUnavailable(v));
517
+ const steerVals = known(reports.map((r) => r.orchestration.steers));
518
+ const waveVals = known(reports.map((r) => r.orchestration.waves));
519
+ const concVals = known(reports.map((r) => r.orchestration.maxConcurrency));
520
+ const utilVals = known(reports.map((r) => r.orchestration.workerUtilization));
521
+ const idleVals = known(reports.map((r) => r.orchestration.idlePct));
522
+ const spawnVals = known(reports.map((r) => r.orchestration.workersSpawned));
523
+ const acceptVals = known(reports.map((r) => r.decision.accepted));
524
+ const usdVals = known(reports.map((r) => r.economics.totalUsd));
525
+ const resolvedVals = known(reports.map((r) => r.outcome.judgeResolved));
526
+ const sum = (xs) => xs.reduce((a, b) => a + b, 0);
527
+ const mean = (xs) => xs.length === 0 ? unavailable("no cell reported this metric") : round(sum(xs) / xs.length, 3);
528
+ const perCell = reports.map((r) => ({
529
+ instanceId: r.instanceId,
530
+ arm: r.arm,
531
+ steers: r.orchestration.steers,
532
+ waves: r.orchestration.waves,
533
+ utilization: r.orchestration.workerUtilization,
534
+ idlePct: r.orchestration.idlePct,
535
+ resolved: r.outcome.judgeResolved,
536
+ usd: r.economics.totalUsd
537
+ }));
538
+ return {
539
+ schema: SUPERVISOR_RUN_ROLLUP_SCHEMA,
540
+ cells: reports.length,
541
+ steersTotal: steerVals.length === 0 ? unavailable("no cell reported a steer count") : sum(steerVals),
542
+ cellsWithSteers: steerVals.length === 0 ? unavailable("no cell reported a steer count") : steerVals.filter((n) => n > 0).length,
543
+ cellsWithUnavailableSteers: reports.filter((r) => isUnavailable(r.orchestration.steers)).length,
544
+ wavesMean: mean(waveVals),
545
+ maxConcurrencyMax: concVals.length === 0 ? unavailable("no cell reported concurrency") : Math.max(...concVals),
546
+ utilizationMean: mean(utilVals),
547
+ idlePctMean: mean(idleVals),
548
+ workersSpawnedTotal: spawnVals.length === 0 ? unavailable("no cell reported spawns") : sum(spawnVals),
549
+ acceptedTotal: acceptVals.length === 0 ? unavailable("no cell reported acceptance") : sum(acceptVals),
550
+ usdTotal: usdVals.length === 0 ? unavailable("no cell reported spend") : round(sum(usdVals), 6),
551
+ resolvedCount: resolvedVals.length === 0 ? unavailable("no cell reported a judge verdict") : resolvedVals.filter((v) => v === true).length,
552
+ perCell
553
+ };
554
+ }
555
+ //#endregion
556
+ //#region src/supervisor-run/claude-code-reader.ts
557
+ /**
558
+ * Supervision-tree reader over a THIRD-PARTY harness: Claude Code.
559
+ *
560
+ * `loops-reader.ts` reads a supervisor we wrote, whose journal was designed
561
+ * for this analysis. This reader reads a harness we do not control, whose
562
+ * transcript was designed for replaying a chat — and recovers the same tree
563
+ * from it. If both produce a `SupervisorRunSources`, the tree model is a
564
+ * property of multi-agent runs, not of our journal format.
565
+ *
566
+ * ## Where the tree hides in a Claude Code transcript
567
+ *
568
+ * | Tree fact | Claude Code evidence |
569
+ * |---|---|
570
+ * | spawn | assistant `tool_use` (`Agent` / `Task`), answered by a `tool_result` whose `toolUseResult.agentId` names the child |
571
+ * | settle | a `<task-notification>` block in a later user line: `<task-id>` = agentId, `<status>` |
572
+ * | steer | assistant `tool_use` (`SendMessage`) with `input.to` = agentId — mid-task, to a LIVE child |
573
+ * | delivered | that steer's `tool_result` carrying `success` / `resumedAgentId` |
574
+ * | cancel | assistant `tool_use` (`TaskStop`) targeting an agentId |
575
+ * | brain spend| `message.usage` on the main thread's assistant lines |
576
+ * | worker spend| `message.usage` inside `<session>/subagents/agent-<id>.jsonl` |
577
+ * | depth | a child transcript that itself contains `Agent` tool_use lines |
578
+ *
579
+ * Every one of those is read through `parseClaudeEntries` — the SAME line
580
+ * parser `src/rollout/readers/claude-jsonl.ts` uses for solo rollouts. There
581
+ * is no second transcript parser.
582
+ *
583
+ * ## What Claude Code cannot say
584
+ *
585
+ * It records tokens but never a price, runs no per-worker verify, and keeps no
586
+ * per-worker patch. Those are declared once in `limits`, so the analyzer
587
+ * reports `unavailable — <reason>` instead of the $0 / 0-accepted that summing
588
+ * an empty field would produce. See `SourceLimits`.
589
+ *
590
+ * ## Metric coverage vs the loops journal
591
+ *
592
+ * Measured on a real 52-agent session (fixture:
593
+ * `tests/fixtures/supervisor-run/claude-code-session-*`).
594
+ *
595
+ * | Metric | loops | Claude Code | Why |
596
+ * |---|---|---|---|
597
+ * | workersSpawned / Settled / Cancelled | full | full | spawn tool_use + task-notification + TaskStop |
598
+ * | steers / steersDelivered / steersByWorker | full | full | `SendMessage`; delivery from its tool_result |
599
+ * | waves / waveSizes / maxConcurrency | full | full | derived from spawn/settle instants |
600
+ * | respawns / repeatedLabels | full | full | same derivation |
601
+ * | delegationDepth | full | full | a child transcript's own spawn calls |
602
+ * | timeToFirstSpawn / supervisorWall | full | full | transcript instants |
603
+ * | idleMs / idlePct / workerUtilization | full | PARTIAL | an agent that never notifies is counted live to the end of the transcript |
604
+ * | observeThenRespawn / respawnWithoutEvidence | full | full | ordering of spawn vs settle instants |
605
+ * | workerEvidenceBytes | full | PARTIAL | the child's closing message; 0 for pruned transcripts |
606
+ * | brain tokens in/out + cache | full | full | main-thread `message.usage` |
607
+ * | worker tokens in/out + cache | via harness join | PARTIAL | only for retained subagent transcripts |
608
+ * | perWorker wall | full | full | spawn → settle instants |
609
+ * | accepted / rejected / emptyPass / settledVerdicts | full | NONE | no per-worker verify step exists |
610
+ * | brain/worker/total usd, costPerAcceptedPatch | full | NONE | transcripts carry no price |
611
+ * | patch stats, delivered, verifyPass/Rc | full | NONE | no diff is handed back |
612
+ * | judgeResolved / Score / Passed / Total | full | NONE | no judge in the loop |
613
+ * | driverSteerCalls, brainTruncations | full | NONE | no outer driver log, no per-call finish_reason tap |
614
+ */
615
+ /** Tool names that spawn a child agent. `Task` is the older name for `Agent`. */
616
+ const DEFAULT_SPAWN_TOOLS = ["Agent", "Task"];
617
+ /** Tool names that deliver a message to an ALREADY-RUNNING child agent. */
618
+ const DEFAULT_STEER_TOOLS = ["SendMessage"];
619
+ /** Tool names that stop a running child agent. */
620
+ const DEFAULT_CANCEL_TOOLS = ["TaskStop", "KillAgent"];
621
+ const SPEND_UNPRICED = "Claude Code transcripts record token usage but never a price — usd is not in the store";
622
+ const NO_VERDICTS = "Claude Code runs no per-worker verify step — a subagent reports prose, not pass/fail";
623
+ const NO_DELIVERABLES = "Claude Code retains no per-worker patch — subagents commit to git, they do not hand back a diff";
624
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
625
+ const str = (v) => typeof v === "string" ? v : null;
626
+ function blockText(content) {
627
+ if (typeof content === "string") return content;
628
+ if (!Array.isArray(content)) return "";
629
+ const parts = [];
630
+ for (const b of content) if (isRecord(b) && b.type === "text" && typeof b.text === "string") parts.push(b.text);
631
+ return parts.join("\n");
632
+ }
633
+ const tag = (xml, name) => {
634
+ const m = xml.match(new RegExp(`<${name}>([\\s\\S]*?)</${name}>`));
635
+ return m === null ? null : m[1];
636
+ };
637
+ /**
638
+ * Task notifications are the settle instants. A notification fires each time an
639
+ * agent stops, so a resumed agent produces several — they are kept in order and
640
+ * the LAST one is the settle the analyzer sees, with the earlier ones acting as
641
+ * the intermediate stops they actually were.
642
+ */
643
+ function parseNotifications(text, at) {
644
+ const out = [];
645
+ for (const m of text.matchAll(/<task-notification>[\s\S]*?<\/task-notification>/g)) {
646
+ const xml = m[0];
647
+ const taskId = tag(xml, "task-id");
648
+ if (taskId === null) continue;
649
+ out.push({
650
+ taskId: taskId.trim(),
651
+ toolUseId: tag(xml, "tool-use-id")?.trim() ?? null,
652
+ status: tag(xml, "status")?.trim() ?? "unknown",
653
+ summary: tag(xml, "summary")?.trim() ?? null,
654
+ at
655
+ });
656
+ }
657
+ return out;
658
+ }
659
+ /** Project entries of ONE thread (main or a single sidechain) into tool traffic. */
660
+ function threadCalls(entries) {
661
+ const uses = [];
662
+ const results = /* @__PURE__ */ new Map();
663
+ const notifications = [];
664
+ let firstAt = null;
665
+ let lastAt = null;
666
+ for (const entry of entries) {
667
+ if (entry.timestamp !== null) {
668
+ if (firstAt === null) firstAt = entry.timestamp;
669
+ lastAt = entry.timestamp;
670
+ }
671
+ const content = entry.message.content;
672
+ if (entry.type === "assistant") {
673
+ if (!Array.isArray(content)) continue;
674
+ for (const block of content) {
675
+ if (!isRecord(block) || block.type !== "tool_use") continue;
676
+ const id = str(block.id);
677
+ const name = str(block.name);
678
+ if (id === null || name === null) continue;
679
+ uses.push({
680
+ id,
681
+ name,
682
+ input: isRecord(block.input) ? block.input : {},
683
+ at: entry.timestamp
684
+ });
685
+ }
686
+ continue;
687
+ }
688
+ if (typeof content === "string") {
689
+ notifications.push(...parseNotifications(content, entry.timestamp));
690
+ continue;
691
+ }
692
+ if (!Array.isArray(content)) continue;
693
+ for (const block of content) {
694
+ if (!isRecord(block)) continue;
695
+ if (block.type === "tool_result" && typeof block.tool_use_id === "string") results.set(block.tool_use_id, {
696
+ id: block.tool_use_id,
697
+ at: entry.timestamp,
698
+ structured: entry.toolUseResult,
699
+ text: blockText(block.content)
700
+ });
701
+ else if (block.type === "text" && typeof block.text === "string") notifications.push(...parseNotifications(block.text, entry.timestamp));
702
+ }
703
+ }
704
+ return {
705
+ uses,
706
+ results,
707
+ notifications,
708
+ firstAt,
709
+ lastAt
710
+ };
711
+ }
712
+ /**
713
+ * The agent id a spawn produced. Claude Code puts it in the structured
714
+ * `toolUseResult`; the same id is echoed in the result text for transcripts
715
+ * written before that field existed, so both are tried before giving up.
716
+ */
717
+ function spawnedAgentId(result) {
718
+ if (result === void 0) return null;
719
+ if (isRecord(result.structured)) {
720
+ const id = str(result.structured.agentId);
721
+ if (id !== null) return id;
722
+ }
723
+ return result.text.match(/agentId:\s*([A-Za-z0-9_-]+)/)?.[1] ?? null;
724
+ }
725
+ async function readChildren(dir) {
726
+ const names = await readdir(dir).catch(() => null);
727
+ if (names === null) return [];
728
+ const out = [];
729
+ for (const name of names.filter((n) => n.endsWith(".jsonl")).sort()) {
730
+ const path = join(dir, name);
731
+ const raw = await readFile(path, "utf8").catch(() => null);
732
+ if (raw === null) continue;
733
+ const entries = parseClaudeEntries(raw);
734
+ const projected = transcriptFromEntries(entries, { includeSidechain: true });
735
+ const metaRaw = await readFile(path.replace(/\.jsonl$/, ".meta.json"), "utf8").catch(() => null);
736
+ let meta = {};
737
+ if (metaRaw !== null) try {
738
+ const parsed = JSON.parse(metaRaw);
739
+ if (isRecord(parsed)) meta = parsed;
740
+ } catch {
741
+ meta = {};
742
+ }
743
+ const agentId = entries.find((e) => e.agentId !== null)?.agentId ?? name.replace(/^agent-/, "").replace(/\.jsonl$/, "");
744
+ out.push({
745
+ agentId,
746
+ path,
747
+ description: str(meta.description),
748
+ spawnToolUseId: str(meta.toolUseId),
749
+ spawnDepth: typeof meta.spawnDepth === "number" ? meta.spawnDepth : null,
750
+ entries,
751
+ tokensIn: projected.usage.tokensIn,
752
+ tokensOut: projected.usage.tokensOut,
753
+ cacheRead: projected.usage.cacheRead,
754
+ cacheWrite: projected.usage.cacheWrite,
755
+ firstAt: projected.startedAt,
756
+ lastAt: projected.endedAt,
757
+ model: projected.model,
758
+ finalReport: [...projected.messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string")?.content ?? null
759
+ });
760
+ }
761
+ return out;
762
+ }
763
+ /** A journal line in the dialect `parseSupervisorTree` reads. */
764
+ const line = (obj) => JSON.stringify(obj);
765
+ /**
766
+ * Read a Claude Code session (plus its subagent transcripts) as supervision-tree
767
+ * source bytes. Never throws on a missing artifact.
768
+ */
769
+ async function readClaudeCodeSupervisorRun(opts) {
770
+ const spawnTools = new Set(opts.spawnTools ?? DEFAULT_SPAWN_TOOLS);
771
+ const steerTools = new Set(opts.steerTools ?? DEFAULT_STEER_TOOLS);
772
+ const cancelTools = new Set(opts.cancelTools ?? DEFAULT_CANCEL_TOOLS);
773
+ const raw = await readFile(opts.transcriptPath, "utf8").catch(() => null);
774
+ const sessionId = basename(opts.transcriptPath).replace(/\.jsonl$/, "");
775
+ const runRef = opts.runRef ?? opts.transcriptPath;
776
+ const limits = {
777
+ spendUsd: SPEND_UNPRICED,
778
+ workerVerdicts: NO_VERDICTS,
779
+ deliverables: null
780
+ };
781
+ const traceCommand = `npx --yes @tangle-network/traces@latest analyze --harness claude-code --session ${sessionId}`;
782
+ if (raw === null) return {
783
+ runRef,
784
+ instanceId: opts.instanceId ?? sessionId,
785
+ arm: opts.arm ?? null,
786
+ supRunDir: null,
787
+ journal: null,
788
+ brainLog: null,
789
+ state: null,
790
+ progress: null,
791
+ workers: null,
792
+ workersMissingReason: `session transcript unreadable at ${opts.transcriptPath}`,
793
+ result: null,
794
+ judge: null,
795
+ judgeSource: null,
796
+ patch: null,
797
+ driverLog: null,
798
+ harnessWorkerTokens: null,
799
+ harnessMissingReason: `session transcript unreadable at ${opts.transcriptPath}`,
800
+ limits: {
801
+ ...limits,
802
+ deliverables: NO_DELIVERABLES
803
+ },
804
+ traceCommand
805
+ };
806
+ const allEntries = parseClaudeEntries(raw);
807
+ const main = threadCalls(allEntries.filter((e) => !e.isSidechain));
808
+ const mainTranscript = transcriptFromEntries(allEntries);
809
+ const subagentsDir = opts.subagentsDir === void 0 ? join(dirname(opts.transcriptPath), sessionId, "subagents") : opts.subagentsDir;
810
+ const children = subagentsDir === null ? [] : await readChildren(subagentsDir);
811
+ const childByAgentId = new Map(children.map((c) => [c.agentId, c]));
812
+ const childBySpawnToolUseId = new Map(children.filter((c) => c.spawnToolUseId !== null).map((c) => [c.spawnToolUseId, c]));
813
+ const threads = [{
814
+ id: sessionId,
815
+ calls: main
816
+ }];
817
+ for (const child of children) threads.push({
818
+ id: child.agentId,
819
+ calls: threadCalls(child.entries)
820
+ });
821
+ const spawns = [];
822
+ const steersByTarget = /* @__PURE__ */ new Map();
823
+ const cancels = [];
824
+ const settles = [];
825
+ for (const thread of threads) {
826
+ for (const use of thread.calls.uses) {
827
+ if (spawnTools.has(use.name)) {
828
+ const result = thread.calls.results.get(use.id);
829
+ const agentId = spawnedAgentId(result) ?? childBySpawnToolUseId.get(use.id)?.agentId ?? null;
830
+ if (agentId === null) continue;
831
+ const label = str(use.input.description) ?? childByAgentId.get(agentId)?.description ?? agentId;
832
+ spawns.push({
833
+ agentId,
834
+ parentId: thread.id,
835
+ label,
836
+ at: result?.at ?? use.at,
837
+ model: isRecord(result?.structured) ? str(result.structured.resolvedModel) : null
838
+ });
839
+ continue;
840
+ }
841
+ if (steerTools.has(use.name)) {
842
+ const target = str(use.input.to) ?? str(use.input.recipient);
843
+ if (target === null) continue;
844
+ const result = thread.calls.results.get(use.id);
845
+ const structured = isRecord(result?.structured) ? result.structured : null;
846
+ const delivered = structured?.success === true || str(structured?.resumedAgentId) === target;
847
+ const rows = steersByTarget.get(target) ?? [];
848
+ rows.push({
849
+ at: use.at,
850
+ delivered
851
+ });
852
+ steersByTarget.set(target, rows);
853
+ continue;
854
+ }
855
+ if (cancelTools.has(use.name)) {
856
+ const target = str(use.input.agentId) ?? str(use.input.to) ?? str(use.input.taskId);
857
+ if (target !== null) cancels.push({
858
+ agentId: target,
859
+ at: use.at
860
+ });
861
+ }
862
+ }
863
+ settles.push(...thread.calls.notifications);
864
+ }
865
+ const spawnedIds = new Set(spawns.map((s) => s.agentId));
866
+ const cancelledIds = new Set(cancels.filter((c) => spawnedIds.has(c.agentId)).map((c) => c.agentId));
867
+ const startedAt = main.firstAt;
868
+ const completedAt = main.lastAt;
869
+ const journalLines = [line({
870
+ kind: "spawned",
871
+ id: sessionId,
872
+ parent: null,
873
+ label: `session:${sessionId}`,
874
+ at: startedAt
875
+ })];
876
+ for (const s of spawns) journalLines.push(line({
877
+ kind: "spawned",
878
+ id: s.agentId,
879
+ parent: s.parentId,
880
+ label: s.label,
881
+ at: s.at
882
+ }));
883
+ const lastNotification = /* @__PURE__ */ new Map();
884
+ for (const n of settles) {
885
+ if (!spawnedIds.has(n.taskId)) continue;
886
+ lastNotification.set(n.taskId, n);
887
+ }
888
+ for (const [agentId, n] of lastNotification) {
889
+ if (cancelledIds.has(agentId)) continue;
890
+ journalLines.push(line({
891
+ kind: "settled",
892
+ id: agentId,
893
+ status: n.status,
894
+ verdict: n.summary,
895
+ at: n.at
896
+ }));
897
+ }
898
+ const lastCancel = /* @__PURE__ */ new Map();
899
+ for (const c of cancels) {
900
+ if (!spawnedIds.has(c.agentId)) continue;
901
+ lastCancel.set(c.agentId, c);
902
+ }
903
+ for (const c of lastCancel.values()) journalLines.push(line({
904
+ kind: "cancelled",
905
+ id: c.agentId,
906
+ reason: "stopped by supervisor",
907
+ at: c.at
908
+ }));
909
+ journalLines.push(line({
910
+ kind: "metered",
911
+ id: sessionId,
912
+ spend: { tokens: {
913
+ input: mainTranscript.usage.tokensIn,
914
+ output: mainTranscript.usage.tokensOut,
915
+ cacheRead: mainTranscript.usage.cacheRead,
916
+ cacheWrite: mainTranscript.usage.cacheWrite
917
+ } },
918
+ at: completedAt
919
+ }));
920
+ const settleAtByAgent = new Map([...lastNotification.entries()].map(([id, n]) => [id, n.at]));
921
+ const spawnAtByAgent = new Map(spawns.map((s) => [s.agentId, s.at]));
922
+ const byLabel = /* @__PURE__ */ new Map();
923
+ for (const s of spawns) {
924
+ const ids = byLabel.get(s.label) ?? [];
925
+ ids.push(s.agentId);
926
+ byLabel.set(s.label, ids);
927
+ }
928
+ const workers = [];
929
+ for (const [label, agentIds] of byLabel) {
930
+ const events = [];
931
+ const inbox = [];
932
+ let tokensIn = null;
933
+ let tokensOut = null;
934
+ let cacheRead = null;
935
+ let cacheWrite = null;
936
+ let transcriptRef = null;
937
+ for (const agentId of agentIds) {
938
+ const child = childByAgentId.get(agentId) ?? null;
939
+ const startAt = child?.firstAt ?? spawnAtByAgent.get(agentId) ?? null;
940
+ const endAt = settleAtByAgent.get(agentId) ?? child?.lastAt ?? null;
941
+ if (startAt !== null) events.push(line({
942
+ kind: "started",
943
+ label,
944
+ at: startAt,
945
+ agentId
946
+ }));
947
+ for (const steer of steersByTarget.get(agentId) ?? []) {
948
+ inbox.push(line({
949
+ id: `${agentId}:${steer.at}`,
950
+ at: steer.at,
951
+ worker: label,
952
+ message: "steer"
953
+ }));
954
+ events.push(line({
955
+ kind: "message",
956
+ label,
957
+ direction: "down",
958
+ at: steer.at,
959
+ requestId: `${agentId}:${steer.at}`,
960
+ delivered: steer.delivered
961
+ }));
962
+ }
963
+ if (endAt !== null) events.push(line({
964
+ kind: "finished",
965
+ label,
966
+ at: endAt,
967
+ agentId,
968
+ ...child?.finalReport === null || child?.finalReport === void 0 ? {} : { evidence: child.finalReport }
969
+ }));
970
+ if (child !== null) {
971
+ tokensIn = (tokensIn ?? 0) + child.tokensIn;
972
+ tokensOut = (tokensOut ?? 0) + child.tokensOut;
973
+ cacheRead = (cacheRead ?? 0) + child.cacheRead;
974
+ cacheWrite = (cacheWrite ?? 0) + child.cacheWrite;
975
+ transcriptRef = child.path;
976
+ }
977
+ }
978
+ workers.push({
979
+ label,
980
+ events: events.length === 0 ? null : `${events.join("\n")}\n`,
981
+ inbox: inbox.length === 0 ? null : `${inbox.join("\n")}\n`,
982
+ patchBytes: null,
983
+ transcriptRef,
984
+ patchPath: null,
985
+ tokensIn,
986
+ tokensOut,
987
+ cacheRead,
988
+ cacheWrite
989
+ });
990
+ }
991
+ const joined = children.length;
992
+ const harnessWorkerTokens = joined === 0 ? null : {
993
+ store: "claude-code subagent transcripts",
994
+ sessions: joined,
995
+ input: children.reduce((a, c) => a + c.tokensIn, 0),
996
+ output: children.reduce((a, c) => a + c.tokensOut, 0),
997
+ cacheRead: children.reduce((a, c) => a + c.cacheRead, 0),
998
+ cacheWrite: children.reduce((a, c) => a + c.cacheWrite, 0)
999
+ };
1000
+ const missingChildren = spawns.filter((s) => !childByAgentId.has(s.agentId)).length;
1001
+ const harnessMissingReason = subagentsDir === null ? "subagent transcript join disabled" : joined === 0 ? `no subagent transcripts under ${subagentsDir}` : missingChildren === 0 ? null : `${missingChildren}/${spawns.length} spawned agents have no retained transcript under ${subagentsDir} (Claude Code prunes them; their tokens are unrecoverable)`;
1002
+ const liveWorkers = spawns.filter((s) => !lastNotification.has(s.agentId) && !cancelledIds.has(s.agentId)).length;
1003
+ const state = JSON.stringify({
1004
+ id: sessionId,
1005
+ status: liveWorkers > 0 ? "running" : "idle",
1006
+ startedAt,
1007
+ completedAt,
1008
+ result: { delivered: null }
1009
+ });
1010
+ return {
1011
+ runRef,
1012
+ instanceId: opts.instanceId ?? sessionId,
1013
+ arm: opts.arm ?? null,
1014
+ supRunDir: subagentsDir,
1015
+ journal: `${journalLines.join("\n")}\n`,
1016
+ brainLog: null,
1017
+ state,
1018
+ progress: null,
1019
+ workers,
1020
+ workersMissingReason: null,
1021
+ result: null,
1022
+ judge: null,
1023
+ judgeSource: null,
1024
+ patch: null,
1025
+ driverLog: null,
1026
+ harnessWorkerTokens,
1027
+ harnessMissingReason,
1028
+ limits: {
1029
+ ...limits,
1030
+ deliverables: NO_DELIVERABLES
1031
+ },
1032
+ rootTranscriptRef: opts.transcriptPath,
1033
+ traceCommand
1034
+ };
1035
+ }
1036
+ /** A `SupervisorRunReader` over a Claude Code session — the same contract loops implements. */
1037
+ function claudeCodeSupervisorRunReader(opts) {
1038
+ return {
1039
+ runRef: opts.runRef ?? opts.transcriptPath,
1040
+ read: () => readClaudeCodeSupervisorRun(opts)
1041
+ };
1042
+ }
1043
+ //#endregion
1044
+ //#region src/supervisor-run/render.ts
1045
+ /**
1046
+ * Human-readable renderings of a supervisor-run report. Zero and unavailable
1047
+ * render differently on purpose (`0` vs `unavailable — <reason>`), because the
1048
+ * two have driven opposite conclusions about the same architecture.
1049
+ */
1050
+ /**
1051
+ * The block appended to a run log after every run — the answers an operator asks
1052
+ * for, in the log tail, with no extra command.
1053
+ */
1054
+ function renderSupervisorRunHeadline(r) {
1055
+ const o = r.orchestration;
1056
+ const steerNote = isUnavailable(o.steers) ? `unavailable — ${o.steers.unavailable}` : o.steers === 0 ? "0 (spawn→wait→respawn only; no mid-task steering)" : `${o.steers} queued / ${showMeasured(o.steersDelivered)} delivered`;
1057
+ return [
1058
+ `RUN-REPORT ${r.instanceId ?? "?"} [${r.arm ?? "?"}]`,
1059
+ ` steers=${steerNote}`,
1060
+ ` waves=${showMeasured(o.waves)} sizes=${isUnavailable(o.waveSizes) ? `unavailable — ${o.waveSizes.unavailable}` : `[${o.waveSizes.join(",")}]`} workers=${showMeasured(o.workersSpawned)} settled=${showMeasured(o.workersSettled)} cancelled=${showMeasured(o.workersCancelled)}`,
1061
+ ` concurrency max=${showMeasured(o.maxConcurrency)} utilization=${showMeasured(o.workerUtilization)} idle=${fmtMs(o.idleMs)} (${showMeasured(o.idlePct)}%) wall=${fmtMs(o.supervisorWallMs)}`,
1062
+ ` respawns=${showMeasured(o.respawns)} evidence→respawn=${showMeasured(r.decision.observeThenRespawn)} blind-respawn=${showMeasured(r.decision.respawnWithoutEvidence)} depth=${showMeasured(o.delegationDepth)}`,
1063
+ ` accepted=${showMeasured(r.decision.accepted)} rejected=${showMeasured(r.decision.rejected)} empty-pass=${showMeasured(r.decision.emptyPass)}`,
1064
+ ` brain=$${showMeasured(r.economics.brain.usd)} total=$${showMeasured(r.economics.totalUsd)} judge.resolved=${showMeasured(r.outcome.judgeResolved)} score=${showMeasured(r.outcome.judgeScore)} verify=${showMeasured(r.outcome.verifyPass)}`,
1065
+ r.gaps.length > 0 ? ` gaps(${r.gaps.length}): ${r.gaps.join("; ")}` : " gaps: none"
1066
+ ].join("\n");
1067
+ }
1068
+ function fmtMs(v) {
1069
+ if (isUnavailable(v)) return `unavailable — ${v.unavailable}`;
1070
+ if (v < 1e3) return `${v}ms`;
1071
+ const s = v / 1e3;
1072
+ if (s < 120) return `${round(s, 1)}s`;
1073
+ return `${round(s / 60, 1)}min`;
1074
+ }
1075
+ function renderSupervisorRunMarkdown(r) {
1076
+ const o = r.orchestration;
1077
+ const d = r.decision;
1078
+ const e = r.economics;
1079
+ const out = [];
1080
+ out.push(`# Run report — ${r.instanceId ?? "unknown instance"} [${r.arm ?? "unknown arm"}]`);
1081
+ out.push("");
1082
+ out.push("```");
1083
+ out.push(renderSupervisorRunHeadline(r));
1084
+ out.push("```");
1085
+ out.push("");
1086
+ out.push(`- Run: \`${r.runRef}\``);
1087
+ out.push(`- Supervisor: \`${showMeasured(r.supervisorId)}\``);
1088
+ out.push(`- Generated: ${r.generatedAt}`);
1089
+ out.push("");
1090
+ out.push("## Orchestration");
1091
+ out.push("");
1092
+ out.push("| Metric | Value |");
1093
+ out.push("|---|---|");
1094
+ out.push(`| Workers spawned | ${showMeasured(o.workersSpawned)} |`);
1095
+ out.push(`| Workers settled | ${showMeasured(o.workersSettled)} |`);
1096
+ out.push(`| Workers cancelled | ${showMeasured(o.workersCancelled)} |`);
1097
+ out.push(`| **Steers (mid-task messages to live workers)** | **${showMeasured(o.steers)}** |`);
1098
+ out.push(`| Steers delivered | ${showMeasured(o.steersDelivered)} |`);
1099
+ out.push(`| Outer-driver \`supervisor_steer\` calls | ${showMeasured(o.driverSteerCalls)} |`);
1100
+ out.push(`| Spawn waves | ${showMeasured(o.waves)} |`);
1101
+ out.push(`| Wave sizes | ${isUnavailable(o.waveSizes) ? showMeasured(o.waveSizes) : `[${o.waveSizes.join(", ")}]`} |`);
1102
+ out.push(`| Max concurrency | ${showMeasured(o.maxConcurrency)} |`);
1103
+ out.push(`| Respawns (spawns after first settle) | ${showMeasured(o.respawns)} |`);
1104
+ out.push(`| Repeated labels | ${isUnavailable(o.repeatedLabels) ? showMeasured(o.repeatedLabels) : o.repeatedLabels.length === 0 ? "none" : o.repeatedLabels.join(", ")} |`);
1105
+ out.push(`| Delegation depth | ${showMeasured(o.delegationDepth)} |`);
1106
+ out.push(`| Time to first spawn | ${fmtMs(o.timeToFirstSpawnMs)} |`);
1107
+ out.push(`| Supervisor wall | ${fmtMs(o.supervisorWallMs)} |`);
1108
+ out.push(`| Idle (zero live workers) | ${fmtMs(o.idleMs)} (${showMeasured(o.idlePct)}%) |`);
1109
+ out.push(`| Worker utilization (Σ worker wall ÷ supervisor wall) | ${showMeasured(o.workerUtilization)} |`);
1110
+ out.push("");
1111
+ if (!isUnavailable(o.steersByWorker) && o.steersByWorker.length > 0) {
1112
+ out.push("### Steers per worker");
1113
+ out.push("");
1114
+ out.push("| Worker | Queued | Delivered |");
1115
+ out.push("|---|---:|---:|");
1116
+ for (const s of o.steersByWorker) out.push(`| \`${s.worker}\` | ${s.queued} | ${s.delivered} |`);
1117
+ out.push("");
1118
+ } else if (isUnavailable(o.steersByWorker)) out.push(`### Steers per worker\n\nunavailable — ${o.steersByWorker.unavailable}\n`);
1119
+ out.push("## Decision quality");
1120
+ out.push("");
1121
+ out.push("| Metric | Value |");
1122
+ out.push("|---|---|");
1123
+ out.push(`| Settled by status | ${fmtCounts(d.settledByStatus)} |`);
1124
+ out.push(`| Settled verdicts | ${fmtCounts(d.settledVerdicts)} |`);
1125
+ out.push(`| Accepted (verify green + patch bytes) | ${showMeasured(d.accepted)} |`);
1126
+ out.push(`| Rejected (verify red) | ${showMeasured(d.rejected)} |`);
1127
+ out.push(`| Empty pass (green, no patch) | ${showMeasured(d.emptyPass)} |`);
1128
+ out.push(`| Evidence → respawn sequences | ${showMeasured(d.observeThenRespawn)} |`);
1129
+ out.push(`| Respawn with no settled evidence in front | ${showMeasured(d.respawnWithoutEvidence)} |`);
1130
+ out.push(`| Review actions (steers + worker questions) | ${showMeasured(d.reviewActions)} |`);
1131
+ out.push(`| Worker evidence returned | ${isUnavailable(d.workerEvidenceBytes) ? showMeasured(d.workerEvidenceBytes) : `${d.workerEvidenceBytes} bytes`} |`);
1132
+ out.push("");
1133
+ out.push("## Economics");
1134
+ out.push("");
1135
+ out.push("| Role | Tokens in | Tokens out | Cache read | Cache write | USD | Source |");
1136
+ out.push("|---|---:|---:|---:|---:|---:|---|");
1137
+ out.push(`| brain | ${showMeasured(e.brain.tokensIn)} | ${showMeasured(e.brain.tokensOut)} | ${showMeasured(e.brain.cacheRead)} | ${showMeasured(e.brain.cacheWrite)} | ${showMeasured(e.brain.usd)} | ${e.brain.source} |`);
1138
+ out.push(`| workers | ${showMeasured(e.workers.tokensIn)} | ${showMeasured(e.workers.tokensOut)} | ${showMeasured(e.workers.cacheRead)} | ${showMeasured(e.workers.cacheWrite)} | ${showMeasured(e.workers.usd)} | ${e.workers.source} |`);
1139
+ out.push("");
1140
+ if (!isUnavailable(e.brainTruncations) && e.brainTruncations > 0) out.push(`- **BRAIN OUTPUT TRUNCATED: ${e.brainTruncations} completion(s) hit \`finish_reason: "length"\`** — the supervisor acted on a half-written plan. Its output ceiling is too low; see \`brain.jsonl\` for the per-call \`req_max_tokens\`.`);
1141
+ else out.push(`- Brain completions truncated (finish_reason=length): ${showMeasured(e.brainTruncations)}`);
1142
+ out.push(`- Total USD: ${showMeasured(e.totalUsd)} (source: ${e.totalUsdSource})`);
1143
+ out.push(`- Cost per accepted patch: ${showMeasured(e.costPerAcceptedPatchUsd)}`);
1144
+ if (isUnavailable(e.workerWallMsDistribution)) out.push(`- Worker wall distribution: unavailable — ${e.workerWallMsDistribution.unavailable}`);
1145
+ else {
1146
+ const w = e.workerWallMsDistribution;
1147
+ out.push(`- Worker wall (n=${w.n}): min ${fmtMs(w.min)} / p50 ${fmtMs(w.p50)} / p90 ${fmtMs(w.p90)} / max ${fmtMs(w.max)} / Σ ${fmtMs(w.sum)}`);
1148
+ }
1149
+ out.push("");
1150
+ if (!isUnavailable(e.perWorker) && e.perWorker.length > 0) {
1151
+ out.push("| Worker | Wall | Tokens in | Tokens out | Patch bytes | Verify passed |");
1152
+ out.push("|---|---:|---:|---:|---:|---|");
1153
+ for (const w of e.perWorker) out.push(`| \`${w.worker}\` | ${w.wallMs === null ? "unavailable — no start/finish pair" : fmtMs(w.wallMs)} | ${w.tokensIn ?? "unavailable — store does not attribute tokens per worker"} | ${w.tokensOut ?? "unavailable — store does not attribute tokens per worker"} | ${w.patchBytes ?? "unavailable — no worker patch file"} | ${w.passed === null ? "unavailable — no finished event" : String(w.passed)} |`);
1154
+ out.push("");
1155
+ }
1156
+ out.push("## Outcome");
1157
+ out.push("");
1158
+ out.push("| Metric | Value |");
1159
+ out.push("|---|---|");
1160
+ out.push(`| Supervisor status | ${showMeasured(r.outcome.supStatus)} |`);
1161
+ out.push(`| Supervisor verdict | ${showMeasured(r.outcome.supVerdict)} |`);
1162
+ out.push(`| Delivered | ${showMeasured(r.outcome.delivered)} |`);
1163
+ out.push(`| Judge resolved | ${showMeasured(r.outcome.judgeResolved)} |`);
1164
+ out.push(`| Judge score | ${showMeasured(r.outcome.judgeScore)} |`);
1165
+ out.push(`| Judge passed / total | ${showMeasured(r.outcome.judgePassed)} / ${showMeasured(r.outcome.judgeTotal)} |`);
1166
+ out.push(`| Judge source | ${r.outcome.judgeSource ?? "unavailable — no judge.json and no ledger row"} |`);
1167
+ out.push(`| Verify gate | pass=${showMeasured(r.outcome.verifyPass)} rc=${showMeasured(r.outcome.verifyRc)} |`);
1168
+ if (isUnavailable(r.outcome.patch)) out.push(`| Patch | unavailable — ${r.outcome.patch.unavailable} |`);
1169
+ else {
1170
+ const p = r.outcome.patch;
1171
+ out.push(`| Patch | ${p.files} file(s), +${p.linesAdded}/-${p.linesRemoved}, test files touched: ${p.testFilesTouched.length === 0 ? "none" : p.testFilesTouched.join(", ")} |`);
1172
+ }
1173
+ out.push("");
1174
+ out.push("## Gaps");
1175
+ out.push("");
1176
+ if (r.gaps.length === 0) out.push("None — every metric above is backed by a present artifact.");
1177
+ else for (const g of r.gaps) out.push(`- ${g}`);
1178
+ out.push("");
1179
+ out.push(`> Harness-session view of the same run (model calls, stuck loops, tool errors): \`${r.traceCommand}\``);
1180
+ out.push("");
1181
+ return out.join("\n");
1182
+ }
1183
+ function fmtCounts(v) {
1184
+ if (isUnavailable(v)) return showMeasured(v);
1185
+ const entries = Object.entries(v);
1186
+ return entries.length === 0 ? "none" : entries.map(([k, n]) => `${k}=${n}`).join(", ");
1187
+ }
1188
+ function renderSupervisorRollupMarkdown(rollup, title = "Round rollup") {
1189
+ const out = [];
1190
+ out.push(`# ${title}`);
1191
+ out.push("");
1192
+ out.push(`- Cells: ${rollup.cells}`);
1193
+ out.push(`- **Steers across all cells: ${showMeasured(rollup.steersTotal)}** (cells with ≥1 steer: ${showMeasured(rollup.cellsWithSteers)}; cells where the steer count is unavailable: ${rollup.cellsWithUnavailableSteers})`);
1194
+ out.push(`- Waves per cell (mean): ${showMeasured(rollup.wavesMean)}`);
1195
+ out.push(`- Max concurrency observed: ${showMeasured(rollup.maxConcurrencyMax)}`);
1196
+ out.push(`- Worker utilization (mean): ${showMeasured(rollup.utilizationMean)}`);
1197
+ out.push(`- Idle share (mean): ${showMeasured(rollup.idlePctMean)}%`);
1198
+ out.push(`- Workers spawned: ${showMeasured(rollup.workersSpawnedTotal)} · accepted: ${showMeasured(rollup.acceptedTotal)}`);
1199
+ out.push(`- Spend: $${showMeasured(rollup.usdTotal)} · judged resolved: ${showMeasured(rollup.resolvedCount)}/${rollup.cells}`);
1200
+ out.push("");
1201
+ out.push("| Instance | Arm | Steers | Waves | Utilization | Idle % | Resolved | USD |");
1202
+ out.push("|---|---|---:|---:|---:|---:|---|---:|");
1203
+ for (const c of rollup.perCell) out.push(`| ${c.instanceId ?? "?"} | ${c.arm ?? "?"} | ${showMeasured(c.steers)} | ${showMeasured(c.waves)} | ${showMeasured(c.utilization)} | ${showMeasured(c.idlePct)} | ${showMeasured(c.resolved)} | ${showMeasured(c.usd)} |`);
1204
+ out.push("");
1205
+ return out.join("\n");
1206
+ }
1207
+ //#endregion
1208
+ //#region src/supervisor-run/loops-reader.ts
1209
+ /**
1210
+ * ONE implementation of `SupervisorRunReader`: the on-disk layout the loops
1211
+ * supervisor writes — `<runDir>/ws/.loops/supervisor/<id>/{journal.jsonl,
1212
+ * state.json, progress.ndjson, workers/*.ndjson}` alongside the run's
1213
+ * `result.json` / `judge.json` / `driver.log` / delivered patch.
1214
+ *
1215
+ * Nothing in `analyze.ts` knows this layout exists. A different store (an
1216
+ * archive, an object bucket, a database) implements the same interface and
1217
+ * gets the same report.
1218
+ *
1219
+ * Worker token recovery reuses the rollout module's opencode reader rather
1220
+ * than opening a second sqlite path — one store client, one corruption policy.
1221
+ */
1222
+ async function readMaybe(path) {
1223
+ return readFile(path, "utf8").catch(() => null);
1224
+ }
1225
+ /** Locate the (single) supervisor run dir under `<ws>/.loops/supervisor`. */
1226
+ async function findSupervisorRunDirIn(ws) {
1227
+ const root = join(ws, ".loops", "supervisor");
1228
+ return (await readdir(root, { withFileTypes: true }).catch(() => [])).filter((e) => e.isDirectory()).map((e) => join(root, e.name))[0] ?? null;
1229
+ }
1230
+ /**
1231
+ * Read a loops supervisor run directory into source bytes. Never throws on a
1232
+ * missing artifact — an absent file becomes a `null` field, which is what makes
1233
+ * the dependent metric `unavailable` instead of 0.
1234
+ */
1235
+ async function readLoopsSupervisorRun(runDir, opts = {}) {
1236
+ const ws = opts.ws ?? join(runDir, "ws");
1237
+ const supRunDir = await findSupervisorRunDirIn(ws);
1238
+ const result = await readMaybe(join(runDir, "result.json"));
1239
+ const resultObj = parseJson(result);
1240
+ let workers = null;
1241
+ let workersMissingReason = null;
1242
+ const workerCwds = [];
1243
+ if (supRunDir === null) workersMissingReason = `no supervisor run dir under ${join(ws, ".loops", "supervisor")}`;
1244
+ else {
1245
+ const workersDir = join(supRunDir, "workers");
1246
+ const entries = await readdir(workersDir).catch(() => null);
1247
+ if (entries === null) workersMissingReason = `workers/ directory absent under ${supRunDir}`;
1248
+ else {
1249
+ const labels = [...new Set(entries.filter((f) => f.endsWith(".ndjson")).map((f) => f.replace(/\.inbox\.ndjson$/, "").replace(/\.ndjson$/, "")))].sort();
1250
+ workers = [];
1251
+ for (const label of labels) {
1252
+ const events = await readMaybe(join(workersDir, `${label}.ndjson`));
1253
+ const inbox = await readMaybe(join(workersDir, `${label}.inbox.ndjson`));
1254
+ const patch = await readMaybe(join(workersDir, `${label}.patch`));
1255
+ workers.push({
1256
+ label,
1257
+ events,
1258
+ inbox,
1259
+ patchBytes: patch === null ? null : Buffer.byteLength(patch)
1260
+ });
1261
+ for (const ev of parseJsonl(events)) if (ev.kind === "started" && typeof ev.cwd === "string") workerCwds.push(ev.cwd);
1262
+ }
1263
+ }
1264
+ }
1265
+ let harnessWorkerTokens = null;
1266
+ let harnessMissingReason = null;
1267
+ if (opts.opencodeDb === null) harnessMissingReason = "opencode join disabled";
1268
+ else if (workerCwds.length === 0) harnessMissingReason = "no worker clone cwds in workers/*.ndjson (nothing to join)";
1269
+ else {
1270
+ const db = await openOpencodeDb(opts.opencodeDb ?? DEFAULT_OPENCODE_DB);
1271
+ if (db === null) harnessMissingReason = `opencode session store unreadable at ${opts.opencodeDb ?? DEFAULT_OPENCODE_DB}`;
1272
+ else try {
1273
+ const seen = /* @__PURE__ */ new Set();
1274
+ let sessions = 0;
1275
+ let input = 0;
1276
+ let output = 0;
1277
+ for (const cwd of new Set(workerCwds)) for (const row of findOpencodeSessionsByDirectory(db, cwd)) {
1278
+ if (seen.has(row.id)) continue;
1279
+ seen.add(row.id);
1280
+ sessions += 1;
1281
+ input += row.tokensInput;
1282
+ output += row.tokensOutput + row.tokensReasoning;
1283
+ }
1284
+ harnessWorkerTokens = {
1285
+ store: "opencode",
1286
+ sessions,
1287
+ input,
1288
+ output
1289
+ };
1290
+ } finally {
1291
+ db.close();
1292
+ }
1293
+ }
1294
+ const patchPath = opts.patchPath ?? (typeof resultObj?.patchPath === "string" ? resultObj.patchPath : null);
1295
+ let judge = await readMaybe(join(runDir, "judge.json"));
1296
+ let judgeSource = judge === null ? null : join(runDir, "judge.json");
1297
+ if (judge === null && opts.ledgerPath !== void 0) {
1298
+ const row = await findLedgerRow(opts.ledgerPath, runDir);
1299
+ if (row !== null) {
1300
+ judge = JSON.stringify(row);
1301
+ judgeSource = `${opts.ledgerPath} (ledger row)`;
1302
+ }
1303
+ }
1304
+ return {
1305
+ runRef: runDir,
1306
+ instanceId: typeof resultObj?.iid === "string" ? resultObj.iid : instanceIdFromPath(runDir),
1307
+ arm: typeof resultObj?.arm === "string" ? resultObj.arm : basename(runDir),
1308
+ supRunDir,
1309
+ journal: supRunDir === null ? null : await readMaybe(join(supRunDir, "journal.jsonl")),
1310
+ brainLog: supRunDir === null ? null : await readMaybe(join(supRunDir, "brain.jsonl")),
1311
+ state: supRunDir === null ? null : await readMaybe(join(supRunDir, "state.json")),
1312
+ progress: supRunDir === null ? null : await readMaybe(join(supRunDir, "progress.ndjson")),
1313
+ workers,
1314
+ workersMissingReason,
1315
+ result,
1316
+ judge,
1317
+ judgeSource,
1318
+ patch: patchPath === null ? null : await readMaybe(patchPath),
1319
+ driverLog: await readMaybe(join(runDir, "driver.log")),
1320
+ harnessWorkerTokens,
1321
+ harnessMissingReason,
1322
+ limits: NO_SOURCE_LIMITS,
1323
+ traceCommand: null
1324
+ };
1325
+ }
1326
+ /** The loops on-disk layout, as a `SupervisorRunReader`. */
1327
+ function loopsSupervisorRunReader(runDir, opts = {}) {
1328
+ return {
1329
+ runRef: runDir,
1330
+ read: () => readLoopsSupervisorRun(runDir, opts)
1331
+ };
1332
+ }
1333
+ /** The ledger row whose `runDir` is this run (falling back to iid + arm match). */
1334
+ async function findLedgerRow(ledgerPath, runDir) {
1335
+ const rows = parseJsonl(await readMaybe(ledgerPath));
1336
+ const exact = rows.find((r) => r.runDir === runDir);
1337
+ if (exact !== void 0) return exact;
1338
+ const iid = instanceIdFromPath(runDir);
1339
+ const arm = basename(runDir);
1340
+ return rows.find((r) => r.iid === iid && r.arm === arm) ?? null;
1341
+ }
1342
+ /** `<outDir>/runs/<iid>/<arm>` → `<iid>`. */
1343
+ function instanceIdFromPath(runDir) {
1344
+ const parts = runDir.split("/").filter(Boolean);
1345
+ const armIdx = parts.length - 1;
1346
+ const iid = parts[armIdx - 1];
1347
+ return parts[armIdx - 2] === "runs" && iid !== void 0 ? iid : null;
1348
+ }
1349
+ /**
1350
+ * Analyze a supervisor run. Accepts a run directory (read through the loops
1351
+ * reader), any `SupervisorRunReader`, or already-read source bytes — so a
1352
+ * caller with its own store never has to touch the filesystem layout.
1353
+ */
1354
+ async function analyzeSupervisorRun(input, opts = {}) {
1355
+ if (typeof input === "string") return analyzeSupervisorRunSources(await readLoopsSupervisorRun(input, opts));
1356
+ if (isReader(input)) return analyzeSupervisorRunSources(await input.read());
1357
+ return analyzeSupervisorRunSources(input);
1358
+ }
1359
+ function isReader(input) {
1360
+ return typeof input.read === "function";
1361
+ }
1362
+ /**
1363
+ * Read a completed run, write `run-report.json` + `run-report.md` beside its
1364
+ * artifacts, and append the headline block to the run log. Never throws on a
1365
+ * missing artifact — a run that produced nothing still yields a report whose
1366
+ * every metric says why.
1367
+ */
1368
+ async function writeSupervisorRunReport(runDir, opts = {}) {
1369
+ const report = analyzeSupervisorRunSources(await readLoopsSupervisorRun(runDir, opts));
1370
+ const md = renderSupervisorRunMarkdown(report);
1371
+ const dest = opts.reportDir ?? runDir;
1372
+ const stem = opts.reportDir === void 0 ? "run-report" : supervisorReportStem(runDir);
1373
+ if (opts.reportDir !== void 0) await mkdir(opts.reportDir, { recursive: true }).catch(() => {});
1374
+ await writeFile(join(dest, `${stem}.json`), JSON.stringify(report, null, 1)).catch(() => {});
1375
+ await writeFile(join(dest, `${stem}.md`), md).catch(() => {});
1376
+ const headline = renderSupervisorRunHeadline(report);
1377
+ if (opts.appendHeadlineTo !== void 0) await appendFile(opts.appendHeadlineTo, `${headline}\n`).catch(() => {});
1378
+ if (opts.echo !== false) console.log(headline);
1379
+ return report;
1380
+ }
1381
+ /**
1382
+ * File stem for out-of-tree reports. Built from the run path's identifying
1383
+ * segments — candidate tag (the segment under `arm-runs/`), rep, instance, arm
1384
+ * — so two runs of the same instance from different candidates/reps never
1385
+ * overwrite each other.
1386
+ */
1387
+ function supervisorReportStem(runDir) {
1388
+ const parts = runDir.split("/").filter(Boolean);
1389
+ const arm = parts[parts.length - 1] ?? "cell";
1390
+ const iid = parts[parts.length - 2] ?? "instance";
1391
+ const rep = parts.find((p) => /^rep-\d+$/.test(p));
1392
+ const armRunsIdx = parts.indexOf("arm-runs");
1393
+ return [
1394
+ armRunsIdx >= 0 ? parts[armRunsIdx + 1] : void 0,
1395
+ rep,
1396
+ iid,
1397
+ arm
1398
+ ].filter((s) => s !== void 0 && s !== "runs").join(".").replace(/[^A-Za-z0-9._-]/g, "_");
1399
+ }
1400
+ /**
1401
+ * Best-effort wrapper for a hot path: a reporting failure must never kill a run
1402
+ * that already produced real work. Returns null and logs the reason instead.
1403
+ */
1404
+ async function writeSupervisorRunReportSafe(runDir, opts = {}) {
1405
+ try {
1406
+ return await writeSupervisorRunReport(runDir, opts);
1407
+ } catch (err) {
1408
+ console.log(`RUN-REPORT failed for ${runDir}: ${err instanceof Error ? err.message : String(err)}`);
1409
+ return null;
1410
+ }
1411
+ }
1412
+ /**
1413
+ * Report every run under an experiment `outDir` (any depth of
1414
+ * `runs/<iid>/<arm>`), write each run's report, and write the rollup at
1415
+ * `<outDir>/run-report-round.{json,md}`.
1416
+ */
1417
+ async function reportSupervisorRound(outDir, opts = {}) {
1418
+ const runDirs = await findSupervisorRunDirs(outDir);
1419
+ const reports = [];
1420
+ for (const runDir of runDirs) {
1421
+ const r = await writeSupervisorRunReportSafe(runDir, {
1422
+ ...opts,
1423
+ echo: opts.echo ?? false
1424
+ });
1425
+ if (r !== null) reports.push(r);
1426
+ }
1427
+ const rollup = rollupSupervisorRuns(reports);
1428
+ const md = renderSupervisorRollupMarkdown(rollup, opts.title ?? `Round rollup — ${basename(outDir)}`);
1429
+ const dest = opts.reportDir ?? outDir;
1430
+ if (opts.reportDir !== void 0) await mkdir(opts.reportDir, { recursive: true }).catch(() => {});
1431
+ await writeFile(join(dest, "run-report-round.json"), JSON.stringify(rollup, null, 1)).catch(() => {});
1432
+ await writeFile(join(dest, "run-report-round.md"), md).catch(() => {});
1433
+ if (opts.appendHeadlineTo !== void 0) await appendFile(opts.appendHeadlineTo, `${md}\n`).catch(() => {});
1434
+ if (opts.echo !== false) console.log(md);
1435
+ return rollup;
1436
+ }
1437
+ /** Every `<...>/runs/<iid>/<arm>` directory under `root`. */
1438
+ async function findSupervisorRunDirs(root) {
1439
+ const found = [];
1440
+ const walk = async (dir, depth) => {
1441
+ if (depth > 8) return;
1442
+ const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
1443
+ for (const e of entries) {
1444
+ if (!e.isDirectory()) continue;
1445
+ if (e.name === "node_modules" || e.name === ".git") continue;
1446
+ const full = join(dir, e.name);
1447
+ if (e.name === "runs") {
1448
+ const iids = await readdir(full, { withFileTypes: true }).catch(() => []);
1449
+ for (const iid of iids) {
1450
+ if (!iid.isDirectory()) continue;
1451
+ const arms = await readdir(join(full, iid.name), { withFileTypes: true }).catch(() => []);
1452
+ for (const arm of arms) if (arm.isDirectory()) found.push(join(full, iid.name, arm.name));
1453
+ }
1454
+ continue;
1455
+ }
1456
+ await walk(full, depth + 1);
1457
+ }
1458
+ };
1459
+ await walk(root, 0);
1460
+ return found.sort();
1461
+ }
1462
+ //#endregion
1463
+ //#region src/supervisor-run/rollout-nodes.ts
1464
+ /**
1465
+ * The supervision tree as `tangle.rollout.v1` rows.
1466
+ *
1467
+ * A supervisor run IS a tree of rollouts, so its nodes are not a new shape:
1468
+ * the root becomes one `RolloutLine` with `role: 'supervisor'`, every spawned
1469
+ * worker becomes a `RolloutLine` with `role: 'worker'` and
1470
+ * `parent_rollout_id` pointing at its spawner. The rows append to the same
1471
+ * ledger as solo-agent rollouts and join to them with the same keys.
1472
+ *
1473
+ * What the journal CANNOT supply is the transcript: a worker's messages live
1474
+ * in its harness store (opencode sqlite, Claude Code jsonl), which the
1475
+ * `src/rollout/readers/*` intake readers own. Rows minted here are therefore
1476
+ * GAP lines (`messages: []`, `provenance.gap` set) carrying identity,
1477
+ * structure, outcome and cost; hydrating them with messages is the readers'
1478
+ * job, keyed on `artifacts.transcript_ref`.
1479
+ *
1480
+ * Timing lives in `outcome.metrics` (`spawned_at` / `settled_at` / `wall_ms`)
1481
+ * rather than a schema field: `tangle.rollout.v1` describes ONE invocation,
1482
+ * and the inter-invocation event timeline — which is what waves, concurrency,
1483
+ * idle and utilization are computed from — is a property of the journal, not
1484
+ * of any single row. The analyzer reads that timeline; these rows carry the
1485
+ * per-node facts.
1486
+ */
1487
+ const EMPTY_COST = {
1488
+ usd: null,
1489
+ tokens_in: null,
1490
+ tokens_out: null,
1491
+ tokens_reasoning: null,
1492
+ cache_read: null,
1493
+ cache_write: null,
1494
+ wall_s: null
1495
+ };
1496
+ /**
1497
+ * Mint the supervision tree as rollout rows. Returns the rows plus the gaps
1498
+ * that made any of them incomplete — same unavailable-vs-zero discipline as
1499
+ * the report: a row with no transcript says WHY, it never pretends to be empty.
1500
+ */
1501
+ function supervisorRunRolloutLines(src, opts = {}) {
1502
+ const gaps = [];
1503
+ const tree = parseSupervisorTree(src);
1504
+ if (src.journal === null) {
1505
+ gaps.push(`tree: ${src.supRunDir === null ? "no supervisor run dir" : "journal absent"} — no nodes recoverable`);
1506
+ return {
1507
+ rootId: null,
1508
+ nodes: [],
1509
+ gaps
1510
+ };
1511
+ }
1512
+ const state = parseJson(src.state);
1513
+ const result = parseJson(src.result);
1514
+ const judge = parseJson(src.judge);
1515
+ const stateResult = asRecord(state?.result);
1516
+ const rootId = tree.rootId;
1517
+ const runId = opts.runId ?? rootId ?? src.runRef;
1518
+ const suite = opts.suite ?? "supervisor-run";
1519
+ const instanceId = src.instanceId ?? src.runRef;
1520
+ const split = opts.split ?? "search";
1521
+ const capturedAt = opts.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
1522
+ const base = {
1523
+ schema: ROLLOUT_SCHEMA,
1524
+ run_id: runId,
1525
+ experiment_id: opts.experimentId ?? null,
1526
+ candidate_id: opts.candidateId ?? null,
1527
+ generation: opts.generation ?? null,
1528
+ candidate_index: opts.candidateIndex ?? null,
1529
+ task: {
1530
+ suite,
1531
+ instance_id: instanceId,
1532
+ split,
1533
+ seed: opts.seed ?? null,
1534
+ rep: opts.rep ?? 0
1535
+ },
1536
+ messages: [],
1537
+ tool_defs: []
1538
+ };
1539
+ const nodes = [];
1540
+ if (rootId !== null) {
1541
+ const judgeResolved = typeof judge?.resolved === "boolean" ? judge.resolved : null;
1542
+ const reward = (typeof judge?.score === "number" ? judge.score : null) ?? (judgeResolved === null ? null : judgeResolved ? 1 : 0);
1543
+ if (reward === null) gaps.push("root.outcome.reward: no judge verdict for this run");
1544
+ const wallMs = tree.startedAt !== null && tree.completedAt !== null && tree.completedAt >= tree.startedAt ? tree.completedAt - tree.startedAt : null;
1545
+ nodes.push({
1546
+ ...base,
1547
+ rollout_id: rootId,
1548
+ parent_rollout_id: null,
1549
+ role: "supervisor",
1550
+ policy: {
1551
+ harness: opts.supervisorHarness ?? null,
1552
+ harness_version: null,
1553
+ model: opts.supervisorModel ?? null,
1554
+ provider: null,
1555
+ profile_commit: null,
1556
+ sampling: null
1557
+ },
1558
+ outcome: {
1559
+ ...unscreenedRewardFields(reward),
1560
+ reward_source: src.judgeSource,
1561
+ verdict: judge ?? null,
1562
+ metrics: {
1563
+ arm: src.arm,
1564
+ sup_status: typeof state?.status === "string" ? state.status : null,
1565
+ sup_verdict: typeof state?.verdict === "string" ? state.verdict : null,
1566
+ delivered: typeof stateResult.delivered === "boolean" ? stateResult.delivered : null,
1567
+ verify_pass: typeof result?.verify_pass === "boolean" ? result.verify_pass : null,
1568
+ started_at: tree.startedAt,
1569
+ completed_at: tree.completedAt,
1570
+ workers_spawned: tree.workerSpawns.length,
1571
+ brain_metered_events: tree.brain.meteredCount
1572
+ },
1573
+ is_completed: state?.status === "completed",
1574
+ is_truncated: false,
1575
+ error: null,
1576
+ realness_gated: false
1577
+ },
1578
+ cost: {
1579
+ ...EMPTY_COST,
1580
+ usd: src.limits.spendUsd !== null ? null : typeof stateResult.spentUsd === "number" ? stateResult.spentUsd : tree.brain.usd,
1581
+ tokens_in: tree.brain.tokensIn,
1582
+ tokens_out: tree.brain.tokensOut,
1583
+ cache_read: tree.brain.hasCache ? tree.brain.cacheRead : null,
1584
+ cache_write: tree.brain.hasCache ? tree.brain.cacheWrite : null,
1585
+ wall_s: wallMs === null ? null : wallMs / 1e3
1586
+ },
1587
+ artifacts: {
1588
+ patch_path: typeof result?.patchPath === "string" ? result.patchPath : null,
1589
+ run_dir: src.supRunDir,
1590
+ transcript_ref: src.rootTranscriptRef !== void 0 ? src.rootTranscriptRef : src.supRunDir === null ? null : `${src.supRunDir}/journal.jsonl`
1591
+ },
1592
+ provenance: {
1593
+ captured_at: capturedAt,
1594
+ capture: "backfill",
1595
+ gap: "supervision journal carries structure and spend, not the brain transcript"
1596
+ }
1597
+ });
1598
+ } else gaps.push("tree.root: no parentless `spawned` event in the journal");
1599
+ const closeById = new Map(tree.closes.map((c) => [c.id, c]));
1600
+ const sourceByLabel = new Map((src.workers ?? []).map((w) => [w.label, w]));
1601
+ for (const spawn of tree.workerSpawns) {
1602
+ const close = closeById.get(spawn.id) ?? null;
1603
+ const facts = tree.workerLogs.get(spawn.label) ?? null;
1604
+ const workerSource = sourceByLabel.get(spawn.label) ?? null;
1605
+ const wallMs = facts?.started != null && facts.finishedAt != null ? facts.finishedAt - facts.started : null;
1606
+ const reward = facts?.passed === null || facts === null ? null : facts.passed ? 1 : 0;
1607
+ if (reward === null) gaps.push(`worker ${spawn.label}: no verify verdict (worker logs absent or unfinished)`);
1608
+ nodes.push({
1609
+ ...base,
1610
+ rollout_id: spawn.id,
1611
+ parent_rollout_id: spawn.parent,
1612
+ role: "worker",
1613
+ policy: {
1614
+ harness: opts.workerHarness ?? null,
1615
+ harness_version: null,
1616
+ model: opts.workerModel ?? null,
1617
+ provider: null,
1618
+ profile_commit: null,
1619
+ sampling: null
1620
+ },
1621
+ outcome: {
1622
+ ...unscreenedRewardFields(reward),
1623
+ reward_source: reward === null ? null : "worker-self-verify",
1624
+ verdict: close === null ? null : {
1625
+ kind: close.kind,
1626
+ status: close.status,
1627
+ verdict: close.verdict
1628
+ },
1629
+ metrics: {
1630
+ label: spawn.label,
1631
+ spawned_at: spawn.at,
1632
+ settled_at: close?.at ?? null,
1633
+ started_at: facts?.started ?? null,
1634
+ finished_at: facts?.finishedAt ?? null,
1635
+ wall_ms: wallMs,
1636
+ patch_bytes: facts?.finishedPatchBytes ?? null,
1637
+ evidence_bytes: facts?.evidenceBytes ?? null,
1638
+ steers_queued: facts?.steersQueued ?? null,
1639
+ steers_delivered: facts?.steersDelivered ?? null,
1640
+ questions: facts?.questions ?? null
1641
+ },
1642
+ is_completed: close?.kind === "settled",
1643
+ is_truncated: close?.kind === "cancelled",
1644
+ error: close?.kind === "cancelled" ? close.verdict ?? "cancelled" : null,
1645
+ realness_gated: false
1646
+ },
1647
+ cost: {
1648
+ ...EMPTY_COST,
1649
+ usd: src.limits.spendUsd !== null || !close?.hasSpend ? null : close.spend.usd,
1650
+ tokens_in: workerSource?.tokensIn ?? (close?.hasSpend ? close.spend.tokens.input : null),
1651
+ tokens_out: workerSource?.tokensOut ?? (close?.hasSpend ? close.spend.tokens.output : null),
1652
+ cache_read: workerSource?.cacheRead ?? (close?.hasSpend && close.spend.tokens.hasCache ? close.spend.tokens.cacheRead : null),
1653
+ cache_write: workerSource?.cacheWrite ?? (close?.hasSpend && close.spend.tokens.hasCache ? close.spend.tokens.cacheWrite : null),
1654
+ wall_s: wallMs === null ? null : wallMs / 1e3
1655
+ },
1656
+ artifacts: {
1657
+ patch_path: workerSource?.patchPath !== void 0 ? workerSource.patchPath : src.supRunDir === null ? null : `${src.supRunDir}/workers/${spawn.label}.patch`,
1658
+ run_dir: src.supRunDir,
1659
+ transcript_ref: workerSource?.transcriptRef !== void 0 ? workerSource.transcriptRef : src.supRunDir === null ? null : `${src.supRunDir}/workers/${spawn.label}.ndjson`
1660
+ },
1661
+ provenance: {
1662
+ captured_at: capturedAt,
1663
+ capture: "backfill",
1664
+ gap: workerSource?.transcriptRef == null ? "worker transcript lives in the harness session store — hydrate via src/rollout/readers" : "worker transcript recorded by the harness; messages not inlined into this row"
1665
+ }
1666
+ });
1667
+ }
1668
+ const invalid = nodes.filter((n) => !isRolloutLine(n));
1669
+ if (invalid.length > 0) gaps.push(`${invalid.length} node(s) failed tangle.rollout.v1 validation`);
1670
+ return {
1671
+ rootId,
1672
+ nodes,
1673
+ gaps
1674
+ };
1675
+ }
1676
+ //#endregion
1677
+ export { NO_SOURCE_LIMITS as C, showMeasured as D, isUnavailable as E, unavailable as O, rollupSupervisorRuns as S, SUPERVISOR_RUN_SCHEMA as T, claudeCodeSupervisorRunReader as _, loopsSupervisorRunReader as a, parsePatch as b, supervisorReportStem as c, renderSupervisorRollupMarkdown as d, renderSupervisorRunHeadline as f, DEFAULT_STEER_TOOLS as g, DEFAULT_SPAWN_TOOLS as h, findSupervisorRunDirs as i, writeSupervisorRunReport as l, DEFAULT_CANCEL_TOOLS as m, analyzeSupervisorRun as n, readLoopsSupervisorRun as o, renderSupervisorRunMarkdown as p, findSupervisorRunDirIn as r, reportSupervisorRound as s, supervisorRunRolloutLines as t, writeSupervisorRunReportSafe as u, readClaudeCodeSupervisorRun as v, SUPERVISOR_RUN_ROLLUP_SCHEMA as w, parseSupervisorTree as x, analyzeSupervisorRunSources as y };
1678
+
1679
+ //# sourceMappingURL=supervisor-run-_lnTLM3z.js.map