humanish 0.106.0 → 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 (459) hide show
  1. package/AGENTS.md +4 -2
  2. package/ARCHITECTURE.md +17 -16
  3. package/CHANGELOG.md +24 -0
  4. package/CONTEXT.md +42 -39
  5. package/CONTRIBUTING.md +8 -6
  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 +31 -4
  16. package/dist/actors/codex/qualified-versions.js +51 -6
  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 +10 -8
  45. package/dist/actors/contract.js +7 -1
  46. package/dist/actors/local-agent/cli.js +1 -1
  47. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  48. package/dist/actors/scripted-browser/journey.js +15 -4
  49. package/dist/actors/scripted-browser/steps.js +18 -0
  50. package/dist/actors/scripted-browser/types.d.ts +11 -1
  51. package/dist/actors/stop-conditions.js +1 -3
  52. package/dist/analysis/automatic-completion.d.ts +13 -8
  53. package/dist/analysis/automatic-completion.js +14 -8
  54. package/dist/analysis/automatic-config.d.ts +1 -1
  55. package/dist/analysis/automatic-config.js +2 -2
  56. package/dist/analysis/automatic.d.ts +10 -4
  57. package/dist/analysis/automatic.js +17 -13
  58. package/dist/analysis/diagnostics.d.ts +23 -0
  59. package/dist/analysis/diagnostics.js +112 -0
  60. package/dist/analysis/evidence-sources.js +2 -2
  61. package/dist/analysis/evidence.js +6 -6
  62. package/dist/analysis/execute.d.ts +7 -1
  63. package/dist/analysis/execute.js +39 -12
  64. package/dist/analysis/job.d.ts +8 -5
  65. package/dist/analysis/job.js +15 -14
  66. package/dist/analysis/load.d.ts +1 -1
  67. package/dist/analysis/load.js +5 -5
  68. package/dist/analysis/provider.d.ts +9 -1
  69. package/dist/analysis/restricted-codex.d.ts +2 -0
  70. package/dist/analysis/restricted-codex.js +10 -1
  71. package/dist/analysis/service.d.ts +2 -0
  72. package/dist/analysis/service.js +31 -12
  73. package/dist/analysis/sharing.d.ts +2 -2
  74. package/dist/analysis/sharing.js +5 -5
  75. package/dist/analysis/store-executions.d.ts +5 -5
  76. package/dist/analysis/store-executions.js +12 -12
  77. package/dist/analysis/store.d.ts +4 -4
  78. package/dist/analysis/store.js +13 -13
  79. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  80. package/dist/cli/commands/analysis-signals.js +4 -1
  81. package/dist/cli/commands/analyze.js +4 -2
  82. package/dist/cli/commands/comms.js +8 -1
  83. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  84. package/dist/cli/commands/lab-route-computer-use.js +26 -14
  85. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  86. package/dist/cli/commands/lab-route-preview.js +3 -4
  87. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  88. package/dist/cli/commands/lab-route-run.js +6 -2
  89. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  90. package/dist/cli/commands/lab-route-scripted.js +0 -1
  91. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  92. package/dist/cli/commands/lab-route-shared-world.js +0 -1
  93. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  94. package/dist/cli/commands/lab-route-terminal.js +0 -1
  95. package/dist/cli/commands/lab-run.js +76 -45
  96. package/dist/cli/commands/lab-scorer.d.ts +0 -2
  97. package/dist/cli/commands/lab.js +12 -6
  98. package/dist/cli/commands/observe.js +22 -0
  99. package/dist/cli/commands/run-signals.d.ts +30 -0
  100. package/dist/cli/commands/run-signals.js +146 -0
  101. package/dist/cli/commands/runs.js +10 -8
  102. package/dist/cli/commands/watch.js +12 -10
  103. package/dist/cli/doctor.d.ts +3 -0
  104. package/dist/cli/doctor.js +10 -2
  105. package/dist/cli/io.d.ts +5 -4
  106. package/dist/cli/io.js +12 -8
  107. package/dist/cli/program.js +3 -3
  108. package/dist/cli/renamed-options.d.ts +11 -0
  109. package/dist/cli/renamed-options.js +18 -0
  110. package/dist/cli/telemetry.d.ts +2 -2
  111. package/dist/cli/telemetry.js +1 -1
  112. package/dist/comms/capture-surface.d.ts +1 -1
  113. package/dist/comms/catch-host.d.ts +1 -1
  114. package/dist/comms/connections.js +4 -4
  115. package/dist/comms/external-evidence.d.ts +27 -0
  116. package/dist/comms/external-evidence.js +93 -0
  117. package/dist/comms/lease-store.js +7 -7
  118. package/dist/comms/types.js +1 -1
  119. package/dist/evidence/browser-hygiene.d.ts +1 -1
  120. package/dist/evidence/browser-hygiene.js +1 -1
  121. package/dist/evidence/redaction.js +1 -1
  122. package/dist/evidence/secret-scrub.d.ts +9 -0
  123. package/dist/evidence/secret-scrub.js +96 -0
  124. package/dist/feedback/draft.js +7 -9
  125. package/dist/feedback/export-bundle.js +4 -4
  126. package/dist/feedback/export.js +9 -9
  127. package/dist/feedback/feedback.d.ts +1 -1
  128. package/dist/index.d.ts +3 -6
  129. package/dist/index.js +3 -6
  130. package/dist/keys/key-resolution.d.ts +3 -1
  131. package/dist/keys/key-resolution.js +18 -16
  132. package/dist/lab/adapter-extension.d.ts +28 -6
  133. package/dist/lab/adapter-extension.js +65 -126
  134. package/dist/lab/adapter-scorer-loader.d.ts +25 -5
  135. package/dist/lab/adapter-scorer-loader.js +24 -0
  136. package/dist/lab/composition-rules.d.ts +2 -0
  137. package/dist/lab/composition-rules.js +35 -26
  138. package/dist/lab/config.js +28 -26
  139. package/dist/lab/device-presets.d.ts +2 -2
  140. package/dist/lab/discover.js +1 -3
  141. package/dist/lab/doctor.d.ts +44 -9
  142. package/dist/lab/doctor.js +149 -41
  143. package/dist/lab/init-plan.js +1 -3
  144. package/dist/lab/keys.js +1 -1
  145. package/dist/lab/lab-deps.d.ts +85 -0
  146. package/dist/lab/lab-deps.js +4 -0
  147. package/dist/lab/parse/actors.js +8 -7
  148. package/dist/lab/parse/comms.js +3 -2
  149. package/dist/lab/parse/execution.js +3 -2
  150. package/dist/lab/parse/subject-state.js +2 -1
  151. package/dist/lab/parse/subject.js +2 -1
  152. package/dist/lab/parse/values.d.ts +0 -1
  153. package/dist/lab/parse/values.js +0 -3
  154. package/dist/lab/persona-resolve.d.ts +3 -3
  155. package/dist/lab/persona-resolve.js +4 -4
  156. package/dist/lab/persona.js +1 -3
  157. package/dist/lab/plan-base.d.ts +6 -2
  158. package/dist/lab/plan-base.js +22 -7
  159. package/dist/lab/plan-participants.d.ts +5 -5
  160. package/dist/lab/plan-participants.js +2 -2
  161. package/dist/lab/plan-types.d.ts +33 -7
  162. package/dist/lab/plan.d.ts +3 -11
  163. package/dist/lab/plan.js +18 -42
  164. package/dist/lab/preflight-result.js +0 -2
  165. package/dist/lab/preflight.d.ts +0 -3
  166. package/dist/lab/preflight.js +1 -1
  167. package/dist/lab/requirements.d.ts +20 -0
  168. package/dist/lab/requirements.js +54 -0
  169. package/dist/lab/route-inputs.d.ts +23 -12
  170. package/dist/lab/route-inputs.js +48 -51
  171. package/dist/lab/routing.d.ts +19 -24
  172. package/dist/lab/routing.js +14 -47
  173. package/dist/lab/run-lab-events.d.ts +6 -11
  174. package/dist/lab/run-lab-events.js +3 -11
  175. package/dist/lab/run-lab-homes.d.ts +64 -0
  176. package/dist/lab/run-lab-homes.js +3 -0
  177. package/dist/lab/run-lab-options.d.ts +12 -66
  178. package/dist/lab/run-lab-options.js +45 -275
  179. package/dist/lab/summary.d.ts +9 -4
  180. package/dist/lab/summary.js +15 -8
  181. package/dist/lab/types.d.ts +132 -132
  182. package/dist/lab/validation.d.ts +15 -15
  183. package/dist/lab/validation.js +28 -28
  184. package/dist/lab/warnings.js +20 -19
  185. package/dist/observer/artifact.d.ts +1 -1
  186. package/dist/observer/artifact.js +3 -3
  187. package/dist/observer/data.js +2 -2
  188. package/dist/observer/render.js +2 -2
  189. package/dist/observer/run-routes.d.ts +1 -1
  190. package/dist/observer/run-routes.js +5 -5
  191. package/dist/observer/serve.d.ts +17 -0
  192. package/dist/observer/serve.js +34 -3
  193. package/dist/observer-app.html +1 -1
  194. package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
  195. package/dist/routes/computer-use/bundle-parts.js +10 -3
  196. package/dist/routes/computer-use/bundle.d.ts +4 -11
  197. package/dist/routes/computer-use/bundle.js +9 -15
  198. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  199. package/dist/routes/computer-use/diagnostics.js +1 -1
  200. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
  201. package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
  202. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  203. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
  204. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
  205. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
  206. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  207. package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
  208. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  209. package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
  210. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  211. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  212. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  213. package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
  214. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  215. package/dist/routes/computer-use/external-comms.js +19 -43
  216. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  217. package/dist/routes/computer-use/fanout-bundle.js +25 -29
  218. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
  219. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  220. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  221. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  222. package/dist/routes/computer-use/live-flush.js +19 -27
  223. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +14 -13
  224. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  225. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  226. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  227. package/dist/routes/computer-use/local-vm.js +39 -66
  228. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  229. package/dist/routes/computer-use/participant-desktop.js +5 -25
  230. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
  231. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
  232. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  233. package/dist/routes/computer-use/participant-facts.js +12 -1
  234. package/dist/routes/computer-use/participant-model.d.ts +19 -11
  235. package/dist/routes/computer-use/participant-model.js +58 -33
  236. package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
  237. package/dist/routes/computer-use/participant-prompt.js +4 -4
  238. package/dist/routes/computer-use/participant-runs.d.ts +6 -6
  239. package/dist/routes/computer-use/participant-runs.js +8 -8
  240. package/dist/routes/computer-use/plan.d.ts +21 -29
  241. package/dist/routes/computer-use/plan.js +59 -65
  242. package/dist/routes/computer-use/preflight.d.ts +6 -11
  243. package/dist/routes/computer-use/preflight.js +26 -18
  244. package/dist/routes/computer-use/rerun-selection.js +10 -6
  245. package/dist/routes/computer-use/result.d.ts +1 -1
  246. package/dist/routes/computer-use/result.js +40 -30
  247. package/dist/routes/computer-use/route.d.ts +3 -4
  248. package/dist/routes/computer-use/route.js +21 -19
  249. package/dist/routes/computer-use/self-report.d.ts +2 -2
  250. package/dist/routes/computer-use/self-report.js +4 -4
  251. package/dist/routes/computer-use/setup.d.ts +8 -17
  252. package/dist/routes/computer-use/setup.js +98 -86
  253. package/dist/routes/computer-use/single-bundle.d.ts +8 -11
  254. package/dist/routes/computer-use/single-bundle.js +20 -25
  255. package/dist/routes/computer-use/subject-projection.d.ts +5 -7
  256. package/dist/routes/computer-use/subject-projection.js +20 -19
  257. package/dist/routes/computer-use/types.d.ts +169 -211
  258. package/dist/routes/computer-use/types.js +13 -6
  259. package/dist/routes/preview.js +0 -1
  260. package/dist/routes/scripted/bundle.d.ts +3 -6
  261. package/dist/routes/scripted/bundle.js +11 -16
  262. package/dist/routes/scripted/plan.d.ts +5 -7
  263. package/dist/routes/scripted/plan.js +6 -4
  264. package/dist/routes/scripted/result.d.ts +4 -1
  265. package/dist/routes/scripted/result.js +10 -6
  266. package/dist/routes/scripted/route.js +10 -11
  267. package/dist/routes/scripted/scenario.d.ts +1 -1
  268. package/dist/routes/scripted/scenario.js +1 -1
  269. package/dist/routes/scripted/setup.d.ts +3 -2
  270. package/dist/routes/scripted/setup.js +22 -21
  271. package/dist/routes/scripted/subject.d.ts +8 -3
  272. package/dist/routes/scripted/subject.js +11 -6
  273. package/dist/routes/scripted/surface-records.js +1 -1
  274. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  275. package/dist/routes/scripted/surface-sessions.js +4 -4
  276. package/dist/routes/scripted/types.d.ts +19 -36
  277. package/dist/routes/scripted/types.js +1 -2
  278. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
  279. package/dist/routes/shared-world/bundle.d.ts +2 -2
  280. package/dist/routes/shared-world/bundle.js +22 -26
  281. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  282. package/dist/routes/shared-world/checkpoints.js +4 -4
  283. package/dist/routes/shared-world/comms.d.ts +5 -4
  284. package/dist/routes/shared-world/comms.js +28 -41
  285. package/dist/routes/shared-world/external-public.d.ts +5 -5
  286. package/dist/routes/shared-world/external-public.js +19 -20
  287. package/dist/routes/shared-world/handoff.d.ts +4 -4
  288. package/dist/routes/shared-world/handoff.js +50 -50
  289. package/dist/routes/shared-world/lobby-code.d.ts +5 -5
  290. package/dist/routes/shared-world/lobby-code.js +13 -13
  291. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
  292. package/dist/routes/shared-world/{seats.js → participant-specs.js} +46 -51
  293. package/dist/routes/shared-world/plan.d.ts +2 -6
  294. package/dist/routes/shared-world/plan.js +1 -2
  295. package/dist/routes/shared-world/provenance.d.ts +4 -4
  296. package/dist/routes/shared-world/provenance.js +4 -4
  297. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  298. package/dist/routes/shared-world/provisioned.js +48 -41
  299. package/dist/routes/shared-world/result.js +31 -19
  300. package/dist/routes/shared-world/route.js +37 -41
  301. package/dist/routes/shared-world/setup.d.ts +5 -4
  302. package/dist/routes/shared-world/setup.js +12 -14
  303. package/dist/routes/shared-world/types.d.ts +53 -126
  304. package/dist/routes/shared-world/types.js +2 -2
  305. package/dist/routes/terminal/adapter.d.ts +8 -8
  306. package/dist/routes/terminal/adapter.js +28 -125
  307. package/dist/routes/terminal/bundle.d.ts +7 -12
  308. package/dist/routes/terminal/bundle.js +24 -34
  309. package/dist/routes/terminal/credentials.d.ts +2 -2
  310. package/dist/routes/terminal/credentials.js +16 -16
  311. package/dist/routes/terminal/dry-run.d.ts +1 -1
  312. package/dist/routes/terminal/dry-run.js +9 -11
  313. package/dist/routes/terminal/encoding.d.ts +1 -1
  314. package/dist/routes/terminal/encoding.js +2 -2
  315. package/dist/routes/terminal/ledger.d.ts +6 -6
  316. package/dist/routes/terminal/ledger.js +9 -9
  317. package/dist/routes/terminal/live-finish.d.ts +1 -2
  318. package/dist/routes/terminal/live-finish.js +21 -20
  319. package/dist/routes/terminal/live-sandbox.d.ts +4 -2
  320. package/dist/routes/terminal/live-sandbox.js +25 -21
  321. package/dist/routes/terminal/participant-text.d.ts +23 -0
  322. package/dist/routes/terminal/participant-text.js +165 -0
  323. package/dist/routes/terminal/plan.d.ts +2 -6
  324. package/dist/routes/terminal/plan.js +13 -9
  325. package/dist/routes/terminal/recorder.d.ts +6 -1
  326. package/dist/routes/terminal/recorder.js +12 -4
  327. package/dist/routes/terminal/result.js +4 -4
  328. package/dist/routes/terminal/route.js +26 -26
  329. package/dist/routes/terminal/runtime.d.ts +3 -2
  330. package/dist/routes/terminal/runtime.js +3 -3
  331. package/dist/routes/terminal/sandbox.d.ts +5 -3
  332. package/dist/routes/terminal/sandbox.js +13 -16
  333. package/dist/routes/terminal/session.js +16 -14
  334. package/dist/routes/terminal/token-usage.js +5 -5
  335. package/dist/routes/terminal/trace.d.ts +5 -8
  336. package/dist/routes/terminal/trace.js +9 -64
  337. package/dist/routes/terminal/types.d.ts +85 -93
  338. package/dist/routes/terminal/types.js +9 -4
  339. package/dist/run/active-runs.d.ts +13 -0
  340. package/dist/run/active-runs.js +12 -0
  341. package/dist/run/bundle-shape.d.ts +2 -1
  342. package/dist/run/bundle-shape.js +4 -4
  343. package/dist/run/bundle.d.ts +63 -56
  344. package/dist/run/bundle.js +9 -8
  345. package/dist/run/cost-summary.js +3 -2
  346. package/dist/run/costs.d.ts +6 -6
  347. package/dist/run/costs.js +10 -10
  348. package/dist/run/detail.d.ts +5 -5
  349. package/dist/run/detail.js +6 -6
  350. package/dist/run/dry-run.js +5 -12
  351. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  352. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  353. package/dist/run/feedback-shape.js +1 -1
  354. package/dist/run/judge.d.ts +16 -4
  355. package/dist/run/judge.js +24 -7
  356. package/dist/run/locate.d.ts +2 -0
  357. package/dist/run/locate.js +3 -1
  358. package/dist/run/outcomes.d.ts +3 -3
  359. package/dist/run/outcomes.js +3 -3
  360. package/dist/run/participant-records.d.ts +2 -2
  361. package/dist/run/participant-records.js +2 -2
  362. package/dist/run/paths.js +1 -1
  363. package/dist/run/pricing.d.ts +19 -9
  364. package/dist/run/pricing.js +30 -18
  365. package/dist/run/projection.d.ts +13 -13
  366. package/dist/run/projection.js +8 -8
  367. package/dist/run/reclaim.d.ts +7 -1
  368. package/dist/run/reclaim.js +24 -4
  369. package/dist/run/results.d.ts +1 -1
  370. package/dist/run/run-index.d.ts +1 -1
  371. package/dist/run/run-index.js +11 -11
  372. package/dist/run/run.d.ts +4 -2
  373. package/dist/run/run.js +9 -5
  374. package/dist/run/sandbox-receipts.d.ts +4 -4
  375. package/dist/run/sandbox-receipts.js +4 -4
  376. package/dist/run/shared-world-evidence.d.ts +47 -47
  377. package/dist/run/shared-world-shape.d.ts +3 -3
  378. package/dist/run/shared-world-shape.js +11 -11
  379. package/dist/run/stats.d.ts +5 -5
  380. package/dist/run/stats.js +8 -8
  381. package/dist/run/status.d.ts +16 -6
  382. package/dist/run/status.js +31 -8
  383. package/dist/run/streams.d.ts +26 -19
  384. package/dist/run/terminal-contract.d.ts +5 -5
  385. package/dist/run/terminal-contract.js +4 -4
  386. package/dist/run/transient-comms-secrets.d.ts +5 -0
  387. package/dist/run/transient-comms-secrets.js +12 -0
  388. package/dist/run-lab.d.ts +36 -34
  389. package/dist/run-lab.js +41 -37
  390. package/dist/subject/desktop-cli.d.ts +1 -1
  391. package/dist/subject/desktop-cli.js +1 -1
  392. package/dist/subject/local-tree-archive.d.ts +1 -1
  393. package/dist/subject/local-tree-archive.js +4 -4
  394. package/dist/subject/local-tree.d.ts +2 -2
  395. package/dist/subject/local-tree.js +1 -1
  396. package/dist/subject/node-bootstrap.d.ts +1 -1
  397. package/dist/subject/node-bootstrap.js +4 -4
  398. package/dist/subject/runtime.js +5 -5
  399. package/dist/subject/serve.js +1 -1
  400. package/dist/subject/steps.d.ts +4 -4
  401. package/dist/subject/steps.js +5 -5
  402. package/dist/substrates/desktop-session.d.ts +2 -0
  403. package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
  404. package/dist/substrates/e2b/cdp-probe.js +1 -1
  405. package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
  406. package/dist/substrates/e2b/desktop-browser.js +4 -4
  407. package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
  408. package/dist/substrates/e2b/desktop-cdp.js +4 -4
  409. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  410. package/dist/substrates/e2b/desktop-geometry.js +3 -3
  411. package/dist/substrates/e2b/desktop-media.js +2 -2
  412. package/dist/substrates/e2b/sandbox.d.ts +2 -0
  413. package/dist/substrates/e2b/sandbox.js +22 -8
  414. package/dist/substrates/e2b/sdk.d.ts +12 -1
  415. package/dist/substrates/e2b/sdk.js +30 -9
  416. package/dist/substrates/local/runtime-host.d.ts +2 -0
  417. package/dist/substrates/local/runtime-host.js +6 -0
  418. package/dist/tui/actions.d.ts +7 -5
  419. package/dist/tui/actions.js +18 -9
  420. package/dist/tui-app.js +42 -42
  421. package/dist/verify/actor.d.ts +10 -10
  422. package/dist/verify/actor.js +15 -15
  423. package/dist/verify/artifacts.d.ts +1 -1
  424. package/dist/verify/artifacts.js +3 -3
  425. package/dist/verify/costs.d.ts +2 -2
  426. package/dist/verify/costs.js +2 -2
  427. package/dist/verify/liveness.d.ts +1 -1
  428. package/dist/verify/liveness.js +4 -1
  429. package/dist/verify/rerun.d.ts +1 -1
  430. package/dist/verify/rerun.js +1 -1
  431. package/dist/verify/shared-world.js +2 -2
  432. package/dist/verify/verify.js +6 -6
  433. package/docs/README.md +1 -1
  434. package/docs/architecture/actor-contract.md +60 -22
  435. package/docs/architecture/desktop-sessions.md +9 -9
  436. package/docs/architecture/external-public-shared-world.md +5 -0
  437. package/docs/architecture/observer.md +4 -4
  438. package/docs/architecture/restricted-codex-analysis.md +40 -4
  439. package/docs/architecture/state-driven-executor.md +4 -5
  440. package/docs/architecture/task-protocol-support.md +3 -5
  441. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
  442. package/docs/contracts/run-bundle.md +10 -8
  443. package/docs/contracts/schemas.md +109 -53
  444. package/docs/contracts/study-analysis.md +24 -0
  445. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  446. package/docs/product/automatic-analysis.md +1 -0
  447. package/docs/ramp/README.md +2 -1
  448. package/package.json +4 -4
  449. package/skills/humanish/SKILL.md +3 -2
  450. package/skills/humanish/agents/openai.yaml +1 -1
  451. package/dist/deprecated.d.ts +0 -90
  452. package/dist/deprecated.js +0 -106
  453. package/dist/lab/bag-overrides.d.ts +0 -18
  454. package/dist/lab/bag-overrides.js +0 -121
  455. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  456. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  457. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  458. /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
  459. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -1,8 +1,8 @@
