humanish 0.106.1 → 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 (668) hide show
  1. package/ARCHITECTURE.md +38 -32
  2. package/CHANGELOG.md +28 -0
  3. package/CONTEXT.md +51 -41
  4. package/README.md +152 -174
  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-client.js +2 -1
  14. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  15. package/dist/actors/codex/app-server-trace.js +1 -3
  16. package/dist/actors/codex/app-server-ui.js +1 -1
  17. package/dist/actors/codex/app-server.js +2 -1
  18. package/dist/actors/codex/codex-admission.d.ts +91 -0
  19. package/dist/actors/codex/codex-admission.js +150 -0
  20. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  21. package/dist/actors/codex/protocol-compat.js +357 -0
  22. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  23. package/dist/actors/codex/protocol-contract.js +471 -0
  24. package/dist/actors/codex/restricted-executable.d.ts +28 -4
  25. package/dist/actors/codex/restricted-executable.js +104 -29
  26. package/dist/actors/codex/restricted-launch.d.ts +9 -2
  27. package/dist/actors/codex/restricted-launch.js +43 -4
  28. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  29. package/dist/actors/codex/restricted-notifications.js +277 -0
  30. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  31. package/dist/actors/codex/restricted-participant.js +66 -6
  32. package/dist/actors/codex/restricted-policy.d.ts +11 -3
  33. package/dist/actors/codex/restricted-policy.js +2 -2
  34. package/dist/actors/codex/restricted-session.d.ts +16 -3
  35. package/dist/actors/codex/restricted-session.js +60 -22
  36. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  37. package/dist/actors/codex/restricted-transport.js +139 -27
  38. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  39. package/dist/actors/codex/restricted-turn.js +43 -30
  40. package/dist/actors/computer-use/actor.d.ts +17 -17
  41. package/dist/actors/computer-use/actor.js +6 -6
  42. package/dist/actors/computer-use/admission-limit.d.ts +1 -1
  43. package/dist/actors/computer-use/admission-limit.js +1 -1
  44. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  45. package/dist/actors/computer-use/loop/actions.js +10 -10
  46. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  47. package/dist/actors/computer-use/loop/backstop.js +15 -13
  48. package/dist/actors/computer-use/loop/ending.d.ts +7 -7
  49. package/dist/actors/computer-use/loop/ending.js +9 -9
  50. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  51. package/dist/actors/computer-use/loop/observation.js +9 -9
  52. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  53. package/dist/actors/computer-use/loop/provider-call.js +1 -1
  54. package/dist/actors/computer-use/loop/session.js +3 -3
  55. package/dist/actors/computer-use/loop/spend.d.ts +2 -2
  56. package/dist/actors/computer-use/loop/spend.js +4 -4
  57. package/dist/actors/computer-use/loop/trace.js +11 -10
  58. package/dist/actors/computer-use/loop/types.d.ts +37 -26
  59. package/dist/actors/computer-use/loop/usage.js +2 -2
  60. package/dist/actors/computer-use/loop.js +4 -4
  61. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  62. package/dist/actors/computer-use/openai-context.js +214 -0
  63. package/dist/actors/computer-use/openai-provider.d.ts +12 -9
  64. package/dist/actors/computer-use/openai-provider.js +47 -36
  65. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  66. package/dist/actors/computer-use/openai-requests.js +82 -15
  67. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  68. package/dist/actors/computer-use/openai-wire.js +36 -34
  69. package/dist/actors/contract.d.ts +86 -49
  70. package/dist/actors/contract.js +29 -23
  71. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  72. package/dist/actors/local-agent/claude-session.js +10 -9
  73. package/dist/actors/local-agent/cli.d.ts +8 -6
  74. package/dist/actors/local-agent/cli.js +24 -28
  75. package/dist/actors/local-agent/readiness.d.ts +2 -2
  76. package/dist/actors/local-agent/readiness.js +4 -4
  77. package/dist/actors/reasoning-effort.js +6 -6
  78. package/dist/actors/registry.d.ts +10 -10
  79. package/dist/actors/registry.js +18 -17
  80. package/dist/actors/scripted-browser/actor.d.ts +8 -8
  81. package/dist/actors/scripted-browser/actor.js +16 -16
  82. package/dist/actors/scripted-browser/browser-command.js +1 -1
  83. package/dist/actors/scripted-browser/journey.js +15 -4
  84. package/dist/actors/scripted-browser/steps.js +19 -1
  85. package/dist/actors/scripted-browser/types.d.ts +12 -2
  86. package/dist/actors/stop-conditions.d.ts +1 -1
  87. package/dist/actors/stop-conditions.js +1 -3
  88. package/dist/analysis/automatic-completion.d.ts +13 -8
  89. package/dist/analysis/automatic-completion.js +14 -8
  90. package/dist/analysis/automatic-config.d.ts +1 -1
  91. package/dist/analysis/automatic-config.js +2 -2
  92. package/dist/analysis/automatic.d.ts +10 -4
  93. package/dist/analysis/automatic.js +17 -13
  94. package/dist/analysis/codex-config.d.ts +6 -2
  95. package/dist/analysis/codex-config.js +22 -14
  96. package/dist/analysis/diagnostics.d.ts +23 -0
  97. package/dist/analysis/diagnostics.js +112 -0
  98. package/dist/analysis/evidence-sources.js +2 -2
  99. package/dist/analysis/evidence.js +6 -6
  100. package/dist/analysis/execute.d.ts +7 -1
  101. package/dist/analysis/execute.js +39 -12
  102. package/dist/analysis/job.d.ts +8 -5
  103. package/dist/analysis/job.js +15 -14
  104. package/dist/analysis/load.d.ts +1 -1
  105. package/dist/analysis/load.js +5 -5
  106. package/dist/analysis/provider.d.ts +9 -1
  107. package/dist/analysis/restricted-codex.d.ts +2 -0
  108. package/dist/analysis/restricted-codex.js +10 -1
  109. package/dist/analysis/service.d.ts +2 -0
  110. package/dist/analysis/service.js +35 -16
  111. package/dist/analysis/sharing.d.ts +2 -2
  112. package/dist/analysis/sharing.js +5 -5
  113. package/dist/analysis/store-executions.d.ts +5 -5
  114. package/dist/analysis/store-executions.js +12 -12
  115. package/dist/analysis/store.d.ts +4 -4
  116. package/dist/analysis/store.js +13 -13
  117. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  118. package/dist/cli/commands/analysis-signals.js +4 -1
  119. package/dist/cli/commands/analyze.js +23 -18
  120. package/dist/cli/commands/codex.js +9 -9
  121. package/dist/cli/commands/comms.js +62 -34
  122. package/dist/cli/commands/feedback.js +20 -21
  123. package/dist/cli/commands/lab-format.d.ts +5 -4
  124. package/dist/cli/commands/lab-format.js +35 -23
  125. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  126. package/dist/cli/commands/lab-route-computer-use.js +32 -21
  127. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  128. package/dist/cli/commands/lab-route-preview.js +7 -7
  129. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  130. package/dist/cli/commands/lab-route-run.js +6 -2
  131. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  132. package/dist/cli/commands/lab-route-scripted.js +0 -1
  133. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  134. package/dist/cli/commands/lab-route-shared-world.js +3 -4
  135. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  136. package/dist/cli/commands/lab-route-terminal.js +0 -1
  137. package/dist/cli/commands/lab-run.js +84 -54
  138. package/dist/cli/commands/lab-scorer.d.ts +2 -4
  139. package/dist/cli/commands/lab-scorer.js +1 -1
  140. package/dist/cli/commands/migrate.d.ts +4 -0
  141. package/dist/cli/commands/migrate.js +65 -0
  142. package/dist/cli/commands/observe.js +168 -107
  143. package/dist/cli/commands/run-command.d.ts +10 -0
  144. package/dist/cli/commands/run-command.js +85 -0
  145. package/dist/cli/commands/run-signals.d.ts +30 -0
  146. package/dist/cli/commands/run-signals.js +146 -0
  147. package/dist/cli/commands/runs.js +137 -136
  148. package/dist/cli/commands/setup.d.ts +2 -2
  149. package/dist/cli/commands/setup.js +26 -21
  150. package/dist/cli/commands/study.d.ts +3 -0
  151. package/dist/cli/commands/study.js +182 -0
  152. package/dist/cli/commands/tui.d.ts +4 -4
  153. package/dist/cli/commands/tui.js +21 -21
  154. package/dist/cli/commands/watch.js +64 -77
  155. package/dist/cli/deprecations.d.ts +18 -0
  156. package/dist/cli/deprecations.js +48 -0
  157. package/dist/cli/doctor.d.ts +18 -5
  158. package/dist/cli/doctor.js +111 -48
  159. package/dist/cli/first-run-path.d.ts +12 -10
  160. package/dist/cli/first-run-path.js +30 -28
  161. package/dist/cli/io.d.ts +46 -10
  162. package/dist/cli/io.js +109 -30
  163. package/dist/cli/observer-follow.d.ts +2 -2
  164. package/dist/cli/observer-follow.js +5 -6
  165. package/dist/cli/orientation.d.ts +6 -3
  166. package/dist/cli/orientation.js +43 -39
  167. package/dist/cli/product-sentence.d.ts +6 -0
  168. package/dist/cli/product-sentence.js +6 -0
  169. package/dist/cli/program.d.ts +6 -1
  170. package/dist/cli/program.js +112 -43
  171. package/dist/cli/telemetry.d.ts +17 -17
  172. package/dist/cli/telemetry.js +49 -41
  173. package/dist/cli.js +1 -1
  174. package/dist/comms/capture-surface.d.ts +14 -13
  175. package/dist/comms/capture-surface.js +23 -22
  176. package/dist/comms/catch-host.d.ts +8 -8
  177. package/dist/comms/catch-host.js +14 -14
  178. package/dist/comms/connections.js +4 -4
  179. package/dist/comms/email-catch.d.ts +3 -3
  180. package/dist/comms/email-catch.js +8 -8
  181. package/dist/comms/external-evidence.d.ts +27 -0
  182. package/dist/comms/external-evidence.js +93 -0
  183. package/dist/comms/extract.js +2 -2
  184. package/dist/comms/fake-inbox.d.ts +2 -2
  185. package/dist/comms/fake-inbox.js +2 -2
  186. package/dist/comms/lease-store.js +7 -7
  187. package/dist/comms/receiving-render.d.ts +1 -1
  188. package/dist/comms/receiving-render.js +2 -2
  189. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  190. package/dist/comms/sandbox-catch-script.js +6 -6
  191. package/dist/comms/sandbox-catch.d.ts +36 -37
  192. package/dist/comms/sandbox-catch.js +34 -35
  193. package/dist/comms/setup.js +42 -8
  194. package/dist/comms/thread-evidence.d.ts +1 -1
  195. package/dist/comms/thread-evidence.js +6 -6
  196. package/dist/comms/types.d.ts +6 -6
  197. package/dist/comms/types.js +4 -4
  198. package/dist/evidence/browser-hygiene.d.ts +1 -1
  199. package/dist/evidence/browser-hygiene.js +1 -1
  200. package/dist/evidence/frame-signature.d.ts +1 -1
  201. package/dist/evidence/frame-signature.js +4 -4
  202. package/dist/evidence/redaction.d.ts +3 -3
  203. package/dist/evidence/redaction.js +5 -5
  204. package/dist/evidence/secret-scrub.d.ts +9 -0
  205. package/dist/evidence/secret-scrub.js +96 -0
  206. package/dist/feedback/draft.js +41 -85
  207. package/dist/feedback/export-bundle.js +5 -5
  208. package/dist/feedback/export.d.ts +5 -1
  209. package/dist/feedback/export.js +16 -17
  210. package/dist/feedback/feedback.d.ts +3 -3
  211. package/dist/feedback/feedback.js +21 -3
  212. package/dist/guest/chromium-text.js +2 -2
  213. package/dist/guest/desktop-native.d.ts +1 -1
  214. package/dist/guest/runtime.js +1 -1
  215. package/dist/index.d.ts +14 -15
  216. package/dist/index.js +10 -11
  217. package/dist/keys/key-resolution.d.ts +7 -5
  218. package/dist/keys/key-resolution.js +40 -38
  219. package/dist/lab/adapter-extension.d.ts +35 -13
  220. package/dist/lab/adapter-extension.js +50 -134
  221. package/dist/lab/adapter-scorer-loader.d.ts +32 -12
  222. package/dist/lab/adapter-scorer-loader.js +56 -32
  223. package/dist/lab/composition-rules.js +58 -58
  224. package/dist/lab/config.js +85 -43
  225. package/dist/lab/deprecated-fields.d.ts +10 -0
  226. package/dist/lab/deprecated-fields.js +24 -0
  227. package/dist/lab/device-presets.d.ts +10 -10
  228. package/dist/lab/device-presets.js +11 -11
  229. package/dist/lab/discover.d.ts +13 -9
  230. package/dist/lab/discover.js +118 -60
  231. package/dist/lab/doctor.d.ts +53 -11
  232. package/dist/lab/doctor.js +193 -47
  233. package/dist/lab/init-plan.js +1 -3
  234. package/dist/lab/init-templates.js +147 -147
  235. package/dist/lab/init.d.ts +1 -1
  236. package/dist/lab/init.js +41 -9
  237. package/dist/lab/keys.d.ts +2 -0
  238. package/dist/lab/keys.js +43 -9
  239. package/dist/lab/lab-deps.d.ts +80 -0
  240. package/dist/lab/lab-deps.js +4 -0
  241. package/dist/lab/parse/actors.js +17 -16
  242. package/dist/lab/parse/comms.js +8 -7
  243. package/dist/lab/parse/execution.js +15 -14
  244. package/dist/lab/parse/study-v3.d.ts +23 -0
  245. package/dist/lab/parse/study-v3.js +259 -0
  246. package/dist/lab/parse/subject-state.d.ts +7 -7
  247. package/dist/lab/parse/subject-state.js +18 -17
  248. package/dist/lab/parse/subject.js +30 -29
  249. package/dist/lab/parse/values.d.ts +1 -2
  250. package/dist/lab/parse/values.js +3 -6
  251. package/dist/lab/persona-resolve.d.ts +7 -7
  252. package/dist/lab/persona-resolve.js +8 -8
  253. package/dist/lab/persona.js +1 -3
  254. package/dist/lab/plan-base.d.ts +0 -2
  255. package/dist/lab/plan-base.js +6 -4
  256. package/dist/lab/plan-participants.d.ts +7 -7
  257. package/dist/lab/plan-participants.js +2 -2
  258. package/dist/lab/plan-types.d.ts +26 -8
  259. package/dist/lab/plan.d.ts +4 -18
  260. package/dist/lab/plan.js +24 -79
  261. package/dist/lab/preflight-probes.js +11 -11
  262. package/dist/lab/preflight-result.d.ts +2 -1
  263. package/dist/lab/preflight-result.js +5 -6
  264. package/dist/lab/preflight.d.ts +7 -8
  265. package/dist/lab/preflight.js +6 -6
  266. package/dist/lab/requirements.d.ts +20 -0
  267. package/dist/lab/requirements.js +54 -0
  268. package/dist/lab/route-inputs.d.ts +23 -12
  269. package/dist/lab/route-inputs.js +48 -51
  270. package/dist/lab/routing.d.ts +42 -41
  271. package/dist/lab/routing.js +66 -68
  272. package/dist/lab/run-lab-events.d.ts +3 -11
  273. package/dist/lab/run-lab-events.js +2 -16
  274. package/dist/lab/run-lab-homes.d.ts +76 -0
  275. package/dist/lab/run-lab-homes.js +7 -0
  276. package/dist/lab/run-lab-options.d.ts +12 -66
  277. package/dist/lab/run-lab-options.js +58 -285
  278. package/dist/lab/summary.d.ts +15 -9
  279. package/dist/lab/summary.js +24 -17
  280. package/dist/lab/tasks.d.ts +15 -15
  281. package/dist/lab/tasks.js +14 -14
  282. package/dist/lab/types.d.ts +201 -195
  283. package/dist/lab/types.js +2 -0
  284. package/dist/lab/validation.d.ts +21 -21
  285. package/dist/lab/validation.js +61 -59
  286. package/dist/lab/warnings.d.ts +10 -0
  287. package/dist/lab/warnings.js +70 -41
  288. package/dist/library-aliases.d.ts +56 -0
  289. package/dist/library-aliases.js +22 -0
  290. package/dist/observer/artifact.d.ts +2 -2
  291. package/dist/observer/artifact.js +9 -9
  292. package/dist/observer/data.d.ts +6 -6
  293. package/dist/observer/data.js +7 -6
  294. package/dist/observer/exposure.d.ts +1 -1
  295. package/dist/observer/exposure.js +11 -11
  296. package/dist/observer/http.js +1 -1
  297. package/dist/observer/library.d.ts +1 -1
  298. package/dist/observer/library.js +4 -2
  299. package/dist/observer/listen.js +5 -4
  300. package/dist/observer/render.d.ts +1 -1
  301. package/dist/observer/render.js +12 -7
  302. package/dist/observer/run-routes.d.ts +4 -4
  303. package/dist/observer/run-routes.js +6 -6
  304. package/dist/observer/serve.d.ts +17 -0
  305. package/dist/observer/serve.js +41 -6
  306. package/dist/observer/tunnel.js +1 -1
  307. package/dist/observer-app.html +4 -4
  308. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  309. package/dist/routes/computer-use/bundle-parts.js +24 -17
  310. package/dist/routes/computer-use/bundle.d.ts +4 -11
  311. package/dist/routes/computer-use/bundle.js +12 -18
  312. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  313. package/dist/routes/computer-use/diagnostics.js +1 -1
  314. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +11 -11
  315. package/dist/routes/computer-use/e2b-desktop/comms.js +24 -27
  316. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  317. package/dist/routes/computer-use/e2b-desktop/desktop.js +8 -11
  318. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +16 -15
  319. package/dist/routes/computer-use/e2b-desktop/fidelity.js +20 -19
  320. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  321. package/dist/routes/computer-use/e2b-desktop/prepare.js +40 -43
  322. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  323. package/dist/routes/computer-use/e2b-desktop/start.js +32 -30
  324. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  325. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  326. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  327. package/dist/routes/computer-use/e2b-desktop/teardown.js +33 -20
  328. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  329. package/dist/routes/computer-use/external-comms.js +19 -43
  330. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  331. package/dist/routes/computer-use/fanout-bundle.js +38 -42
  332. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +33 -28
  333. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  334. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  335. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  336. package/dist/routes/computer-use/live-flush.js +20 -28
  337. package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +4 -2
  338. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +17 -16
  339. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  340. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  341. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  342. package/dist/routes/computer-use/local-vm.js +40 -67
  343. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  344. package/dist/routes/computer-use/participant-desktop.js +5 -25
  345. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +11 -11
  346. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +39 -26
  347. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  348. package/dist/routes/computer-use/participant-facts.js +12 -1
  349. package/dist/routes/computer-use/participant-model.d.ts +25 -11
  350. package/dist/routes/computer-use/participant-model.js +76 -34
  351. package/dist/routes/computer-use/participant-prompt.d.ts +13 -13
  352. package/dist/routes/computer-use/participant-prompt.js +8 -8
  353. package/dist/routes/computer-use/participant-runs.d.ts +11 -11
  354. package/dist/routes/computer-use/participant-runs.js +18 -18
  355. package/dist/routes/computer-use/plan.d.ts +21 -29
  356. package/dist/routes/computer-use/plan.js +70 -78
  357. package/dist/routes/computer-use/preflight.d.ts +3 -5
  358. package/dist/routes/computer-use/preflight.js +40 -36
  359. package/dist/routes/computer-use/rerun-selection.js +11 -7
  360. package/dist/routes/computer-use/result.d.ts +1 -1
  361. package/dist/routes/computer-use/result.js +48 -38
  362. package/dist/routes/computer-use/route.d.ts +5 -5
  363. package/dist/routes/computer-use/route.js +36 -33
  364. package/dist/routes/computer-use/self-report.d.ts +8 -8
  365. package/dist/routes/computer-use/self-report.js +33 -33
  366. package/dist/routes/computer-use/setup.d.ts +9 -15
  367. package/dist/routes/computer-use/setup.js +106 -83
  368. package/dist/routes/computer-use/single-bundle.d.ts +13 -16
  369. package/dist/routes/computer-use/single-bundle.js +46 -53
  370. package/dist/routes/computer-use/subject-projection.d.ts +6 -8
  371. package/dist/routes/computer-use/subject-projection.js +24 -23
  372. package/dist/routes/computer-use/types.d.ts +195 -238
  373. package/dist/routes/computer-use/types.js +21 -13
  374. package/dist/routes/preview.d.ts +8 -2
  375. package/dist/routes/preview.js +8 -5
  376. package/dist/routes/scripted/bundle.d.ts +5 -8
  377. package/dist/routes/scripted/bundle.js +23 -27
  378. package/dist/routes/scripted/plan.d.ts +6 -8
  379. package/dist/routes/scripted/plan.js +15 -13
  380. package/dist/routes/scripted/result.d.ts +4 -1
  381. package/dist/routes/scripted/result.js +15 -11
  382. package/dist/routes/scripted/route.js +15 -17
  383. package/dist/routes/scripted/scenario.d.ts +1 -1
  384. package/dist/routes/scripted/scenario.js +3 -3
  385. package/dist/routes/scripted/setup.d.ts +3 -2
  386. package/dist/routes/scripted/setup.js +27 -26
  387. package/dist/routes/scripted/subject.d.ts +8 -3
  388. package/dist/routes/scripted/subject.js +10 -6
  389. package/dist/routes/scripted/surface-records.js +4 -4
  390. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  391. package/dist/routes/scripted/surface-sessions.js +4 -4
  392. package/dist/routes/scripted/types.d.ts +21 -40
  393. package/dist/routes/scripted/types.js +2 -3
  394. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +17 -16
  395. package/dist/routes/shared-world/bundle.d.ts +7 -7
  396. package/dist/routes/shared-world/bundle.js +60 -62
  397. package/dist/routes/shared-world/checkpoints.d.ts +5 -5
  398. package/dist/routes/shared-world/checkpoints.js +5 -5
  399. package/dist/routes/shared-world/comms.d.ts +8 -7
  400. package/dist/routes/shared-world/comms.js +38 -51
  401. package/dist/routes/shared-world/external-public.d.ts +6 -5
  402. package/dist/routes/shared-world/external-public.js +28 -25
  403. package/dist/routes/shared-world/handoff.d.ts +10 -9
  404. package/dist/routes/shared-world/handoff.js +89 -81
  405. package/dist/routes/shared-world/lobby-code.d.ts +7 -7
  406. package/dist/routes/shared-world/lobby-code.js +22 -22
  407. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +15 -12
  408. package/dist/routes/shared-world/{seats.js → participant-specs.js} +65 -63
  409. package/dist/routes/shared-world/plan.d.ts +2 -6
  410. package/dist/routes/shared-world/plan.js +8 -9
  411. package/dist/routes/shared-world/provenance.d.ts +4 -4
  412. package/dist/routes/shared-world/provenance.js +4 -4
  413. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  414. package/dist/routes/shared-world/provisioned.js +55 -48
  415. package/dist/routes/shared-world/result.js +47 -36
  416. package/dist/routes/shared-world/route.js +54 -57
  417. package/dist/routes/shared-world/setup.d.ts +6 -5
  418. package/dist/routes/shared-world/setup.js +16 -18
  419. package/dist/routes/shared-world/types.d.ts +70 -141
  420. package/dist/routes/shared-world/types.js +5 -5
  421. package/dist/routes/terminal/adapter.d.ts +10 -10
  422. package/dist/routes/terminal/adapter.js +32 -129
  423. package/dist/routes/terminal/bundle.d.ts +10 -15
  424. package/dist/routes/terminal/bundle.js +43 -52
  425. package/dist/routes/terminal/credentials.d.ts +4 -4
  426. package/dist/routes/terminal/credentials.js +20 -20
  427. package/dist/routes/terminal/dry-run.d.ts +1 -1
  428. package/dist/routes/terminal/dry-run.js +13 -15
  429. package/dist/routes/terminal/encoding.d.ts +1 -1
  430. package/dist/routes/terminal/encoding.js +4 -4
  431. package/dist/routes/terminal/ledger.d.ts +8 -8
  432. package/dist/routes/terminal/ledger.js +22 -22
  433. package/dist/routes/terminal/live-finish.d.ts +1 -2
  434. package/dist/routes/terminal/live-finish.js +24 -23
  435. package/dist/routes/terminal/live-sandbox.d.ts +3 -2
  436. package/dist/routes/terminal/live-sandbox.js +31 -32
  437. package/dist/routes/terminal/participant-text.d.ts +23 -0
  438. package/dist/routes/terminal/participant-text.js +165 -0
  439. package/dist/routes/terminal/persona.js +1 -1
  440. package/dist/routes/terminal/plan.d.ts +2 -6
  441. package/dist/routes/terminal/plan.js +23 -19
  442. package/dist/routes/terminal/recorder.d.ts +6 -1
  443. package/dist/routes/terminal/recorder.js +12 -4
  444. package/dist/routes/terminal/result.js +12 -12
  445. package/dist/routes/terminal/route.js +30 -31
  446. package/dist/routes/terminal/runtime.d.ts +3 -2
  447. package/dist/routes/terminal/runtime.js +3 -3
  448. package/dist/routes/terminal/sandbox.d.ts +4 -4
  449. package/dist/routes/terminal/sandbox.js +10 -10
  450. package/dist/routes/terminal/session.js +22 -19
  451. package/dist/routes/terminal/token-usage.d.ts +1 -1
  452. package/dist/routes/terminal/token-usage.js +10 -11
  453. package/dist/routes/terminal/trace.d.ts +7 -10
  454. package/dist/routes/terminal/trace.js +11 -66
  455. package/dist/routes/terminal/types.d.ts +104 -114
  456. package/dist/routes/terminal/types.js +12 -7
  457. package/dist/run/active-runs.d.ts +13 -0
  458. package/dist/run/active-runs.js +12 -0
  459. package/dist/run/bundle-shape.d.ts +2 -1
  460. package/dist/run/bundle-shape.js +7 -7
  461. package/dist/run/bundle.d.ts +99 -92
  462. package/dist/run/bundle.js +10 -8
  463. package/dist/run/cost-summary.js +6 -5
  464. package/dist/run/costs.d.ts +6 -6
  465. package/dist/run/costs.js +17 -11
  466. package/dist/run/detail.d.ts +9 -9
  467. package/dist/run/detail.js +10 -10
  468. package/dist/run/dry-run-inputs.js +1 -1
  469. package/dist/run/dry-run.js +23 -30
  470. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  471. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  472. package/dist/run/feedback-shape.js +1 -1
  473. package/dist/run/judge.d.ts +34 -16
  474. package/dist/run/judge.js +41 -14
  475. package/dist/run/locate.d.ts +2 -0
  476. package/dist/run/locate.js +3 -1
  477. package/dist/run/outcomes.d.ts +3 -3
  478. package/dist/run/outcomes.js +3 -3
  479. package/dist/run/participant-records.d.ts +2 -2
  480. package/dist/run/participant-records.js +2 -2
  481. package/dist/run/paths.d.ts +1 -1
  482. package/dist/run/paths.js +2 -2
  483. package/dist/run/pricing.d.ts +30 -15
  484. package/dist/run/pricing.js +49 -30
  485. package/dist/run/projection.d.ts +27 -27
  486. package/dist/run/projection.js +23 -23
  487. package/dist/run/reclaim.d.ts +6 -0
  488. package/dist/run/reclaim.js +15 -5
  489. package/dist/run/results.d.ts +5 -5
  490. package/dist/run/run-index.d.ts +9 -7
  491. package/dist/run/run-index.js +24 -25
  492. package/dist/run/run-not-found.d.ts +5 -0
  493. package/dist/run/run-not-found.js +15 -0
  494. package/dist/run/run.d.ts +7 -4
  495. package/dist/run/run.js +10 -6
  496. package/dist/run/sandbox-receipts.d.ts +5 -5
  497. package/dist/run/sandbox-receipts.js +6 -6
  498. package/dist/run/shared-world-evidence.d.ts +67 -66
  499. package/dist/run/shared-world-evidence.js +4 -4
  500. package/dist/run/shared-world-shape.d.ts +3 -3
  501. package/dist/run/shared-world-shape.js +16 -16
  502. package/dist/run/stats.d.ts +17 -11
  503. package/dist/run/stats.js +124 -66
  504. package/dist/run/status.d.ts +21 -32
  505. package/dist/run/status.js +34 -33
  506. package/dist/run/stored-runs.js +2 -1
  507. package/dist/run/stream-shape.js +1 -1
  508. package/dist/run/streams.d.ts +29 -22
  509. package/dist/run/study-provenance.d.ts +47 -0
  510. package/dist/run/study-provenance.js +63 -0
  511. package/dist/run/study-result.d.ts +16 -0
  512. package/dist/run/study-result.js +9 -0
  513. package/dist/run/terminal-contract.d.ts +5 -5
  514. package/dist/run/terminal-contract.js +4 -4
  515. package/dist/run/text.d.ts +2 -0
  516. package/dist/run/text.js +4 -0
  517. package/dist/run/transient-comms-secrets.d.ts +5 -0
  518. package/dist/run/transient-comms-secrets.js +12 -0
  519. package/dist/run-lab.d.ts +40 -38
  520. package/dist/run-lab.js +42 -40
  521. package/dist/study/convert.d.ts +33 -0
  522. package/dist/study/convert.js +432 -0
  523. package/dist/study/field-paths.d.ts +12 -0
  524. package/dist/study/field-paths.js +126 -0
  525. package/dist/study/files.d.ts +26 -0
  526. package/dist/study/files.js +43 -0
  527. package/dist/study/migrate.d.ts +48 -0
  528. package/dist/study/migrate.js +408 -0
  529. package/dist/study/owned-files.d.ts +38 -0
  530. package/dist/study/owned-files.js +182 -0
  531. package/dist/subject/clone.d.ts +1 -1
  532. package/dist/subject/desktop-cli.d.ts +2 -2
  533. package/dist/subject/desktop-cli.js +3 -3
  534. package/dist/subject/local-tree-archive.d.ts +1 -1
  535. package/dist/subject/local-tree-archive.js +5 -5
  536. package/dist/subject/local-tree.d.ts +3 -3
  537. package/dist/subject/local-tree.js +1 -1
  538. package/dist/subject/node-bootstrap.d.ts +1 -1
  539. package/dist/subject/node-bootstrap.js +4 -4
  540. package/dist/subject/runtime.js +10 -11
  541. package/dist/subject/serve.d.ts +1 -1
  542. package/dist/subject/serve.js +4 -4
  543. package/dist/subject/state.d.ts +1 -1
  544. package/dist/subject/steps.d.ts +8 -8
  545. package/dist/subject/steps.js +7 -7
  546. package/dist/substrates/command-failure.d.ts +3 -3
  547. package/dist/substrates/command-failure.js +3 -3
  548. package/dist/substrates/detached.d.ts +6 -6
  549. package/dist/substrates/detached.js +7 -7
  550. package/dist/substrates/e2b/cdp-probe.d.ts +11 -11
  551. package/dist/substrates/e2b/cdp-probe.js +15 -18
  552. package/dist/substrates/e2b/desktop-browser.d.ts +5 -5
  553. package/dist/substrates/e2b/desktop-browser.js +12 -12
  554. package/dist/substrates/e2b/desktop-cdp.d.ts +15 -15
  555. package/dist/substrates/e2b/desktop-cdp.js +11 -11
  556. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  557. package/dist/substrates/e2b/desktop-executor.js +1 -1
  558. package/dist/substrates/e2b/desktop-geometry.d.ts +6 -6
  559. package/dist/substrates/e2b/desktop-geometry.js +9 -9
  560. package/dist/substrates/e2b/desktop-media.d.ts +1 -1
  561. package/dist/substrates/e2b/desktop-media.js +3 -3
  562. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  563. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  564. package/dist/substrates/e2b/sandbox.d.ts +1 -1
  565. package/dist/substrates/e2b/sandbox.js +2 -2
  566. package/dist/substrates/e2b/sdk.d.ts +11 -11
  567. package/dist/substrates/e2b/sdk.js +8 -8
  568. package/dist/substrates/local/runtime-host.d.ts +2 -0
  569. package/dist/substrates/local/runtime-host.js +6 -0
  570. package/dist/tui/actions.d.ts +8 -6
  571. package/dist/tui/actions.js +31 -22
  572. package/dist/tui/contract.d.ts +16 -16
  573. package/dist/tui/contract.js +10 -10
  574. package/dist/tui/launch.d.ts +4 -4
  575. package/dist/tui/launch.js +18 -19
  576. package/dist/tui/project.js +5 -5
  577. package/dist/tui-app.js +83 -83
  578. package/dist/verify/actor.d.ts +14 -14
  579. package/dist/verify/actor.js +45 -45
  580. package/dist/verify/artifacts.d.ts +3 -3
  581. package/dist/verify/artifacts.js +6 -6
  582. package/dist/verify/context-growth.d.ts +9 -0
  583. package/dist/verify/context-growth.js +62 -0
  584. package/dist/verify/costs.d.ts +7 -7
  585. package/dist/verify/costs.js +9 -9
  586. package/dist/verify/liveness.d.ts +1 -1
  587. package/dist/verify/liveness.js +4 -1
  588. package/dist/verify/rerun.d.ts +1 -1
  589. package/dist/verify/rerun.js +1 -1
  590. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  591. package/dist/verify/shared-world-concurrent.js +79 -76
  592. package/dist/verify/shared-world.d.ts +2 -2
  593. package/dist/verify/shared-world.js +18 -18
  594. package/dist/verify/subject.d.ts +4 -4
  595. package/dist/verify/subject.js +18 -18
  596. package/dist/verify/verify.js +98 -49
  597. package/docs/README.md +26 -33
  598. package/docs/architecture/actor-contract.md +105 -98
  599. package/docs/architecture/desktop-sessions.md +14 -14
  600. package/docs/architecture/external-public-shared-world.md +66 -59
  601. package/docs/architecture/github-feedback-loop.md +1 -4
  602. package/docs/architecture/guest-desktop.md +2 -2
  603. package/docs/architecture/observer.md +37 -37
  604. package/docs/architecture/restricted-codex-analysis.md +70 -30
  605. package/docs/architecture/serve.md +34 -37
  606. package/docs/architecture/state-driven-executor.md +55 -59
  607. package/docs/architecture/task-protocol-support.md +7 -9
  608. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +83 -115
  609. package/docs/contracts/README.md +24 -0
  610. package/docs/contracts/adapter-admission.md +3 -3
  611. package/docs/contracts/adapter-fixtures.md +2 -5
  612. package/docs/contracts/core.md +1 -3
  613. package/docs/contracts/errors.md +62 -0
  614. package/docs/contracts/feedback.md +8 -9
  615. package/docs/contracts/policy.md +7 -12
  616. package/docs/contracts/run-bundle.md +54 -51
  617. package/docs/contracts/schemas.md +505 -390
  618. package/docs/contracts/study-analysis.md +26 -2
  619. package/docs/contracts/study-costs.md +11 -7
  620. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  621. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  622. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  623. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  624. package/docs/principles/actor-fidelity.md +4 -4
  625. package/docs/principles/engineering.md +3 -3
  626. package/docs/principles/invariants-and-defaults.md +38 -38
  627. package/docs/principles/self-driving-harness.md +1 -5
  628. package/docs/principles/three-roles.md +1 -1
  629. package/docs/product/automatic-analysis.md +8 -7
  630. package/examples/participant/README.md +5 -5
  631. package/examples/participant/run.mjs +11 -10
  632. package/examples/scorer/README.md +3 -3
  633. package/examples/scorer/run.mjs +11 -12
  634. package/package.json +16 -17
  635. package/skills/humanish/SKILL.md +63 -60
  636. package/skills/humanish/agents/openai.yaml +1 -1
  637. package/AGENTS.md +0 -99
  638. package/CONTRIBUTING.md +0 -148
  639. package/dist/actors/codex/qualified-versions.d.ts +0 -45
  640. package/dist/actors/codex/qualified-versions.js +0 -87
  641. package/dist/cli/commands/lab.d.ts +0 -3
  642. package/dist/cli/commands/lab.js +0 -193
  643. package/dist/deprecated.d.ts +0 -90
  644. package/dist/deprecated.js +0 -106
  645. package/dist/lab/bag-overrides.d.ts +0 -18
  646. package/dist/lab/bag-overrides.js +0 -121
  647. package/dist/observer/static.d.ts +0 -39
  648. package/dist/observer/static.js +0 -369
  649. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  650. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  651. package/docs/architecture/comms-inbox.md +0 -122
  652. package/docs/architecture/desktop-recording.md +0 -80
  653. package/docs/architecture/local-browser-runtime.md +0 -178
  654. package/docs/architecture/observer-review.md +0 -144
  655. package/docs/architecture/participant-media.md +0 -90
  656. package/docs/architecture/project-layout.md +0 -62
  657. package/docs/architecture/real-email-receiving.md +0 -136
  658. package/docs/assets/humanish-drawdb-hero.png +0 -0
  659. package/docs/assets/humanish-observer-hero.png +0 -0
  660. package/docs/goals/current.md +0 -207
  661. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  662. package/docs/product/open-source-install-experience.md +0 -240
  663. package/docs/ramp/README.md +0 -294
  664. package/docs/release/open-source-readiness.md +0 -222
  665. package/docs/release/public-readiness-standard.md +0 -210
  666. package/docs/roadmap/world-class-open-source-v0.md +0 -311
  667. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  668. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -8,8 +8,8 @@
