humanish 0.106.1 → 0.107.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 (453) hide show
  1. package/AGENTS.md +4 -4
  2. package/ARCHITECTURE.md +17 -16
  3. package/CHANGELOG.md +14 -0
  4. package/CONTEXT.md +42 -39
  5. package/CONTRIBUTING.md +8 -8
  6. package/README.md +8 -3
  7. package/dist/actors/codex/app-server-client.js +2 -1
  8. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  9. package/dist/actors/codex/app-server-trace.js +1 -3
  10. package/dist/actors/codex/app-server.js +2 -1
  11. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  12. package/dist/actors/codex/protocol-compat.js +357 -0
  13. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  14. package/dist/actors/codex/protocol-contract.js +471 -0
  15. package/dist/actors/codex/qualified-versions.d.ts +30 -3
  16. package/dist/actors/codex/qualified-versions.js +50 -5
  17. package/dist/actors/codex/restricted-executable.d.ts +24 -0
  18. package/dist/actors/codex/restricted-executable.js +97 -22
  19. package/dist/actors/codex/restricted-launch.d.ts +7 -1
  20. package/dist/actors/codex/restricted-launch.js +42 -3
  21. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  22. package/dist/actors/codex/restricted-notifications.js +277 -0
  23. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  24. package/dist/actors/codex/restricted-participant.js +60 -2
  25. package/dist/actors/codex/restricted-policy.d.ts +9 -1
  26. package/dist/actors/codex/restricted-session.d.ts +14 -1
  27. package/dist/actors/codex/restricted-session.js +50 -17
  28. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  29. package/dist/actors/codex/restricted-transport.js +139 -27
  30. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  31. package/dist/actors/codex/restricted-turn.js +43 -30
  32. package/dist/actors/computer-use/actor.d.ts +1 -1
  33. package/dist/actors/computer-use/actor.js +4 -4
  34. package/dist/actors/computer-use/loop/backstop.js +1 -1
  35. package/dist/actors/computer-use/loop/ending.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/ending.js +2 -2
  37. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/spend.js +3 -3
  39. package/dist/actors/computer-use/loop/trace.js +2 -2
  40. package/dist/actors/computer-use/loop/types.d.ts +14 -5
  41. package/dist/actors/computer-use/loop.js +4 -4
  42. package/dist/actors/computer-use/openai-provider.d.ts +1 -1
  43. package/dist/actors/computer-use/openai-provider.js +2 -2
  44. package/dist/actors/contract.d.ts +9 -7
  45. package/dist/actors/local-agent/cli.js +1 -1
  46. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  47. package/dist/actors/scripted-browser/journey.js +15 -4
  48. package/dist/actors/scripted-browser/steps.js +18 -0
  49. package/dist/actors/scripted-browser/types.d.ts +11 -1
  50. package/dist/actors/stop-conditions.js +1 -3
  51. package/dist/analysis/automatic-completion.d.ts +13 -8
  52. package/dist/analysis/automatic-completion.js +14 -8
  53. package/dist/analysis/automatic-config.d.ts +1 -1
  54. package/dist/analysis/automatic-config.js +2 -2
  55. package/dist/analysis/automatic.d.ts +10 -4
  56. package/dist/analysis/automatic.js +17 -13
  57. package/dist/analysis/diagnostics.d.ts +23 -0
  58. package/dist/analysis/diagnostics.js +112 -0
  59. package/dist/analysis/evidence-sources.js +2 -2
  60. package/dist/analysis/evidence.js +6 -6
  61. package/dist/analysis/execute.d.ts +7 -1
  62. package/dist/analysis/execute.js +39 -12
  63. package/dist/analysis/job.d.ts +8 -5
  64. package/dist/analysis/job.js +15 -14
  65. package/dist/analysis/load.d.ts +1 -1
  66. package/dist/analysis/load.js +5 -5
  67. package/dist/analysis/provider.d.ts +9 -1
  68. package/dist/analysis/restricted-codex.d.ts +2 -0
  69. package/dist/analysis/restricted-codex.js +10 -1
  70. package/dist/analysis/service.d.ts +2 -0
  71. package/dist/analysis/service.js +31 -12
  72. package/dist/analysis/sharing.d.ts +2 -2
  73. package/dist/analysis/sharing.js +5 -5
  74. package/dist/analysis/store-executions.d.ts +5 -5
  75. package/dist/analysis/store-executions.js +12 -12
  76. package/dist/analysis/store.d.ts +4 -4
  77. package/dist/analysis/store.js +13 -13
  78. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  79. package/dist/cli/commands/analysis-signals.js +4 -1
  80. package/dist/cli/commands/analyze.js +4 -2
  81. package/dist/cli/commands/comms.js +8 -1
  82. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  83. package/dist/cli/commands/lab-route-computer-use.js +26 -14
  84. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  85. package/dist/cli/commands/lab-route-preview.js +3 -4
  86. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  87. package/dist/cli/commands/lab-route-run.js +6 -2
  88. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  89. package/dist/cli/commands/lab-route-scripted.js +0 -1
  90. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  91. package/dist/cli/commands/lab-route-shared-world.js +0 -1
  92. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  93. package/dist/cli/commands/lab-route-terminal.js +0 -1
  94. package/dist/cli/commands/lab-run.js +76 -45
  95. package/dist/cli/commands/lab-scorer.d.ts +0 -2
  96. package/dist/cli/commands/lab.js +12 -6
  97. package/dist/cli/commands/observe.js +22 -0
  98. package/dist/cli/commands/run-signals.d.ts +30 -0
  99. package/dist/cli/commands/run-signals.js +146 -0
  100. package/dist/cli/commands/runs.js +10 -8
  101. package/dist/cli/commands/watch.js +12 -10
  102. package/dist/cli/doctor.d.ts +3 -0
  103. package/dist/cli/doctor.js +10 -2
  104. package/dist/cli/io.d.ts +5 -4
  105. package/dist/cli/io.js +12 -8
  106. package/dist/cli/program.js +3 -3
  107. package/dist/cli/renamed-options.d.ts +11 -0
  108. package/dist/cli/renamed-options.js +18 -0
  109. package/dist/cli/telemetry.d.ts +2 -2
  110. package/dist/cli/telemetry.js +1 -1
  111. package/dist/comms/capture-surface.d.ts +1 -1
  112. package/dist/comms/catch-host.d.ts +1 -1
  113. package/dist/comms/connections.js +4 -4
  114. package/dist/comms/external-evidence.d.ts +27 -0
  115. package/dist/comms/external-evidence.js +93 -0
  116. package/dist/comms/lease-store.js +7 -7
  117. package/dist/comms/types.js +1 -1
  118. package/dist/evidence/browser-hygiene.d.ts +1 -1
  119. package/dist/evidence/browser-hygiene.js +1 -1
  120. package/dist/evidence/redaction.js +1 -1
  121. package/dist/evidence/secret-scrub.d.ts +9 -0
  122. package/dist/evidence/secret-scrub.js +96 -0
  123. package/dist/feedback/draft.js +7 -9
  124. package/dist/feedback/export-bundle.js +4 -4
  125. package/dist/feedback/export.js +9 -9
  126. package/dist/feedback/feedback.d.ts +1 -1
  127. package/dist/index.d.ts +3 -6
  128. package/dist/index.js +3 -6
  129. package/dist/keys/key-resolution.d.ts +3 -1
  130. package/dist/keys/key-resolution.js +18 -16
  131. package/dist/lab/adapter-extension.d.ts +28 -6
  132. package/dist/lab/adapter-extension.js +65 -126
  133. package/dist/lab/adapter-scorer-loader.d.ts +25 -5
  134. package/dist/lab/adapter-scorer-loader.js +24 -0
  135. package/dist/lab/composition-rules.js +20 -20
  136. package/dist/lab/config.js +28 -26
  137. package/dist/lab/device-presets.d.ts +2 -2
  138. package/dist/lab/discover.js +1 -3
  139. package/dist/lab/doctor.d.ts +44 -9
  140. package/dist/lab/doctor.js +149 -41
  141. package/dist/lab/init-plan.js +1 -3
  142. package/dist/lab/keys.js +1 -1
  143. package/dist/lab/lab-deps.d.ts +85 -0
  144. package/dist/lab/lab-deps.js +4 -0
  145. package/dist/lab/parse/actors.js +8 -7
  146. package/dist/lab/parse/comms.js +3 -2
  147. package/dist/lab/parse/execution.js +3 -2
  148. package/dist/lab/parse/subject-state.js +2 -1
  149. package/dist/lab/parse/subject.js +2 -1
  150. package/dist/lab/parse/values.d.ts +0 -1
  151. package/dist/lab/parse/values.js +0 -3
  152. package/dist/lab/persona-resolve.d.ts +3 -3
  153. package/dist/lab/persona-resolve.js +4 -4
  154. package/dist/lab/persona.js +1 -3
  155. package/dist/lab/plan-base.d.ts +0 -2
  156. package/dist/lab/plan-base.js +6 -4
  157. package/dist/lab/plan-participants.d.ts +5 -5
  158. package/dist/lab/plan-participants.js +2 -2
  159. package/dist/lab/plan-types.d.ts +22 -4
  160. package/dist/lab/plan.d.ts +3 -11
  161. package/dist/lab/plan.js +18 -42
  162. package/dist/lab/preflight-result.js +0 -2
  163. package/dist/lab/preflight.d.ts +0 -3
  164. package/dist/lab/preflight.js +1 -1
  165. package/dist/lab/requirements.d.ts +20 -0
  166. package/dist/lab/requirements.js +54 -0
  167. package/dist/lab/route-inputs.d.ts +23 -12
  168. package/dist/lab/route-inputs.js +48 -51
  169. package/dist/lab/routing.d.ts +19 -24
  170. package/dist/lab/routing.js +14 -47
  171. package/dist/lab/run-lab-events.d.ts +6 -11
  172. package/dist/lab/run-lab-events.js +3 -11
  173. package/dist/lab/run-lab-homes.d.ts +64 -0
  174. package/dist/lab/run-lab-homes.js +3 -0
  175. package/dist/lab/run-lab-options.d.ts +12 -66
  176. package/dist/lab/run-lab-options.js +45 -275
  177. package/dist/lab/summary.d.ts +9 -4
  178. package/dist/lab/summary.js +15 -8
  179. package/dist/lab/types.d.ts +132 -132
  180. package/dist/lab/validation.d.ts +15 -15
  181. package/dist/lab/validation.js +28 -28
  182. package/dist/lab/warnings.js +20 -19
  183. package/dist/observer/artifact.d.ts +1 -1
  184. package/dist/observer/artifact.js +3 -3
  185. package/dist/observer/data.js +2 -2
  186. package/dist/observer/render.js +2 -2
  187. package/dist/observer/run-routes.d.ts +1 -1
  188. package/dist/observer/run-routes.js +5 -5
  189. package/dist/observer/serve.d.ts +17 -0
  190. package/dist/observer/serve.js +34 -3
  191. package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
  192. package/dist/routes/computer-use/bundle-parts.js +10 -3
  193. package/dist/routes/computer-use/bundle.d.ts +4 -11
  194. package/dist/routes/computer-use/bundle.js +9 -15
  195. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  196. package/dist/routes/computer-use/diagnostics.js +1 -1
  197. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
  198. package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
  199. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  200. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
  201. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
  202. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
  203. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  204. package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
  205. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  206. package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
  207. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  208. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  209. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  210. package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
  211. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  212. package/dist/routes/computer-use/external-comms.js +19 -43
  213. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  214. package/dist/routes/computer-use/fanout-bundle.js +25 -29
  215. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
  216. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  217. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  218. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  219. package/dist/routes/computer-use/live-flush.js +19 -27
  220. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +12 -11
  221. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  222. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  223. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  224. package/dist/routes/computer-use/local-vm.js +39 -66
  225. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  226. package/dist/routes/computer-use/participant-desktop.js +5 -25
  227. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
  228. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
  229. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  230. package/dist/routes/computer-use/participant-facts.js +12 -1
  231. package/dist/routes/computer-use/participant-model.d.ts +19 -11
  232. package/dist/routes/computer-use/participant-model.js +49 -25
  233. package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
  234. package/dist/routes/computer-use/participant-prompt.js +4 -4
  235. package/dist/routes/computer-use/participant-runs.d.ts +6 -6
  236. package/dist/routes/computer-use/participant-runs.js +8 -8
  237. package/dist/routes/computer-use/plan.d.ts +21 -29
  238. package/dist/routes/computer-use/plan.js +52 -60
  239. package/dist/routes/computer-use/preflight.d.ts +3 -5
  240. package/dist/routes/computer-use/preflight.js +20 -16
  241. package/dist/routes/computer-use/rerun-selection.js +10 -6
  242. package/dist/routes/computer-use/result.d.ts +1 -1
  243. package/dist/routes/computer-use/result.js +40 -30
  244. package/dist/routes/computer-use/route.d.ts +3 -4
  245. package/dist/routes/computer-use/route.js +21 -19
  246. package/dist/routes/computer-use/self-report.d.ts +2 -2
  247. package/dist/routes/computer-use/self-report.js +4 -4
  248. package/dist/routes/computer-use/setup.d.ts +8 -14
  249. package/dist/routes/computer-use/setup.js +96 -72
  250. package/dist/routes/computer-use/single-bundle.d.ts +8 -11
  251. package/dist/routes/computer-use/single-bundle.js +20 -25
  252. package/dist/routes/computer-use/subject-projection.d.ts +5 -7
  253. package/dist/routes/computer-use/subject-projection.js +20 -19
  254. package/dist/routes/computer-use/types.d.ts +169 -210
  255. package/dist/routes/computer-use/types.js +13 -5
  256. package/dist/routes/preview.js +0 -1
  257. package/dist/routes/scripted/bundle.d.ts +3 -6
  258. package/dist/routes/scripted/bundle.js +11 -16
  259. package/dist/routes/scripted/plan.d.ts +5 -7
  260. package/dist/routes/scripted/plan.js +6 -4
  261. package/dist/routes/scripted/result.d.ts +4 -1
  262. package/dist/routes/scripted/result.js +10 -6
  263. package/dist/routes/scripted/route.js +10 -11
  264. package/dist/routes/scripted/scenario.d.ts +1 -1
  265. package/dist/routes/scripted/scenario.js +1 -1
  266. package/dist/routes/scripted/setup.d.ts +3 -2
  267. package/dist/routes/scripted/setup.js +22 -21
  268. package/dist/routes/scripted/subject.d.ts +8 -3
  269. package/dist/routes/scripted/subject.js +9 -5
  270. package/dist/routes/scripted/surface-records.js +1 -1
  271. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  272. package/dist/routes/scripted/surface-sessions.js +4 -4
  273. package/dist/routes/scripted/types.d.ts +19 -36
  274. package/dist/routes/scripted/types.js +1 -2
  275. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
  276. package/dist/routes/shared-world/bundle.d.ts +2 -2
  277. package/dist/routes/shared-world/bundle.js +22 -26
  278. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  279. package/dist/routes/shared-world/checkpoints.js +4 -4
  280. package/dist/routes/shared-world/comms.d.ts +5 -4
  281. package/dist/routes/shared-world/comms.js +28 -41
  282. package/dist/routes/shared-world/external-public.d.ts +5 -5
  283. package/dist/routes/shared-world/external-public.js +19 -20
  284. package/dist/routes/shared-world/handoff.d.ts +4 -4
  285. package/dist/routes/shared-world/handoff.js +50 -50
  286. package/dist/routes/shared-world/lobby-code.d.ts +5 -5
  287. package/dist/routes/shared-world/lobby-code.js +13 -13
  288. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
  289. package/dist/routes/shared-world/{seats.js → participant-specs.js} +43 -48
  290. package/dist/routes/shared-world/plan.d.ts +2 -6
  291. package/dist/routes/shared-world/plan.js +1 -2
  292. package/dist/routes/shared-world/provenance.d.ts +4 -4
  293. package/dist/routes/shared-world/provenance.js +4 -4
  294. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  295. package/dist/routes/shared-world/provisioned.js +46 -40
  296. package/dist/routes/shared-world/result.js +31 -19
  297. package/dist/routes/shared-world/route.js +37 -41
  298. package/dist/routes/shared-world/setup.d.ts +5 -4
  299. package/dist/routes/shared-world/setup.js +12 -14
  300. package/dist/routes/shared-world/types.d.ts +53 -126
  301. package/dist/routes/shared-world/types.js +2 -2
  302. package/dist/routes/terminal/adapter.d.ts +8 -8
  303. package/dist/routes/terminal/adapter.js +28 -125
  304. package/dist/routes/terminal/bundle.d.ts +7 -12
  305. package/dist/routes/terminal/bundle.js +24 -34
  306. package/dist/routes/terminal/credentials.d.ts +2 -2
  307. package/dist/routes/terminal/credentials.js +16 -16
  308. package/dist/routes/terminal/dry-run.d.ts +1 -1
  309. package/dist/routes/terminal/dry-run.js +9 -11
  310. package/dist/routes/terminal/encoding.d.ts +1 -1
  311. package/dist/routes/terminal/encoding.js +2 -2
  312. package/dist/routes/terminal/ledger.d.ts +6 -6
  313. package/dist/routes/terminal/ledger.js +9 -9
  314. package/dist/routes/terminal/live-finish.d.ts +1 -2
  315. package/dist/routes/terminal/live-finish.js +21 -20
  316. package/dist/routes/terminal/live-sandbox.d.ts +3 -2
  317. package/dist/routes/terminal/live-sandbox.js +20 -20
  318. package/dist/routes/terminal/participant-text.d.ts +23 -0
  319. package/dist/routes/terminal/participant-text.js +165 -0
  320. package/dist/routes/terminal/plan.d.ts +2 -6
  321. package/dist/routes/terminal/plan.js +13 -9
  322. package/dist/routes/terminal/recorder.d.ts +6 -1
  323. package/dist/routes/terminal/recorder.js +12 -4
  324. package/dist/routes/terminal/result.js +4 -4
  325. package/dist/routes/terminal/route.js +26 -26
  326. package/dist/routes/terminal/runtime.d.ts +3 -2
  327. package/dist/routes/terminal/runtime.js +3 -3
  328. package/dist/routes/terminal/sandbox.d.ts +3 -3
  329. package/dist/routes/terminal/sandbox.js +9 -9
  330. package/dist/routes/terminal/session.js +16 -14
  331. package/dist/routes/terminal/token-usage.js +5 -5
  332. package/dist/routes/terminal/trace.d.ts +5 -8
  333. package/dist/routes/terminal/trace.js +9 -64
  334. package/dist/routes/terminal/types.d.ts +85 -93
  335. package/dist/routes/terminal/types.js +9 -4
  336. package/dist/run/active-runs.d.ts +13 -0
  337. package/dist/run/active-runs.js +12 -0
  338. package/dist/run/bundle-shape.d.ts +2 -1
  339. package/dist/run/bundle-shape.js +4 -4
  340. package/dist/run/bundle.d.ts +63 -56
  341. package/dist/run/bundle.js +9 -8
  342. package/dist/run/cost-summary.js +3 -2
  343. package/dist/run/costs.d.ts +6 -6
  344. package/dist/run/costs.js +10 -10
  345. package/dist/run/detail.d.ts +5 -5
  346. package/dist/run/detail.js +6 -6
  347. package/dist/run/dry-run.js +5 -12
  348. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  349. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  350. package/dist/run/feedback-shape.js +1 -1
  351. package/dist/run/judge.d.ts +16 -4
  352. package/dist/run/judge.js +24 -7
  353. package/dist/run/locate.d.ts +2 -0
  354. package/dist/run/locate.js +3 -1
  355. package/dist/run/outcomes.d.ts +3 -3
  356. package/dist/run/outcomes.js +3 -3
  357. package/dist/run/participant-records.d.ts +2 -2
  358. package/dist/run/participant-records.js +2 -2
  359. package/dist/run/paths.js +1 -1
  360. package/dist/run/pricing.d.ts +19 -9
  361. package/dist/run/pricing.js +30 -18
  362. package/dist/run/projection.d.ts +13 -13
  363. package/dist/run/projection.js +8 -8
  364. package/dist/run/reclaim.d.ts +6 -0
  365. package/dist/run/reclaim.js +13 -3
  366. package/dist/run/results.d.ts +1 -1
  367. package/dist/run/run-index.d.ts +1 -1
  368. package/dist/run/run-index.js +11 -11
  369. package/dist/run/run.d.ts +4 -2
  370. package/dist/run/run.js +9 -5
  371. package/dist/run/sandbox-receipts.d.ts +4 -4
  372. package/dist/run/sandbox-receipts.js +4 -4
  373. package/dist/run/shared-world-evidence.d.ts +47 -47
  374. package/dist/run/shared-world-shape.d.ts +3 -3
  375. package/dist/run/shared-world-shape.js +11 -11
  376. package/dist/run/stats.d.ts +5 -5
  377. package/dist/run/stats.js +8 -8
  378. package/dist/run/status.d.ts +16 -6
  379. package/dist/run/status.js +31 -8
  380. package/dist/run/streams.d.ts +26 -19
  381. package/dist/run/terminal-contract.d.ts +5 -5
  382. package/dist/run/terminal-contract.js +4 -4
  383. package/dist/run/transient-comms-secrets.d.ts +5 -0
  384. package/dist/run/transient-comms-secrets.js +12 -0
  385. package/dist/run-lab.d.ts +36 -34
  386. package/dist/run-lab.js +41 -37
  387. package/dist/subject/desktop-cli.d.ts +1 -1
  388. package/dist/subject/desktop-cli.js +1 -1
  389. package/dist/subject/local-tree-archive.d.ts +1 -1
  390. package/dist/subject/local-tree-archive.js +4 -4
  391. package/dist/subject/local-tree.d.ts +2 -2
  392. package/dist/subject/local-tree.js +1 -1
  393. package/dist/subject/node-bootstrap.d.ts +1 -1
  394. package/dist/subject/node-bootstrap.js +4 -4
  395. package/dist/subject/runtime.js +5 -5
  396. package/dist/subject/serve.js +1 -1
  397. package/dist/subject/steps.d.ts +4 -4
  398. package/dist/subject/steps.js +5 -5
  399. package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
  400. package/dist/substrates/e2b/cdp-probe.js +1 -1
  401. package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
  402. package/dist/substrates/e2b/desktop-browser.js +4 -4
  403. package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
  404. package/dist/substrates/e2b/desktop-cdp.js +4 -4
  405. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  406. package/dist/substrates/e2b/desktop-geometry.js +3 -3
  407. package/dist/substrates/e2b/desktop-media.js +2 -2
  408. package/dist/substrates/e2b/sandbox.js +1 -1
  409. package/dist/substrates/e2b/sdk.js +2 -2
  410. package/dist/substrates/local/runtime-host.d.ts +2 -0
  411. package/dist/substrates/local/runtime-host.js +6 -0
  412. package/dist/tui/actions.d.ts +7 -5
  413. package/dist/tui/actions.js +18 -9
  414. package/dist/tui-app.js +42 -42
  415. package/dist/verify/actor.d.ts +10 -10
  416. package/dist/verify/actor.js +15 -15
  417. package/dist/verify/artifacts.d.ts +1 -1
  418. package/dist/verify/artifacts.js +3 -3
  419. package/dist/verify/costs.d.ts +2 -2
  420. package/dist/verify/costs.js +2 -2
  421. package/dist/verify/liveness.d.ts +1 -1
  422. package/dist/verify/liveness.js +4 -1
  423. package/dist/verify/rerun.d.ts +1 -1
  424. package/dist/verify/rerun.js +1 -1
  425. package/dist/verify/shared-world.js +2 -2
  426. package/dist/verify/verify.js +6 -6
  427. package/docs/README.md +1 -1
  428. package/docs/architecture/actor-contract.md +60 -22
  429. package/docs/architecture/desktop-sessions.md +9 -9
  430. package/docs/architecture/external-public-shared-world.md +5 -0
  431. package/docs/architecture/observer.md +4 -4
  432. package/docs/architecture/restricted-codex-analysis.md +36 -2
  433. package/docs/architecture/state-driven-executor.md +4 -5
  434. package/docs/architecture/task-protocol-support.md +3 -5
  435. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
  436. package/docs/contracts/run-bundle.md +10 -8
  437. package/docs/contracts/schemas.md +109 -53
  438. package/docs/contracts/study-analysis.md +24 -0
  439. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  440. package/docs/product/automatic-analysis.md +1 -0
  441. package/docs/ramp/README.md +2 -1
  442. package/package.json +4 -4
  443. package/skills/humanish/SKILL.md +3 -2
  444. package/skills/humanish/agents/openai.yaml +1 -1
  445. package/dist/deprecated.d.ts +0 -90
  446. package/dist/deprecated.js +0 -106
  447. package/dist/lab/bag-overrides.d.ts +0 -18
  448. package/dist/lab/bag-overrides.js +0 -121
  449. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  450. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  451. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  452. /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
  453. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -1,4 +1,4 @@