1
1
  import type { LabConfig } from "./types.js";
2
2
  /**
3
- * Cross-validate the computer-use fan-out declaration (per-lane worlds). Returns the failure
4
- * message, or null when valid. Enforced at parse AND re-enforced in the engine (runCuaActorLab
5
- * is itself exported npm surface). Structural lane shape (id/device validity, id uniqueness) is
3
+ * Cross-validate the computer-use fan-out declaration (`per-lane-worlds`). Returns the failure
4
+ * message, or null when valid. Enforced at parse and re-enforced in the engine (runCuaActorLab
5
+ * is itself exported npm surface). Structural roster shape (id/device validity, id uniqueness) is
6
6
  * already checked in parseLanes; this is the route-scoped XOR/cap/policy layer.
7
7
  */
8
8
  export declare function cuaLaneValidationReason(config: LabConfig): string | null;
@@ -43,24 +43,24 @@ export declare function scenarioCapsValidationReason(config: LabConfig): string
43
43
  /** Refuse a claimed output bound when the route cannot pass it to the first-party provider. */
44
44
  export declare function outputTokenLimitValidationReason(config: LabConfig): string | null;
45
45
  /**
46
- * Cross-validate a CONCURRENT shared-world declaration (#164 phase 2). Returns the failure message,
47
- * or null when valid. Includes the base shared-world checks PLUS the concurrent extras: a synthetic
48
- * subject attestation (FIX-3), a 0.0.0.0 serve bind (FIX-4 — getHost only routes to a port bound on
49
- * all interfaces), and no `subject.clone.keep`/`subject.localTree.keep` (FIX-9 - either would
50
- * orphan actor sandboxes). Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld
46
+ * Cross-validate a concurrent shared-world declaration (#164 phase 2). Returns the failure message,
47
+ * or null when valid. Includes the base shared-world checks plus the concurrent extras: a synthetic
48
+ * subject attestation, a 0.0.0.0 serve bind (getHost only routes to a port bound on
49
+ * all interfaces), and no `subject.clone.keep`/`subject.localTree.keep` (either would
50
+ * orphan actor sandboxes). Enforced at parse and re-enforced in the engine (runConcurrentSharedWorld
51
51
  * is exported npm surface).
52
52
  */
