humanish 0.107.0 → 0.108.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 (521) hide show
  1. package/ARCHITECTURE.md +22 -17
  2. package/CHANGELOG.md +14 -0
  3. package/CONTEXT.md +51 -44
  4. package/README.md +145 -172
  5. package/SECURITY.md +16 -26
  6. package/TELEMETRY.md +8 -6
  7. package/dist/actors/affordance.d.ts +4 -4
  8. package/dist/actors/affordance.js +12 -12
  9. package/dist/actors/agent-session.d.ts +2 -2
  10. package/dist/actors/agent-session.js +7 -7
  11. package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
  12. package/dist/actors/codex/app-server-actor-trace.js +1 -1
  13. package/dist/actors/codex/app-server-ui.js +1 -1
  14. package/dist/actors/codex/codex-admission.d.ts +91 -0
  15. package/dist/actors/codex/codex-admission.js +150 -0
  16. package/dist/actors/codex/restricted-executable.d.ts +4 -4
  17. package/dist/actors/codex/restricted-executable.js +8 -8
  18. package/dist/actors/codex/restricted-launch.d.ts +2 -1
  19. package/dist/actors/codex/restricted-launch.js +1 -1
  20. package/dist/actors/codex/restricted-participant.js +8 -6
  21. package/dist/actors/codex/restricted-policy.d.ts +2 -2
  22. package/dist/actors/codex/restricted-policy.js +2 -2
  23. package/dist/actors/codex/restricted-session.d.ts +2 -2
  24. package/dist/actors/codex/restricted-session.js +10 -5
  25. package/dist/actors/computer-use/actor.d.ts +16 -16
  26. package/dist/actors/computer-use/actor.js +2 -2
  27. package/dist/actors/computer-use/admission-limit.d.ts +1 -1
  28. package/dist/actors/computer-use/admission-limit.js +1 -1
  29. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  30. package/dist/actors/computer-use/loop/actions.js +10 -10
  31. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  32. package/dist/actors/computer-use/loop/backstop.js +14 -12
  33. package/dist/actors/computer-use/loop/ending.d.ts +5 -5
  34. package/dist/actors/computer-use/loop/ending.js +7 -7
  35. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/observation.js +9 -9
  37. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/provider-call.js +1 -1
  39. package/dist/actors/computer-use/loop/session.js +3 -3
  40. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  41. package/dist/actors/computer-use/loop/spend.js +1 -1
  42. package/dist/actors/computer-use/loop/trace.js +9 -8
  43. package/dist/actors/computer-use/loop/types.d.ts +25 -23
  44. package/dist/actors/computer-use/loop/usage.js +2 -2
  45. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  46. package/dist/actors/computer-use/openai-context.js +214 -0
  47. package/dist/actors/computer-use/openai-provider.d.ts +11 -8
  48. package/dist/actors/computer-use/openai-provider.js +45 -34
  49. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  50. package/dist/actors/computer-use/openai-requests.js +82 -15
  51. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  52. package/dist/actors/computer-use/openai-wire.js +36 -34
  53. package/dist/actors/contract.d.ts +78 -43
  54. package/dist/actors/contract.js +29 -23
  55. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  56. package/dist/actors/local-agent/claude-session.js +10 -9
  57. package/dist/actors/local-agent/cli.d.ts +8 -6
  58. package/dist/actors/local-agent/cli.js +24 -28
  59. package/dist/actors/local-agent/readiness.d.ts +2 -2
  60. package/dist/actors/local-agent/readiness.js +4 -4
  61. package/dist/actors/reasoning-effort.js +6 -6
  62. package/dist/actors/registry.d.ts +10 -10
  63. package/dist/actors/registry.js +18 -17
  64. package/dist/actors/scripted-browser/actor.d.ts +8 -8
  65. package/dist/actors/scripted-browser/actor.js +16 -16
  66. package/dist/actors/scripted-browser/browser-command.js +1 -1
  67. package/dist/actors/scripted-browser/steps.js +1 -1
  68. package/dist/actors/scripted-browser/types.d.ts +1 -1
  69. package/dist/actors/stop-conditions.d.ts +1 -1
  70. package/dist/analysis/codex-config.d.ts +6 -2
  71. package/dist/analysis/codex-config.js +22 -14
  72. package/dist/analysis/service.js +5 -5
  73. package/dist/cli/commands/analyze.js +19 -16
  74. package/dist/cli/commands/codex.js +9 -9
  75. package/dist/cli/commands/comms.js +54 -33
  76. package/dist/cli/commands/feedback.js +20 -21
  77. package/dist/cli/commands/lab-format.d.ts +5 -4
  78. package/dist/cli/commands/lab-format.js +35 -23
  79. package/dist/cli/commands/lab-route-computer-use.js +6 -7
  80. package/dist/cli/commands/lab-route-preview.js +4 -3
  81. package/dist/cli/commands/lab-route-shared-world.js +3 -3
  82. package/dist/cli/commands/lab-run.js +10 -11
  83. package/dist/cli/commands/lab-scorer.d.ts +2 -2
  84. package/dist/cli/commands/lab-scorer.js +1 -1
  85. package/dist/cli/commands/migrate.d.ts +4 -0
  86. package/dist/cli/commands/migrate.js +65 -0
  87. package/dist/cli/commands/observe.js +147 -108
  88. package/dist/cli/commands/run-command.d.ts +10 -0
  89. package/dist/cli/commands/run-command.js +85 -0
  90. package/dist/cli/commands/runs.js +137 -138
  91. package/dist/cli/commands/setup.d.ts +2 -2
  92. package/dist/cli/commands/setup.js +26 -21
  93. package/dist/cli/commands/study.d.ts +3 -0
  94. package/dist/cli/commands/study.js +182 -0
  95. package/dist/cli/commands/tui.d.ts +4 -4
  96. package/dist/cli/commands/tui.js +21 -21
  97. package/dist/cli/commands/watch.js +60 -75
  98. package/dist/cli/deprecations.d.ts +18 -0
  99. package/dist/cli/deprecations.js +48 -0
  100. package/dist/cli/doctor.d.ts +15 -5
  101. package/dist/cli/doctor.js +103 -48
  102. package/dist/cli/first-run-path.d.ts +12 -10
  103. package/dist/cli/first-run-path.js +30 -28
  104. package/dist/cli/io.d.ts +41 -6
  105. package/dist/cli/io.js +97 -22
  106. package/dist/cli/observer-follow.d.ts +2 -2
  107. package/dist/cli/observer-follow.js +5 -6
  108. package/dist/cli/orientation.d.ts +6 -3
  109. package/dist/cli/orientation.js +43 -39
  110. package/dist/cli/product-sentence.d.ts +6 -0
  111. package/dist/cli/product-sentence.js +6 -0
  112. package/dist/cli/program.d.ts +6 -1
  113. package/dist/cli/program.js +109 -40
  114. package/dist/cli/telemetry.d.ts +15 -15
  115. package/dist/cli/telemetry.js +48 -40
  116. package/dist/cli.js +1 -1
  117. package/dist/comms/capture-surface.d.ts +13 -12
  118. package/dist/comms/capture-surface.js +23 -22
  119. package/dist/comms/catch-host.d.ts +7 -7
  120. package/dist/comms/catch-host.js +14 -14
  121. package/dist/comms/email-catch.d.ts +3 -3
  122. package/dist/comms/email-catch.js +8 -8
  123. package/dist/comms/external-evidence.js +2 -2
  124. package/dist/comms/extract.js +2 -2
  125. package/dist/comms/fake-inbox.d.ts +2 -2
  126. package/dist/comms/fake-inbox.js +2 -2
  127. package/dist/comms/receiving-render.d.ts +1 -1
  128. package/dist/comms/receiving-render.js +2 -2
  129. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  130. package/dist/comms/sandbox-catch-script.js +6 -6
  131. package/dist/comms/sandbox-catch.d.ts +36 -37
  132. package/dist/comms/sandbox-catch.js +34 -35
  133. package/dist/comms/setup.js +42 -8
  134. package/dist/comms/thread-evidence.d.ts +1 -1
  135. package/dist/comms/thread-evidence.js +6 -6
  136. package/dist/comms/types.d.ts +6 -6
  137. package/dist/comms/types.js +3 -3
  138. package/dist/evidence/frame-signature.d.ts +1 -1
  139. package/dist/evidence/frame-signature.js +4 -4
  140. package/dist/evidence/redaction.d.ts +3 -3
  141. package/dist/evidence/redaction.js +4 -4
  142. package/dist/feedback/draft.js +36 -78
  143. package/dist/feedback/export-bundle.js +1 -1
  144. package/dist/feedback/export.d.ts +5 -1
  145. package/dist/feedback/export.js +7 -8
  146. package/dist/feedback/feedback.d.ts +2 -2
  147. package/dist/feedback/feedback.js +21 -3
  148. package/dist/guest/chromium-text.js +2 -2
  149. package/dist/guest/desktop-native.d.ts +1 -1
  150. package/dist/guest/runtime.js +1 -1
  151. package/dist/index.d.ts +12 -10
  152. package/dist/index.js +8 -6
  153. package/dist/keys/key-resolution.d.ts +5 -5
  154. package/dist/keys/key-resolution.js +23 -23
  155. package/dist/lab/adapter-extension.d.ts +7 -7
  156. package/dist/lab/adapter-extension.js +13 -36
  157. package/dist/lab/adapter-scorer-loader.d.ts +7 -7
  158. package/dist/lab/adapter-scorer-loader.js +32 -32
  159. package/dist/lab/composition-rules.js +42 -42
  160. package/dist/lab/config.js +65 -25
  161. package/dist/lab/deprecated-fields.d.ts +10 -0
  162. package/dist/lab/deprecated-fields.js +24 -0
  163. package/dist/lab/device-presets.d.ts +8 -8
  164. package/dist/lab/device-presets.js +11 -11
  165. package/dist/lab/discover.d.ts +13 -9
  166. package/dist/lab/discover.js +117 -57
  167. package/dist/lab/doctor.d.ts +10 -3
  168. package/dist/lab/doctor.js +47 -9
  169. package/dist/lab/init-templates.js +147 -147
  170. package/dist/lab/init.d.ts +1 -1
  171. package/dist/lab/init.js +41 -9
  172. package/dist/lab/keys.d.ts +2 -0
  173. package/dist/lab/keys.js +42 -8
  174. package/dist/lab/lab-deps.d.ts +7 -12
  175. package/dist/lab/parse/actors.js +9 -9
  176. package/dist/lab/parse/comms.js +5 -5
  177. package/dist/lab/parse/execution.js +13 -13
  178. package/dist/lab/parse/study-v3.d.ts +23 -0
  179. package/dist/lab/parse/study-v3.js +259 -0
  180. package/dist/lab/parse/subject-state.d.ts +7 -7
  181. package/dist/lab/parse/subject-state.js +16 -16
  182. package/dist/lab/parse/subject.js +28 -28
  183. package/dist/lab/parse/values.d.ts +1 -1
  184. package/dist/lab/parse/values.js +3 -3
  185. package/dist/lab/persona-resolve.d.ts +4 -4
  186. package/dist/lab/persona-resolve.js +4 -4
  187. package/dist/lab/plan-participants.d.ts +2 -2
  188. package/dist/lab/plan-types.d.ts +4 -4
  189. package/dist/lab/plan.d.ts +1 -7
  190. package/dist/lab/plan.js +10 -41
  191. package/dist/lab/preflight-probes.js +11 -11
  192. package/dist/lab/preflight-result.d.ts +2 -1
  193. package/dist/lab/preflight-result.js +5 -4
  194. package/dist/lab/preflight.d.ts +7 -5
  195. package/dist/lab/preflight.js +5 -5
  196. package/dist/lab/routing.d.ts +31 -25
  197. package/dist/lab/routing.js +60 -29
  198. package/dist/lab/run-lab-events.d.ts +0 -3
  199. package/dist/lab/run-lab-events.js +0 -6
  200. package/dist/lab/run-lab-homes.d.ts +22 -10
  201. package/dist/lab/run-lab-homes.js +5 -1
  202. package/dist/lab/run-lab-options.d.ts +1 -1
  203. package/dist/lab/run-lab-options.js +16 -13
  204. package/dist/lab/summary.d.ts +7 -6
  205. package/dist/lab/summary.js +10 -10
  206. package/dist/lab/tasks.d.ts +15 -15
  207. package/dist/lab/tasks.js +14 -14
  208. package/dist/lab/types.d.ts +101 -95
  209. package/dist/lab/types.js +2 -0
  210. package/dist/lab/validation.d.ts +13 -13
  211. package/dist/lab/validation.js +44 -42
  212. package/dist/lab/warnings.d.ts +10 -0
  213. package/dist/lab/warnings.js +61 -33
  214. package/dist/library-aliases.d.ts +56 -0
  215. package/dist/library-aliases.js +22 -0
  216. package/dist/observer/artifact.d.ts +1 -1
  217. package/dist/observer/artifact.js +6 -6
  218. package/dist/observer/data.d.ts +6 -6
  219. package/dist/observer/data.js +5 -4
  220. package/dist/observer/exposure.d.ts +1 -1
  221. package/dist/observer/exposure.js +11 -11
  222. package/dist/observer/http.js +1 -1
  223. package/dist/observer/library.d.ts +1 -1
  224. package/dist/observer/library.js +4 -2
  225. package/dist/observer/listen.js +5 -4
  226. package/dist/observer/render.d.ts +1 -1
  227. package/dist/observer/render.js +10 -5
  228. package/dist/observer/run-routes.d.ts +3 -3
  229. package/dist/observer/run-routes.js +1 -1
  230. package/dist/observer/serve.js +7 -3
  231. package/dist/observer/tunnel.js +1 -1
  232. package/dist/observer-app.html +4 -4
  233. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  234. package/dist/routes/computer-use/bundle-parts.js +15 -15
  235. package/dist/routes/computer-use/bundle.js +3 -3
  236. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
  237. package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
  238. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
  239. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
  240. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
  241. package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
  242. package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
  243. package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
  244. package/dist/routes/computer-use/external-comms.d.ts +1 -1
  245. package/dist/routes/computer-use/external-comms.js +1 -1
  246. package/dist/routes/computer-use/fanout-bundle.js +18 -18
  247. package/dist/routes/computer-use/fanout-records.js +10 -11
  248. package/dist/routes/computer-use/live-flush.d.ts +1 -1
  249. package/dist/routes/computer-use/live-flush.js +6 -6
  250. package/dist/routes/computer-use/live-phase.d.ts +4 -2
  251. package/dist/routes/computer-use/live-phase.js +6 -6
  252. package/dist/routes/computer-use/local-vm.js +1 -1
  253. package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
  254. package/dist/routes/computer-use/participant-desktop.js +4 -4
  255. package/dist/routes/computer-use/participant-execution.d.ts +4 -4
  256. package/dist/routes/computer-use/participant-execution.js +9 -9
  257. package/dist/routes/computer-use/participant-model.d.ts +6 -0
  258. package/dist/routes/computer-use/participant-model.js +31 -13
  259. package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
  260. package/dist/routes/computer-use/participant-prompt.js +6 -6
  261. package/dist/routes/computer-use/participant-runs.d.ts +7 -7
  262. package/dist/routes/computer-use/participant-runs.js +13 -13
  263. package/dist/routes/computer-use/plan.js +22 -22
  264. package/dist/routes/computer-use/preflight.js +21 -21
  265. package/dist/routes/computer-use/rerun-selection.js +1 -1
  266. package/dist/routes/computer-use/result.js +11 -11
  267. package/dist/routes/computer-use/route.d.ts +2 -1
  268. package/dist/routes/computer-use/route.js +15 -14
  269. package/dist/routes/computer-use/self-report.d.ts +7 -7
  270. package/dist/routes/computer-use/self-report.js +31 -31
  271. package/dist/routes/computer-use/setup.d.ts +1 -1
  272. package/dist/routes/computer-use/setup.js +17 -18
  273. package/dist/routes/computer-use/single-bundle.d.ts +7 -7
  274. package/dist/routes/computer-use/single-bundle.js +28 -30
  275. package/dist/routes/computer-use/subject-projection.d.ts +1 -1
  276. package/dist/routes/computer-use/subject-projection.js +6 -6
  277. package/dist/routes/computer-use/types.d.ts +40 -42
  278. package/dist/routes/computer-use/types.js +10 -10
  279. package/dist/routes/preview.d.ts +8 -2
  280. package/dist/routes/preview.js +8 -4
  281. package/dist/routes/scripted/bundle.d.ts +2 -2
  282. package/dist/routes/scripted/bundle.js +13 -12
  283. package/dist/routes/scripted/plan.d.ts +1 -1
  284. package/dist/routes/scripted/plan.js +9 -9
  285. package/dist/routes/scripted/result.js +5 -5
  286. package/dist/routes/scripted/route.js +5 -6
  287. package/dist/routes/scripted/scenario.js +2 -2
  288. package/dist/routes/scripted/setup.js +7 -7
  289. package/dist/routes/scripted/subject.js +1 -1
  290. package/dist/routes/scripted/surface-records.js +3 -3
  291. package/dist/routes/scripted/types.d.ts +3 -5
  292. package/dist/routes/scripted/types.js +1 -1
  293. package/dist/routes/shared-world/bundle-records.js +9 -8
  294. package/dist/routes/shared-world/bundle.d.ts +5 -5
  295. package/dist/routes/shared-world/bundle.js +40 -38
  296. package/dist/routes/shared-world/checkpoints.d.ts +1 -1
  297. package/dist/routes/shared-world/checkpoints.js +1 -1
  298. package/dist/routes/shared-world/comms.d.ts +5 -5
  299. package/dist/routes/shared-world/comms.js +14 -14
  300. package/dist/routes/shared-world/external-public.d.ts +4 -3
  301. package/dist/routes/shared-world/external-public.js +16 -12
  302. package/dist/routes/shared-world/handoff.d.ts +7 -6
  303. package/dist/routes/shared-world/handoff.js +65 -57
  304. package/dist/routes/shared-world/lobby-code.d.ts +2 -2
  305. package/dist/routes/shared-world/lobby-code.js +9 -9
  306. package/dist/routes/shared-world/participant-specs.d.ts +7 -6
  307. package/dist/routes/shared-world/participant-specs.js +31 -24
  308. package/dist/routes/shared-world/plan.js +7 -7
  309. package/dist/routes/shared-world/provenance.d.ts +2 -2
  310. package/dist/routes/shared-world/provenance.js +2 -2
  311. package/dist/routes/shared-world/provisioned.js +14 -13
  312. package/dist/routes/shared-world/result.js +20 -21
  313. package/dist/routes/shared-world/route.js +23 -22
  314. package/dist/routes/shared-world/setup.d.ts +3 -3
  315. package/dist/routes/shared-world/setup.js +4 -4
  316. package/dist/routes/shared-world/types.d.ts +30 -28
  317. package/dist/routes/shared-world/types.js +4 -4
  318. package/dist/routes/terminal/adapter.d.ts +3 -3
  319. package/dist/routes/terminal/adapter.js +5 -5
  320. package/dist/routes/terminal/bundle.d.ts +3 -3
  321. package/dist/routes/terminal/bundle.js +22 -21
  322. package/dist/routes/terminal/credentials.d.ts +4 -4
  323. package/dist/routes/terminal/credentials.js +7 -7
  324. package/dist/routes/terminal/dry-run.js +4 -4
  325. package/dist/routes/terminal/encoding.js +2 -2
  326. package/dist/routes/terminal/ledger.d.ts +3 -3
  327. package/dist/routes/terminal/ledger.js +14 -14
  328. package/dist/routes/terminal/live-finish.js +3 -3
  329. package/dist/routes/terminal/live-sandbox.js +12 -13
  330. package/dist/routes/terminal/persona.js +1 -1
  331. package/dist/routes/terminal/plan.js +11 -11
  332. package/dist/routes/terminal/recorder.js +2 -2
  333. package/dist/routes/terminal/result.js +8 -8
  334. package/dist/routes/terminal/route.js +6 -7
  335. package/dist/routes/terminal/sandbox.d.ts +1 -1
  336. package/dist/routes/terminal/sandbox.js +1 -1
  337. package/dist/routes/terminal/session.js +8 -7
  338. package/dist/routes/terminal/token-usage.d.ts +1 -1
  339. package/dist/routes/terminal/token-usage.js +7 -8
  340. package/dist/routes/terminal/trace.d.ts +2 -2
  341. package/dist/routes/terminal/trace.js +2 -2
  342. package/dist/routes/terminal/types.d.ts +26 -28
  343. package/dist/routes/terminal/types.js +3 -3
  344. package/dist/run/bundle-shape.js +3 -3
  345. package/dist/run/bundle.d.ts +46 -46
  346. package/dist/run/bundle.js +2 -1
  347. package/dist/run/cost-summary.js +3 -3
  348. package/dist/run/costs.js +7 -1
  349. package/dist/run/detail.d.ts +6 -6
  350. package/dist/run/detail.js +4 -4
  351. package/dist/run/dry-run-inputs.js +1 -1
  352. package/dist/run/dry-run.js +18 -18
  353. package/dist/run/judge.d.ts +19 -13
  354. package/dist/run/judge.js +18 -8
  355. package/dist/run/paths.d.ts +1 -1
  356. package/dist/run/paths.js +1 -1
  357. package/dist/run/pricing.d.ts +11 -6
  358. package/dist/run/pricing.js +20 -13
  359. package/dist/run/projection.d.ts +14 -14
  360. package/dist/run/projection.js +15 -15
  361. package/dist/run/reclaim.js +2 -2
  362. package/dist/run/results.d.ts +5 -5
  363. package/dist/run/run-index.d.ts +8 -6
  364. package/dist/run/run-index.js +15 -16
  365. package/dist/run/run-not-found.d.ts +5 -0
  366. package/dist/run/run-not-found.js +15 -0
  367. package/dist/run/run.d.ts +5 -4
  368. package/dist/run/run.js +1 -1
  369. package/dist/run/sandbox-receipts.d.ts +2 -2
  370. package/dist/run/sandbox-receipts.js +3 -3
  371. package/dist/run/shared-world-evidence.d.ts +36 -35
  372. package/dist/run/shared-world-evidence.js +4 -4
  373. package/dist/run/shared-world-shape.d.ts +1 -1
  374. package/dist/run/shared-world-shape.js +6 -6
  375. package/dist/run/stats.d.ts +12 -6
  376. package/dist/run/stats.js +116 -58
  377. package/dist/run/status.d.ts +8 -29
  378. package/dist/run/status.js +5 -27
  379. package/dist/run/stored-runs.js +2 -1
  380. package/dist/run/stream-shape.js +1 -1
  381. package/dist/run/streams.d.ts +6 -6
  382. package/dist/run/study-provenance.d.ts +47 -0
  383. package/dist/run/study-provenance.js +63 -0
  384. package/dist/run/study-result.d.ts +16 -0
  385. package/dist/run/study-result.js +9 -0
  386. package/dist/run/text.d.ts +2 -0
  387. package/dist/run/text.js +4 -0
  388. package/dist/run-lab.d.ts +7 -7
  389. package/dist/run-lab.js +1 -3
  390. package/dist/study/convert.d.ts +33 -0
  391. package/dist/study/convert.js +432 -0
  392. package/dist/study/field-paths.d.ts +12 -0
  393. package/dist/study/field-paths.js +126 -0
  394. package/dist/study/files.d.ts +26 -0
  395. package/dist/study/files.js +43 -0
  396. package/dist/study/migrate.d.ts +48 -0
  397. package/dist/study/migrate.js +408 -0
  398. package/dist/study/owned-files.d.ts +38 -0
  399. package/dist/study/owned-files.js +182 -0
  400. package/dist/subject/clone.d.ts +1 -1
  401. package/dist/subject/desktop-cli.d.ts +1 -1
  402. package/dist/subject/desktop-cli.js +2 -2
  403. package/dist/subject/local-tree-archive.js +1 -1
  404. package/dist/subject/local-tree.d.ts +1 -1
  405. package/dist/subject/node-bootstrap.js +1 -1
  406. package/dist/subject/runtime.js +8 -9
  407. package/dist/subject/serve.d.ts +1 -1
  408. package/dist/subject/serve.js +3 -3
  409. package/dist/subject/state.d.ts +1 -1
  410. package/dist/subject/steps.d.ts +5 -5
  411. package/dist/subject/steps.js +4 -4
  412. package/dist/substrates/command-failure.d.ts +3 -3
  413. package/dist/substrates/command-failure.js +3 -3
  414. package/dist/substrates/detached.d.ts +6 -6
  415. package/dist/substrates/detached.js +7 -7
  416. package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
  417. package/dist/substrates/e2b/cdp-probe.js +14 -17
  418. package/dist/substrates/e2b/desktop-browser.d.ts +2 -2
  419. package/dist/substrates/e2b/desktop-browser.js +8 -8
  420. package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
  421. package/dist/substrates/e2b/desktop-cdp.js +8 -8
  422. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  423. package/dist/substrates/e2b/desktop-executor.js +1 -1
  424. package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
  425. package/dist/substrates/e2b/desktop-geometry.js +7 -7
  426. package/dist/substrates/e2b/desktop-media.d.ts +1 -1
  427. package/dist/substrates/e2b/desktop-media.js +1 -1
  428. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  429. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  430. package/dist/substrates/e2b/sandbox.d.ts +1 -1
  431. package/dist/substrates/e2b/sandbox.js +1 -1
  432. package/dist/substrates/e2b/sdk.d.ts +11 -11
  433. package/dist/substrates/e2b/sdk.js +6 -6
  434. package/dist/tui/actions.d.ts +1 -1
  435. package/dist/tui/actions.js +13 -13
  436. package/dist/tui/contract.d.ts +16 -16
  437. package/dist/tui/contract.js +10 -10
  438. package/dist/tui/launch.d.ts +4 -4
  439. package/dist/tui/launch.js +18 -19
  440. package/dist/tui/project.js +5 -5
  441. package/dist/tui-app.js +82 -82
  442. package/dist/verify/actor.d.ts +8 -8
  443. package/dist/verify/actor.js +36 -36
  444. package/dist/verify/artifacts.d.ts +2 -2
  445. package/dist/verify/artifacts.js +3 -3
  446. package/dist/verify/context-growth.d.ts +9 -0
  447. package/dist/verify/context-growth.js +62 -0
  448. package/dist/verify/costs.d.ts +6 -6
  449. package/dist/verify/costs.js +8 -8
  450. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  451. package/dist/verify/shared-world-concurrent.js +79 -76
  452. package/dist/verify/shared-world.d.ts +2 -2
  453. package/dist/verify/shared-world.js +16 -16
  454. package/dist/verify/subject.d.ts +4 -4
  455. package/dist/verify/subject.js +18 -18
  456. package/dist/verify/verify.js +92 -43
  457. package/docs/README.md +25 -32
  458. package/docs/architecture/actor-contract.md +56 -87
  459. package/docs/architecture/desktop-sessions.md +7 -7
  460. package/docs/architecture/external-public-shared-world.md +61 -59
  461. package/docs/architecture/github-feedback-loop.md +1 -4
  462. package/docs/architecture/guest-desktop.md +2 -2
  463. package/docs/architecture/observer.md +34 -34
  464. package/docs/architecture/restricted-codex-analysis.md +34 -28
  465. package/docs/architecture/serve.md +34 -37
  466. package/docs/architecture/state-driven-executor.md +55 -58
  467. package/docs/architecture/task-protocol-support.md +5 -5
  468. package/docs/architecture/terminal-product-route.md +67 -107
  469. package/docs/contracts/README.md +24 -0
  470. package/docs/contracts/adapter-admission.md +3 -3
  471. package/docs/contracts/adapter-fixtures.md +2 -5
  472. package/docs/contracts/core.md +1 -3
  473. package/docs/contracts/errors.md +62 -0
  474. package/docs/contracts/feedback.md +8 -9
  475. package/docs/contracts/policy.md +7 -12
  476. package/docs/contracts/run-bundle.md +45 -44
  477. package/docs/contracts/schemas.md +421 -362
  478. package/docs/contracts/study-analysis.md +3 -3
  479. package/docs/contracts/study-costs.md +11 -7
  480. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  481. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  482. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  483. package/docs/principles/actor-fidelity.md +4 -4
  484. package/docs/principles/engineering.md +3 -3
  485. package/docs/principles/invariants-and-defaults.md +38 -38
  486. package/docs/principles/self-driving-harness.md +1 -5
  487. package/docs/principles/three-roles.md +1 -1
  488. package/docs/product/automatic-analysis.md +7 -7
  489. package/examples/participant/README.md +5 -5
  490. package/examples/participant/run.mjs +11 -10
  491. package/examples/scorer/README.md +3 -3
  492. package/examples/scorer/run.mjs +11 -12
  493. package/package.json +16 -17
  494. package/skills/humanish/SKILL.md +60 -58
  495. package/skills/humanish/agents/openai.yaml +1 -1
  496. package/AGENTS.md +0 -99
  497. package/CONTRIBUTING.md +0 -148
  498. package/dist/actors/codex/qualified-versions.d.ts +0 -72
  499. package/dist/actors/codex/qualified-versions.js +0 -132
  500. package/dist/cli/commands/lab.d.ts +0 -3
  501. package/dist/cli/commands/lab.js +0 -199
  502. package/dist/cli/renamed-options.d.ts +0 -11
  503. package/dist/cli/renamed-options.js +0 -18
  504. package/dist/observer/static.d.ts +0 -39
  505. package/dist/observer/static.js +0 -369
  506. package/docs/architecture/comms-inbox.md +0 -122
  507. package/docs/architecture/desktop-recording.md +0 -80
  508. package/docs/architecture/local-browser-runtime.md +0 -178
  509. package/docs/architecture/observer-review.md +0 -144
  510. package/docs/architecture/participant-media.md +0 -90
  511. package/docs/architecture/project-layout.md +0 -62
  512. package/docs/architecture/real-email-receiving.md +0 -136
  513. package/docs/assets/humanish-drawdb-hero.png +0 -0
  514. package/docs/assets/humanish-observer-hero.png +0 -0
  515. package/docs/goals/current.md +0 -207
  516. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  517. package/docs/product/open-source-install-experience.md +0 -240
  518. package/docs/ramp/README.md +0 -295
  519. package/docs/release/open-source-readiness.md +0 -222
  520. package/docs/release/public-readiness-standard.md +0 -210
  521. package/docs/roadmap/world-class-open-source-v0.md +0 -311