1
- // What ONE run is doing right now: who is in it, what they are thinking, how far they have got.
1
+ // What one run is doing right now: who is in it, what they are thinking, how far they have got.
2
2
  // Unlike the run index, it opens the bundle, which is affordable for the one run someone is
3
3
  // looking at.
4
4
  //
@@ -7,7 +7,7 @@
7
7
  // - `stream.actor` once it has finished.
8
8
  // Reading both means the same screen renders a run the whole way through rather than going blank
9
9
  // at the moment it completes.
10
- import { readAutomaticStudyAnalysis } from "../analysis/automatic.js";
10
+ import { readAutomaticAnalysis } from "../analysis/automatic.js";
11
11
  import path from "node:path";
12
12
  import { estimateActorCostForExecution } from "./pricing.js";
13
13
  import { resolveRunPath } from "./locate.js";
@@ -18,7 +18,7 @@ const RUN_DETAIL_SCHEMA = "humanish.run-detail.v1";
18
18
  /**
19
19
  * The latest reasoning a participant has recorded.
20
20
  *
21
- * Takes the LAST reasoning item rather than the newest by timestamp: the trace is append-ordered by
21
+ * Takes the last reasoning item rather than the newest by timestamp: the trace is append-ordered by
22
22
  * construction, and half of a live flush may not carry `at` yet. An item still in flight is skipped
23
23
  * — a partial thought read mid-write would be quoted as though the participant had finished it.
24
24
  */