53
53
  export declare function concurrentSharedWorldValidationReason(config: LabConfig): string | null;
54
54
  /**
55
- * Cross-validate the EXTERNAL-PUBLIC shared-world declaration (#164 phase 2): a real PUBLIC
56
- * deployment used DIRECTLY as the shared plane (no getHost, no clone, no subject sandbox, no seed).
57
- * The honest analog of concurrentSharedWorldValidationReason for a plane the harness does NOT own:
58
- * it FORBIDS every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
59
- * are inert with no sandbox — fail closed, never silently ignored, per invariant 6), and REQUIRES a
55
+ * Cross-validate the external-public shared-world declaration (#164 phase 2): a real public
56
+ * deployment used directly as the shared plane (no getHost, no clone, no subject sandbox, no seed).
57
+ * The counterpart of concurrentSharedWorldValidationReason for a plane the harness does not own:
58
+ * it rejects every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
59
+ * are inert with no sandbox, so they fail closed per invariant 6), and requires a
60
60
  * non-loopback appUrl + allowPublicTargets + the operator-ownership attestation subject.publicTarget +
61
- * concurrency >= 2 + an actors[0].lanes roster of ≥2 with EXACTLY ONE host lane. The getHost synthetic
61
+ * concurrency >= 2 + an actors[0].lanes roster of ≥2 with exactly one host participant. The getHost synthetic
62
62
  * gate is deliberately unreachable here (there is no internet-reachable harness-owned URL to attest).
63
- * Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
63
+ * Enforced at parse and re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
64
64
  */