@@ -13,9 +13,10 @@ export interface ExternalPublicPlaneOutcome {
13
13
  /**
14
14
  * The operator-declared origin (from subject.appUrl), recorded for evidence and reference only. The
15
15
  * operator-ownership claim rests on the subject.publicTarget.authorized attestation + this declared
16
- * appUrl; digest equality plays no part (blocker 2): a normal cross-origin redirect (apex->www, http->https;
17
- * lobby-trivia.example.test 307-redirects) makes the seats' observed origin differ from the declared one, which
18
- * is expected and must not fail the run. Persisted digest-only (never the raw origin).
16
+ * appUrl; digest equality plays no part: a normal cross-origin redirect (apex->www, http->https;
17
+ * lobby-trivia.example.test 307-redirects) makes the participants' observed origin differ from the
18
+ * declared one, which is expected and must not fail the run. Persisted digest-only (never the raw
19
+ * origin).
19
20
  */
20
21
  export declare function declaredOriginDigestOf(publicAppUrl: string): string | undefined;
21
22
  export declare function runExternalPublicPlane(ctx: PlaneContext, live: LiveParticipants, inbox: ExternalCommsWiring | undefined): Promise<ExternalPublicPlaneOutcome>;
@@ -1,8 +1,9 @@
1
- // External-public plane (#164 phase 2): no subject sandbox, no getHost, no prober. The shared plane
2
- // is the operator-declared public deployment (publicAppUrl); each seat opens it directly and reaches
3
- // the shared session through the real UI. A host-first barrier extracts the /lobby/CODE from the host
4
- // seat's CDP-observed URL (onObservedUrl) and threads it into the follower missions; a follower fails
5
- // closed without opening if the host never yields a code within the handoff deadline.
1
+ // External-public plane: no subject sandbox, no getHost, no prober. The shared plane is the
2
+ // operator-declared public deployment (publicAppUrl); each participant opens it directly and
3
+ // reaches the shared session through the real UI. A host-first barrier extracts the /lobby/CODE
4
+ // from the host's CDP-observed URL (onObservedUrl) and threads it into the follower missions; a
5
+ // follower fails closed without opening if the host never yields a code within the handoff
6
+ // deadline.
6
7
  import { liveObserverResult } from "../../observer/live.js";
7
8
  import { redactText, toErrorMessage } from "../../evidence/redaction.js";
8
9
  import { mapWithConcurrency } from "../../run/concurrency.js";
@@ -15,9 +16,10 @@ import { participantRunDeps, startParticipantFlush } from "./participant-specs.j
15
16
  /**
16
17
  * The operator-declared origin (from subject.appUrl), recorded for evidence and reference only. The
17
18
  * operator-ownership claim rests on the subject.publicTarget.authorized attestation + this declared
18
- * appUrl; digest equality plays no part (blocker 2): a normal cross-origin redirect (apex->www, http->https;
19
- * lobby-trivia.example.test 307-redirects) makes the seats' observed origin differ from the declared one, which
20
- * is expected and must not fail the run. Persisted digest-only (never the raw origin).
19
+ * appUrl; digest equality plays no part: a normal cross-origin redirect (apex->www, http->https;
20
+ * lobby-trivia.example.test 307-redirects) makes the participants' observed origin differ from the
21
+ * declared one, which is expected and must not fail the run. Persisted digest-only (never the raw
22
+ * origin).
21
23
  */
22
24
  export function declaredOriginDigestOf(publicAppUrl) {
23
25
  return publicAppUrl ? hostOriginDigest(publicAppUrl) : undefined;
@@ -35,8 +37,9 @@ export async function runExternalPublicPlane(ctx, live, inbox) {
35
37
  timeoutMs: ctx.timeoutMs,
36
38
  deadlineMs: seams.handoffDeadlineMs,
37
39
  scrubKnownValues: ctx.scrubKnownValues,
38
- // The per-seat vision lobby-code reader (default: the real single-frame OpenAI read). Injectable
39
- // so the barrier's handoff + convergence proof are testable without a live vision call.
40
+ // The per-participant vision lobby-code reader (default: the real single-frame OpenAI read).
41
+ // Injectable so the barrier's handoff + convergence proof are testable without a live vision
42
+ // call.
40
43
  readLobbyCode: seams.readLobbyCodeFromFrame ?? readLobbyCodeFromFrame,
41
44
  openaiApiKey: ctx.openaiApiKey,
42
45
  });
@@ -62,8 +65,9 @@ export async function runExternalPublicPlane(ctx, live, inbox) {
62
65
  subject: { source: "app-url", envNames: [], state: { provenance: "external-public" } },
63
66
  seedDigest: ctx.seedDigest,
64
67
  planeClass: "external-public",
65
- // Pre-fan-out snapshot: no seat has observed an origin yet, so the observed publicOriginDigest
66
- // is not available; surface the declared origin for the live Observer's reference.
68
+ // Pre-fan-out snapshot: no participant has observed an origin yet, so the observed
69
+ // publicOriginDigest is not available; surface the declared origin for the live Observer's
70
+ // reference.
67
71
  ...(declaredOriginDigest === undefined ? {} : { declaredOriginDigest }),
68
72
  };
69
73
  const inProgressBundle = buildConcurrentSharedWorldBundle({
@@ -9,10 +9,11 @@ export interface HandoffParticipantDeps {
9
9
  now: () => number;
10
10
  }
11
11
  /**
12
- * The handoff latch, its deadline and what each seat observed. The latched code and observed URLs
13
- * are runtime-only and land in persisted metadata only as digests (origin + convergence). (The code
14
- * is a shareable game code, not a secret, and it still renders in the host's screenshots, which are
15
- * full-fidelity unless redactScreenshots is set — the digesting is about narration/URL metadata.)
12
+ * The handoff latch, its deadline and what each participant observed. The latched code and observed
13
+ * URLs are runtime-only and land in persisted metadata only as digests (origin + convergence). (The
14
+ * code is a shareable game code, not a secret, and it still renders in the host's screenshots,
15
+ * which are full-fidelity unless redactScreenshots is set. The digesting is about narration/URL
16
+ * metadata.)
16
17
  */
17
18
  export declare class LobbyHandoff {
18
19
  readonly observedFinalUrls: (string | undefined)[];
@@ -20,7 +21,7 @@ export declare class LobbyHandoff {
20
21
  latchedLobbyCode: string | undefined;
21
22
  /** A follower gave up because the deadline passed. */
22
23
  timedOut: boolean;
23
- /** Why the host seat ended without producing a lobby code. */
24
+ /** Why the host ended without producing a lobby code. */
24
25
  hostFailure: string | undefined;
25
26
  readonly deadlineMs: number;
26
27
  private readonly lobbyCodeLatch;
@@ -52,7 +53,7 @@ export declare class LobbyHandoff {
52
53
  waitForHostCode(): Promise<string>;
53
54
  /** Releases waiting followers to fail closed when the host ended without a code. */
54
55
  releaseFollowersIfUnlatched(outcome: ParticipantRunOutcome | undefined): void;
55
- /** The digest-only convergence proofs over what the seats observed. */
56
+ /** The digest-only convergence proofs over what the participants observed. */
56
57
  convergence(declaredOriginDigest: string | undefined): {
57
58
  publicOriginDigest: string | undefined;
58
59
  lobbyConvergenceDigest: string | undefined;
@@ -1,10 +1,10 @@
1
- // The external-public plane's host-first handoff. The host seat opens a lobby; each follower waits
1
+ // The external-public plane's host-first handoff. The host opens a lobby; each follower waits
2
2
  // for the host's lobby code, read from the host's URL, narration or screen, and then joins with it.
3
3
  // A follower fails closed without opening if the host never yields a code within the deadline.
4
4
  //
5
- // Temporary shim (tracked by #296): this CDP URL-relay handoff reads the host's /lobby/CODE off its
5
+ // Temporary shim: this CDP URL-relay handoff reads the host's /lobby/CODE off its
6
6
  // own browser and threads it into the follower missions.
7
- // It is to be augmented/replaced by the actor message bus (fake SMS/email invite) in #297: the
7
+ // It is to be augmented/replaced by the actor message bus (fake SMS/email invite): the
8
8
  // human-realistic version is the host sending the invite link and followers receiving and tapping
9
9
  // it, rather than the orchestrator relaying the code out-of-band.
10
10
  import { commandDigestOf } from "../../subject/state.js";
@@ -15,23 +15,24 @@ import { runCuaParticipant } from "../computer-use/participant-execution.js";
15
15
  import { extractLobbyCode, extractLobbyCodeFromNarration } from "./lobby-code.js";
16
16
  import { hostOriginDigest } from "./provenance.js";
17
17
  import { makeBlockedFollowerOutcome, withLobbyCodeMission, } from "./participant-specs.js";
18
- // The floor for the host-first handoff barrier deadline (ms). The host seat must surface a
18
+ // The floor for the host-first handoff barrier deadline (ms). The host must surface a
19
19
  // shared-session (/lobby/CODE) URL within the deadline or the run fails closed and no follower
20
- // opens. The effective deadline scales with the per-seat run budget (execution.timeoutMs): a fixed
21
- // 2 min is too tight for a real create-a-lobby flow on a mobile-layout seat once you subtract the
22
- // seat's own desktop provisioning — the host reaches /lobby/CODE, but after the followers already
23
- // gave up. So use max(floor, 40% of the budget), capped at the budget. The latch resolves the
24
- // instant the host actually reaches /lobby, so a generous ceiling only affects the fail-closed case.
20
+ // opens. The effective deadline scales with the per-participant run budget (execution.timeoutMs): a
21
+ // fixed 2 min is too tight for a real create-a-lobby flow on a mobile-layout participant once you
22
+ // subtract the participant's own desktop provisioning: the host reaches /lobby/CODE, but after the
23
+ // followers already gave up. So use max(floor, 40% of the budget), capped at the budget. The latch
24
+ // resolves the instant the host actually reaches /lobby, so a generous ceiling only affects the
25
+ // fail-closed case.
25
26
  const DEFAULT_HANDOFF_DEADLINE_MS = 120_000;
26
27
  const HANDOFF_DEADLINE_BUDGET_FRACTION = 0.4;
27
- // Per-seat runaway backstop for the vision-off-frame lobby-code read (used by the host to latch the
28
- // handoff code, and by each follower to independently observe its own code for the convergence proof):
29
- // at most this many single-frame reads before the seat is assumed to be somewhere without a code. Each
30
- // reader stops the instant it has what it needs, so in practice only a handful fire (a seat reaches its
31
- // /lobby within a few turns). NOTE: these reads are out-of-band OpenAI calls (external-public route
32
- // only) and are left out of execution.caps.maxUsd, so this hard cap is what bounds their spend
33
- // (each read is one cheap single-frame OCR call). If this route ever runs under a strict
34
- // budget, fold the estimate in.
28
+ // Per-participant runaway backstop for the vision-off-frame lobby-code read (used by the host to
29
+ // latch the handoff code, and by each follower to independently observe its own code for the
30
+ // convergence proof): at most this many single-frame reads before the participant is assumed to be
31
+ // somewhere without a code. Each reader stops the instant it has what it needs, so in practice only
32
+ // a handful fire (a participant reaches its /lobby within a few turns). NOTE: these reads are
33
+ // out-of-band OpenAI calls (external-public route only) and are left out of execution.caps.maxUsd,
34
+ // so this hard cap is what bounds their spend (each read is one cheap single-frame OCR call). If
35
+ // this route ever runs under a strict budget, fold the estimate in.
35
36
  const MAX_LOBBY_CODE_VISION_READS = 30;
36
37
  // Idle/no-progress backstop for the host participant specifically (default is 6/8). The host legitimately sits
37
38
  // on an unchanging waiting-room screen while followers provision and join; it must not give up first.
@@ -66,21 +67,23 @@ class HandoffTimeoutError extends Error {
66
67
  }
67
68
  }
68
69
  /**
69
- * The handoff latch, its deadline and what each seat observed. The latched code and observed URLs
70
- * are runtime-only and land in persisted metadata only as digests (origin + convergence). (The code
71
- * is a shareable game code, not a secret, and it still renders in the host's screenshots, which are
72
- * full-fidelity unless redactScreenshots is set — the digesting is about narration/URL metadata.)
70
+ * The handoff latch, its deadline and what each participant observed. The latched code and observed
71
+ * URLs are runtime-only and land in persisted metadata only as digests (origin + convergence). (The
72
+ * code is a shareable game code, not a secret, and it still renders in the host's screenshots,
73
+ * which are full-fidelity unless redactScreenshots is set. The digesting is about narration/URL
74
+ * metadata.)
73
75
  */
74
76
  export class LobbyHandoff {
75
77
  // Per-participant runtime-only observed state (never persisted raw): the last observed URL and the last
76
- // observed /lobby/CODE per seat, fed by onObservedUrl. The URL is digested to its origin for each seat's
77
- // routeHostDigest (no code leaks); the codes drive the cross-seat lobby-convergence digest.
78
+ // observed /lobby/CODE per participant, fed by onObservedUrl. The URL is digested to its origin
79
+ // for each participant's routeHostDigest (no code leaks); the codes drive the cross-participant
80
+ // lobby-convergence digest.
78
81
  observedFinalUrls;
79
82
  observedLobbyCodes;
80
83
  latchedLobbyCode;
81
84
  /** A follower gave up because the deadline passed. */
82
85
  timedOut = false;
83
- /** Why the host seat ended without producing a lobby code. */
86
+ /** Why the host ended without producing a lobby code. */
84
87
  hostFailure;
85
88
  deadlineMs;
86
89
  lobbyCodeLatch = deferred();
@@ -133,11 +136,12 @@ export class LobbyHandoff {
133
136
  this.stopDeadline();
134
137
  this.lobbyCodeLatch.resolve(code);
135
138
  }
136
- // Build an onScreenshot handler that vision-reads the lobby code off this seat's own frame (the
137
- // CDP-independent observation). `done()` short-circuits once this seat has what it needs (the host
138
- // once latched; a follower once it has recorded its own observed code), `onCode` records/latches the
139
- // result. One read in flight at a time, bounded by MAX_LOBBY_CODE_VISION_READS so a seat that never
140
- // reaches a lobby can't rack up unbounded calls (fire-and-forget; the loop never awaits it).
139
+ // Build an onScreenshot handler that vision-reads the lobby code off this participant's own frame
140
+ // (the CDP-independent observation). `done()` short-circuits once this participant has what it
141
+ // needs (the host once latched; a follower once it has recorded its own observed code), `onCode`
142
+ // records/latches the result. One read in flight at a time, bounded by
143
+ // MAX_LOBBY_CODE_VISION_READS so a participant that never reaches a lobby can't rack up unbounded
144
+ // calls (fire-and-forget; the loop never awaits it).
141
145
  makeLobbyCodeVisionReader(done, onCode) {
142
146
  let inFlight = false;
143
147
  let reads = 0;
@@ -184,32 +188,34 @@ export class LobbyHandoff {
184
188
  this.lobbyCodeLatch.reject(new Error(this.hostFailure));
185
189
  }
186
190
  }
187
- /** The digest-only convergence proofs over what the seats observed. */
191
+ /** The digest-only convergence proofs over what the participants observed. */
188
192
  convergence(declaredOriginDigest) {
189
- // Observed-origin convergence proof (blocker 2): the convergence claim is about what the seats
190
- // observed. Digest each observing seat's origin and require one shared origin; that agreement is
191
- // the convergence proof and becomes plane.publicOriginDigest. A normal
192
- // cross-origin redirect (declared apex -> observed www) is therefore tolerated: the seats still
193
- // converge on one observed origin. Leave it undefined (verify fails closed) only if the seats did
194
- // not converge on a single observed origin (or none observed one).
193
+ // Observed-origin convergence proof: the convergence claim is about what the participants
194
+ // observed. Digest each observing participant's origin and require one shared origin; that
195
+ // agreement is the convergence proof and becomes plane.publicOriginDigest. A normal
196
+ // cross-origin redirect (declared apex -> observed www) is therefore tolerated: the
197
+ // participants still converge on one observed origin. Leave it undefined (verify fails closed)
198
+ // only if the participants did not converge on a single observed origin (or none observed one).
195
199
  const observedOriginDigests = this.observedFinalUrls
196
200
  .filter((url) => typeof url === "string" && url.length > 0)
197
201
  .map((url) => hostOriginDigest(url));
198
202
  const distinctObservedOrigins = new Set(observedOriginDigests);
199
203
  const publicOriginDigest = distinctObservedOrigins.size === 1
200
204
  ? [...distinctObservedOrigins][0]
201
- : // Nothing observed (e.g. a handoff-timeout run where no seat ever navigated): fall back to the
202
- // declared origin so a failed run's bundle stays structurally valid (every seat's route then
203
- // digests to the declared origin too). The run still fails closed for its own reason
204
- // (`HANDOFF_TIMEOUT`, no lobby convergence, no overlap-on-pass). Real divergence (≥2 distinct observed
205
- // origins) leaves it undefined so verify fails closed on the non-convergence.
205
+ : // Nothing observed (e.g. a handoff-timeout run where no participant ever navigated): fall
206
+ // back to the declared origin so a failed run's bundle stays structurally valid (every
207
+ // participant's route then digests to the declared origin too). The run still fails
208
+ // closed for its own reason (`HANDOFF_TIMEOUT`, no lobby convergence, no
209
+ // overlap-on-pass). Real divergence (≥2 distinct observed origins) leaves it undefined so
210
+ // verify fails closed on the non-convergence.
206
211
  distinctObservedOrigins.size === 0
207
212
  ? declaredOriginDigest
208
213
  : undefined;
209
- // Lobby-convergence proof: a digest of the shared /lobby/CODE path iff every seat converged on the
210
- // same code (a follower stuck on "/" yields no code, so no false convergence). Digest-only.
211
- // observedLobbyCodes may be a sparse array (a seat that never observed a code leaves a hole), and
212
- // Array.prototype.every skips holes, so count the defined codes explicitly instead of every().
214
+ // Lobby-convergence proof: a digest of the shared /lobby/CODE path iff every participant
215
+ // converged on the same code (a follower stuck on "/" yields no code, so no false convergence).
216
+ // Digest-only. observedLobbyCodes may be a sparse array (a participant that never observed a
217
+ // code leaves a hole), and Array.prototype.every skips holes, so count the defined codes
218
+ // explicitly instead of every().
213
219
  const definedCodes = this.observedLobbyCodes.filter((code) => code !== undefined);
214
220
  const distinctCodes = new Set(definedCodes);
215
221
  const lobbyConvergenceDigest = distinctCodes.size === 1 && definedCodes.length === this.observedLobbyCodes.length
@@ -218,7 +224,7 @@ export class LobbyHandoff {
218
224
  return { publicOriginDigest, lobbyConvergenceDigest };
219
225
  }
220
226
  }
221
- // Adopter-hosted inbox (#387): the persona is told its address and inbox URL on this plane.
227
+ // Adopter-hosted inbox: the persona is told its address and inbox URL on this plane.
222
228
  function withParticipantInbox(spec, inbox) {
223
229
  return inbox && participantHasInboxRecipient(inbox.email, spec.planned.id)
224
230
  ? withInboxMission(spec, inbox.inboxUrl, inboxRecipientFor(inbox.email, spec.planned.id)?.address)
@@ -235,11 +241,11 @@ function withParticipantInbox(spec, inbox) {
235
241
  // (host + up to concurrency-1 followers), preserving the spend cap.
236
242
  export async function runHost(handoff, deps, spec, participantIndex) {
237
243
  const onObservedUrl = handoff.makeObservedUrl(participantIndex, true);
238
- // CDP-INDEPENDENT handoff paths (the E2B-desktop CDP url-read the onObservedUrl path relies on is
244
+ // CDP-independent handoff paths (the E2B-desktop CDP url-read the onObservedUrl path relies on is
239
245
  // unreliable in practice). Two backups, both resolving the same latch; whichever sees the code first
240
246
  // wins, all digest-only:
241
247
  // (1) onMessage: scan the host's own narration if it happens to state the lobby URL; and
242
- // (2) onScreenshot — vision-read the code straight off the host's waiting-room frame. This is the
248
+ // (2) onScreenshot: vision-read the code straight off the host's waiting-room frame. This is the
243
249
  // robust one: the code is rendered on screen even when CDP fails and when the host never
244
250
  // narrates it, and the host is never asked to announce anything, so it keeps
245
251
  // running (create -> wait for players -> Start -> play) instead of ending on a stray message.
@@ -256,7 +262,8 @@ export async function runHost(handoff, deps, spec, participantIndex) {
256
262
  // followers provision their own desktops and walk the Join flow (easily 15-30 turns of an
257
263
  // unchanging "waiting for players" screen). At the default idle backstop (6) the host would give up
258
264
  // before anyone arrives, orphaning the lobby (exactly the earlier failure). Raise the host's idle /
259
- // no-progress tolerance so it waits patiently; the per-seat timeout still bounds a truly stuck host.
265
+ // no-progress tolerance so it waits patiently; the per-participant timeout still bounds a truly
266
+ // stuck host.
260
267
  const hostSpec = {
261
268
  ...withParticipantInbox(spec, deps.inbox),
262
269
  backstop: {
@@ -310,9 +317,10 @@ export async function runFollower(handoff, deps, spec, participantIndex) {
310
317
  route: deps.publicAppUrl,
311
318
  };
312
319
  }
313
- // Followers also idle-wait — in the waiting room until the host starts, and between rounds. Raise
320
+ // Followers also idle-wait: in the waiting room until the host starts, and between rounds. Raise
314
321
  // their idle backstop too (less than the host's: they wait less), so a follower that joins ahead of
315
- // the other does not give up before the game begins. Per-seat timeout still bounds a stuck follower.
322
+ // the other does not give up before the game begins. Per-participant timeout still bounds a stuck
323
+ // follower.
316
324
  const followerSpec = {
317
325
  ...withLobbyCodeMission(withParticipantInbox(spec, deps.inbox), code),
318
326
  backstop: {
@@ -321,12 +329,12 @@ export async function runFollower(handoff, deps, spec, participantIndex) {
321
329
  },
322
330
  };
323
331
  // Independently observe this follower's own lobby code by vision-reading its waiting-room frame,
324
- // and record it for the cross-seat convergence proof. This latches nothing (followers gate on the
325
- // host's code). It fills this seat's observedLobbyCodes slot from a
326
- // reliable signal instead of the flaky CDP url-read, so lobbyConvergenceDigest can prove all seats
327
- // reached the same /lobby/CODE. If a follower somehow joined another lobby, it reads a different
328
- // code and convergence correctly fails (no false proof); if it never reads one, the seat stays a
329
- // hole and convergence is honestly "not observed" for that seat.
332
+ // and record it for the cross-participant convergence proof. This latches nothing (followers gate
333
+ // on the host's code). It fills this participant's observedLobbyCodes slot from a
334
+ // reliable signal instead of the flaky CDP url-read, so lobbyConvergenceDigest can prove all
335
+ // participants reached the same /lobby/CODE. If a follower somehow joined another lobby, it reads
336
+ // a different code and convergence correctly fails (no false proof); if it never reads one, the
337
+ // participant stays a hole and convergence is recorded as "not observed" for that participant.
330
338
  const onScreenshot = handoff.makeLobbyCodeVisionReader(() => handoff.observedLobbyCodes[participantIndex] !== undefined, (observed) => {
331
339
  handoff.observedLobbyCodes[participantIndex] = observed;
332
340
  });
@@ -1,12 +1,12 @@
1
1
  /** Extract the shared-session code from a (runtime-only) observed URL, or undefined. Exported for the
2
- * handoff regex table test — pure, no side effects, never persists its input. */
2
+ * handoff regex table test. Pure, no side effects, never persists its input. */
3
3
  export declare function extractLobbyCode(url: string | undefined): string | undefined;
4
4
  export declare function extractLobbyCodeFromNarration(text: string | undefined): string | undefined;
5
5
  /** Pull the assistant's plain text out of an OpenAI Responses API body (`output_text` convenience
6
6
  * field, else the concatenated `output[].content[].text`). Tolerant of shape drift; pure. */
7
7
  export declare function extractResponsesOutputText(parsed: unknown): string | undefined;
8
8
  /** Parse a vision reply into a lobby code. Precision-first: accept only when the whole reply is the
9
- * six-character code, or when it echoes an explicit /lobby/CODE — never a bare 6-letter token buried in
9
+ * six-character code, or when it echoes an explicit /lobby/CODE; never a bare 6-letter token buried in
10
10
  * prose (e.g. "I see a home `SCREEN`"), because a wrong latch fails the entire run, whereas a miss just
11
11
  * retries on the next frame while the host keeps waiting. `NONE` (the instructed "no code" reply) is
12
12
  * rejected. Pure. */
@@ -1,15 +1,15 @@
1
- // Reads a lobby code (the /lobby/CODE path segment) from a URL, from a seat's narration or, through
2
- // a vision model call, from a seat's screenshot. The external-public plane uses it to hand the
3
- // host's lobby to the followers.
1
+ // Reads a lobby code (the /lobby/CODE path segment) from a URL, from a participant's narration or,
2
+ // through a vision model call, from a participant's screenshot. The external-public plane uses it
3
+ // to hand the host's lobby to the followers.
4
4
  import { OPENAI_RESPONSES_URL } from "../../actors/openai-endpoint.js";
5
5
  /**
6
6
  * The lobby-trivia (and general "/lobby/CODE") shared-session URL matcher. A code is exactly 6 chars of
7
- * the [A-Z2-9] class; a locale prefix (/en/lobby/…) and a query/hash suffix are tolerated. RUNTIME-ONLY
7
+ * the [A-Z2-9] class; a locale prefix (/en/lobby/…) and a query/hash suffix are tolerated. Runtime-only
8
8
  * input (a live location.href); only the extracted code is used, and it lands only as a digest.
9
9
  */
10
10
  const LOBBY_CODE_PATTERN = /\/lobby\/([A-Z2-9]{6})(?:$|[/?#])/;
11
11
  /** Extract the shared-session code from a (runtime-only) observed URL, or undefined. Exported for the
12
- * handoff regex table test — pure, no side effects, never persists its input. */
12
+ * handoff regex table test. Pure, no side effects, never persists its input. */
13
13
  export function extractLobbyCode(url) {
14
14
  if (typeof url !== "string")
15
15
  return undefined;
@@ -19,8 +19,8 @@ export function extractLobbyCode(url) {
19
19
  /**
20
20
  * Extract a lobby code from free-form actor narration (the host's reasoning/message where it states
21
21
  * the lobby URL it sees), where the /lobby/CODE is followed by arbitrary prose (a space, backtick,
22
- * newline) rather than end-of-string or /?# — so the strict LOBBY_CODE_PATTERN would miss it. Uses a
23
- * negative-lookahead boundary (exactly 6 code chars). This is the CDP-INDEPENDENT handoff path: the
22
+ * newline) rather than end-of-string or /?#, so the strict LOBBY_CODE_PATTERN would miss it. Uses a
23
+ * negative-lookahead boundary (exactly 6 code chars). This is the CDP-independent handoff path: the
24
24
  * host reads the code on screen and states it, and this reads it from the model's own text. Pure;
25
25
  * input is runtime-only; only the code is used (as a digest).
26
26
  */
@@ -68,7 +68,7 @@ export function extractResponsesOutputText(parsed) {
68
68
  return parts.length > 0 ? parts.join("\n") : undefined;
69
69
  }
70
70
  /** Parse a vision reply into a lobby code. Precision-first: accept only when the whole reply is the
71
- * six-character code, or when it echoes an explicit /lobby/CODE — never a bare 6-letter token buried in
71
+ * six-character code, or when it echoes an explicit /lobby/CODE; never a bare 6-letter token buried in
72
72
  * prose (e.g. "I see a home `SCREEN`"), because a wrong latch fails the entire run, whereas a miss just
73
73
  * retries on the next frame while the host keeps waiting. `NONE` (the instructed "no code" reply) is
74
74
  * rejected. Pure. */
@@ -89,7 +89,7 @@ const LOBBY_CODE_VISION_PROMPT = "This is a screenshot of a the example multipla
89
89
  "exactly those 6 characters in uppercase and NOTHING else (no words, no punctuation). If no lobby " +
90
90
  "code is visible on this screen (e.g. it is the home screen or a game round), reply exactly NONE.";
91
91
  // A single-frame OCR-style read. gpt-5.5 (the computer-use default) is used deliberately: it reliably reads the
92
- // 6-char code off a dense MOBILE-viewport waiting room — a smaller/cheaper model (gpt-4.1-mini) was
92
+ // 6-char code off a dense mobile-viewport waiting room. A smaller/cheaper model (gpt-4.1-mini) was
93
93
  // tried and could not read it. reasoning.effort stays "low" (minimal) and the output budget is small
94
94
  // but comfortably clear of the "incomplete on reasoning overflow" edge. Kept on the same account/key
95
95
  // as the actor; the same full-fidelity frame is already sent to this API by the computer-use provider, so this
@@ -4,8 +4,8 @@ import type { RunBundle } from "../../run/bundle.js";
4
4
  import type { CuaParticipantDeps, DesktopParticipantRun, ParticipantRunOutcome } from "../computer-use/types.js";
5
5
  import type { LiveParticipants, PlaneContext } from "./types.js";
6
6
  export declare function defaultSessionTimeoutMs(plan: SharedWorldPlan): number;
7
- /** Resolve an actor's seat URL against the harness-minted getHost base (entry is a same-origin
8
- * relative path, validated at parse against serve.url). */
7
+ /** Resolve an actor's participant URL against the harness-minted getHost base (entry is a
8
+ * same-origin relative path, validated at parse against serve.url). */
9
9
  export declare function resolveActorEntryUrl(baseUrl: string, entry: string | undefined): string;
10
10
  export declare function participantTaxonomyLabel(labels: Participant["labels"]): string;
11
11
  /** Thread the host-yielded lobby code into a follower's mission at runtime (external-public route).
@@ -19,9 +19,10 @@ export declare function makeBlockedFollowerOutcome(spec: DesktopParticipantRun,
19
19
  /** The computer-use runner deps every participant shares, on either plane. */
20
20
  export type ParticipantRunDeps = Omit<CuaParticipantDeps, "signalProvisioned" | "appUrl" | "onObservedUrl">;
21
21
  /**
22
- * A live run publishes an in-progress bundle before its seats start, whether or not an Observer
23
- * is attached, and the seats' live traces rewrite it as they go, as on the computer-use route. A
24
- * run killed mid-way leaves that evidence on disk. The flush starts with the first snapshot.
22
+ * A live run publishes an in-progress bundle before its participants start, whether or not an
23
+ * Observer is attached, and the participants' live traces rewrite it as they go, as on the
24
+ * computer-use route. A run killed mid-way leaves that evidence on disk. The flush starts with the
25
+ * first snapshot.
25
26
  */
26
27
  export declare function startParticipantFlush(ctx: PlaneContext, live: LiveParticipants, bundle: RunBundle): void;
27
28
  /**
@@ -34,7 +35,7 @@ export declare function startParticipantFlush(ctx: PlaneContext, live: LiveParti
34
35
  export declare function participantRunDeps(ctx: PlaneContext, live: LiveParticipants, scrubKnownValues: (text: string) => string): ParticipantRunDeps;
35
36
  /**
36
37
  * Each participant's actor spec, with committed personas compiled in so each prompt carries real
37
- * behavioral directives (#381). Evidence copies of the assignment, instructions and persona are
38
+ * behavioral directives. Evidence copies of the assignment, instructions and persona are
38
39
  * scrubbed of the run's known secret values.
39
40
  */
40
41
  export declare function buildParticipantSpecs(participants: readonly SharedWorldParticipant[], cwd: string, scrubKnownValues: (text: string) => string): Promise<DesktopParticipantRun[]>;
@@ -12,13 +12,14 @@ import { participantAssignment } from "../../lab/participant-assignment.js";
12
12
  import { redactText } from "../../evidence/redaction.js";
13
13
  import { MAX_SANDBOX_MS, SANDBOX_TIMEOUT_BUFFER_MS, SUBJECT_PROVISION_BUDGET_MS, } from "../../substrates/e2b/lifetime.js";
14
14
  import { DEFAULT_STATE_STEP_TIMEOUT_MS } from "../../subject/state.js";
15
- // The default per-seat session budget is derived from the route. On a provisioned route the binding
16
- // constraint is the subject sandbox (it must outlive every seat: timeoutMs + provisioning +
17
- // seeding + teardown buffer, and E2B refuses a sandbox over one hour), so the derivation hands
18
- // each seat the most that cap allows — capped at 15 minutes, floored at the historical 300s so a
19
- // seed-heavy lab never gets less room than it always had. App-url seats have no subject sandbox
20
- // and default to 30 minutes (seat sandbox: 30m + 10m buffer stays well under the hour). An
21
- // explicit execution.timeoutMs is never adjusted. The handoff latch scales off this (40%).
15
+ // The default per-participant session budget is derived from the route. On a provisioned route the
16
+ // binding constraint is the subject sandbox (it must outlive every participant: timeoutMs +
17
+ // provisioning + seeding + teardown buffer, and E2B refuses a sandbox over one hour), so the
18
+ // derivation hands each participant the most that cap allows, capped at 15 minutes, floored at the
19
+ // historical 300s so a seed-heavy study never gets less room than it always had. App-url
20
+ // participants have no subject sandbox and default to 30 minutes (participant sandbox: 30m + 10m
21
+ // buffer stays well under the hour). An explicit execution.timeoutMs is never adjusted. The handoff
22
+ // latch scales off this (40%).
22
23
  const MAX_DERIVED_SESSION_MS = 15 * 60_000;
23
24
  const MIN_DERIVED_SESSION_MS = 300_000;
24
25
  const DEFAULT_APP_URL_SESSION_MS = 30 * 60_000;
@@ -29,9 +30,10 @@ export function defaultSessionTimeoutMs(plan) {
29
30
  const room = MAX_SANDBOX_MS - SUBJECT_PROVISION_BUDGET_MS - stateBudgetMs - SANDBOX_TIMEOUT_BUFFER_MS;
30
31
  return Math.max(MIN_DERIVED_SESSION_MS, Math.min(MAX_DERIVED_SESSION_MS, room));
31
32
  }
33
+ // prose-check: model prompt (the participant model reads this, not a person)
32
34
  const DEFAULT_MISSION = "You are one of MANY users hitting a shared web application at the same time. The browser is already open at the app. Accomplish your role's task, then stop.";
33
- /** Resolve an actor's seat URL against the harness-minted getHost base (entry is a same-origin
34
- * relative path, validated at parse against serve.url). */
35
+ /** Resolve an actor's participant URL against the harness-minted getHost base (entry is a
36
+ * same-origin relative path, validated at parse against serve.url). */
35
37
  export function resolveActorEntryUrl(baseUrl, entry) {
36
38
  if (!entry)
37
39
  return baseUrl;
@@ -80,6 +82,7 @@ function buildActorSpec(participant, personas) {
80
82
  * the model reads (never a raw bundle field), and the lab scrubs the code from all narration. The
81
83
  * follower joins through the real UI (a direct /lobby/CODE visit does not auto-join a non-member). */
82
84
  export function withLobbyCodeMission(spec, code) {
85
+ // prose-check: model prompt (the participant model reads this, not a person)
83
86
  return {
84
87
  ...spec,
85
88
  instructions: `${spec.instructions}\n\nThe multiplayer lobby code is ${code}. On the home screen choose Join, enter this lobby code, enter your name, and submit to join the shared game (do not open a lobby URL directly — go through the Join flow).`,
@@ -90,7 +93,7 @@ export function withLobbyCodeMission(spec, code) {
90
93
  export function makeBlockedFollowerOutcome(spec, reason, timedOut) {
91
94
  return {
92
95
  spec,
93
- sessionError: `handoff barrier: ${reason}; this follower failed closed WITHOUT opening (no wasted turns).`,
96
+ sessionError: `handoff barrier: ${reason}; this follower stopped before opening the app, so no turns were spent.`,
94
97
  killed: false,
95
98
  streamUrlPresent: false,
96
99
  screenshots: [],
@@ -104,9 +107,10 @@ export function makeBlockedFollowerOutcome(spec, reason, timedOut) {
104
107
  };
105
108
  }
106
109
  /**
107
- * A live run publishes an in-progress bundle before its seats start, whether or not an Observer
108
- * is attached, and the seats' live traces rewrite it as they go, as on the computer-use route. A
109
- * run killed mid-way leaves that evidence on disk. The flush starts with the first snapshot.
110
+ * A live run publishes an in-progress bundle before its participants start, whether or not an
111
+ * Observer is attached, and the participants' live traces rewrite it as they go, as on the
112
+ * computer-use route. A run killed mid-way leaves that evidence on disk. The flush starts with the
113
+ * first snapshot.
110
114
  */
111
115
  export function startParticipantFlush(ctx, live, bundle) {
112
116
  live.flush = startLiveTraceFlush({
@@ -117,14 +121,14 @@ export function startParticipantFlush(ctx, live, bundle) {
117
121
  });
118
122
  }
119
123
  /**
120
- * The runtime stream URLs each seat reports to the live Observer. The Observer learns of a stream
121
- * before the caller's onStream runs.
124
+ * The runtime stream URLs each participant reports to the live Observer. The Observer learns of a
125
+ * stream before the caller's onStream runs.
122
126
  */
123
127
  function participantStreams(onStream, live) {
124
128
  return (event) => {
125
129
  if (event.type === "ready")
126
130
  live.streamUrls.push({ streamId: event.streamId, url: event.url });
127
- // Mark, never remove (#357): the tile falls back to recorded evidence and says why.
131
+ // Mark, never remove: the tile falls back to recorded evidence and says why.
128
132
  else
129
133
  for (const entry of live.streamUrls)
130
134
  if (entry.streamId === event.streamId)
@@ -164,33 +168,36 @@ export function participantRunDeps(ctx, live, scrubKnownValues) {
164
168
  redactScreenshots: ctx.redactScreenshots,
165
169
  scrubKnownValues,
166
170
  runSession: ctx.runSession,
167
- // A local-agent brain runs each seat on the operator's signed-in agent, as on computer use.
171
+ // A local-agent brain runs each participant on the operator's signed-in agent, as on computer
172
+ // use.
168
173
  brain: ctx.plan.brain,
169
174
  ...(receiving ? { receiving } : {}),
170
175
  now: ctx.now,
171
- // The seat's desktop seams, and the caller's prepareDesktop with the seat as its target.
176
+ // The participant's desktop seams, and the caller's prepareDesktop with the participant as its
177
+ // target.
172
178
  ...(ctx.deps.desktopModule === undefined ? {} : { desktopModule: ctx.deps.desktopModule }),
173
179
  ...(ctx.deps.detachedTimers === undefined ? {} : { detachedTimers: ctx.deps.detachedTimers }),
174
180
  ...(ctx.input.prepareDesktop === undefined ? {} : { prepareDesktop: ctx.input.prepareDesktop }),
175
181
  onStream: participantStreams(ctx.input.onStream, live),
176
- // A seat visits the shared app and provisions no subject, so it reports no phase of its own.
182
+ // A participant visits the shared app and provisions no subject, so it reports no phase of its
183
+ // own.
177
184
  reportSubjectPhase: defaultSubjectPhaseSink,
178
185
  ...(runBudget === undefined ? {} : { runBudget }),
179
- // Concurrent participants are independent evidence seats: a requested-vs-verified screen
186
+ // Concurrent participants are independent evidence: a requested-vs-verified screen
180
187
  // mismatch is recorded as separate facts + a warning instead of failing the participant's
181
- // device claim closed, so one seat's window-manager drift cannot abort the whole
188
+ // device claim closed, so one participant's window-manager drift cannot abort the whole
182
189
  // live multi-actor world (the single-participant/fan-out routes keep fail-closed).
183
190
  screenMismatchPolicy: "record-evidence",
184
191
  };
185
192
  }
186
193
  /**
187
194
  * Each participant's actor spec, with committed personas compiled in so each prompt carries real
188
- * behavioral directives (#381). Evidence copies of the assignment, instructions and persona are
195
+ * behavioral directives. Evidence copies of the assignment, instructions and persona are
189
196
  * scrubbed of the run's known secret values.
190
197
  */
191
198
  export async function buildParticipantSpecs(participants, cwd, scrubKnownValues) {
192
- // Only the personas the participants use: an actors[0].persona that every seat overrides is
193
- // never applied, so it is not read.
199
+ // Only the personas the participants use: an actors[0].persona that every participant overrides
200
+ // is never applied, so it is not read.
194
201
  const personaResolution = await resolveCommittedPersonasForCwd(cwd, participants.map((participant) => participant.personaId));
195
202
  const actorSpecs = participants.map((participant) => buildActorSpec(participant, personaResolution.personas));
196
203
  for (const spec of actorSpecs) {
@@ -10,7 +10,7 @@ import { sharedWorldParticipants } from "../../lab/plan-participants.js";
10
10
  import { PUBLIC_TARGET_OWNER_PATTERN } from "../../lab/parse/subject.js";
11
11
  import { REPO_SLUG_PATTERN } from "../../lab/parse/values.js";
12
12
  import { concurrentSharedWorldValidationReason, desktopMediaValidationReason, externalPublicSharedWorldValidationReason, outputTokenLimitValidationReason, receivingEmailValidationReason, scenarioCapsValidationReason, taskProtocolValidationReason, } from "../../lab/validation.js";
13
- import { MODEL_RATES } from "../../run/pricing.js";
13
+ import { MODEL_RATES, unpricedCapMessage } from "../../run/pricing.js";
14
14
  /** The registered descriptor for a planned actor; planSharedWorldLab checked the registry. */
15
15
  export function sharedWorldDescriptorOf(actorType) {
16
16
  const descriptor = actorRegistry[actorType];
@@ -27,20 +27,20 @@ export function planSharedWorldLab(config, input) {
27
27
  ok: false,
28
28
  refusal: { route: "shared-world", code, message, ...(actor === undefined ? {} : { actor }) },
29
29
  });
30
- const invalid = "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID";
30
+ const invalid = "HUMANISH_SHARED_WORLD_INVALID";
31
31
  const mediaReason = desktopMediaValidationReason(config, false);
32
32
  if (mediaReason)
33
33
  return refuse(invalid, mediaReason);
34
34
  const analysis = resolveAutomaticAnalysis(config.review?.analysis);
35
35
  if (!analysis.ok)
36
- return refuse("HUMANISH_LAB_ANALYSIS_INVALID", analysis.message);
36
+ return refuse("HUMANISH_STUDY_ANALYSIS_INVALID", analysis.message);
37
37
  const tasksReason = taskProtocolValidationReason(config, false);
38
38
  if (tasksReason)
39
- return refuse("HUMANISH_LAB_TASKS_UNSUPPORTED", tasksReason);
39
+ return refuse("HUMANISH_STUDY_TASKS_UNSUPPORTED", tasksReason);
40
40
  const actorType = config.actors[0]?.type ?? "";
41
41
  const descriptor = actorRegistry[actorType];
42
42
  if (!descriptor || !isCuaActorDescriptor(descriptor))
43
- return refuse("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_ACTOR_UNSUPPORTED", `actors[0].type "${actorType}" is not a registered computer-use actor.`);
43
+ return refuse("HUMANISH_SHARED_WORLD_ACTOR_UNSUPPORTED", `actors[0].type "${actorType}" is not a registered computer-use actor.`);
44
44
  const actor = descriptor.id;
45
45
  // An app-url subject is the external-public plane (a real operator-owned deployment used
46
46
  // directly, with no getHost, clone, subject sandbox or seed); every other subject is the
@@ -61,7 +61,7 @@ export function planSharedWorldLab(config, input) {
61
61
  if (!input.dryRun && (caps?.maxUsd !== undefined || caps?.maxTotalUsd !== undefined)) {
62
62
  const model = (config.actors[0]?.model ?? DEFAULT_OPENAI_CU_MODEL).trim().toLowerCase();
63
63
  if (!MODEL_RATES[model])
64
- return refuse("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_UNPRICED_CAP", `The declared spend cap cannot be enforced for unpriced model "${model}".`, actor);
64
+ return refuse("HUMANISH_SHARED_WORLD_UNPRICED_CAP", unpricedCapMessage(model), actor);
65
65
  }
66
66
  const receivingReason = receivingEmailValidationReason(config);
67
67
  if (receivingReason)
@@ -113,7 +113,7 @@ export function planSharedWorldLab(config, input) {
113
113
  externalCatch: plane.kind === "external-public",
114
114
  }),
115
115
  // The external-public plane reads the host's lobby code with the OpenAI API, whatever
116
- // brain drives the seats.
116
+ // brain drives the participants.
117
117
  ...(plane.kind === "external-public" && brain.kind !== "openai"
118
118
  ? [{ kind: "key", name: "OPENAI_API_KEY" }]
119
119
  : []),