@@ -68,7 +68,7 @@ function participantFrom(stream, index) {
68
68
  /**
69
69
  * What a participant has spent, priced the same way whether the run is finished or in flight.
70
70
  *
71
- * A finished trace carries its own `estimatedCost`. A live one carries the RUNNING usage and the
71
+ * A finished trace carries its own `estimatedCost`. A live one carries the running usage and the
72
72
  * model it prices at, so the same estimator gives a figure mid-run instead of the screen reporting
73
73
  * the cost as unknown until the moment the run ends — which is the half of a run where knowing what
74
74
  * it is costing actually changes what you do.
@@ -98,7 +98,7 @@ function costOf(trace) {
98
98
  * Read one run's participants. Returns null when the run has no readable bundle yet — an ordinary
99
99
  * state for a run that has just started, not a failure.
100
100
  *
101
- * Reads the bundle NARROWLY rather than through `loadRunBundle`, which applies the strict
101
+ * Reads the bundle narrowly rather than through `loadRunBundle`, which applies the strict
102
102
  * evidence-of-record guard. That guard is right for verification and wrong here: a mid-run flush is
103
103
  * a partial document by definition, so validating it as a complete bundle would make the live view
104
104
  * — the only view that needs this — the one case that never renders. Nothing read here is treated
@@ -126,7 +126,7 @@ export async function readRunDetail(cwdInput, runId) {
126
126
  }
127
127
  const streams = Array.isArray(bundle.streams) ? bundle.streams : [];
128
128
  const observerAbsolute = path.join(runPaths.absoluteRunRoot, "observer", "index.html");
129
- const automaticAnalysis = await readAutomaticStudyAnalysis(cwd, runId);
129
+ const automaticAnalysis = await readAutomaticAnalysis(cwd, runId);
130
130
  return {
131
131
  ...(automaticAnalysis === undefined ? {} : { automaticAnalysis }),
132
132
  schema: RUN_DETAIL_SCHEMA,
@@ -37,7 +37,7 @@ async function runDryRunInScope(options, scope) {
37
37
  if (participants === null) {
38
38
  return refused(requestedCwd, warnings, {
39
39
  code: "HUMANISH_INVALID_SIM_COUNT",
40
- message: "--sims must be a positive integer.",
40
+ message: "--count must be a positive integer.",
41
41
  });
42
42
  }
43
43
  // Bind the physical project, as the lab routes do: a symlinked cwd retargeted mid-run cannot
@@ -66,6 +66,8 @@ async function runDryRunInScope(options, scope) {
66
66
  mode: options.dryRun ? "dry-run" : "live",
67
67
  lab: options.lab,
68
68
  renderReview: renderReviewMarkdown,
69
+ // The run starts at the time its id and source were stamped with.
70
+ now: () => Date.parse(createdAt),
69
71
  ...(options.observer === undefined ? {} : { observer: { open: options.observer.open } }),
70
72
  });
71
73
  if (!started.ok)
@@ -85,16 +87,7 @@ async function runDryRunInScope(options, scope) {
85
87
  });
86
88
  const judgment = judgePreview();
87
89
  const bundle = {
88
- ...bundleHead({
89
- runId,
90
- mode: "dry-run",
91
- participants,
92
- createdAt,
93
- cwd,
94
- artifactRoot,
95
- ...(options.lab === undefined ? {} : { lab: options.lab }),
96
- source,
97
- }),
90
+ ...bundleHead(run, { participants, cwd, artifactRoot, source }),
98
91
  persona: inputs.persona,
99
92
  scenario: inputs.scenario,
100
93
  lifecycle: [
@@ -211,7 +204,7 @@ async function renderPreviewObserver(finished, warnings) {
211
204
  return undefined;
212
205
  }
213
206
  }
214
- /** One synthetic stream per lane kind; the preview cycles through them. */
207
+ /** One synthetic stream per stream kind (UI, terminal and the rest); the preview cycles through them. */
215
208
  const SYNTHETIC_STREAM_TEMPLATES = [
216
209
  {
217
210
  kind: "ui",
@@ -4,7 +4,7 @@ import { type PreparedOutputRoot } from "./contained-output.js";
4
4
  * percent-decoded up to five times, and each round must still be a plain relative path, so an
5
5
  * encoded `..` or separator cannot survive into a later decode.
6
6
  */
7
- export declare function isStudyEvidencePath(value: string): boolean;
7
+ export declare function isEvidencePath(value: string): boolean;
8
8
  /**
9
9
  * True when `value` (at most `maxLength` characters) stays a plain relative path through up to five
10
10
  * rounds of percent-decoding: no round may match `unsafe`, have an empty, `.` or `..` segment, or
@@ -16,13 +16,13 @@ export declare function decodesToPlainRelativePath(value: string, maxLength: num
16
16
  * not turn an analysis budget into an unbounded read. No returned bytes have
17
17
  * authority to select another file or initiate a network request.
18
18
  */
19
- export declare function readBoundedStudyFile(root: PreparedOutputRoot, relativePath: string, maxBytes: number): Promise<Buffer | null>;
19
+ export declare function readBoundedFile(root: PreparedOutputRoot, relativePath: string, maxBytes: number): Promise<Buffer | null>;
20
20
  /**
21
21
  * After a bounded read returned nothing: true when the file is absent, false when something is
22
22
  * there that could not be read. Errors other than ENOENT propagate.
23
23
  */
24
24
  export declare function pathMissing(filePath: string): Promise<boolean>;
25
- export type BoundedStudyFileResult = {
25
+ export type BoundedFileResult = {
26
26
  state: "read";
27
27
  bytes: Buffer;
28
28
  } | {
@@ -32,4 +32,4 @@ export type BoundedStudyFileResult = {
32
32
  state: "unavailable";
33
33
  };
34
34
  /** Size refusals are distinguished only after the same contained regular-file checks. */
35
- export declare function readBoundedStudyFileResult(root: PreparedOutputRoot, relativePath: string, maxBytes: number): Promise<BoundedStudyFileResult>;
35
+ export declare function readBoundedFileResult(root: PreparedOutputRoot, relativePath: string, maxBytes: number): Promise<BoundedFileResult>;
@@ -12,7 +12,7 @@ import { isNodeError } from "./type-guards.js";
12
12
  * percent-decoded up to five times, and each round must still be a plain relative path, so an
13
13
  * encoded `..` or separator cannot survive into a later decode.
14
14
  */
15
- export function isStudyEvidencePath(value) {
15
+ export function isEvidencePath(value) {
16
16
  return decodesToPlainRelativePath(value, 1024, /[\\:\x00-\x1f\x7f]|^\//);
17
17
  }
18
18
  /**
@@ -54,8 +54,8 @@ export function decodesToPlainRelativePath(value, maxLength, unsafe) {
54
54
  * not turn an analysis budget into an unbounded read. No returned bytes have
55
55
  * authority to select another file or initiate a network request.
56
56
  */
57
- export async function readBoundedStudyFile(root, relativePath, maxBytes) {
58
- const result = await readBoundedStudyFileResult(root, relativePath, maxBytes);
57
+ export async function readBoundedFile(root, relativePath, maxBytes) {
58
+ const result = await readBoundedFileResult(root, relativePath, maxBytes);
59
59
  return result.state === "read" ? result.bytes : null;
60
60
  }
61
61
  /**
@@ -89,8 +89,8 @@ export async function pathMissing(filePath) {
89
89
  }
90
90
  const unavailable = { state: "unavailable" };
91
91
  /** Size refusals are distinguished only after the same contained regular-file checks. */
92
- export async function readBoundedStudyFileResult(root, relativePath, maxBytes) {
93
- if (!isStudyEvidencePath(relativePath) || !Number.isSafeInteger(maxBytes) || maxBytes < 1)
92
+ export async function readBoundedFileResult(root, relativePath, maxBytes) {
93
+ if (!isEvidencePath(relativePath) || !Number.isSafeInteger(maxBytes) || maxBytes < 1)
94
94
  return unavailable;
95
95
  const validateRoot = async () => {
96
96
  if ("physicalRunRoot" in root) {
@@ -31,7 +31,7 @@ export function isRunFeedbackCandidate(value) {
31
31
  isFeedbackNextState(value.proposed_next_state) &&
32
32
  Array.isArray(value.acceptance_proof) &&
33
33
  value.acceptance_proof.every((item) => typeof item === "string") &&
34
- // Optional, adapter-namespaced product-noun block: when present, validate only its SHAPE
34
+ // Optional, adapter-namespaced product-noun block: when present, validate only its shape
35
35
  // (a non-empty namespace + a data record). Core never inspects the keys inside `data`.
36
36
  (value.adapter === undefined || isFeedbackAdapterBlock(value.adapter)));
37
37
  }
@@ -60,7 +60,7 @@ export declare function participantHarnessFailed(participant: ParticipantFacts):
60
60
  * goal_satisfied claim with zero engagement is a session that ran out before anything happened;
61
61
  * one whose final message describes a blocker is a participant who could not proceed and said so.
62
62
  * Both keep their trace status (the claim is evidence); neither is a participant who reached the
63
- * goal. One rule for the single lane and the fan-out roll-up (#476).
63
+ * goal. One rule for the single participant and the fan-out roll-up (#476).
64
64
  */
65
65
  export declare function participantStatus(status: ActorStatus, judgments: {
66
66
  noEngagement: boolean;
@@ -86,7 +86,7 @@ export interface Judgment {
86
86
  /** The judgment for a verdict: a run passes when its verdict is pass, and a dry run passes. */
87
87
  export declare function judgmentOf(verdict: Verdict, dryRun: boolean): Judgment;
88
88
  /** What kind of execution failure a run recorded. */
89
- type ExecutionFailureKind = "harness" | "provider-cleanup" | "sandbox-cleanup" | "evidence" | "cap" | "run";
89
+ type ExecutionFailureKind = "harness" | "provider-cleanup" | "provider-policy" | "sandbox-cleanup" | "evidence" | "cap" | "run";
90
90
  /** One way the run failed as an execution. The message is scrubbed; status.json shows it. */
91
91
  export interface ExecutionFailure {
92
92
  kind: ExecutionFailureKind;
@@ -98,7 +98,19 @@ export interface ExecutionOutcome {
98
98
  succeeded: boolean;
99
99
  /** The failures the policy counts, in the order the route recorded them. */
100
100
  failures: ExecutionFailure[];
101
+ /**
102
+ * The failures the policy lets warn, such as a sandbox whose release is unconfirmed on a route
103
+ * whose evidence stands. They leave `succeeded` and the result's ok alone but stay visible in
104
+ * status.json. Omitted when there are none.
105
+ */
106
+ warnings?: ExecutionFailure[];
101
107
  }
108
+ /**
109
+ * The execution failure for one sandbox whose release is unconfirmed. `warning` is the route's
110
+ * release warning, already scrubbed. `recovery` says how to release it by hand; without one,
111
+ * reclaim kills by the id the run recorded at create time.
112
+ */
113
+ export declare function sandboxCleanupFailure(owner: string, warning: string | undefined, runId: string, recovery?: string): ExecutionFailure;
102
114
  /**
103
115
  * How a route turns the facts into its result's ok. A gate route needs every participant to
104
116
  * pass. On an evidence route a participant that failed, was blocked or timed out is captured
@@ -131,7 +143,7 @@ export interface SharedWorldJudgment extends Judgment {
131
143
  * A run with one participant: its tallied status is the verdict, so a hollow pass fails and a
132
144
  * self-reported blocker reads as blocked. Without a session, a harness failure fails the run and
133
145
  * a dry run is a contract. A run still in progress is a contract until it finishes. Computer-use
134
- * calls it for one lane with no rerun, and terminal calls it through judgeTerminal.
146
+ * calls it for one participant with no rerun, and terminal calls it through judgeTerminal.
135
147
  */
136
148
  export declare function judgeOneParticipant(args: {
137
149
  dryRun: boolean;
@@ -195,7 +207,7 @@ export declare function judgePreview(): Judgment;
195
207
  * stays as it was, so scoring can never improve a verdict. No failures returns the review as is.
196
208
  */
197
209
  export declare function foldScorerFailures(review: ReviewSummary, failures: readonly string[]): ReviewSummary;
198
- /** The run's execution outcome under its route's policy. A failure of a kind the policy lets warn is dropped. */
210
+ /** The run's execution outcome under its route's policy. A failure of a kind the policy lets warn is a warning. */
199
211
  export declare function judgeExecution(failures: readonly ExecutionFailure[], policy: OutcomePolicy): ExecutionOutcome;
200
212
  /**
201
213
  * The result's ok: the run worked as an execution, no scorer failed it, and on a gate route every
package/dist/run/judge.js CHANGED
@@ -6,7 +6,7 @@
6
6
  // participantPassed, participantHarnessFailed);
7
7
  // 2. the judgment shapes (Judgment and judgmentOf, SharedWorldJudgment, ExecutionOutcome,
8
8
  // OutcomePolicy);
9
- // 3. one judge per route: computer-use calls judgeOneParticipant (one lane, no rerun) or
9
+ // 3. one judge per route: computer-use calls judgeOneParticipant (one participant, no rerun) or
10
10
  // judgeParticipants, shared-world calls judgeSharedWorld, terminal calls judgeTerminal,
11
11
  // scripted calls judgeScripted and preview calls judgePreview;
12
12
  // 4. foldScorerFailures, which every route with a scorer applies before the run finishes;
@@ -65,7 +65,7 @@ export function participantHarnessFailed(participant) {
65
65
  * goal_satisfied claim with zero engagement is a session that ran out before anything happened;
66
66
  * one whose final message describes a blocker is a participant who could not proceed and said so.
67
67
  * Both keep their trace status (the claim is evidence); neither is a participant who reached the
68
- * goal. One rule for the single lane and the fan-out roll-up (#476).
68
+ * goal. One rule for the single participant and the fan-out roll-up (#476).
69
69
  */
70
70
  export function participantStatus(status, judgments) {
71
71
  if (status !== "passed" || judgments === undefined)
@@ -98,6 +98,17 @@ export function verdictForStatus(status) {
98
98
  export function judgmentOf(verdict, dryRun) {
99
99
  return { verdict, passed: dryRun || verdict === "pass" };
100
100
  }
101
+ /**
102
+ * The execution failure for one sandbox whose release is unconfirmed. `warning` is the route's
103
+ * release warning, already scrubbed. `recovery` says how to release it by hand; without one,
104
+ * reclaim kills by the id the run recorded at create time.
105
+ */
106
+ export function sandboxCleanupFailure(owner, warning, runId, recovery) {
107
+ return {
108
+ kind: "sandbox-cleanup",
109
+ message: `${owner}: ${warning ?? "Sandbox release is unconfirmed."} ${recovery ?? `Reclaim it by recorded id with \`humanish reclaim --run ${runId}\`.`}`,
110
+ };
111
+ }
101
112
  /** Each route's outcome policy, in one place. */
102
113
  export const OUTCOME_POLICIES = {
103
114
  "computer-use": { participants: "gate", sandboxCleanup: "warns", evidence: "fails" },
@@ -111,7 +122,7 @@ export const OUTCOME_POLICIES = {
111
122
  * A run with one participant: its tallied status is the verdict, so a hollow pass fails and a
112
123
  * self-reported blocker reads as blocked. Without a session, a harness failure fails the run and
113
124
  * a dry run is a contract. A run still in progress is a contract until it finishes. Computer-use
114
- * calls it for one lane with no rerun, and terminal calls it through judgeTerminal.
125
+ * calls it for one participant with no rerun, and terminal calls it through judgeTerminal.
115
126
  */
116
127
  export function judgeOneParticipant(args) {
117
128
  const status = args.participant === undefined ? undefined : judgedStatus(args.participant);
@@ -220,14 +231,20 @@ export function foldScorerFailures(review, failures) {
220
231
  }
221
232
  return folded;
222
233
  }
223
- /** The run's execution outcome under its route's policy. A failure of a kind the policy lets warn is dropped. */
234
+ /** The run's execution outcome under its route's policy. A failure of a kind the policy lets warn is a warning. */
224
235
  export function judgeExecution(failures, policy) {
225
- const counted = failures.filter((failure) => failure.kind === "sandbox-cleanup"
236
+ const counts = (failure) => failure.kind === "sandbox-cleanup"
226
237
  ? policy.sandboxCleanup === "fails"
227
238
  : failure.kind === "evidence"
228
239
  ? policy.evidence === "fails"
229
- : true);
230
- return { succeeded: counted.length === 0, failures: counted };
240
+ : true;
241
+ const counted = failures.filter(counts);
242
+ const warnings = failures.filter((failure) => !counts(failure));
243
+ return {
244
+ succeeded: counted.length === 0,
245
+ failures: counted,
246
+ ...(warnings.length === 0 ? {} : { warnings }),
247
+ };
231
248
  }
232
249
  /**
233
250
  * The result's ok: the run worked as an execution, no scorer failed it, and on a gate route every
@@ -2,6 +2,8 @@ import { type PreparedRunArtifactPaths } from "./paths.js";
2
2
  import { type PreparedSelectedOutputDirectory } from "./contained-output.js";
3
3
  import type { RunPointer } from "./results.js";
4
4
  import { type RunBundle } from "./bundle.js";
5
+ /** The run input that resolves through latest.json rather than naming a run directory. */
6
+ export declare const LATEST_RUN_ALIAS = "latest";
5
7
  /** Resolve "latest" or an explicit run id to its prepared artifact paths. */
6
8
  export declare function resolveRunPath(cwd: string, runInput: string): Promise<PreparedRunArtifactPaths | null>;
7
9
  export declare function readLatest(runsRoot: PreparedSelectedOutputDirectory): Promise<RunPointer | null>;
@@ -5,9 +5,11 @@ import { assertPreparedSelectedOutputDirectory, bindExistingManagedHumanishOutpu
5
5
  import { RUN_BUNDLE_FILE } from "./bundle.js";
6
6
  import { isRunBundle, isRunPointer } from "./bundle-shape.js";
7
7
  import { isNodeError } from "./type-guards.js";
8
+ /** The run input that resolves through latest.json rather than naming a run directory. */
9
+ export const LATEST_RUN_ALIAS = "latest";
8
10
  /** Resolve "latest" or an explicit run id to its prepared artifact paths. */
9
11
  export async function resolveRunPath(cwd, runInput) {
10
- if (runInput === "latest") {
12
+ if (runInput === LATEST_RUN_ALIAS) {
11
13
  const runsRoot = await bindExistingManagedHumanishOutputDirectory(cwd, "runs");
12
14
  if (!runsRoot) {
13
15
  return null;
@@ -1,16 +1,16 @@
1
1
  import { type ActorStatus } from "../actors/contract.js";
2
2
  import { type CuaGoalSource } from "../actors/goal-source.js";
3
3
  import type { TaskFunnel } from "../lab/tasks.js";
4
- import type { ParticipantOutcomes, ReviewSummary, StudyTaskFunnel } from "./bundle.js";
4
+ import type { ParticipantOutcomes, ReviewSummary, RunTaskFunnel } from "./bundle.js";
5
5
  /** Tally participant outcomes from actor statuses. Statuses this does not recognise are counted in
6
6
  * `total` but nowhere else, so the parts can never exceed the whole. */
7
7
  export declare function tallyParticipantOutcomes(statuses: readonly ActorStatus[],
8
8
  /** Per-participant: did this one report friction or a defect? Same order as `statuses`. */
9
9
  reportedFriction?: readonly boolean[]): ParticipantOutcomes;
10
10
  /** Roll per-participant funnels up into the study funnel. Undefined when nothing measured one. */
11
- export declare function aggregateTaskFunnels(funnels: readonly TaskFunnel[]): StudyTaskFunnel | undefined;
11
+ export declare function aggregateTaskFunnels(funnels: readonly TaskFunnel[]): RunTaskFunnel | undefined;
12
12
  /** The funnel as one line, denominator on every number: `signup 2/2 · verify-email 1/2`. */
13
- export declare function formatStudyTaskFunnel(funnel: StudyTaskFunnel): string;
13
+ export declare function formatRunTaskFunnel(funnel: RunTaskFunnel): string;
14
14
  type ParticipantOutcomeDetail = {
15
15
  status: ActorStatus;
16
16
  label?: string;
@@ -68,7 +68,7 @@ export function aggregateTaskFunnels(funnels) {
68
68
  };
69
69
  }
70
70
  /** The funnel as one line, denominator on every number: `signup 2/2 · verify-email 1/2`. */
71
- export function formatStudyTaskFunnel(funnel) {
71
+ export function formatRunTaskFunnel(funnel) {
72
72
  if (funnel.tasks.length === 0)
73
73
  return "no tasks declared";
74
74
  return funnel.tasks
@@ -138,7 +138,7 @@ export function formatParticipantOutcomes(outcomes, terminalCauses = []) {
138
138
  };
139
139
  append(outcomes.abandoned, ["abandoned"], "gave up");
140
140
  append(outcomes.ranOut, ["incomplete", "timed_out"], "interrupted (stop details unavailable)");
141
- // "blocked" covers an approval the run could not give AND a blocker the participant reported in
141
+ // "blocked" covers an approval the run could not give and a blocker the participant reported in
142
142
  // its own words, so the label names no cause.
143
143
  if (outcomes.blocked > 0)
144
144
  parts.push(`${outcomes.blocked} blocked`);
@@ -191,7 +191,7 @@ export function withCuaReviewProvenance(review, streams) {
191
191
  const outcomes = formatParticipantOutcomes(review.participants, details);
192
192
  // Preserve rerun context, participant narration and adapter-specific findings. Refreshing a
193
193
  // historical summary qualifies its old tally instead of silently discarding that context.
194
- const header = `Run gate: ${review.verdict}. Participants: ${outcomes}.${review.tasks ? ` Tasks: ${formatStudyTaskFunnel(review.tasks)}.` : ""}`;
194
+ const header = `Run gate: ${review.verdict}. Participants: ${outcomes}.${review.tasks ? ` Tasks: ${formatRunTaskFunnel(review.tasks)}.` : ""}`;
195
195
  const prefix = `${header} Recorded summary: `;
196
196
  const recorded = review.summary.startsWith(prefix)
197
197
  ? review.summary.slice(prefix.length)
@@ -12,7 +12,7 @@ export declare function participantIds(position: number): ParticipantIds;
12
12
  /** A participant's record, at its 1-based place in the bundle, with its one stream. */
13
13
  export declare function participantRecord(ids: ParticipantIds, place: number, fields: Omit<RunSimulation, "id" | "index" | "streamIds">): RunSimulation;
14
14
  /**
15
- * A participant's stream. `participantId` is the route's own participant id (a fan-out lane's id),
15
+ * A participant's stream. `participantId` is the route's own participant id (a fan-out entry's `lane-NN` id),
16
16
  * saved right after the record id when the route has one.
17
17
  */
18
18
  export declare function participantStream(ids: ParticipantIds, fields: Omit<RunStream, "id" | "simId" | "laneId">, participantId?: string): RunStream;
@@ -24,5 +24,5 @@ export declare function participantResourceIds(ids: ParticipantIds, participantI
24
24
  export declare function recordIdOf(stream: RunStream): string;
25
25
  /** The record id a saved event names, when it names one. */
26
26
  export declare function eventRecordIdOf(event: RunEvent): string | undefined;
27
- /** The participant id an adapter recorded on a saved stream (a fan-out lane id), when it has one. */
27
+ /** The participant id an adapter recorded on a saved stream (a fan-out `lane-NN` id), when it has one. */
28
28
  export declare function streamParticipantIdOf(stream: RunStream): string | undefined;
@@ -30,7 +30,7 @@ export function participantRecord(ids, place, fields) {
30
30
  };
31
31
  }
32
32
  /**
33
- * A participant's stream. `participantId` is the route's own participant id (a fan-out lane's id),
33
+ * A participant's stream. `participantId` is the route's own participant id (a fan-out entry's `lane-NN` id),
34
34
  * saved right after the record id when the route has one.
35
35
  */
36
36
  export function participantStream(ids, fields, participantId) {
@@ -57,7 +57,7 @@ export function recordIdOf(stream) {
57
57
  export function eventRecordIdOf(event) {
58
58
  return event.simId;
59
59
  }
60
- /** The participant id an adapter recorded on a saved stream (a fan-out lane id), when it has one. */
60
+ /** The participant id an adapter recorded on a saved stream (a fan-out `lane-NN` id), when it has one. */
61
61
  export function streamParticipantIdOf(stream) {
62
62
  return stream.laneId;
63
63
  }
package/dist/run/paths.js CHANGED
@@ -262,7 +262,7 @@ async function assertNoSymlinkDescendants(directory) {
262
262
  const entries = await readdir(directory, { withFileTypes: true });
263
263
  for (const entry of entries) {
264
264
  const child = path.join(directory, entry.name);
265
- // A run directory can be written CONCURRENTLY with this walk — the atomic writer creates a
265
+ // A run directory can be written concurrently with this walk: the atomic writer creates a
266
266
  // `.humanish-write-*.tmp` sibling and renames it, and a run now also refreshes its own status
267
267
  // record on a cadence. An entry that vanished between readdir and lstat therefore proves
268
268
  // nothing except that it is gone, and a path that no longer exists cannot be a symlink escape:
@@ -10,12 +10,12 @@ export interface ModelRate {
10
10
  * a reduced rate. Optional: absent means we do not model a discount and every input token is
11
11
  * billed at `inputUsdPerToken`. */
12
12
  cachedInputUsdPerToken?: number;
13
- /** USD per input token newly WRITTEN to the provider's prompt cache, when the provider bills
13
+ /** USD per input token newly written to the provider's prompt cache, when the provider bills
14
14
  * writes (OpenAI: GPT-5.6+ bills `cache_write_tokens` at 1.25x the uncached input rate, as the
15
- * TOTAL rate for those tokens — not an extra charge on top). Absent = writes are free (every
15
+ * total rate for those tokens, with no extra charge on top). Absent = writes are free (every
16
16
  * pre-5.6 model) and any reported write tokens price at the plain input rate. */
17
17
  cacheWriteUsdPerToken?: number;
18
- /** Long-context tier, when the provider re-prices the WHOLE request past an input-size
18
+ /** Long-context tier, when the provider re-prices the whole request past an input-size
19
19
  * threshold (OpenAI GPT-5.6: >272K input tokens => 2x input-side, 1.5x output, full request).
20
20
  * Priced exactly only when the usage carries per-request `turns` records; totals alone cannot
21
21
  * say which requests crossed, so without turns the estimate stays on the short-context rate,
@@ -29,7 +29,7 @@ export interface ModelRate {
29
29
  asOf: string;
30
30
  /** Public pricing page the number came from (a comment/URL, never a secret). */
31
31
  source: string;
32
- /** true = a stand-in NOT copied from a live sheet; the estimate carries this flag so a
32
+ /** true = a stand-in that was not copied from a live sheet; the estimate carries this flag so a
33
33
  * placeholder rate is never mistaken for a confirmed one. */
34
34
  placeholder?: boolean;
35
35
  }
@@ -52,8 +52,8 @@ export interface DesktopResourceRate {
52
52
  source: string;
53
53
  }
54
54
  /**
55
- * The token-derived cost ESTIMATE for one actor lane. `estimatedCostUsd: null` = DECLARED ABSENT
56
- * (unknown rate or no token usage) — never coerced to 0. A non-null figure ALWAYS carries its
55
+ * The token-derived cost estimate for one actor trace. `estimatedCostUsd: null` = declared absent
56
+ * (unknown rate or no token usage) and is never coerced to 0. A non-null figure always carries its
57
57
  * pricing provenance (`ratesAsOf` + `source`) so the mechanism (a rate-table multiply) matches
58
58
  * the claim (an estimate, not a charge). Defined here so the rate table and the field that
59
59
  * consumes it live together; `ActorTrace` imports it type-only.
@@ -71,13 +71,17 @@ export interface ActorEstimatedCost {
71
71
  modelId?: string;
72
72
  /** true when the rate is a stand-in, not a live sheet. */
73
73
  placeholder?: boolean;
74
+ /** Set when usage arrived as runtime-turn totals that each sum several requests. No request's
75
+ * own size is known, so no per-request long-context tier was applied: tokens are priced at the
76
+ * base tier, cached input at the cached rate. */
77
+ basis?: "aggregated_turns_base_rate";
74
78
  breakdown?: {
75
79
  inputUsd: number;
76
80
  outputUsd: number;
77
81
  inputTokens: number;
78
82
  outputTokens: number;
79
83
  /** Of `inputTokens`, how many were billed at the reduced cached rate. Present only when the
80
- * provider reported cache hits AND the rate sheet models a cached rate. */
84
+ * provider reported cache hits and the rate sheet models a cached rate. */
81
85
  cachedInputTokens?: number;
82
86
  /** Of `inputTokens`, how many were billed at the cache-WRITE rate (OpenAI 5.6+). */
83
87
  cacheWriteInputTokens?: number;
@@ -86,7 +90,7 @@ export interface ActorEstimatedCost {
86
90
  longContextTurns?: number;
87
91
  };
88
92
  }
89
- /** The desktop-minute cost ESTIMATE (host-side create->teardown span * a per-minute rate). Same
93
+ /** The desktop-minute cost estimate (host-side create->teardown span * a per-minute rate). Same
90
94
  * null-discipline as ActorEstimatedCost: `estimatedCostUsd: null` = not measured (no duration). */
91
95
  export interface DesktopCostEstimate {
92
96
  estimatedCostUsd: number | null;
@@ -108,13 +112,19 @@ export declare function estimateAllocatedDesktopCost(minutes: number | undefined
108
112
  * precision. */
109
113
  export declare function round6(n: number): number;
110
114
  /**
111
- * Estimate one actor lane's model-token cost from its trace tokenUsage + model id. Deterministic;
115
+ * Estimate one actor trace's model-token cost from its trace tokenUsage + model id. Deterministic;
112
116
  * the rate table is injectable (tests pass a fake sheet). Returns a DECLARED-ABSENT estimate
113
117
  * (estimatedCostUsd: null + a reason) for a missing rate or missing usage — never a guessed cost.
114
118
  */
115
119
  export declare function estimateActorCostForExecution(usage: ActorTokenUsage | undefined, modelId: string | undefined, profile?: {
116
120
  billing?: unknown;
117
121
  }): ActorEstimatedCost;
122
+ /**
123
+ * Price usage reported as runtime-turn totals, such as Codex `turn.completed`, which sums every
124
+ * request in the turn. Pricing a turn as one request would apply the long-context tier to the
125
+ * whole turn, so the per-turn records are dropped and the totals price on the base tier.
126
+ */
127
+ export declare function estimateAggregatedTurnCost(tokenUsage: ActorTokenUsage | undefined, modelId: string | undefined): ActorEstimatedCost;
118
128
  export declare function estimateActorCost(tokenUsage: ActorTokenUsage | undefined, modelId: string | undefined, rates?: Record<string, ModelRate>): ActorEstimatedCost;
119
129
  /**
120
130
  * Estimate the E2B desktop-minute cost from a host-side create->teardown span (minutes). The rate
@@ -1,18 +1,18 @@
1
- // OPERATOR-EDITABLE ESTIMATES — NOT authoritative prices. Providers change pricing without
2
- // notice. When they do, update BOTH the number AND the `asOf` date on the affected entry.
3
- // Every dollar figure humanish derives from this table is surfaced/persisted as an ESTIMATE,
4
- // labeled "estimated (rates as of <asOf>)", and is NEVER presented as an exact charge.
1
+ // Operator-editable estimates, which are not authoritative prices. Providers change pricing without
2
+ // notice. When they do, update both the number and the `asOf` date on the affected entry.
3
+ // Every dollar figure humanish derives from this table is surfaced/persisted as an estimate,
4
+ // labeled "estimated (rates as of <asOf>)", and is never presented as an exact charge.
5
5
  //
6
- // This module is PURE (node builtins only, no deps) and deterministic: the estimator functions take
7
- // an OPTIONAL injected rate table/rate so tests drive assertions with a fake sheet and never depend
8
- // on the live numbers below. An UNKNOWN model/desktop rate yields a DECLARED-ABSENT estimate
9
- // (estimatedCostUsd: null + a reason), NEVER a guessed or silent-zero cost (invariant 5). A bare
6
+ // This module is pure (node builtins only, no deps) and deterministic: the estimator functions take
7
+ // an optional injected rate table/rate so tests drive assertions with a fake sheet and never depend
8
+ // on the live numbers below. An unknown model/desktop rate yields a declared-absent estimate
9
+ // (estimatedCostUsd: null + a reason) and never a guessed or silent-zero cost (invariant 5). A bare
10
10
  // `costUsd` elsewhere in the contract means a provider actually billed that amount; the
11
11
  // token-derived estimate here always lives under `estimatedCostUsd` so a reader can never confuse
12
12
  // an estimate for an authoritative charge (invariant 6).
13
13
  export const PRICING_SCHEMA = "humanish.pricing.v1";
14
14
  export const ACTOR_ESTIMATED_COST_SCHEMA = "humanish.actor-estimated-cost.v1";
15
- // The gpt-5.6 long-context tier: >272K input tokens re-prices the FULL request at 2x
15
+ // The gpt-5.6 long-context tier: >272K input tokens re-prices the full request at 2x
16
16
  // input-side / 1.5x output (developers.openai.com/api/docs/models/gpt-5.6-sol, 2026-08-18).
17
17
  const LONG_CONTEXT_TIER_272K = {
18
18
  thresholdInputTokens: 272_000,
@@ -41,7 +41,7 @@ function rateWithLongContextTier(inPer1M, cachedPer1M, writePer1M, outPer1M, asO
41
41
  const GPT56_SOL_PROMO_AS_OF = "2026-09-03";
42
42
  const GPT6_ASTRA_AS_OF = "2026-09-03";
43
43
  // Per-model rates, keyed on the model id that lands in trace.ids.model (lookup is
44
- // case-insensitive on a trimmed id). An id NOT present here is DECLARED ABSENT, never guessed.
44
+ // case-insensitive on a trimmed id). An id missing here is declared absent, never guessed.
45
45
  export const MODEL_RATES = {
46
46
  // OpenAI computer-use-preview (the classic CUA model). ~$3 / 1M input, ~$12 / 1M output.
47
47
  // source: openai.com/api/pricing (verify — providers change without notice).
@@ -74,7 +74,7 @@ export const MODEL_RATES = {
74
74
  "gpt-5.6-cyber": rateWithLongContextTier(12.5, 1.25, 15.625, 75),
75
75
  // Daybreak program aliases (blue -> sol, red -> cyber today). OpenAI repoints these as new
76
76
  // frontier models ship, so prefer the explicit tier id in labs; the entries exist so a
77
- // configured alias still prices at what the alias bills TODAY.
77
+ // configured alias still prices at what the alias bills today.
78
78
  "daybreak-blue-latest": rateWithLongContextTier(4, 0.4, 5, 20, GPT56_SOL_PROMO_AS_OF),
79
79
  "daybreak-red-latest": rateWithLongContextTier(12.5, 1.25, 15.625, 75),
80
80
  // gpt-6-astra (shipped 2026-09-03; API access announced as rolling out). Same two mechanics
@@ -157,7 +157,7 @@ export function round6(n) {
157
157
  return Math.round(n * 1e6) / 1e6;
158
158
  }
159
159
  /**
160
- * Estimate one actor lane's model-token cost from its trace tokenUsage + model id. Deterministic;
160
+ * Estimate one actor trace's model-token cost from its trace tokenUsage + model id. Deterministic;
161
161
  * the rate table is injectable (tests pass a fake sheet). Returns a DECLARED-ABSENT estimate
162
162
  * (estimatedCostUsd: null + a reason) for a missing rate or missing usage — never a guessed cost.
163
163
  */
@@ -172,6 +172,18 @@ export function estimateActorCostForExecution(usage, modelId, profile) {
172
172
  }
173
173
  : estimateActorCost(usage, modelId);
174
174
  }
175
+ /**
176
+ * Price usage reported as runtime-turn totals, such as Codex `turn.completed`, which sums every
177
+ * request in the turn. Pricing a turn as one request would apply the long-context tier to the
178
+ * whole turn, so the per-turn records are dropped and the totals price on the base tier.
179
+ */
180
+ export function estimateAggregatedTurnCost(tokenUsage, modelId) {
181
+ const { turns: _turns, ...totals } = tokenUsage ?? {};
182
+ const estimate = estimateActorCost(tokenUsage === undefined ? undefined : totals, modelId);
183
+ return estimate.estimatedCostUsd === null
184
+ ? estimate
185
+ : { ...estimate, basis: "aggregated_turns_base_rate" };
186
+ }
175
187
  export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
176
188
  if (!tokenUsage || (tokenUsage.input === undefined && tokenUsage.output === undefined)) {
177
189
  return {
@@ -193,15 +205,15 @@ export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
193
205
  }
194
206
  const inTok = tokenUsage.input ?? 0;
195
207
  const outTok = tokenUsage.output ?? 0;
196
- // Long-context tiering needs to know each REQUEST's input size (the provider re-prices whole
197
- // requests past the threshold), so it engages only when per-turn usage records exist AND their
208
+ // Long-context tiering needs to know each request's input size (the provider re-prices whole
209
+ // requests past the threshold), so it engages only when per-turn usage records exist and their
198
210
  // input sums to the reported total — a partial turn ledger must not silently price the missing
199
211
  // remainder at the wrong tier. Otherwise totals price on the base (short-context) rate, which is
200
212
  // the under-estimate direction and never trips a cap early.
201
213
  const turns = tokenUsage.turns ?? [];
202
214
  const sumOf = (field) => turns.reduce((sum, turn) => sum + (turn[field] ?? 0), 0);
203
- // The ledger is trusted only when it decomposes the totals EXACTLY — all four sums, not just
204
- // input/output. A ledger that carries request sizes but not the cache splits would otherwise
215
+ // The ledger is trusted only when it decomposes the totals exactly, in all four sums including the
216
+ // cache splits. A ledger that carries request sizes but not the cache splits would otherwise
205
217
  // price every token at the full rate while the session totals sit ignored, overstating spend
206
218
  // 3.5-5x and tripping caps early. Inconsistent evidence falls back to the totals path, which
207
219
  // honors the declared splits on the base tier.
@@ -217,8 +229,8 @@ export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
217
229
  let writeTotal = 0;
218
230
  let longContextTurns = 0;
219
231
  // Price one request's usage at one tier. Cached input is billed at a fraction of the full rate,
220
- // and on a session that threads provider state it is the MAJORITY of input — pricing it at the
221
- // full rate overstates real spend by up to ~10x. Cache WRITES bill at their own rate (1.25x on
232
+ // and on a session that threads provider state it is the majority of input, and pricing it at the
233
+ // full rate overstates real spend by up to ~10x. Cache writes bill at their own rate (1.25x on
222
234
  // OpenAI 5.6+) as the total rate for those tokens; a sheet without a write rate prices writes as
223
235
  // plain input (pre-5.6: writes are free-of-extra-fee, i.e. plain input). Every piece is honestly
224
236
  // absent: no reported split means no discount and no surcharge assumed.