65
65
  export declare function externalPublicSharedWorldValidationReason(config: LabConfig): string | null;
66
66
  /** Analysis requires a live recording producer, including supported dry-run previews. */
@@ -4,9 +4,9 @@ import { isHttpUrl, isLoopbackUrl } from "./parse/subject.js";
4
4
  import { declaredTargets } from "./plan-participants.js";
5
5
  import { actorResolvesToComputerUse, cuaLaneCount, MAX_CUA_LANES, registeredComputerUseActors, resolveSeatUrl, isComputerUseComposition, isScriptedBrowserComposition, isSharedWorldComposition, isTerminalProductComposition, } from "./routing.js";
6
6
  /**
7
- * Cross-validate the computer-use fan-out declaration (per-lane worlds). Returns the failure
8
- * message, or null when valid. Enforced at parse AND re-enforced in the engine (runCuaActorLab
9
- * is itself exported npm surface). Structural lane shape (id/device validity, id uniqueness) is
7
+ * Cross-validate the computer-use fan-out declaration (`per-lane-worlds`). Returns the failure
8
+ * message, or null when valid. Enforced at parse and re-enforced in the engine (runCuaActorLab
9
+ * is itself exported npm surface). Structural roster shape (id/device validity, id uniqueness) is
10
10
  * already checked in parseLanes; this is the route-scoped XOR/cap/policy layer.
11
11
  */