8
8
  import { isLoopbackUrl } from "./parse/subject.js";
9
9
  import { REPO_SLUG_PATTERN } from "./parse/values.js";
10
10
  import { declaredTargets } from "./plan-participants.js";
11
- import { actorResolvesToComputerUse, actorResolvesToScriptedBrowser, actorResolvesToTerminal, cuaLaneCount, registeredComputerUseActors, registeredScriptedBrowserActors, registeredTerminalActors, isComputerUseComposition, } from "./routing.js";
12
- import { cloneTargetValidationReason, cuaLaneValidationReason, sharedWorldValidationReason, } from "./validation.js";
11
+ import { actorResolvesToComputerUse, actorResolvesToScriptedBrowser, actorResolvesToTerminal, computerUseParticipantCount, registeredComputerUseActors, registeredScriptedBrowserActors, registeredTerminalActors, isComputerUseComposition, } from "./routing.js";
12
+ import { cloneTargetValidationReason, computerUseValidationReason, sharedWorldValidationReason, } from "./validation.js";
13
13
  import { rosterOf } from "./parse/actors.js";
14
14
  /** The first composition rule a config breaks, in the parser's order, or null. */
15
15
  export function compositionReason(config) {
@@ -21,10 +21,10 @@ export function compositionReason(config) {
21
21
  cloneTargetValidationReason(config) ??
22
22
  cloneComputerUseValidationReason(config) ??
23
23
  localTreeValidationReason(config) ??
24
- // Independent computer-use lanes: the roster contract on every route that resolves to cua.
25
- (isComputerUseComposition(config) ? cuaLaneValidationReason(config) : null) ??
24
+ // Independent computer-use participants: the roster contract on every route that resolves to cua.
25
+ (isComputerUseComposition(config) ? computerUseValidationReason(config) : null) ??
26
26
  // Whenever shared world is declared, not only when it routes, so a half-declared shared world
27
- // fails with a precise reason instead of running as independent lanes.
27
+ // fails with a precise reason instead of running as independent participants.
28
28
  (config.subject.topology === "shared-world" ? sharedWorldValidationReason(config) : null) ??
29
29
  desktopCliValidationReason(config) ??
30
30
  terminalValidationReason(config) ??
@@ -32,7 +32,7 @@ export function compositionReason(config) {
32
32
  }
33
33
  /** Why a this-repo lab cannot run live. The parser and the preview planner both refuse with it. */
34
34
  export const THIS_REPO_DRY_RUN_ONLY = "this-repo labs are dry-run only; use a clone or app-url subject for a live run.";
35
- // this-repo subjects run locally and dry-run only — there is no live execution target for the
35
+ // this-repo subjects run locally and dry-run only: there is no live execution target for the
36
36
  // host repo (clone/app-url provide that). Reject the mis-configs rather than silently mishandle.
37
37
  function thisRepoValidationReason(config) {
38
38
  if (config.subject.source === "this-repo") {
@@ -45,57 +45,57 @@ function thisRepoValidationReason(config) {
45
45
  }
46
46
  return null;
47
47
  }
48
- // local-app route: an already-running LOCAL dev server driven IN-PROCESS via a custom
48
+ // local-app route: an already-running local dev server driven in-process via a custom
49
49
  // CuaExecutor (no clone, no E2B desktop). Parse-validated fail-closed: a computer-use actor
50
- // only, execution.target local or absent (NEVER e2b-desktop — the whole point is to skip the
50
+ // only, execution.target local or absent (never e2b-desktop, because the route exists to skip the
51
51
  // desktop), and no public-target policy (it is always loopback; the loopback shape was already
52
- // enforced in parseSubject). The actual "no buildExecutor hook supplied" case is inherently an
53
- // engine-time decision (the parser cannot know whether a library caller will pass hooks), so
54
- // it fails closed in runCuaActorLab with HUMANISH_CUA_LAB_LOCAL_APP_NO_EXECUTOR.
52
+ // enforced in parseSubject). The actual "no inProcess executor supplied" case is inherently an
53
+ // engine-time decision (the parser cannot know whether a library caller will pass one), so
54
+ // it fails closed in runCuaActorLab with HUMANISH_COMPUTER_USE_LOCAL_APP_NO_EXECUTOR.
55
55
  function localAppValidationReason(config) {
56
56
  if (config.subject.source === "local-app") {
57
57
  const type = config.actors[0]?.type ?? "";
58
58
  if (config.execution?.target !== undefined && config.execution.target !== "local") {
59
- return "local-app subjects drive an in-process LOCAL dev server with NO E2B desktop — set `execution.target: local` or omit it (absent means local); `e2b-desktop` is rejected (use an app-url subject for the hosted-desktop route).";
59
+ return "A local-app subject drives a local dev server in this process, with no E2B desktop. Set `execution.target: local` or omit it. To run on a hosted desktop, use an app-url subject with `execution.target: e2b-desktop`.";
60
60
  }
61
61
  if (!actorResolvesToComputerUse(type)) {
62
62
  return `actors[0].type must be a registered computer-use actor for local-app subjects (one of: ${registeredComputerUseActors().join(", ")}); the caller's custom executor runs the computer-use loop. Got "${type}".`;
63
63
  }
64
- if (cuaLaneCount(config) > 1) {
64
+ if (computerUseParticipantCount(config) > 1) {
65
65
  return "Fan-out to more than one participant is not supported on the in-process/local-app route: fan-out provisions one independent E2B desktop per participant, which the in-process route deliberately skips. Set actors[0].count to 1 and drop actors[0].lanes (use an app-url or clone subject on execution.target: e2b-desktop for fan-out).";
66
66
  }
67
67
  if (rosterOf(config.actors[0]) !== undefined) {
68
68
  return "`actors[0].lanes` (fan-out roster) is not supported on the in-process/local-app route: it provisions one E2B desktop per participant, which this route skips. Use an app-url or clone subject with execution.target: e2b-desktop.";
69
69
  }
70
70
  if (config.policies?.allowPublicTargets === true) {
71
- return "`policies.allowPublicTargets` is not supported on the local-app route — a local-app subject is always a loopback dev server; there is no public target to allow.";
71
+ return "`policies.allowPublicTargets` does not apply to a local-app subject: it is always a loopback dev server, so there is no public target to allow. Remove the setting.";
72
72
  }
73
73
  }
74
74
  return null;
75
75
  }
76
- // app-url routes: the actor type is a REAL dispatch key (registry-resolved). The actor LANE
76
+ // app-url routes: the actor type is a real dispatch key (registry-resolved). The actor's run kind
77
77
  // picks the substrate: a scripted-browser actor runs locally against the declared loopback
78
78
  // app; a computer-use actor drives a hosted desktop browser. Fail closed on mis-configs.
79
79
  function appUrlValidationReason(config) {
80
80
  if (config.subject.source === "app-url") {
81
81
  const type = config.actors[0]?.type ?? "";
82
82
  if (actorResolvesToScriptedBrowser(type)) {
83
- // Scripted-browser route (all fail-closed: invariant 6 — a field that cannot act on
83
+ // Scripted-browser route (all fail-closed, so claims match mechanism: a field that cannot act on
84
84
  // this route is rejected, never silently ignored).
85
85
  if (config.execution?.target !== undefined && config.execution.target !== "local") {
86
- return "scripted-browser actors run on the operator's machine — set `execution.target: local` or omit it (absent means local); in-sandbox scripted execution is a later slice.";
86
+ return "A scripted-browser actor on an app-url subject runs on this machine. Set `execution.target: local` or omit it. To run scripted steps on a hosted desktop, use a clone subject.";
87
87
  }
88
88
  if (!config.scenario?.ref) {
89
- return "scripted-browser labs require `scenario.ref` — the committed scenario's browser steps are what this actor executes.";
89
+ return "A scripted-browser study needs `scenario.ref`: the actor runs the browser steps in that scenario file.";
90
90
  }
91
91
  if ((config.actors[0]?.count ?? 1) > 2) {
92
- return "scripted-browser labs support actors[0].count of 1 (desktop surface) or 2 (desktop + mobile); larger fan-out is a later slice.";
92
+ return "A scripted-browser study takes `actors[0].count` 1 (desktop) or 2 (desktop and mobile). Higher counts are not supported yet.";
93
93
  }
94
94
  if (config.policies?.redactScreenshots === true) {
95
- return "`policies.redactScreenshots: true` is not implemented on the scripted-browser route yet — screenshots persist raw in gitignored .humanish; a silently ignored redaction policy would be a safety lie, so it is rejected.";
95
+ return "`policies.redactScreenshots: true` is not supported on the scripted-browser route yet, so its screenshots would be stored unredacted in .humanish/. Remove the setting, or use a computer-use actor, which blurs screenshots as it takes them.";
96
96
  }
97
97
  if (config.policies?.allowPublicTargets === true) {
98
- return "`policies.allowPublicTargets` is not supported on the scripted-browser route — the scripted step driver enforces loopback at every navigation; public targets on this route are a later slice.";
98
+ return "`policies.allowPublicTargets` is not supported on the scripted-browser route: the step driver allows only loopback URLs at every navigation. Remove the setting, or drive the public URL with a computer-use actor.";
99
99
  }
100
100
  if (!isLoopbackUrl(config.subject.appUrl ?? "")) {
101
101
  return "`subject.appUrl` must be a loopback URL (127.0.0.1/localhost) on the scripted-browser route.";
@@ -108,15 +108,15 @@ function appUrlValidationReason(config) {
108
108
  if (!actorResolvesToComputerUse(type)) {
109
109
  return `actors[0].type must be a registered computer-use actor for app-url × e2b-desktop labs (one of: ${registeredComputerUseActors().join(", ")}); for local scripted execution use a registered scripted-browser actor (${registeredScriptedBrowserActors().join(", ")}). Got "${type}".`;
110
110
  }
111
- // Multi-lane fan-out is CONSUMED on this route (per-lane worlds; the shared cua-lane
112
- // cross-validation below enforces lanes/count XOR rules, the 16 cap, and the
113
- // lane-level target gates, and the allowPublicTargets+N>1 rejection for ambiguous one-target
111
+ // Multi-participant fan-out is consumed on this route (`per-lane-worlds`; the shared cua
112
+ // cross-validation below enforces `lanes`/`count` XOR rules, the 16 cap, and the
113
+ // per-participant target gates, and the allowPublicTargets+N>1 rejection for ambiguous one-target
114
114
  // fan-out).
115
115
  // Loopback by default; an owner may declare a public/preview target via policies.
116
116
  const targets = [config.subject.appUrl ?? "", ...declaredTargets(config)];
117
117
  const unsafeTarget = targets.find((target) => !config.policies?.allowPublicTargets && !isLoopbackUrl(target));
118
118
  if (unsafeTarget !== undefined) {
119
- return "`subject.appUrl` and `actors[0].lanes[].target` must be loopback URLs (127.0.0.1/localhost) unless `policies.allowPublicTargets: true` is set — set it to drive deployed/preview URLs you own.";
119
+ return "`subject.appUrl` and `actors[0].lanes[].target` must be loopback URLs (127.0.0.1 or localhost). To drive a deployed or preview URL you own, set `policies.allowPublicTargets: true`.";
120
120
  }
121
121
  }
122
122
  }
@@ -130,10 +130,10 @@ function scriptedBrowserValidationReason(config) {
130
130
  return "scripted-browser actors require `subject.source: app-url` (a running app at a loopback URL) or `subject.source: clone` with `execution.target: e2b-desktop` (a provisioned synthetic subject).";
131
131
  }
132
132
  if (config.execution?.target !== "e2b-desktop") {
133
- return "clone subjects with scripted-browser actors require `execution.target: e2b-desktop` — the lab provisions the clone in E2B, exposes it with getHost, then drives deterministic browser steps.";
133
+ return "A clone subject with a scripted-browser actor needs `execution.target: e2b-desktop`: humanish builds the clone in an E2B sandbox, opens it at a public sandbox URL and runs the scenario's browser steps against it.";
134
134
  }
135
135
  if (!config.subject.serve) {
136
- return "clone subjects with scripted-browser actors require `subject.serve` (start + url) — the lab serves the app in-sandbox before the scripted browser drives it.";
136
+ return "A clone subject with a scripted-browser actor needs `subject.serve` (start and url): humanish starts the app in the sandbox before the browser steps run.";
137
137
  }
138
138
  if ((config.subject.repos?.length ?? 0) !== 1) {
139
139
  return "clone scripted-browser labs require exactly one repo in subject.repos.";
@@ -143,49 +143,49 @@ function scriptedBrowserValidationReason(config) {
143
143
  return `subject.repos[0] must be an owner/repo slug (got "${repo}").`;
144
144
  }
145
145
  if (config.subject.topology !== undefined) {
146
- return "clone scripted-browser labs do not support `subject.topology` yet — this slice provisions one synthetic subject and one deterministic scripted actor roster, not a shared-world run.";
146
+ return "A clone scripted-browser study does not support `subject.topology` yet: it runs one synthetic subject for its scripted actor. Remove `subject.topology`.";
147
147
  }
148
148
  if (config.subject.clone?.fanout !== undefined || config.subject.clone?.keep === true) {
149
- return "clone scripted-browser labs do not support `subject.clone.fanout` or `subject.clone.keep` yet — the provisioned subject is always a single disposable E2B sandbox.";
149
+ return "A clone scripted-browser study does not support `subject.clone.fanout` or `subject.clone.keep` yet: its subject is always one sandbox, removed after the run.";
150
150
  }
151
151
  if (!config.scenario?.ref) {
152
- return "scripted-browser labs require `scenario.ref` — the committed scenario's browser steps are what this actor executes.";
152
+ return "A scripted-browser study needs `scenario.ref`: the actor runs the browser steps in that scenario file.";
153
153
  }
154
154
  if ((config.actors[0]?.count ?? 1) > 2) {
155
- return "scripted-browser labs support actors[0].count of 1 (desktop surface) or 2 (desktop + mobile); larger fan-out is a later slice.";
155
+ return "A scripted-browser study takes `actors[0].count` 1 (desktop) or 2 (desktop and mobile). Higher counts are not supported yet.";
156
156
  }
157
157
  if (rosterOf(config.actors[0]) !== undefined) {
158
- return "`actors[0].lanes` is not supported on the scripted-browser route yet — use actors[0].count for the deterministic surface roster.";
158
+ return "`actors[0].lanes` is not supported on the scripted-browser route yet. Use `actors[0].count` to choose the desktop and mobile surfaces.";
159
159
  }
160
160
  if (config.policies?.redactScreenshots === true) {
161
- return "`policies.redactScreenshots: true` is not implemented on the scripted-browser route yet — screenshots persist raw in gitignored .humanish; a silently ignored redaction policy would be a safety lie, so it is rejected.";
161
+ return "`policies.redactScreenshots: true` is not supported on the scripted-browser route yet, so its screenshots would be stored unredacted in .humanish/. Remove the setting, or use a computer-use actor, which blurs screenshots as it takes them.";
162
162
  }
163
163
  if (config.policies?.allowPublicTargets === true) {
164
- return "`policies.allowPublicTargets` is not supported on the clone scripted-browser route — the only external host is the harness-minted getHost URL for a provisioned synthetic subject.";
164
+ return "`policies.allowPublicTargets` does not apply to a clone scripted-browser study: its only public URL is the sandbox URL humanish opens for its synthetic subject. Remove the setting.";
165
165
  }
166
166
  if (config.subject.exposure !== "synthetic") {
167
- return "clone scripted-browser labs require `subject.exposure: synthetic` — the subject is exposed on an internet-reachable getHost URL for the run, so the author must attest it is synthetic seeded data.";
167
+ return "A clone scripted-browser study needs `subject.exposure: synthetic`. The subject is reachable from the internet at a public sandbox URL during the run, so the study must declare that its data is synthetic.";
168
168
  }
169
169
  if (!config.subject.state?.seed ||
170
170
  config.subject.state.seed.length === 0 ||
171
171
  (config.subject.state.external?.length ?? 0) > 0) {
172
- return "clone scripted-browser labs require `subject.state.seed` and do not allow `subject.state.external` — getHost-exposed subjects must be synthetic seeded data, not external/unpinned state.";
172
+ return "A clone scripted-browser study needs `subject.state.seed` and cannot use `subject.state.external`: a subject at a public sandbox URL may hold only seeded synthetic data.";
173
173
  }
174
174
  if (!config.subject.serve.start.includes("0.0.0.0")) {
175
- return "clone scripted-browser labs require `subject.serve.start` to bind all interfaces (e.g. `-H 0.0.0.0` / `--host 0.0.0.0` / `HOST=0.0.0.0`) — getHost only routes to a 0.0.0.0-bound port; the readiness probe stays loopback.";
175
+ return "A clone scripted-browser study needs `subject.serve.start` to listen on all interfaces (for example `-H 0.0.0.0`, `--host 0.0.0.0` or `HOST=0.0.0.0`): the public sandbox URL reaches only a port bound to 0.0.0.0. The readiness probe still uses loopback.";
176
176
  }
177
177
  }
178
178
  return null;
179
179
  }
180
- // clone × e2b-desktop disambiguates on the actor lane: a computer-use actor means the lab
181
- // clones AND serves the subject in-sandbox, then drives it. Scripted-browser actors were checked
180
+ // clone × e2b-desktop disambiguates on the actor's run kind: a computer-use actor means the study
181
+ // clones and serves the subject in-sandbox, then drives it. Scripted-browser actors were checked
182
182
  // above.
183
183
  function cloneComputerUseValidationReason(config) {
184
184
  if (config.subject.source === "clone" &&
185
185
  config.execution?.target === "e2b-desktop" &&
186
186
  actorResolvesToComputerUse(config.actors[0]?.type)) {
187
187
  if (!config.subject.serve) {
188
- return "clone subjects on the computer-use route require `subject.serve` (start + url) — the lab serves the app in-sandbox before the actor drives it.";
188
+ return "A clone subject on the computer-use route needs `subject.serve` (start and url): humanish starts the app in the sandbox before the participant opens it.";
189
189
  }
190
190
  if ((config.subject.repos?.length ?? 0) !== 1) {
191
191
  return "computer-use clone labs serve one repo; declare exactly one repo in subject.repos.";
@@ -194,15 +194,15 @@ function cloneComputerUseValidationReason(config) {
194
194
  if (!REPO_SLUG_PATTERN.test(repo)) {
195
195
  return `subject.repos[0] must be an owner/repo slug (got "${repo}").`;
196
196
  }
197
- // Fan-out is CONSUMED here: N lanes each clone the SAME single repo into their own E2B
198
- // desktop (per-lane worlds). The shared cua-lane cross-validation below enforces the
199
- // lanes/count rules and the 16 cap; the single-repo rule above is unchanged.
197
+ // Fan-out is consumed here: N participants each clone the same single repo into their own
198
+ // E2B desktop (`per-lane-worlds`). The shared cua cross-validation below enforces the
199
+ // `lanes`/`count` rules and the 16 cap; the single-repo rule above is unchanged.
200
200
  }
201
201
  return null;
202
202
  }
203
203
  // local-tree route: packs and uploads the operator's own working tree, then serves it exactly
204
204
  // like a computer-use clone subject. The scripted-browser route has no packed-working-tree
205
- // mode, so e2b-desktop + a computer-use actor are the ONLY combination this source supports.
205
+ // mode, so e2b-desktop + a computer-use actor are the only combination this source supports.
206
206
  // `subject.serve` is already required at parse time (parseSubject); the repos/clone rejection
207
207
  // also already happened there (local-tree never carries git slugs).
208
208
  function localTreeValidationReason(config) {
@@ -216,18 +216,18 @@ function localTreeValidationReason(config) {
216
216
  }
217
217
  return null;
218
218
  }
219
- // desktop-cli route: a computer-use participant studies a CLI/TUI the way a person does — at a
219
+ // desktop-cli route: a computer-use participant studies a CLI/TUI the way a person does: at a
220
220
  // desktop, in a terminal window, by looking at it. The sibling of terminal-product, and the
221
- // distinction is the POPULATION, not the product: terminal-product sends an autonomous agent
222
- // through a pipe with stdin disabled, which is the honest way to study what an agent meets and
221
+ // distinction is the population: terminal-product sends an autonomous agent
222
+ // through a pipe with stdin disabled, which matches what an agent meets and
223
223
  // structurally cannot study an interactive surface. This route sends someone who can see it.
224
224
  //
225
- // Fail-closed on the pairing (invariant 6): a hosted desktop and a computer-use actor, because
225
+ // Fail-closed on the pairing: a hosted desktop and a computer-use actor, because
226
226
  // "watch a person use a terminal" is not something the other substrates can do.
227
227
  /** A desktop-cli subject with no product to study. The computer-use planner checks this too. */
228
228
  export function desktopCliProductReason(config) {
229
229
  return config.subject.source === "desktop-cli" && config.subject.product?.name === undefined
230
- ? "desktop-cli subjects need `subject.product.name` — the CLI the participant is being asked to use."
230
+ ? "A desktop-cli subject needs `subject.product.name`: the CLI the participant is asked to use."
231
231
  : null;
232
232
  }
233
233
  function desktopCliValidationReason(config) {
@@ -236,7 +236,7 @@ function desktopCliValidationReason(config) {
236
236
  return productReason;
237
237
  if (config.subject.source === "desktop-cli" && config.subject.product !== undefined) {
238
238
  if (config.execution?.target !== undefined && config.execution.target !== "e2b-desktop") {
239
- return "desktop-cli subjects are studied at a hosted desktop — set `execution.target: e2b-desktop` or omit it.";
239
+ return "A desktop-cli subject runs on a hosted desktop. Set `execution.target: e2b-desktop` or omit it.";
240
240
  }
241
241
  if (!actorResolvesToComputerUse(config.actors[0]?.type ?? "")) {
242
242
  return "desktop-cli subjects need a registered computer-use actor: the participant reads the screen and types, which is what makes an interactive surface studiable at all.";
@@ -248,16 +248,16 @@ function desktopCliValidationReason(config) {
248
248
  }
249
249
  return null;
250
250
  }
251
- // terminal-product route: a real autonomous agent studies a CLI/product from PUBLIC surfaces
252
- // inside an E2B shell. Fail-closed (invariant 6 — a field that cannot act on this route is an
253
- // honest parse error): a registered terminal actor only, execution.target e2b-terminal or absent
254
- // (absent defaults to e2b-terminal — the only honest target for an in-sandbox agent), single
255
- // lane until fan-out lands.
251
+ // terminal-product route: a real autonomous agent studies a CLI/product from public surfaces inside
252
+ // an E2B shell. Fail-closed (claims match mechanism: a field that cannot act on this route is a
253
+ // parse error): a registered terminal actor only, execution.target e2b-terminal or absent (absent
254
+ // defaults to e2b-terminal, the only target where an in-sandbox agent runs), one participant until
255
+ // fan-out lands.
256
256
  function terminalValidationReason(config) {
257
257
  if (config.subject.source === "terminal-product") {
258
258
  const type = config.actors[0]?.type ?? "";
259
259
  if (config.execution?.target !== undefined && config.execution.target !== "e2b-terminal") {
260
- return "terminal-product subjects run the agent inside an E2B shell — set `execution.target: e2b-terminal` or omit it (absent means e2b-terminal); `local`/`e2b-desktop` are rejected.";
260
+ return "A terminal-product subject runs its agent in an E2B shell. Set `execution.target: e2b-terminal` or omit it; `local` and `e2b-desktop` are not supported.";
261
261
  }
262
262
  if (!actorResolvesToTerminal(type)) {
263
263
  return `actors[0].type must be a registered terminal actor for terminal-product subjects (one of: ${registeredTerminalActors().join(", ")}). Got "${type}".`;
@@ -267,8 +267,8 @@ function terminalValidationReason(config) {
267
267
  }
268
268
  }
269
269
  else if (config.execution?.target === "e2b-terminal") {
270
- // e2b-terminal is the terminal-product substrate ONLY. Any other source declaring it is a
271
- // mis-config — reject, never silently mishandle (mirrors app-url's e2b-desktop pairing rule).
270
+ // e2b-terminal is the terminal-product substrate only. Any other source declaring it is a
271
+ // mis-config: reject, never silently mishandle (mirrors app-url's e2b-desktop pairing rule).
272
272
  return "`execution.target: e2b-terminal` requires `subject.source: terminal-product` with a registered terminal actor.";
273
273
  }
274
274
  else if (actorResolvesToTerminal(config.actors[0]?.type)) {
@@ -1,64 +1,69 @@
1
- // humanish.lab.v2 — a lab is a COMPOSITION over code primitives, not a hardcoded kind.
1
+ // humanish.lab.v2: a lab is a composition over code primitives. There is no hardcoded lab kind.
2
+ // A humanish.study.v3 file is rewritten into this spelling first (parse/study-v3.ts), and then must
3
+ // take the route it declares and set no field that route does not read.
2
4
  //
3
- // HONEST SCOPE (read before trusting field names): the engine routes by
4
- // subject.source × execution.target (disambiguated by the actor lane where both axes
5
+ // Scope (read before trusting field names): the engine routes by
6
+ // subject.source × execution.target (disambiguated by the actor's run kind where both axes
5
7
  // collide) and consumes a deliberately small set of fields:
6
8
  // subject.source/repos/appUrl/serve/env/state/clone.{depth,fanout,keep}, actors[0].count,
7
9
  // execution.target + execution.desktop.codexAppServer, scenario.mode,
8
10
  // policies.redactRepos, defaults.open.
9
11
  // On the computer-use routes (app-url × e2b-desktop, and clone × e2b-desktop with a
10
- // computer-use actor), `actors[0].type` IS load-bearing: it must resolve to a registered
12
+ // computer-use actor), `actors[0].type` selects the actor: it must resolve to a registered
11
13
  // computer-use actor, and that descriptor runs the session. Those routes also consume
12
14
  // actors[0].{mission,persona,laneFocus.instruction,model,reasoningEffort}, execution.timeoutMs,
13
15
  // execution.desktop.{browser,resolution,sandboxTimeoutMs}, and (clone)
14
16
  // subject.{serve,env,state,clone.depth}.
15
17
  // On the scripted-browser route (app-url × local-or-absent, or clone × e2b-desktop, with a
16
- // registered scripted-browser actor), `actors[0].type` is equally load-bearing, and the route
17
- // consumes scenario.ref (REQUIRED there — the committed scenario's browser steps ARE what the
18
+ // registered scripted-browser actor), `actors[0].type` selects the actor too, and the route
19
+ // consumes scenario.ref (required there, because the committed scenario's browser steps are what the
18
20
  // actor executes), actors[0].{persona,count}, and execution.timeoutMs. On the provisioned
19
21
  // clone slice it also consumes subject.{repos,serve,env,state,exposure,clone.depth} and
20
22
  // execution.desktop.template. actors[0].{mission,laneFocus,model} are inert on that route
21
23
  // because no model runs, and most execution.desktop.* fields remain forward-declared (device
22
- // presets belong to the cua route — scripted surfaces are the driver's own desktop/mobile
23
- // viewports where isMobile/DSF genuinely RENDER via playwright emulation).
24
- // On the other routes those fields remain FORWARD-DECLARED and NOT yet consumed —
24
+ // presets belong to the computer-use route; scripted surfaces are the driver's own desktop/mobile
25
+ // viewports where isMobile/DSF genuinely render via playwright emulation).
26
+ // On the other routes those fields remain forward-declared and are not yet consumed:
25
27
  // parseLabConfig emits a warning listing any such field that is set, so `lab inspect` shows
26
28
  // the truth.
27
29
  //
28
- // NOTE on actors[0].count: it now carries ROUTE-SPECIFIC meanings — synthetic route: simCount;
30
+ // NOTE on actors[0].count: it carries route-specific meanings. Preview route: simCount;
29
31
  // scripted-browser route: surface roster {1 = desktop, 2 = desktop + mobile}, default 1 (the
30
- // defaults-table single-lane row governs; count: 2 is the declared override); computer-use
31
- // E2B route: the HOMOGENEOUS fan-out lane count (N identical lanes, each its own E2B desktop),
32
- // capped at 16; the in-process/local-app cua route stays single lane (no E2B to fan out).
32
+ // defaults-table single-participant row governs; count: 2 is the declared override); computer-use
33
+ // E2B route: the homogeneous fan-out participant count (N identical participants, each its own E2B
34
+ // desktop), capped at 16; the in-process/local-app computer-use route stays single-participant (no
35
+ // E2B to fan out).
33
36
  //
34
- // NOTE on actors[0].lanes / actors[0].roster (computer-use E2B route, this slice): a
35
- // DIFFERENTIATED fan-out roster — each `{ id?, persona?, device?, instruction?, target? }` becomes one
36
- // independent E2B desktop (per-lane worlds, the default topology). `roster[]` is parser sugar for
37
+ // NOTE on actors[0].lanes / actors[0].roster (computer-use E2B route): a
38
+ // differentiated fan-out roster: each `{ id?, persona?, device?, instruction?, target? }` becomes one
39
+ // independent E2B desktop (`per-lane-worlds`, the default topology). `roster[]` is parser sugar for
37
40
  // repeated groups and is normalized into `lanes[]` before the engine sees it. `lanes|roster` XOR
38
- // `count` (declare a differentiated roster OR a homogeneous count, never both); `lanes|roster`
39
- // XOR `actors[0].laneFocus` (per-lane `instruction` is the roster's steer); `lanes[].device` XOR
40
- // raw `execution.desktop.resolution`. `execution.concurrency` bounds in-flight lanes (default: the
41
- // lane count, every lane at once; env HUMANISH_CUA_MAX_CONCURRENCY may only LOWER it — invariant
42
- // 3). On every non-cua route normalized `lanes` are inert (warned). subject.clone.fanout is
43
- // REJECTED on the cua route. `lanes[].target` is app-url × computer-use ONLY: an absolute browser
44
- // URL this lane opens instead of `subject.appUrl`; it is the generic setup-produced-target
45
- // handoff, not a service topology primitive.
41
+ // `count` (declare a differentiated roster or a homogeneous count, never both); `lanes|roster`
42
+ // XOR `actors[0].laneFocus` (each entry's `instruction` is the roster's steer); `lanes[].device` XOR
43
+ // raw `execution.desktop.resolution`. `execution.concurrency` bounds in-flight participants (default:
44
+ // the participant count, all at once; env HUMANISH_CUA_MAX_CONCURRENCY may only lower it, per invariant
45
+ // 3). On every non-computer-use route normalized `lanes` are inert (warned). subject.clone.fanout
46
+ // is rejected on the computer-use route. `lanes[].target` is app-url × computer-use only: an
47
+ // absolute browser URL this participant opens instead of `subject.appUrl`; it is the generic
48
+ // setup-produced-target handoff, not a service topology primitive.
46
49
  //
47
- // There is deliberately NO v1 compatibility: v1 had zero real users. Breaking schema changes
48
- // bump the version honestly.
50
+ // There is deliberately no v1 compatibility: v1 had zero real users. Breaking schema changes
51
+ // bump the version.
49
52
  import { isLocalBrowserLab, localBrowserDefaults, localBrowserUnsupportedReason, } from "../substrates/local/runtime-config.js";
53
+ import { isRecord } from "../run/type-guards.js";
50
54
  import { compositionReason } from "./composition-rules.js";
51
55
  import { findUnknownLabKey } from "./keys.js";
52
56
  import { parseActors, rosterOf } from "./parse/actors.js";
53
57
  import { parseComms, recipientParticipantId } from "./parse/comms.js";
54
58
  import { parseDefaults, parseExecution, parsePersonas, parsePolicies, parseReview, parseScenario, } from "./parse/execution.js";
59
+ import { studySpelling, studyToV2 } from "./parse/study-v3.js";
55
60
  import { parseSubject } from "./parse/subject.js";
56
- import { invalid, isRecord, optionalStr, str } from "./parse/values.js";
57
- import { isComputerUseComposition, isSharedWorldComposition } from "./routing.js";
61
+ import { invalid, optionalStr, str } from "./parse/values.js";
62
+ import { isComputerUseComposition, isSharedWorldComposition, routeOf } from "./routing.js";
58
63
  import { declaredParticipantIds } from "./plan-participants.js";
59
- import { ID_PATTERN, LAB_CONFIG_SCHEMA, } from "./types.js";
64
+ import { ID_PATTERN, LAB_CONFIG_SCHEMA, STUDY_SCHEMA, } from "./types.js";
60
65
  import { automaticAnalysisRouteReason, desktopMediaValidationReason, outputTokenLimitValidationReason, receivingEmailValidationReason, scenarioCapsValidationReason, taskProtocolValidationReason, } from "./validation.js";
61
- import { forwardDeclaredWarnings } from "./warnings.js";
66
+ import { forwardDeclaredWarnings, inertFieldLabels } from "./warnings.js";
62
67
  /**
63
68
  * Validate a parsed YAML object into a LabConfig. Pure: the caller owns file IO. Structural
64
69
  * validation only. Fields the engine does not yet consume are accepted but reported in
@@ -68,9 +73,41 @@ export function parseLabConfig(raw) {
68
73
  if (!isRecord(raw)) {
69
74
  return invalid("Lab manifest must be a YAML object.");
70
75
  }
76
+ if (raw.schema === STUDY_SCHEMA)
77
+ return parseStudy(raw);
71
78
  if (raw.schema !== LAB_CONFIG_SCHEMA) {
72
- return invalid(`Lab schema must be ${LAB_CONFIG_SCHEMA}.`);
79
+ return invalid(`Lab schema must be ${STUDY_SCHEMA} or ${LAB_CONFIG_SCHEMA}.`);
73
80
  }
81
+ return parseV2(raw);
82
+ }
83
+ /**
84
+ * A v3 study parses through the v2 parser, then must take the route it declares and set no field
85
+ * that route does not read. A v2 file gets those fields as a warning instead.
86
+ */
87
+ function parseStudy(raw) {
88
+ const document = studyToV2(raw);
89
+ if (!document.ok)
90
+ return document;
91
+ const { route, v2, participantSource } = document.value;
92
+ const spell = (message) => studySpelling(message, route, participantSource);
93
+ const parsed = parseV2(v2);
94
+ if (!parsed.ok)
95
+ return invalid(spell(parsed.error.message));
96
+ const taken = routeOf(parsed.config);
97
+ if (taken !== route) {
98
+ return invalid(`This study declares route: ${route}, but its subject (source: ${parsed.config.subject.source}) and actor (type: ${parsed.config.actors[0]?.type}) take the ${taken} route. Change \`route\`, or change the subject or actor.`);
99
+ }
100
+ const inert = inertFieldLabels(parsed.config);
101
+ if (inert.length > 0) {
102
+ return invalid(spell(`route: ${route} does not read ${inert.join(", ")}. Remove ${inert.length === 1 ? "it" : "them"}.`));
103
+ }
104
+ return {
105
+ ok: true,
106
+ config: { ...parsed.config, schema: STUDY_SCHEMA },
107
+ warnings: parsed.warnings.map(spell),
108
+ };
109
+ }
110
+ function parseV2(raw) {
74
111
  const unknownKey = findUnknownLabKey(raw);
75
112
  if (unknownKey)
76
113
  return invalid(unknownKey);
@@ -148,11 +185,12 @@ export function parseLabConfig(raw) {
148
185
  const scenarioCapsReason = scenarioCapsValidationReason(config);
149
186
  if (scenarioCapsReason)
150
187
  return invalid(scenarioCapsReason);
151
- // All-parallel default (#350): a multi-seat lab that does not declare execution.concurrency runs
152
- // every seat at once; the declared field is a cap the author chose, never a mode. Independent
153
- // computer-use lanes resolve that default from the final seat count when they plan, after any
154
- // --count override, so the parser leaves it unset for them. A shared world's roster is fixed, so
155
- // its default is filled here for the envelopes and warnings that read the parsed config.
188
+ // All-parallel default: a multi-participant study that does not declare execution.concurrency
189
+ // runs every participant at once; the declared field is a cap the author chose, never a mode.
190
+ // Independent computer-use participants resolve that default from the final participant count
191
+ // when they plan, after any --count override, so the parser leaves it unset for them. A shared
192
+ // world's roster is fixed, so its default is filled here for the envelopes and warnings that read
193
+ // the parsed config.
156
194
  {
157
195
  const participantCount = rosterOf(config.actors[0])?.length ?? config.actors[0]?.count ?? 1;
158
196
  if (participantCount > 1 &&
@@ -161,12 +199,12 @@ export function parseLabConfig(raw) {
161
199
  config.execution = { ...config.execution, concurrency: participantCount };
162
200
  }
163
201
  }
164
- // Email that just works (#351): the funnel's ONLY handoff to an actor is the per-lane inbox
165
- // instruction, gated on recipients[]. Guessed lane names broke a field run — recipients copied
166
- // from a single-lane example matched nothing, so every actor was left inbox-blind with zero
167
- // signal. Omitted recipients are therefore FILLED (one deterministic address per lane); a
168
- // recipient naming an unknown lane is a hard error listing the real lane ids; declared
169
- // recipients covering zero lanes are a hard error (a guaranteed-dead funnel).
202
+ // Email that just works: the funnel's only handoff to an actor is the per-participant
203
+ // inbox instruction, gated on recipients[]. Guessed participant ids broke a field run:
204
+ // recipients copied from a single-participant example matched nothing, so every actor was left inbox-blind with zero
205
+ // signal. Omitted recipients are therefore filled (one deterministic address per participant);
206
+ // a recipient naming an unknown participant is a hard error listing the real ids; declared
207
+ // recipients covering zero participants are a hard error (a guaranteed-dead funnel).
170
208
  const receivingReason = receivingEmailValidationReason(config);
171
209
  if (receivingReason)
172
210
  return invalid(receivingReason);
@@ -204,5 +242,9 @@ export function parseLabConfig(raw) {
204
242
  if (reason)
205
243
  return invalid(reason);
206
244
  }
207
- return { ok: true, config: normalized, warnings: forwardDeclaredWarnings(normalized) };
245
+ return {
246
+ ok: true,
247
+ config: normalized,
248
+ warnings: forwardDeclaredWarnings(normalized),
249
+ };
208
250
  }
@@ -0,0 +1,10 @@
1
+ /** One deprecated field: what to read instead, and how to compute the old value. */
2
+ export interface DeprecatedField {
3
+ readonly replacement: string;
4
+ readonly read: () => unknown;
5
+ }
6
+ /** Adds `fields` to `value` as warning getters and returns `value`. */
7
+ export declare function withDeprecatedFields<T extends object>(value: T, owner: {
8
+ readonly name: string;
9
+ readonly code: `HUMANISH_${string}`;
10
+ }, fields: Readonly<Record<string, DeprecatedField>>): T;
@@ -0,0 +1,24 @@
1
+ // Deprecated fields on a value humanish hands to a caller. Each is a getter that warns once per
2
+ // process when read. The getters are not enumerable, so a spread, `Object.assign`,
3
+ // `JSON.stringify` or `structuredClone` of the value skips them and warns about no field the
4
+ // caller never named; `"name" in value` still finds them. Core never reads them.
5
+ const warned = new Set();
6
+ /** Adds `fields` to `value` as warning getters and returns `value`. */
7
+ export function withDeprecatedFields(value, owner, fields) {
8
+ return Object.defineProperties(value, Object.fromEntries(Object.entries(fields).map(([field, { replacement, read }]) => [
9
+ field,
10
+ {
11
+ enumerable: false,
12
+ get: () => {
13
+ warnOnce(`${owner.name}.${field}`, replacement, owner.code);
14
+ return read();
15
+ },
16
+ },
17
+ ])));
18
+ }
19
+ function warnOnce(name, replacement, code) {
20
+ if (warned.has(name))
21
+ return;
22
+ warned.add(name);
23
+ process.emitWarning(`${name} is deprecated and is removed in the next minor. Use ${replacement}.`, { type: "DeprecationWarning", code });
24
+ }
@@ -4,9 +4,9 @@ export interface DevicePreset {
4
4
  width: number;
5
5
  /** Requested device height, used for the hosted physical screen. */
6
6
  height: number;
7
- /** Mobile identity; enables emulation only when the hosted lane explicitly opts in. */
7
+ /** Mobile identity; enables emulation only when the hosted participant explicitly opts in. */
8
8
  isMobile: boolean;
9
- /** Requested DPR; applied on hosted mobile lanes only with opt-in CDP emulation. */
9
+ /** Requested DPR; applied on hosted mobile participants only with opt-in CDP emulation. */
10
10
  deviceScaleFactor: number;
11
11
  }
12
12
  /**
@@ -55,7 +55,7 @@ export declare const DEVICE_PRESETS: {
55
55
  export type DevicePresetName = keyof typeof DEVICE_PRESETS;
56
56
  /**
57
57
  * Default device for a run that does not declare one. `desktop` (1440x950) is the median
58
- * first-run laptop screen — the in-house desktop default, within 10px of the 1440x960 dry-run
58
+ * first-run laptop screen, the in-house desktop default, within 10px of the 1440x960 dry-run
59
59
  * surface in src/run/dry-run.ts. `wide` (1920x1080), the most-common external monitor, is one
60
60
  * keystroke away (`execution.desktop.device: wide`) but is deliberately not the default,
61
61
  * because the median device a first-time user arrives on is a laptop, not a 1080p monitor.
@@ -67,22 +67,22 @@ export declare function isDevicePresetName(value: unknown): value is DevicePrese
67
67
  /** Resolve a preset name (or undefined) to its preset, falling back to the default. */
68
68
  export declare function resolveDevicePreset(name: DevicePresetName | undefined): DevicePreset;
69
69
  /**
70
- * The narrowest browser WINDOW Chrome/Chromium will render on the E2B desktop. Chrome refuses to
70
+ * The narrowest browser window Chrome/Chromium will render on the E2B desktop. Chrome refuses to
71
71
  * make its window narrower than this (~500 CSS px observed: a 414-wide X screen produced a 500-wide
72
- * window that OVERFLOWED it, clipping the right edge of the page off-screen). So the physically
73
- * RENDERED screen width is floored here: a sub-500 mobile preset (mobile 414, small-mobile 360,
74
- * narrow-mobile 320) gets a 500-wide screen the window fits exactly — no clip. The device PRESET keeps
72
+ * window that overflowed it, clipping the right edge of the page off-screen). So the physically
73
+ * rendered screen width is floored here: a sub-500 mobile preset (mobile 414, small-mobile 360,
74
+ * narrow-mobile 320) gets a 500-wide screen the window fits exactly, with no clip. The device preset keeps
75
75
  * its true identity (isMobile, nominal width) for the persona prompt + metadata; only the rendered
76
76
  * screen is floored. True sub-500 CSS-viewport rendering (page laid out at 414 regardless of window
77
- * width, via CDP device-metric emulation) is the separate #221 upgrade.
77
+ * width, via CDP device-metric emulation) is the separate mobileEmulation option.
78
78
  */
79
79
  export declare const MIN_DESKTOP_RENDER_WIDTH = 500;
80
- /** Floor a screen resolution's WIDTH to what Chrome can actually render (see MIN_DESKTOP_RENDER_WIDTH). */
80
+ /** Floor a screen resolution's width to what Chrome can actually render (see MIN_DESKTOP_RENDER_WIDTH). */
81
81
  export declare function floorRenderResolution(resolution: readonly [number, number]): [number, number];
82
82
  /**
83
83
  * Resolve a participant's device + rendered resolution (most-specific wins, exactly as the
84
84
  * single-participant path always has): a raw execution.desktop.resolution escape hatch (only legal
85
- * when no roster entry sets a device — XOR enforced at parse) → the participant's named device → the run-wide
85
+ * when no roster entry sets a device; XOR enforced at parse) → the participant's named device → the run-wide
86
86
  * execution.desktop.device → the default preset. A raw resolution is an unnamed custom desktop
87
87
  * (non-mobile, DSF 1): we never claim a named preset's mobile/DPR for hand-set geometry. The rendered
88
88
  * `resolution` is floored to MIN_DESKTOP_RENDER_WIDTH so the browser window fits its X screen (no clip);