12
12
  export function cuaLaneValidationReason(config) {
@@ -16,8 +16,8 @@ export function cuaLaneValidationReason(config) {
16
16
  if (structuralReason) {
17
17
  return structuralReason;
18
18
  }
19
- // clone.fanout is a DECLARED behavior change: rejected on the cua route (was inert-warned).
20
- // Fan-out is declared via actors[0].count/lanes; subject.clone.fanout never applied here.
19
+ // clone.fanout is a declared behavior change: rejected on the cua route (was inert-warned).
20
+ // Fan-out is declared via `actors[0].count` or `actors[0].lanes`; subject.clone.fanout never applied here.
21
21
  if (config.subject.clone?.fanout !== undefined) {
22
22
  return "`subject.clone.fanout` is not used on the computer-use route: declare fan-out with actors[0].count (homogeneous) or actors[0].lanes (a roster of participants). (No current route reads clone.fanout.)";
23
23
  }
@@ -49,11 +49,11 @@ export function cuaLaneValidationReason(config) {
49
49
  if (participantCount > MAX_CUA_LANES) {
50
50
  return `Computer-use fan-out is capped at ${MAX_CUA_LANES} participants (declared ${participantCount}); N concurrent paid desktops is real spend, and there is no override above the cap this slice.`;
51
51
  }
52
- // Public targets fan out into N independent worlds driving the SAME public app — that is an
53
- // ambiguous shared-world-ish shape, not a per-lane target swarm. Permit N>1 public runs only when
54
- // every roster lane declares its own target, making the adapter-owned topology explicit. But when
55
- // `subject.topology: shared-world` is ALSO declared, N lanes against one public target is the
56
- // EXTERNAL-PUBLIC shared-world topology (#164 phase 2) — ROUTE it there (a real public deployment
52
+ // Public targets fan out into N independent worlds driving the same public app, which is an
53
+ // ambiguous shared-world-ish shape, not a per-participant target swarm. Permit N>1 public runs only
54
+ // when every roster entry declares its own target, making the adapter-owned topology explicit. But when
55
+ // `subject.topology: shared-world` is also declared, N participants against one public target is the
56
+ // external-public shared-world topology (#164 phase 2), so route it there (a real public deployment
57
57
  // as the shared plane) instead of refusing; externalPublicSharedWorldValidationReason then applies.
58
58
  if (participantCount > 1 &&
59
59
  config.policies?.allowPublicTargets === true &&
@@ -107,9 +107,9 @@ export function sharedWorldValidationReason(config) {
107
107
  : concurrentSharedWorldValidationReason(config);
108
108
  }
109
109
  /**
110
- * The structural checks every provisioned shared world shares. It REQUIRES: a clone or local-tree source + e2b-desktop
110
+ * The structural checks every provisioned shared world shares. It requires: a clone or local-tree source + e2b-desktop
111
111
  * target + a computer-use actor + a `subject.serve` block + an `actors[0].lanes` roster of ≥2 roles (the
112
- * roster IS the role roster — no parallel roles[] field), and every role `entry` must resolve
112
+ * roster is the role roster; there is no separate roles[] field), and every role `entry` must resolve
113
113
  * same-origin (loopback) with serve.url. Fail-closed: a half-declared shared-world is rejected,
114
114
  * never silently downgraded.
115
115
  */
@@ -263,7 +263,7 @@ export function outputTokenLimitValidationReason(config) {
263
263
  * Shared-world participants share one live app, so at least two must be live at once. The
264
264
  * sequential shared-world route (`execution.concurrency: 1`) was removed in 0.106.0; the parser
265
265
  * fills an omitted concurrency with the participant count. Both callers check it after their
266
- * two-lane roster floor, so a one-seat roster gets the roster refusal, never this one.
266
+ * two-participant roster floor, so a one-seat roster gets the roster refusal, never this one.
267
267
  */
268
268
  function sharedWorldConcurrencyReason(config) {
269
269
  // Direct library callers skip the parser, so an omitted value defaults here exactly as the
@@ -275,11 +275,11 @@ function sharedWorldConcurrencyReason(config) {
275
275
  return `shared-world labs need \`execution.concurrency\` of at least 2 (got ${concurrency}). Sequential shared-world turns (concurrency 1) were removed in 0.106.0: omit execution.concurrency to run every participant at once, or set it to 2 or more. A provisioned subject also needs \`subject.exposure: synthetic\` and a \`serve.start\` that binds 0.0.0.0.`;
276
276
  }
277
277
  /**
278
- * Cross-validate a CONCURRENT shared-world declaration (#164 phase 2). Returns the failure message,
279
- * or null when valid. Includes the base shared-world checks PLUS the concurrent extras: a synthetic
280
- * subject attestation (FIX-3), a 0.0.0.0 serve bind (FIX-4 — getHost only routes to a port bound on
281
- * all interfaces), and no `subject.clone.keep`/`subject.localTree.keep` (FIX-9 - either would
282
- * orphan actor sandboxes). Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld
278
+ * Cross-validate a concurrent shared-world declaration (#164 phase 2). Returns the failure message,
279
+ * or null when valid. Includes the base shared-world checks plus the concurrent extras: a synthetic
280
+ * subject attestation, a 0.0.0.0 serve bind (getHost only routes to a port bound on
281
+ * all interfaces), and no `subject.clone.keep`/`subject.localTree.keep` (either would
282
+ * orphan actor sandboxes). Enforced at parse and re-enforced in the engine (runConcurrentSharedWorld
283
283
  * is exported npm surface).
284
284
  */
285
285
  export function concurrentSharedWorldValidationReason(config) {
@@ -304,15 +304,15 @@ export function concurrentSharedWorldValidationReason(config) {
304
304
  return null;
305
305
  }
306
306
  /**
307
- * Cross-validate the EXTERNAL-PUBLIC shared-world declaration (#164 phase 2): a real PUBLIC
308
- * deployment used DIRECTLY as the shared plane (no getHost, no clone, no subject sandbox, no seed).
309
- * The honest analog of concurrentSharedWorldValidationReason for a plane the harness does NOT own:
310
- * it FORBIDS every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
311
- * are inert with no sandbox — fail closed, never silently ignored, per invariant 6), and REQUIRES a
307
+ * Cross-validate the external-public shared-world declaration (#164 phase 2): a real public
308
+ * deployment used directly as the shared plane (no getHost, no clone, no subject sandbox, no seed).
309
+ * The counterpart of concurrentSharedWorldValidationReason for a plane the harness does not own:
310
+ * it rejects every provisioned-subject field (serve/state.seed/state.checkpoint/exposure/clone/repos
311
+ * are inert with no sandbox, so they fail closed per invariant 6), and requires a
312
312
  * non-loopback appUrl + allowPublicTargets + the operator-ownership attestation subject.publicTarget +
313
- * concurrency >= 2 + an actors[0].lanes roster of ≥2 with EXACTLY ONE host lane. The getHost synthetic
313
+ * concurrency >= 2 + an actors[0].lanes roster of ≥2 with exactly one host participant. The getHost synthetic
314
314
  * gate is deliberately unreachable here (there is no internet-reachable harness-owned URL to attest).
315
- * Enforced at parse AND re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
315
+ * Enforced at parse and re-enforced in the engine (runConcurrentSharedWorld is exported npm surface).
316
316
  */
317
317
  export function externalPublicSharedWorldValidationReason(config) {
318
318
  const structuralReason = rosterStructuralValidationReason(config);
@@ -343,13 +343,13 @@ export function externalPublicSharedWorldValidationReason(config) {
343
343
  return "the external-public shared-world route requires a non-loopback http(s) `subject.appUrl` — a loopback URL is not a shared public plane (use the getHost provisioned route for a local subject).";
344
344
  }
345
345
  // The operator-ownership attestation (the honest analog of exposure: synthetic — you cannot claim
346
- // synthetic on a real site, but you MUST attest you own/operate it). Author-trust; unverifiable.
346
+ // synthetic on a real site, but you must attest you own/operate it). Author-trust; unverifiable.
347
347
  if (config.subject.publicTarget?.authorized !== true) {
348
348
  return "the external-public shared-world route requires `subject.publicTarget: { owner, authorized: true }` — you must attest you own/operate the public deployment used as the shared plane (author-trust; the harness cannot verify ownership).";
349
349
  }
350
- // FORBID every provisioned-subject field: with no sandbox they cannot act, so they are rejected
350
+ // No provisioned-subject field is allowed: with no sandbox they cannot act, so they are rejected
351
351
  // with a precise reason, never silently ignored (invariant 6). exposure: synthetic in particular
352
- // would be a LIE on a real site (the harness neither provisioned nor exposed it).
352
+ // would be a false claim on a real site (the harness neither provisioned nor exposed it).
353
353
  if (config.subject.exposure !== undefined) {
354
354
  return "`subject.exposure: synthetic` is forbidden on the external-public shared-world route — you cannot attest a real public deployment is synthetic seeded data; use `subject.publicTarget` to attest ownership instead.";
355
355
  }
@@ -12,13 +12,14 @@ const scriptedRoute = (routes) => !promptRoute(routes) && routes.scripted;
12
12
  const otherRoute = (routes) => !promptRoute(routes) && !routes.scripted;
13
13
  /** Rows for each actor, reported as `actors[<index>].<field>`, in this order per actor. */
14
14
  const ACTOR_ROWS = [
15
- // Shared-world ONLY fields on the roster: per-role `entry` is inert anywhere else (invariant 6).
15
+ // Shared-world-only fields on the roster: a participant's `entry` is inert anywhere else
16
+ // (invariant 6).
16
17
  {
17
18
  field: "lanes[].entry",
18
- reason: "the per-role loopback entry is a shared-world capability; needs subject.topology: shared-world",
19
+ reason: "the per-participant loopback entry is a shared-world capability; needs subject.topology: shared-world",
19
20
  applies: (actor, routes) => Boolean(rosterOf(actor)?.some((entry) => entry.entry !== undefined)) && !routes.shared,
20
21
  },
21
- // The host-seat marker acts ONLY on the external-public shared-world route; inert elsewhere.
22
+ // The host-seat marker acts only on the external-public shared-world route; inert elsewhere.
22
23
  {
23
24
  field: "lanes[].host",
24
25
  reason: "the designated host-participant marker; needs the external-public shared-world route: app-url × topology shared-world × allowPublicTargets",
@@ -57,7 +58,7 @@ const ACTOR_ROWS = [
57
58
  reason: "the scripted-browser route fans out via actors[0].count, not an actors[0].lanes roster",
58
59
  applies: (actor, routes) => scriptedRoute(routes) && Boolean(rosterOf(actor)),
59
60
  },
60
- // On every other route the prompt fields, persona and the lane roster are inert.
61
+ // On every other route the prompt fields, persona and the `lanes[]` roster are inert.
61
62
  { field: "mission", applies: (actor, routes) => otherRoute(routes) && Boolean(actor.mission) },
62
63
  {
63
64
  field: "laneFocus",
@@ -89,7 +90,7 @@ const CONFIG_ROWS = [
89
90
  field: "subject.state",
90
91
  applies: (config, routes) => Boolean(config.subject.state) && !routes.cua && !routes.scripted,
91
92
  },
92
- // topology + checkpoint act ONLY on the shared-world route (#164); a set-but-unconsumed value
93
+ // topology + checkpoint act only on the shared-world route (#164); a set-but-unconsumed value
93
94
  // (incl. an explicit per-lane-worlds, which the cua route already is by mechanism) warns inert.
94
95
  {
95
96
  field: "subject.topology",
@@ -101,14 +102,14 @@ const CONFIG_ROWS = [
101
102
  reason: "the shared-world state-checkpoint probe; needs subject.topology: shared-world",
102
103
  applies: (config, routes) => config.subject.state?.checkpoint !== undefined && !routes.shared,
103
104
  },
104
- // publicTarget (the external-public ownership attestation) acts ONLY on the external-public
105
+ // publicTarget (the external-public ownership attestation) acts only on the external-public
105
106
  // shared-world route; inert elsewhere. (It is already parse-rejected on non-app-url sources.)
106
107
  {
107
108
  field: "subject.publicTarget",
108
109
  reason: "the external-public ownership attestation; needs the external-public shared-world route: app-url × topology shared-world × allowPublicTargets",
109
110
  applies: (config, routes) => config.subject.publicTarget !== undefined && !routes.externalPublic,
110
111
  },
111
- // exposure (the synthetic-subject attestation) acts ONLY on the shared-world route (the
112
+ // exposure (the synthetic-subject attestation) acts only on the shared-world route (the
112
113
  // getHost-exposed plane) and on scripted clones; inert elsewhere.
113
114
  {
114
115
  field: "subject.exposure",
@@ -117,7 +118,7 @@ const CONFIG_ROWS = [
117
118
  !routes.shared &&
118
119
  !(routes.scripted && config.subject.source === "clone"),
119
120
  },
120
- // comms.email drives the in-sandbox email/SMS catch, which needs a subject sandbox HUMANISH
121
+ // comms.email drives the in-sandbox email/SMS catch, which needs a subject sandbox that humanish
121
122
  // provisions (clone or local-tree) so it holds a handle to host the catch. On an app-url /
122
123
  // operator-provided subject there is no such handle, so a declared comms block would silently
123
124
  // collect nothing — a false green. Warn at parse time (fires on inspect + dry-run too).
@@ -138,8 +139,8 @@ const CONFIG_ROWS = [
138
139
  applies: (config) => Boolean(config.comms?.email?.external) &&
139
140
  (config.subject.source === "clone" || config.subject.source === "local-tree"),
140
141
  },
141
- // clone.keep IS consumed on the cua route (honored on FAILURE: the sandbox is left up to debug
142
- // a failed install/boot; otherwise always killed). clone.fanout is REJECTED on the cua route
142
+ // clone.keep is consumed on the cua route (honored on failure: the sandbox is left up to debug
143
+ // a failed install/boot; otherwise always killed). clone.fanout is rejected on the cua route
143
144
  // (a hard parse error above), so it can never reach this warning list there.
144
145
  {
145
146
  field: "execution.timeoutMs",
@@ -152,13 +153,13 @@ const CONFIG_ROWS = [
152
153
  field: "execution.completionTimeoutMs",
153
154
  applies: (config) => config.execution?.completionTimeoutMs !== undefined,
154
155
  },
155
- // execution.concurrency is CONSUMED on the cua route (it bounds in-flight fan-out lanes);
156
+ // execution.concurrency is consumed on the cua route (it bounds in-flight fan-out participants);
156
157
  // inert (warned) everywhere else.
157
158
  {
158
159
  field: "execution.concurrency",
159
160
  applies: (config, routes) => config.execution?.concurrency !== undefined && !routes.cua,
160
161
  },
161
- // execution.caps is CONSUMED on the cua route (maxUsd is the fail-closed spend abort); inert
162
+ // execution.caps is consumed on the cua route (maxUsd is the fail-closed spend abort); inert
162
163
  // (warned) everywhere else so a misplaced budget field is never trusted to cap a route it cannot.
163
164
  {
164
165
  field: "execution.caps",
@@ -167,7 +168,7 @@ const CONFIG_ROWS = [
167
168
  },
168
169
  // terminal-product consumes subject.product, scenario.caps, execution.{terminal,runtimeAuth}:
169
170
  // dry-run records the contract; live execution enforces caps and command-scoped auth. On every
170
- // OTHER route they are inert and must warn so a
171
+ // other route they are inert and must warn so a
171
172
  // misplaced safety/budget field is never trusted to do something it cannot (invariant 6).
172
173
  {
173
174
  field: "subject.product",
@@ -227,9 +228,9 @@ const CONFIG_ROWS = [
227
228
  field: "execution.desktop.sandboxTimeoutMs",
228
229
  applies: (config, routes) => !routes.cua && config.execution?.desktop?.sandboxTimeoutMs !== undefined,
229
230
  },
230
- // execution.desktop.template (the custom E2B desktop image) is consumed ONLY where a desktop is
231
+ // execution.desktop.template (the custom E2B desktop image) is consumed only where a desktop is
231
232
  // actually created via Sandbox.create — the e2b-desktop computer-use routes (cua/shared-world/
232
- // concurrent). It is INERT on every other route (incl. the in-process local-app cua route, which
233
+ // concurrent). It is inert on every other route (incl. the in-process local-app cua route, which
233
234
  // creates no desktop): warn so an unconsumed template is never silently ignored (invariant 6).
234
235
  {
235
236
  field: "execution.desktop.template",
@@ -243,7 +244,7 @@ const CONFIG_ROWS = [
243
244
  reason: "no current route reads it",
244
245
  applies: (config) => config.execution?.desktop?.codexAppServer !== undefined,
245
246
  },
246
- // scenario.ref is CONSUMED on the scripted-browser route (required there); forward-declared
247
+ // scenario.ref is consumed on the scripted-browser route (required there); forward-declared
247
248
  // everywhere else.
248
249
  {
249
250
  field: "scenario.ref",
@@ -251,7 +252,7 @@ const CONFIG_ROWS = [
251
252
  },
252
253
  { field: "scenario.inline", applies: (config) => Boolean(config.scenario?.inline) },
253
254
  // review.{scoring,milestones,vocabulary} stay forward-declared (reserved for #319) on every route.
254
- // review.scorer (#316) IS consumed (loaded + wired, or fail-closed at load) on every scorer-capable
255
+ // review.scorer (#316) is consumed (loaded + wired, or fail-closed at load) on every scorer-capable
255
256
  // route, so it does not warn there; on the scripted-browser route the actor carries no scorer seam,
256
257
  // so a declared scorer is flagged inert (the run also fails closed at load).
257
258
  {
@@ -297,7 +298,7 @@ function rowLabel(row, prefix = "") {
297
298
  : `${prefix}${row.field} (${row.reason})`;
298
299
  }
299
300
  // Report fields that are present but not yet consumed by the engine, so a user never trusts a
300
- // setting that silently does nothing. Keeps the schema forward-correct AND honest.
301
+ // setting that silently does nothing. Keeps the schema forward-correct and honest.
301
302
  export function forwardDeclaredWarnings(config) {
302
303
  const routes = routesOf(config);
303
304
  const inert = [];
@@ -324,7 +325,7 @@ export function forwardDeclaredWarnings(config) {
324
325
  warnings.push(`execution.concurrency ${cap} caps a ${participantCount}-participant roster: participants run in waves of ${cap}, never all live at once. Remove execution.concurrency (the default runs all ${participantCount} participants simultaneously) or set it to ${participantCount}; declare a lower cap only to bound simultaneous paid desktops.`);
325
326
  }
326
327
  }
327
- // Partial email coverage is legal but loud (#351): a lane without an addressed recipient never
328
+ // Partial email coverage is legal but loud (#351): a participant without an addressed recipient never
328
329
  // hears an inbox exists, so an email-gated flow on that seat dead-ends by construction.
329
330
  if (routes.cua && config.comms?.email?.recipients) {
330
331
  const participantIds = declaredParticipantIds(config);
@@ -3,7 +3,7 @@ import { type ObserverData } from "./data.js";
3
3
  /**
4
4
  * Resolve — and in a repo checkout, build — the Observer artifact BEFORE any run or
5
5
  * lab work starts. A missing artifact must cost seconds at startup, never a completed
6
- * session (a live lane spends real money before the render step would have noticed).
6
+ * session (a live participant spends real money before the render step would have noticed).
7
7
  * Unconditional on purpose: the artifact is the only renderer now, so the fail-before-
8
8
  * spend property this preflight bought under the flag matters more, not less.
9
9
  */
@@ -5,7 +5,7 @@ import { execSync } from "node:child_process";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
- import { projectShareCheckedAnalysis, studyAnalysisSharingProblems } from "../analysis/sharing.js";
8
+ import { projectShareCheckedAnalysis, analysisSharingProblems } from "../analysis/sharing.js";
9
9
  import { withObserverEndings } from "./data.js";
10
10
  const OBSERVER_DATA_PLACEHOLDER = "__HUMANISH_OBSERVER_DATA__";
11
11
  const OBSERVER_DATA_SLOT = `<script id="observer-data" type="application/json">${OBSERVER_DATA_PLACEHOLDER}</script>`;
@@ -13,7 +13,7 @@ let cachedObserverArtifact = null;
13
13
  /**
14
14
  * Resolve — and in a repo checkout, build — the Observer artifact BEFORE any run or
15
15
  * lab work starts. A missing artifact must cost seconds at startup, never a completed
16
- * session (a live lane spends real money before the render step would have noticed).
16
+ * session (a live participant spends real money before the render step would have noticed).
17
17
  * Unconditional on purpose: the artifact is the only renderer now, so the fail-before-
18
18
  * spend property this preflight bought under the flag matters more, not less.
19
19
  */
@@ -192,7 +192,7 @@ export function renderObserverHtml(data, options = {}) {
192
192
  },
193
193
  };
194
194
  }
195
- const sharing = studyAnalysisSharingProblems(analysis);
195
+ const sharing = analysisSharingProblems(analysis);
196
196
  if (data.publicSafety && (sharing.sensitive || sharing.unverified)) {
197
197
  const share = data.publicSafety.share;
198
198
  data = {
@@ -1,6 +1,6 @@
1
1
  import { actorEnding } from "../actors/stop-cause.js";
2
2
  import { isCommsReceivingEvidence, receivingAnalysisContext } from "../comms/receiving-evidence.js";
3
- import { formatParticipantOutcomes, formatStudyTaskFunnel, participantOutcomeDetails, withCuaReviewProvenance, } from "../run/outcomes.js";
3
+ import { formatParticipantOutcomes, formatRunTaskFunnel, participantOutcomeDetails, withCuaReviewProvenance, } from "../run/outcomes.js";
4
4
  import { cuaGoalSource, CUA_COMPLETION_NOTE } from "../actors/goal-source.js";
5
5
  export const OBSERVER_DATA_SCHEMA = "humanish.observer-data.v1";
6
6
  /** Discard a forged or stale runtime grant before projecting persisted evidence. */
@@ -95,7 +95,7 @@ export function buildObserverData(bundle, generatedAt = new Date().toISOString()
95
95
  ? {}
96
96
  : {
97
97
  tasks: bundle.review.tasks,
98
- tasksLine: formatStudyTaskFunnel(bundle.review.tasks),
98
+ tasksLine: formatRunTaskFunnel(bundle.review.tasks),
99
99
  }),
100
100
  },
101
101
  summary: {
@@ -5,7 +5,7 @@ import { createServer } from "node:http";
5
5
  import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import { projectShareCheckedAnalysis } from "../analysis/sharing.js";
8
- import { loadStudyAnalysis } from "../analysis/load.js";
8
+ import { loadAnalysis } from "../analysis/load.js";
9
9
  import { physicalCwdOf, runIdOf, bindExistingRunArtifactPaths, isSafeRunIdSegment, resolveLatestRunDirectory, validatePreparedRunArtifactPaths, } from "../run/paths.js";
10
10
  import { writeContainedOutputFile } from "../run/contained-output.js";
11
11
  import { loadRunBundlePrepared } from "../run/locate.js";
@@ -87,7 +87,7 @@ export async function renderObserver(cwdInput, runInput, options = {}) {
87
87
  throw new Error("Observer output directory does not match the selected run.");
88
88
  }
89
89
  const observerPath = path.join(preparedRunPaths.physicalRunRoot, "observer", "index.html");
90
- const analysis = projectShareCheckedAnalysis(await loadStudyAnalysis(preparedRunPaths));
90
+ const analysis = projectShareCheckedAnalysis(await loadAnalysis(preparedRunPaths));
91
91
  const observerData = buildObserverData(loaded.bundle);
92
92
  observerData.publicSafety.share = {
93
93
  status: verified.shareSafety.status,
@@ -4,7 +4,7 @@ import { type PinnedDirectory } from "./pinned-files.js";
4
4
  export interface ObserverRuntimeStreamUrl {
5
5
  streamId: string;
6
6
  url: string;
7
- /** Set when the lane's sandbox is gone (finished or torn down). An ended stream's live URL is a
7
+ /** Set when the participant's sandbox is gone (finished or torn down). An ended stream's live URL is a
8
8
  * dead noVNC page — the overlay stops injecting it so the tile falls back to the recorded
9
9
  * evidence (keyframe replay/screenshot) instead of rendering "sandbox not found" (#357). */
10
10
  ended?: boolean;
@@ -2,8 +2,8 @@
2
2
  // URLs, its analysis, and its media with byte ranges. serveObserver (render.ts) and the library
3
3
  // server (serve.ts) both route requests through them.
4
4
  import path from "node:path";
5
- import { isStudyAnalysisRecordPath, projectShareCheckedAnalysis } from "../analysis/sharing.js";
6
- import { loadStudyAnalysis } from "../analysis/load.js";
5
+ import { isAnalysisRecordPath, projectShareCheckedAnalysis } from "../analysis/sharing.js";
6
+ import { loadAnalysis } from "../analysis/load.js";
7
7
  import { listRuns } from "../run/stored-runs.js";
8
8
  import { bindExistingRunArtifactPaths, isPathInside, isSafeRunIdSegment } from "../run/paths.js";
9
9
  import { RUN_STATUS_FILE, RUN_STATUS_STALE_MS, isRunStatusRecord } from "../run/status.js";
@@ -23,7 +23,7 @@ async function readObserverAnalysis(runRoot) {
23
23
  prepared.runRootIdentity.ino !== runRoot.ino) {
24
24
  throw new Error("ANALYSIS_STORAGE_CHANGED");
25
25
  }
26
- return projectShareCheckedAnalysis(await loadStudyAnalysis(prepared));
26
+ return projectShareCheckedAnalysis(await loadAnalysis(prepared));
27
27
  }
28
28
  catch {
29
29
  return {
@@ -51,7 +51,7 @@ export async function serveRunPath(runRoot, relativePath, response, runtimeStrea
51
51
  const derivedLeaf = path.posix.basename(cleanedRelativePath);
52
52
  if (derivedRoot === ".analysis-lock" ||
53
53
  derivedLeaf.startsWith(".humanish-write-") ||
54
- isStudyAnalysisRecordPath(cleanedRelativePath)) {
54
+ isAnalysisRecordPath(cleanedRelativePath)) {
55
55
  writeResponse(response, 404, "Not found", "text/plain; charset=utf-8");
56
56
  return;
57
57
  }
@@ -148,7 +148,7 @@ async function withLocalRunStatus(runRoot, input) {
148
148
  if (record.state === "finished") {
149
149
  state = "finished";
150
150
  }
151
- else if (now - updated <= RUN_STATUS_STALE_MS) {
151
+ else if (record.state === "running" && now - updated <= RUN_STATUS_STALE_MS) {
152
152
  state = "running";
153
153
  }
154
154
  }
@@ -28,6 +28,8 @@ export interface ServeResult {
28
28
  };
29
29
  runsListed: number;
30
30
  shareReadyCount?: number;
31
+ /** With --safe: the runs left out, grouped by grade and reasons. */
32
+ hiddenRuns?: HiddenRunGroup[];
31
33
  entryRunId?: string;
32
34
  opened?: boolean;
33
35
  openCommand?: string;
@@ -46,9 +48,22 @@ interface ServeControlPlane {
46
48
  runId?: string;
47
49
  }>;
48
50
  }
51
+ /** Why verify kept a run out of a share-safe library: its grade and reason codes. */
52
+ interface ShareRefusal {
53
+ status: string;
54
+ reasons: string[];
55
+ }
56
+ /** Runs a share-safe library left out for the same grade and reasons. */
57
+ export interface HiddenRunGroup {
58
+ status: string;
59
+ reasons: string[];
60
+ runs: number;
61
+ }
49
62
  export interface ShareSafetyAdmission {
50
63
  /** The files verify found share_ready, or null when the run is not admitted. */
51
64
  admit(runId: string): Promise<AdmittedRun | null>;
65
+ /** Why verify refused the run, after admit returned null for it; undefined otherwise. */
66
+ refusal(runId: string): ShareRefusal | undefined;
52
67
  }
53
68
  export declare function createShareSafetyAdmission(cwd: string, options?: {
54
69
  verifyImpl?: typeof verifyRun;
@@ -79,6 +94,8 @@ export interface ServeLibraryServer {
79
94
  mode: ServeMode;
80
95
  runsListed: number;
81
96
  shareReadyCount?: number;
97
+ /** With safe: the runs left out, grouped by grade and reasons. */
98
+ hiddenRuns?: HiddenRunGroup[];
82
99
  entryRunId?: string;
83
100
  addPublicOrigin(origin: string): void;
84
101
  close(): Promise<void>;
@@ -19,11 +19,17 @@ export function createShareSafetyAdmission(cwd, options = {}) {
19
19
  // content hash at read time, which drops the entry.
20
20
  const cache = new Map();
21
21
  const shareReady = (verified) => verified.ok === true && verified.shareSafety.status === "share_ready";
22
- const verifyAdmission = async (runId, runDirectory, before, forget) => {
22
+ const verifyAdmission = async (runId, runDirectory, before, entry, forget) => {
23
23
  // A run verify refuses is never served, so its bytes are never hashed. Hashing reads every
24
24
  // byte, and one large file in a refused run would otherwise cost startup time for nothing.
25
- if (!shareReady(await verifyImpl(cwd, runId)))
25
+ const verified = await verifyImpl(cwd, runId);
26
+ if (!shareReady(verified)) {
27
+ entry.refusal = {
28
+ status: verified.shareSafety.status === "share_ready" ? "blocked" : verified.shareSafety.status,
29
+ reasons: verified.shareSafety.reasons.map((reason) => reason.code),
30
+ };
26
31
  return null;
32
+ }
27
33
  // Admitted: hash, verify again, and hash after, so the served bytes are the ones verify scanned.
28
34
  const hashesBefore = await hashRunInventory(runDirectory, before);
29
35
  if (!hashesBefore)
@@ -62,12 +68,31 @@ export function createShareSafetyAdmission(cwd, options = {}) {
62
68
  if (cache.get(runId) === entry)
63
69
  cache.delete(runId);
64
70
  };
65
- entry.admitted = verifyAdmission(runId, runDirectory, before, forget).catch(() => null);
71
+ entry.admitted = verifyAdmission(runId, runDirectory, before, entry, forget).catch(() => {
72
+ entry.refusal = { status: "unverifiable", reasons: ["VERIFY_FAILED"] };
73
+ return null;
74
+ });
66
75
  cache.set(runId, entry);
67
76
  return entry.admitted;
68
77
  },
78
+ refusal(runId) {
79
+ return cache.get(runId)?.refusal;
80
+ },
69
81
  };
70
82
  }
83
+ /** The refused runs grouped by grade and reasons, the largest group first. */
84
+ function hiddenRunGroups(refusals) {
85
+ const groups = new Map();
86
+ for (const refusal of refusals) {
87
+ const key = `${refusal.status}\0${refusal.reasons.join(",")}`;
88
+ const group = groups.get(key);
89
+ if (group)
90
+ group.runs += 1;
91
+ else
92
+ groups.set(key, { ...refusal, runs: 1 });
93
+ }
94
+ return [...groups.values()].sort((left, right) => right.runs - left.runs);
95
+ }
71
96
  function sameHashes(left, right) {
72
97
  return left.size === right.size && [...left].every(([key, hash]) => right.get(key) === hash);
73
98
  }
@@ -215,10 +240,15 @@ export async function serveObserverLibrary(cwdInput, options) {
215
240
  const allRuns = (await listRuns(cwd)).runs;
216
241
  let runsListed;
217
242
  let shareReadyCount;
243
+ let hiddenRuns;
218
244
  if (options.safe) {
219
245
  const admitted = await Promise.all(allRuns.map((run) => admission.admit(run.runId)));
220
246
  shareReadyCount = admitted.filter((run) => run !== null).length;
221
247
  runsListed = shareReadyCount;
248
+ // A run refused before verify ran, such as one whose files cannot be listed, is unverifiable.
249
+ hiddenRuns = hiddenRunGroups(allRuns
250
+ .filter((_run, index) => admitted[index] === null)
251
+ .map((run) => admission.refusal(run.runId) ?? { status: "unverifiable", reasons: ["VERIFY_FAILED"] }));
222
252
  }
223
253
  else {
224
254
  runsListed = allRuns.length;
@@ -266,6 +296,7 @@ export async function serveObserverLibrary(cwdInput, options) {
266
296
  mode,
267
297
  runsListed,
268
298
  ...(shareReadyCount !== undefined ? { shareReadyCount } : {}),
299
+ ...(hiddenRuns !== undefined ? { hiddenRuns } : {}),
269
300
  ...(entryRunId ? { entryRunId } : {}),
270
301
  // A tunnel's public origin is only known after the tunnel starts (post bind); this lets the
271
302
  // caller declare it, extending the Host allowlist so the authenticated edge forwarding under