humanish 0.106.1 → 0.107.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. package/AGENTS.md +4 -4
  2. package/ARCHITECTURE.md +17 -16
  3. package/CHANGELOG.md +14 -0
  4. package/CONTEXT.md +42 -39
  5. package/CONTRIBUTING.md +8 -8
  6. package/README.md +8 -3
  7. package/dist/actors/codex/app-server-client.js +2 -1
  8. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  9. package/dist/actors/codex/app-server-trace.js +1 -3
  10. package/dist/actors/codex/app-server.js +2 -1
  11. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  12. package/dist/actors/codex/protocol-compat.js +357 -0
  13. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  14. package/dist/actors/codex/protocol-contract.js +471 -0
  15. package/dist/actors/codex/qualified-versions.d.ts +30 -3
  16. package/dist/actors/codex/qualified-versions.js +50 -5
  17. package/dist/actors/codex/restricted-executable.d.ts +24 -0
  18. package/dist/actors/codex/restricted-executable.js +97 -22
  19. package/dist/actors/codex/restricted-launch.d.ts +7 -1
  20. package/dist/actors/codex/restricted-launch.js +42 -3
  21. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  22. package/dist/actors/codex/restricted-notifications.js +277 -0
  23. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  24. package/dist/actors/codex/restricted-participant.js +60 -2
  25. package/dist/actors/codex/restricted-policy.d.ts +9 -1
  26. package/dist/actors/codex/restricted-session.d.ts +14 -1
  27. package/dist/actors/codex/restricted-session.js +50 -17
  28. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  29. package/dist/actors/codex/restricted-transport.js +139 -27
  30. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  31. package/dist/actors/codex/restricted-turn.js +43 -30
  32. package/dist/actors/computer-use/actor.d.ts +1 -1
  33. package/dist/actors/computer-use/actor.js +4 -4
  34. package/dist/actors/computer-use/loop/backstop.js +1 -1
  35. package/dist/actors/computer-use/loop/ending.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/ending.js +2 -2
  37. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/spend.js +3 -3
  39. package/dist/actors/computer-use/loop/trace.js +2 -2
  40. package/dist/actors/computer-use/loop/types.d.ts +14 -5
  41. package/dist/actors/computer-use/loop.js +4 -4
  42. package/dist/actors/computer-use/openai-provider.d.ts +1 -1
  43. package/dist/actors/computer-use/openai-provider.js +2 -2
  44. package/dist/actors/contract.d.ts +9 -7
  45. package/dist/actors/local-agent/cli.js +1 -1
  46. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  47. package/dist/actors/scripted-browser/journey.js +15 -4
  48. package/dist/actors/scripted-browser/steps.js +18 -0
  49. package/dist/actors/scripted-browser/types.d.ts +11 -1
  50. package/dist/actors/stop-conditions.js +1 -3
  51. package/dist/analysis/automatic-completion.d.ts +13 -8
  52. package/dist/analysis/automatic-completion.js +14 -8
  53. package/dist/analysis/automatic-config.d.ts +1 -1
  54. package/dist/analysis/automatic-config.js +2 -2
  55. package/dist/analysis/automatic.d.ts +10 -4
  56. package/dist/analysis/automatic.js +17 -13
  57. package/dist/analysis/diagnostics.d.ts +23 -0
  58. package/dist/analysis/diagnostics.js +112 -0
  59. package/dist/analysis/evidence-sources.js +2 -2
  60. package/dist/analysis/evidence.js +6 -6
  61. package/dist/analysis/execute.d.ts +7 -1
  62. package/dist/analysis/execute.js +39 -12
  63. package/dist/analysis/job.d.ts +8 -5
  64. package/dist/analysis/job.js +15 -14
  65. package/dist/analysis/load.d.ts +1 -1
  66. package/dist/analysis/load.js +5 -5
  67. package/dist/analysis/provider.d.ts +9 -1
  68. package/dist/analysis/restricted-codex.d.ts +2 -0
  69. package/dist/analysis/restricted-codex.js +10 -1
  70. package/dist/analysis/service.d.ts +2 -0
  71. package/dist/analysis/service.js +31 -12
  72. package/dist/analysis/sharing.d.ts +2 -2
  73. package/dist/analysis/sharing.js +5 -5
  74. package/dist/analysis/store-executions.d.ts +5 -5
  75. package/dist/analysis/store-executions.js +12 -12
  76. package/dist/analysis/store.d.ts +4 -4
  77. package/dist/analysis/store.js +13 -13
  78. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  79. package/dist/cli/commands/analysis-signals.js +4 -1
  80. package/dist/cli/commands/analyze.js +4 -2
  81. package/dist/cli/commands/comms.js +8 -1
  82. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  83. package/dist/cli/commands/lab-route-computer-use.js +26 -14
  84. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  85. package/dist/cli/commands/lab-route-preview.js +3 -4
  86. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  87. package/dist/cli/commands/lab-route-run.js +6 -2
  88. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  89. package/dist/cli/commands/lab-route-scripted.js +0 -1
  90. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  91. package/dist/cli/commands/lab-route-shared-world.js +0 -1
  92. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  93. package/dist/cli/commands/lab-route-terminal.js +0 -1
  94. package/dist/cli/commands/lab-run.js +76 -45
  95. package/dist/cli/commands/lab-scorer.d.ts +0 -2
  96. package/dist/cli/commands/lab.js +12 -6
  97. package/dist/cli/commands/observe.js +22 -0
  98. package/dist/cli/commands/run-signals.d.ts +30 -0
  99. package/dist/cli/commands/run-signals.js +146 -0
  100. package/dist/cli/commands/runs.js +10 -8
  101. package/dist/cli/commands/watch.js +12 -10
  102. package/dist/cli/doctor.d.ts +3 -0
  103. package/dist/cli/doctor.js +10 -2
  104. package/dist/cli/io.d.ts +5 -4
  105. package/dist/cli/io.js +12 -8
  106. package/dist/cli/program.js +3 -3
  107. package/dist/cli/renamed-options.d.ts +11 -0
  108. package/dist/cli/renamed-options.js +18 -0
  109. package/dist/cli/telemetry.d.ts +2 -2
  110. package/dist/cli/telemetry.js +1 -1
  111. package/dist/comms/capture-surface.d.ts +1 -1
  112. package/dist/comms/catch-host.d.ts +1 -1
  113. package/dist/comms/connections.js +4 -4
  114. package/dist/comms/external-evidence.d.ts +27 -0
  115. package/dist/comms/external-evidence.js +93 -0
  116. package/dist/comms/lease-store.js +7 -7
  117. package/dist/comms/types.js +1 -1
  118. package/dist/evidence/browser-hygiene.d.ts +1 -1
  119. package/dist/evidence/browser-hygiene.js +1 -1
  120. package/dist/evidence/redaction.js +1 -1
  121. package/dist/evidence/secret-scrub.d.ts +9 -0
  122. package/dist/evidence/secret-scrub.js +96 -0
  123. package/dist/feedback/draft.js +7 -9
  124. package/dist/feedback/export-bundle.js +4 -4
  125. package/dist/feedback/export.js +9 -9
  126. package/dist/feedback/feedback.d.ts +1 -1
  127. package/dist/index.d.ts +3 -6
  128. package/dist/index.js +3 -6
  129. package/dist/keys/key-resolution.d.ts +3 -1
  130. package/dist/keys/key-resolution.js +18 -16
  131. package/dist/lab/adapter-extension.d.ts +28 -6
  132. package/dist/lab/adapter-extension.js +65 -126
  133. package/dist/lab/adapter-scorer-loader.d.ts +25 -5
  134. package/dist/lab/adapter-scorer-loader.js +24 -0
  135. package/dist/lab/composition-rules.js +20 -20
  136. package/dist/lab/config.js +28 -26
  137. package/dist/lab/device-presets.d.ts +2 -2
  138. package/dist/lab/discover.js +1 -3
  139. package/dist/lab/doctor.d.ts +44 -9
  140. package/dist/lab/doctor.js +149 -41
  141. package/dist/lab/init-plan.js +1 -3
  142. package/dist/lab/keys.js +1 -1
  143. package/dist/lab/lab-deps.d.ts +85 -0
  144. package/dist/lab/lab-deps.js +4 -0
  145. package/dist/lab/parse/actors.js +8 -7
  146. package/dist/lab/parse/comms.js +3 -2
  147. package/dist/lab/parse/execution.js +3 -2
  148. package/dist/lab/parse/subject-state.js +2 -1
  149. package/dist/lab/parse/subject.js +2 -1
  150. package/dist/lab/parse/values.d.ts +0 -1
  151. package/dist/lab/parse/values.js +0 -3
  152. package/dist/lab/persona-resolve.d.ts +3 -3
  153. package/dist/lab/persona-resolve.js +4 -4
  154. package/dist/lab/persona.js +1 -3
  155. package/dist/lab/plan-base.d.ts +0 -2
  156. package/dist/lab/plan-base.js +6 -4
  157. package/dist/lab/plan-participants.d.ts +5 -5
  158. package/dist/lab/plan-participants.js +2 -2
  159. package/dist/lab/plan-types.d.ts +22 -4
  160. package/dist/lab/plan.d.ts +3 -11
  161. package/dist/lab/plan.js +18 -42
  162. package/dist/lab/preflight-result.js +0 -2
  163. package/dist/lab/preflight.d.ts +0 -3
  164. package/dist/lab/preflight.js +1 -1
  165. package/dist/lab/requirements.d.ts +20 -0
  166. package/dist/lab/requirements.js +54 -0
  167. package/dist/lab/route-inputs.d.ts +23 -12
  168. package/dist/lab/route-inputs.js +48 -51
  169. package/dist/lab/routing.d.ts +19 -24
  170. package/dist/lab/routing.js +14 -47
  171. package/dist/lab/run-lab-events.d.ts +6 -11
  172. package/dist/lab/run-lab-events.js +3 -11
  173. package/dist/lab/run-lab-homes.d.ts +64 -0
  174. package/dist/lab/run-lab-homes.js +3 -0
  175. package/dist/lab/run-lab-options.d.ts +12 -66
  176. package/dist/lab/run-lab-options.js +45 -275
  177. package/dist/lab/summary.d.ts +9 -4
  178. package/dist/lab/summary.js +15 -8
  179. package/dist/lab/types.d.ts +132 -132
  180. package/dist/lab/validation.d.ts +15 -15
  181. package/dist/lab/validation.js +28 -28
  182. package/dist/lab/warnings.js +20 -19
  183. package/dist/observer/artifact.d.ts +1 -1
  184. package/dist/observer/artifact.js +3 -3
  185. package/dist/observer/data.js +2 -2
  186. package/dist/observer/render.js +2 -2
  187. package/dist/observer/run-routes.d.ts +1 -1
  188. package/dist/observer/run-routes.js +5 -5
  189. package/dist/observer/serve.d.ts +17 -0
  190. package/dist/observer/serve.js +34 -3
  191. package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
  192. package/dist/routes/computer-use/bundle-parts.js +10 -3
  193. package/dist/routes/computer-use/bundle.d.ts +4 -11
  194. package/dist/routes/computer-use/bundle.js +9 -15
  195. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  196. package/dist/routes/computer-use/diagnostics.js +1 -1
  197. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
  198. package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
  199. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  200. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
  201. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
  202. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
  203. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  204. package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
  205. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  206. package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
  207. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  208. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  209. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  210. package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
  211. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  212. package/dist/routes/computer-use/external-comms.js +19 -43
  213. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  214. package/dist/routes/computer-use/fanout-bundle.js +25 -29
  215. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
  216. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  217. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  218. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  219. package/dist/routes/computer-use/live-flush.js +19 -27
  220. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +12 -11
  221. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  222. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  223. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  224. package/dist/routes/computer-use/local-vm.js +39 -66
  225. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  226. package/dist/routes/computer-use/participant-desktop.js +5 -25
  227. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
  228. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
  229. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  230. package/dist/routes/computer-use/participant-facts.js +12 -1
  231. package/dist/routes/computer-use/participant-model.d.ts +19 -11
  232. package/dist/routes/computer-use/participant-model.js +49 -25
  233. package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
  234. package/dist/routes/computer-use/participant-prompt.js +4 -4
  235. package/dist/routes/computer-use/participant-runs.d.ts +6 -6
  236. package/dist/routes/computer-use/participant-runs.js +8 -8
  237. package/dist/routes/computer-use/plan.d.ts +21 -29
  238. package/dist/routes/computer-use/plan.js +52 -60
  239. package/dist/routes/computer-use/preflight.d.ts +3 -5
  240. package/dist/routes/computer-use/preflight.js +20 -16
  241. package/dist/routes/computer-use/rerun-selection.js +10 -6
  242. package/dist/routes/computer-use/result.d.ts +1 -1
  243. package/dist/routes/computer-use/result.js +40 -30
  244. package/dist/routes/computer-use/route.d.ts +3 -4
  245. package/dist/routes/computer-use/route.js +21 -19
  246. package/dist/routes/computer-use/self-report.d.ts +2 -2
  247. package/dist/routes/computer-use/self-report.js +4 -4
  248. package/dist/routes/computer-use/setup.d.ts +8 -14
  249. package/dist/routes/computer-use/setup.js +96 -72
  250. package/dist/routes/computer-use/single-bundle.d.ts +8 -11
  251. package/dist/routes/computer-use/single-bundle.js +20 -25
  252. package/dist/routes/computer-use/subject-projection.d.ts +5 -7
  253. package/dist/routes/computer-use/subject-projection.js +20 -19
  254. package/dist/routes/computer-use/types.d.ts +169 -210
  255. package/dist/routes/computer-use/types.js +13 -5
  256. package/dist/routes/preview.js +0 -1
  257. package/dist/routes/scripted/bundle.d.ts +3 -6
  258. package/dist/routes/scripted/bundle.js +11 -16
  259. package/dist/routes/scripted/plan.d.ts +5 -7
  260. package/dist/routes/scripted/plan.js +6 -4
  261. package/dist/routes/scripted/result.d.ts +4 -1
  262. package/dist/routes/scripted/result.js +10 -6
  263. package/dist/routes/scripted/route.js +10 -11
  264. package/dist/routes/scripted/scenario.d.ts +1 -1
  265. package/dist/routes/scripted/scenario.js +1 -1
  266. package/dist/routes/scripted/setup.d.ts +3 -2
  267. package/dist/routes/scripted/setup.js +22 -21
  268. package/dist/routes/scripted/subject.d.ts +8 -3
  269. package/dist/routes/scripted/subject.js +9 -5
  270. package/dist/routes/scripted/surface-records.js +1 -1
  271. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  272. package/dist/routes/scripted/surface-sessions.js +4 -4
  273. package/dist/routes/scripted/types.d.ts +19 -36
  274. package/dist/routes/scripted/types.js +1 -2
  275. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
  276. package/dist/routes/shared-world/bundle.d.ts +2 -2
  277. package/dist/routes/shared-world/bundle.js +22 -26
  278. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  279. package/dist/routes/shared-world/checkpoints.js +4 -4
  280. package/dist/routes/shared-world/comms.d.ts +5 -4
  281. package/dist/routes/shared-world/comms.js +28 -41
  282. package/dist/routes/shared-world/external-public.d.ts +5 -5
  283. package/dist/routes/shared-world/external-public.js +19 -20
  284. package/dist/routes/shared-world/handoff.d.ts +4 -4
  285. package/dist/routes/shared-world/handoff.js +50 -50
  286. package/dist/routes/shared-world/lobby-code.d.ts +5 -5
  287. package/dist/routes/shared-world/lobby-code.js +13 -13
  288. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
  289. package/dist/routes/shared-world/{seats.js → participant-specs.js} +43 -48
  290. package/dist/routes/shared-world/plan.d.ts +2 -6
  291. package/dist/routes/shared-world/plan.js +1 -2
  292. package/dist/routes/shared-world/provenance.d.ts +4 -4
  293. package/dist/routes/shared-world/provenance.js +4 -4
  294. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  295. package/dist/routes/shared-world/provisioned.js +46 -40
  296. package/dist/routes/shared-world/result.js +31 -19
  297. package/dist/routes/shared-world/route.js +37 -41
  298. package/dist/routes/shared-world/setup.d.ts +5 -4
  299. package/dist/routes/shared-world/setup.js +12 -14
  300. package/dist/routes/shared-world/types.d.ts +53 -126
  301. package/dist/routes/shared-world/types.js +2 -2
  302. package/dist/routes/terminal/adapter.d.ts +8 -8
  303. package/dist/routes/terminal/adapter.js +28 -125
  304. package/dist/routes/terminal/bundle.d.ts +7 -12
  305. package/dist/routes/terminal/bundle.js +24 -34
  306. package/dist/routes/terminal/credentials.d.ts +2 -2
  307. package/dist/routes/terminal/credentials.js +16 -16
  308. package/dist/routes/terminal/dry-run.d.ts +1 -1
  309. package/dist/routes/terminal/dry-run.js +9 -11
  310. package/dist/routes/terminal/encoding.d.ts +1 -1
  311. package/dist/routes/terminal/encoding.js +2 -2
  312. package/dist/routes/terminal/ledger.d.ts +6 -6
  313. package/dist/routes/terminal/ledger.js +9 -9
  314. package/dist/routes/terminal/live-finish.d.ts +1 -2
  315. package/dist/routes/terminal/live-finish.js +21 -20
  316. package/dist/routes/terminal/live-sandbox.d.ts +3 -2
  317. package/dist/routes/terminal/live-sandbox.js +20 -20
  318. package/dist/routes/terminal/participant-text.d.ts +23 -0
  319. package/dist/routes/terminal/participant-text.js +165 -0
  320. package/dist/routes/terminal/plan.d.ts +2 -6
  321. package/dist/routes/terminal/plan.js +13 -9
  322. package/dist/routes/terminal/recorder.d.ts +6 -1
  323. package/dist/routes/terminal/recorder.js +12 -4
  324. package/dist/routes/terminal/result.js +4 -4
  325. package/dist/routes/terminal/route.js +26 -26
  326. package/dist/routes/terminal/runtime.d.ts +3 -2
  327. package/dist/routes/terminal/runtime.js +3 -3
  328. package/dist/routes/terminal/sandbox.d.ts +3 -3
  329. package/dist/routes/terminal/sandbox.js +9 -9
  330. package/dist/routes/terminal/session.js +16 -14
  331. package/dist/routes/terminal/token-usage.js +5 -5
  332. package/dist/routes/terminal/trace.d.ts +5 -8
  333. package/dist/routes/terminal/trace.js +9 -64
  334. package/dist/routes/terminal/types.d.ts +85 -93
  335. package/dist/routes/terminal/types.js +9 -4
  336. package/dist/run/active-runs.d.ts +13 -0
  337. package/dist/run/active-runs.js +12 -0
  338. package/dist/run/bundle-shape.d.ts +2 -1
  339. package/dist/run/bundle-shape.js +4 -4
  340. package/dist/run/bundle.d.ts +63 -56
  341. package/dist/run/bundle.js +9 -8
  342. package/dist/run/cost-summary.js +3 -2
  343. package/dist/run/costs.d.ts +6 -6
  344. package/dist/run/costs.js +10 -10
  345. package/dist/run/detail.d.ts +5 -5
  346. package/dist/run/detail.js +6 -6
  347. package/dist/run/dry-run.js +5 -12
  348. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  349. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  350. package/dist/run/feedback-shape.js +1 -1
  351. package/dist/run/judge.d.ts +16 -4
  352. package/dist/run/judge.js +24 -7
  353. package/dist/run/locate.d.ts +2 -0
  354. package/dist/run/locate.js +3 -1
  355. package/dist/run/outcomes.d.ts +3 -3
  356. package/dist/run/outcomes.js +3 -3
  357. package/dist/run/participant-records.d.ts +2 -2
  358. package/dist/run/participant-records.js +2 -2
  359. package/dist/run/paths.js +1 -1
  360. package/dist/run/pricing.d.ts +19 -9
  361. package/dist/run/pricing.js +30 -18
  362. package/dist/run/projection.d.ts +13 -13
  363. package/dist/run/projection.js +8 -8
  364. package/dist/run/reclaim.d.ts +6 -0
  365. package/dist/run/reclaim.js +13 -3
  366. package/dist/run/results.d.ts +1 -1
  367. package/dist/run/run-index.d.ts +1 -1
  368. package/dist/run/run-index.js +11 -11
  369. package/dist/run/run.d.ts +4 -2
  370. package/dist/run/run.js +9 -5
  371. package/dist/run/sandbox-receipts.d.ts +4 -4
  372. package/dist/run/sandbox-receipts.js +4 -4
  373. package/dist/run/shared-world-evidence.d.ts +47 -47
  374. package/dist/run/shared-world-shape.d.ts +3 -3
  375. package/dist/run/shared-world-shape.js +11 -11
  376. package/dist/run/stats.d.ts +5 -5
  377. package/dist/run/stats.js +8 -8
  378. package/dist/run/status.d.ts +16 -6
  379. package/dist/run/status.js +31 -8
  380. package/dist/run/streams.d.ts +26 -19
  381. package/dist/run/terminal-contract.d.ts +5 -5
  382. package/dist/run/terminal-contract.js +4 -4
  383. package/dist/run/transient-comms-secrets.d.ts +5 -0
  384. package/dist/run/transient-comms-secrets.js +12 -0
  385. package/dist/run-lab.d.ts +36 -34
  386. package/dist/run-lab.js +41 -37
  387. package/dist/subject/desktop-cli.d.ts +1 -1
  388. package/dist/subject/desktop-cli.js +1 -1
  389. package/dist/subject/local-tree-archive.d.ts +1 -1
  390. package/dist/subject/local-tree-archive.js +4 -4
  391. package/dist/subject/local-tree.d.ts +2 -2
  392. package/dist/subject/local-tree.js +1 -1
  393. package/dist/subject/node-bootstrap.d.ts +1 -1
  394. package/dist/subject/node-bootstrap.js +4 -4
  395. package/dist/subject/runtime.js +5 -5
  396. package/dist/subject/serve.js +1 -1
  397. package/dist/subject/steps.d.ts +4 -4
  398. package/dist/subject/steps.js +5 -5
  399. package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
  400. package/dist/substrates/e2b/cdp-probe.js +1 -1
  401. package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
  402. package/dist/substrates/e2b/desktop-browser.js +4 -4
  403. package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
  404. package/dist/substrates/e2b/desktop-cdp.js +4 -4
  405. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  406. package/dist/substrates/e2b/desktop-geometry.js +3 -3
  407. package/dist/substrates/e2b/desktop-media.js +2 -2
  408. package/dist/substrates/e2b/sandbox.js +1 -1
  409. package/dist/substrates/e2b/sdk.js +2 -2
  410. package/dist/substrates/local/runtime-host.d.ts +2 -0
  411. package/dist/substrates/local/runtime-host.js +6 -0
  412. package/dist/tui/actions.d.ts +7 -5
  413. package/dist/tui/actions.js +18 -9
  414. package/dist/tui-app.js +42 -42
  415. package/dist/verify/actor.d.ts +10 -10
  416. package/dist/verify/actor.js +15 -15
  417. package/dist/verify/artifacts.d.ts +1 -1
  418. package/dist/verify/artifacts.js +3 -3
  419. package/dist/verify/costs.d.ts +2 -2
  420. package/dist/verify/costs.js +2 -2
  421. package/dist/verify/liveness.d.ts +1 -1
  422. package/dist/verify/liveness.js +4 -1
  423. package/dist/verify/rerun.d.ts +1 -1
  424. package/dist/verify/rerun.js +1 -1
  425. package/dist/verify/shared-world.js +2 -2
  426. package/dist/verify/verify.js +6 -6
  427. package/docs/README.md +1 -1
  428. package/docs/architecture/actor-contract.md +60 -22
  429. package/docs/architecture/desktop-sessions.md +9 -9
  430. package/docs/architecture/external-public-shared-world.md +5 -0
  431. package/docs/architecture/observer.md +4 -4
  432. package/docs/architecture/restricted-codex-analysis.md +36 -2
  433. package/docs/architecture/state-driven-executor.md +4 -5
  434. package/docs/architecture/task-protocol-support.md +3 -5
  435. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
  436. package/docs/contracts/run-bundle.md +10 -8
  437. package/docs/contracts/schemas.md +109 -53
  438. package/docs/contracts/study-analysis.md +24 -0
  439. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  440. package/docs/product/automatic-analysis.md +1 -0
  441. package/docs/ramp/README.md +2 -1
  442. package/package.json +4 -4
  443. package/skills/humanish/SKILL.md +3 -2
  444. package/skills/humanish/agents/openai.yaml +1 -1
  445. package/dist/deprecated.d.ts +0 -90
  446. package/dist/deprecated.js +0 -106
  447. package/dist/lab/bag-overrides.d.ts +0 -18
  448. package/dist/lab/bag-overrides.js +0 -121
  449. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  450. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  451. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  452. /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
  453. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -1,14 +1,51 @@
1
1
  import path from "node:path";
2
- import { isFeedbackIdempotencyKey } from "../run/feedback-shape.js";
2
+ import { isRunAdapterScore } from "../run/bundle-shape.js";
3
+ import { isRunFeedbackCandidate } from "../run/feedback-shape.js";
4
+ import { isRecord } from "../run/type-guards.js";
5
+ const OLDER_BACKEND = {
6
+ "computer-use": "cua",
7
+ "shared-world": "concurrent-shared-world",
8
+ };
9
+ const warnedFields = new Set();
10
+ function warnOlderField(name, replacement) {
11
+ if (warnedFields.has(name))
12
+ return;
13
+ warnedFields.add(name);
14
+ process.emitWarning(`BrowserLabScoringContext.${name} is deprecated and is removed in the next minor. Use ${replacement}.`, { type: "DeprecationWarning", code: "HUMANISH_SCORING_CONTEXT_FIELD_DEPRECATED" });
15
+ }
16
+ /**
17
+ * The scorer's context: the facts, plus the older `backend` and `laneCount` as getters that warn
18
+ * once when a scorer reads them. They are not enumerable, so a spread, `Object.assign`,
19
+ * `JSON.stringify` or `structuredClone` of the context skips them and warns about no field the
20
+ * code never named. `"backend" in ctx` still finds them. Core never reads them.
21
+ */
22
+ function scorerContext(facts) {
23
+ return Object.defineProperties({ ...facts }, {
24
+ backend: {
25
+ enumerable: false,
26
+ get: () => {
27
+ warnOlderField("backend", "route");
28
+ return OLDER_BACKEND[facts.route];
29
+ },
30
+ },
31
+ laneCount: {
32
+ enumerable: false,
33
+ get: () => {
34
+ warnOlderField("laneCount", "participantCount");
35
+ return facts.participantCount;
36
+ },
37
+ },
38
+ });
39
+ }
3
40
  /** A DECLARED scorer that returned a malformed value never rendered a verdict. */
4
41
  export const DECLARED_SCORER_MALFORMED = "Declared product scorer returned a malformed value instead of a verdict; a declared gate that cannot render a pass is recorded as a fail, never a silent pass.";
5
42
  /** A DECLARED scorer that threw never rendered a verdict. `detail` is already sanitized. */
6
43
  export function declaredScorerThrew(detail) {
7
44
  return `Declared product scorer threw before returning a verdict (${detail}); a crashed declared gate is recorded as a fail, never a silent pass.`;
8
45
  }
9
- export async function applyBrowserAdapterHooks(args) {
10
- const { hooks, context, bundle, sanitize, warnings, hookLabel, scorerProvenance } = args;
11
- if (!hooks?.score && !hooks?.deriveFeedback && !hooks?.deriveArtifacts)
46
+ export async function applyBrowserScorer(args) {
47
+ const { scorer, context, bundle, sanitize, warnings, scorerProvenance } = args;
48
+ if (!scorer?.score && !scorer?.deriveFeedback && !scorer?.deriveArtifacts)
12
49
  return { failures: [] };
13
50
  const declared = scorerProvenance !== undefined;
14
51
  // Record the loaded scorer's identity regardless of hook outcome (a throwing/invalid scorer was
@@ -19,78 +56,86 @@ export async function applyBrowserAdapterHooks(args) {
19
56
  // The scorer sees a READ-ONLY view of the bundle: it cannot mutate noSpend/cost/review in place to
20
57
  // launder a verdict (a tamper attempt throws in the scorer's strict-mode ESM and is caught below as
21
58
  // a hook failure). The seam still stamps the REAL bundle.
22
- const scoringContext = {
59
+ const scoringContext = scorerContext({
23
60
  ...context,
24
61
  bundle: frozenBundleView(context.bundle),
25
- };
62
+ });
26
63
  const scrubValue = (value) => {
27
64
  const encoded = JSON.stringify(value);
28
65
  return encoded === undefined ? value : JSON.parse(sanitize(encoded));
29
66
  };
30
67
  const failures = [];
31
- if (hooks.score) {
68
+ if (scorer?.score) {
32
69
  try {
33
- const score = await hooks.score(scoringContext);
70
+ const score = await scorer.score(scoringContext);
34
71
  const cleaned = scrubValue(score);
35
- if (isAdapterScoreShape(cleaned)) {
72
+ if (isRunAdapterScore(cleaned)) {
36
73
  bundle.adapterScore = cleaned;
37
74
  const message = adapterScoreFailureMessage(bundle);
38
75
  if (message !== undefined)
39
76
  failures.push(message);
40
77
  }
41
78
  else {
42
- warnings.push(`${hookLabel}.score returned a value that is not a well-formed humanish.adapter-score.v1 (non-empty namespace + status + numeric score + summary); dropped so the bundle stays verifiable.`);
79
+ warnings.push(`scorer.score returned a value that is not a well-formed humanish.adapter-score.v1 (non-empty namespace + status + numeric score + summary); dropped so the bundle stays verifiable.`);
43
80
  if (declared)
44
81
  failures.push(DECLARED_SCORER_MALFORMED);
45
82
  }
46
83
  }
47
84
  catch (error) {
48
85
  const detail = sanitize(error instanceof Error ? error.message : String(error));
49
- warnings.push(`${hookLabel}.score threw (${detail}); dropped so the bundle stays verifiable.`);
86
+ warnings.push(`scorer.score threw (${detail}); dropped so the bundle stays verifiable.`);
50
87
  if (declared)
51
88
  failures.push(declaredScorerThrew(detail));
52
89
  }
53
90
  }
54
- if (hooks.deriveFeedback) {
91
+ if (scorer?.deriveFeedback) {
55
92
  try {
56
- const candidates = await hooks.deriveFeedback(scoringContext);
93
+ const candidates = await scorer.deriveFeedback(scoringContext);
57
94
  const accepted = [];
58
95
  for (const candidate of Array.isArray(candidates) ? candidates : []) {
59
96
  const cleaned = scrubValue(candidate);
60
- if (isAdapterFeedbackCandidateShape(cleaned))
97
+ if (isAdapterFeedbackCandidate(cleaned))
61
98
  accepted.push(cleaned);
62
99
  else
63
- warnings.push(`${hookLabel}.deriveFeedback returned a candidate that is not a well-formed humanish.feedback-candidate.v1 (or its adapter block lacked a non-empty namespace + data record); dropped so the bundle stays verifiable.`);
100
+ warnings.push(`scorer.deriveFeedback returned a candidate that is not a well-formed humanish.feedback-candidate.v1 (or its adapter block lacked a non-empty namespace + data record); dropped so the bundle stays verifiable.`);
64
101
  }
65
102
  if (accepted.length > 0) {
66
103
  bundle.feedbackCandidates = [...bundle.feedbackCandidates, ...accepted];
67
104
  }
68
105
  }
69
106
  catch (error) {
70
- warnings.push(`${hookLabel}.deriveFeedback threw (${sanitize(error instanceof Error ? error.message : String(error))}); dropped so the bundle stays verifiable.`);
107
+ warnings.push(`scorer.deriveFeedback threw (${sanitize(error instanceof Error ? error.message : String(error))}); dropped so the bundle stays verifiable.`);
71
108
  }
72
109
  }
73
- if (hooks.deriveArtifacts) {
110
+ if (scorer?.deriveArtifacts) {
74
111
  try {
75
- const artifacts = await hooks.deriveArtifacts(scoringContext);
112
+ const artifacts = await scorer.deriveArtifacts(scoringContext);
76
113
  const accepted = [];
77
114
  for (const artifact of Array.isArray(artifacts) ? artifacts : []) {
78
115
  const cleaned = scrubValue(artifact);
79
116
  if (isAdapterArtifactShape(cleaned))
80
117
  accepted.push(cleaned);
81
118
  else
82
- warnings.push(`${hookLabel}.deriveArtifacts returned an artifact that is not a well-formed humanish.adapter-artifact.v1 (non-empty namespace + label + local path + supported kind); dropped so the bundle stays verifiable.`);
119
+ warnings.push(`scorer.deriveArtifacts returned an artifact that is not a well-formed humanish.adapter-artifact.v1 (non-empty namespace + label + local path + supported kind); dropped so the bundle stays verifiable.`);
83
120
  }
84
121
  if (accepted.length > 0) {
85
122
  bundle.adapterArtifacts = [...(bundle.adapterArtifacts ?? []), ...accepted];
86
123
  }
87
124
  }
88
125
  catch (error) {
89
- warnings.push(`${hookLabel}.deriveArtifacts threw (${sanitize(error instanceof Error ? error.message : String(error))}); dropped so the bundle stays verifiable.`);
126
+ warnings.push(`scorer.deriveArtifacts threw (${sanitize(error instanceof Error ? error.message : String(error))}); dropped so the bundle stays verifiable.`);
90
127
  }
91
128
  }
92
129
  return { failures };
93
130
  }
131
+ /**
132
+ * A feedback candidate a scorer returned, accepted at the seam: the bundle's candidate shape with a
133
+ * non-empty summary. The browser and terminal seams both use it, so a candidate either seam drops
134
+ * never reaches a bundle.
135
+ */
136
+ export function isAdapterFeedbackCandidate(value) {
137
+ return isRunFeedbackCandidate(value) && value.summary.trim().length > 0;
138
+ }
94
139
  export function adapterScoreFailureMessage(bundle) {
95
140
  return bundle.adapterScore?.status === "fail"
96
141
  ? `Adapter scorer failed the run: ${bundle.adapterScore.summary}`
@@ -115,62 +160,6 @@ export function frozenBundleView(bundle) {
115
160
  freeze(clone);
116
161
  return clone;
117
162
  }
118
- function isAdapterScoreShape(value) {
119
- return (typeof value === "object" &&
120
- value !== null &&
121
- !Array.isArray(value) &&
122
- value.schema === "humanish.adapter-score.v1" &&
123
- typeof value.namespace === "string" &&
124
- value.namespace.trim().length > 0 &&
125
- ["pass", "partial", "fail"].includes(value.status) &&
126
- typeof value.score === "number" &&
127
- Number.isFinite(value.score) &&
128
- typeof value.summary === "string" &&
129
- (value.data === undefined ||
130
- (typeof value.data === "object" &&
131
- value.data !== null &&
132
- !Array.isArray(value.data))));
133
- }
134
- function isAdapterFeedbackCandidateShape(value) {
135
- if (!isRecord(value))
136
- return false;
137
- const candidate = value;
138
- if (candidate.schema !== "humanish.feedback-candidate.v1" ||
139
- typeof candidate.id !== "string" ||
140
- typeof candidate.run_id !== "string" ||
141
- (candidate.stream_id !== undefined && typeof candidate.stream_id !== "string") ||
142
- typeof candidate.adapter_id !== "string" ||
143
- typeof candidate.scenario_id !== "string" ||
144
- typeof candidate.persona_id !== "string" ||
145
- !isFeedbackActor(candidate.actor) ||
146
- !isFeedbackSubstrate(candidate.substrate) ||
147
- !isFeedbackFailureOwner(candidate.failure_owner) ||
148
- typeof candidate.summary !== "string" ||
149
- candidate.summary.trim().length === 0 ||
150
- typeof candidate.expected !== "string" ||
151
- typeof candidate.actual !== "string" ||
152
- !Array.isArray(candidate.evidence) ||
153
- !candidate.evidence.every(isFeedbackEvidence) ||
154
- !isRecord(candidate.redaction) ||
155
- candidate.redaction.status !== "passed" ||
156
- typeof candidate.redaction.notes !== "string" ||
157
- !isFeedbackIdempotencyKey(candidate.idempotency_key) ||
158
- !isFeedbackNextState(candidate.proposed_next_state) ||
159
- !Array.isArray(candidate.acceptance_proof) ||
160
- !candidate.acceptance_proof.every((item) => typeof item === "string")) {
161
- return false;
162
- }
163
- if (candidate.adapter !== undefined) {
164
- const adapter = candidate.adapter;
165
- if (!isRecord(adapter) ||
166
- typeof adapter.namespace !== "string" ||
167
- adapter.namespace.trim().length === 0 ||
168
- !isRecord(adapter.data)) {
169
- return false;
170
- }
171
- }
172
- return true;
173
- }
174
163
  function isAdapterArtifactShape(value) {
175
164
  if (!isRecord(value))
176
165
  return false;
@@ -186,9 +175,6 @@ function isAdapterArtifactShape(value) {
186
175
  typeof artifact.note === "string" &&
187
176
  artifact.note.trim().length > 0);
188
177
  }
189
- function isRecord(value) {
190
- return typeof value === "object" && value !== null && !Array.isArray(value);
191
- }
192
178
  function isSafeRelativeArtifactPath(value) {
193
179
  return (value.trim().length > 0 &&
194
180
  !path.isAbsolute(value) &&
@@ -204,50 +190,3 @@ function isAdapterArtifactKind(value) {
204
190
  value === "filesystem" ||
205
191
  value === "summary");
206
192
  }
207
- function isFeedbackActor(value) {
208
- return (value === "codex-tui" ||
209
- value === "codex-exec" ||
210
- value === "codex-app-server" ||
211
- value === "computer-use" ||
212
- value === "synthetic-dry-run" ||
213
- value === "unknown");
214
- }
215
- function isFeedbackSubstrate(value) {
216
- return (value === "e2b-desktop" ||
217
- value === "local-desktop" ||
218
- value === "e2b-terminal" ||
219
- value === "local-filesystem" ||
220
- value === "codex-app-server" ||
221
- value === "unknown");
222
- }
223
- function isFeedbackFailureOwner(value) {
224
- return (value === "harness" ||
225
- value === "target-app" ||
226
- value === "actor" ||
227
- value === "environment" ||
228
- value === "unknown");
229
- }
230
- function isFeedbackNextState(value) {
231
- return (value === "watch" ||
232
- value === "adapter-hardening" ||
233
- value === "target-app-setup" ||
234
- value === "actor-auth" ||
235
- value === "setup-quality-review" ||
236
- value === "study-quality-review");
237
- }
238
- function isFeedbackEvidence(value) {
239
- if (!isRecord(value))
240
- return false;
241
- return (typeof value.path === "string" &&
242
- value.path.length > 0 &&
243
- !path.isAbsolute(value.path) &&
244
- !value.path.includes("://") &&
245
- !value.path.includes("..") &&
246
- (value.kind === "review" ||
247
- value.kind === "state" ||
248
- value.kind === "log" ||
249
- value.kind === "trace" ||
250
- value.kind === "screenshot" ||
251
- value.kind === "filesystem") &&
252
- typeof value.note === "string");
253
- }
@@ -3,20 +3,40 @@ import type { TerminalProductScoringContext } from "../routes/terminal/types.js"
3
3
  import type { LabRoute } from "./plan.js";
4
4
  import type { RunAdapterArtifact, RunAdapterScore, RunFeedbackCandidate, RunScorerProvenance } from "../run/bundle.js";
5
5
  /** The read-model context a loaded scorer sees — the terminal or browser scoring context. The module
6
- * narrows it at runtime (`"product" in ctx` ⇒ terminal; `"backend" in ctx` ⇒ browser). */
6
+ * narrows it at runtime (`"product" in ctx` ⇒ terminal; `"route" in ctx` ⇒ browser). */
7
7
  export type AdapterScoringContext = TerminalProductScoringContext | BrowserLabScoringContext;
8
8
  /**
9
9
  * The adopter-facing scorer module contract (#316). Export any subset of these from a `.mjs` (or a
10
10
  * `.js`/`.cjs` whose package.json type matches) — named exports OR a single default object. The
11
11
  * loader wires ONLY these three; an exported `executor`/`env`/`provisionSubject`/`costProbe` is never
12
12
  * picked up (the whitelist is the scope guard). A module exporting NONE of them is a hard load error.
13
+ *
14
+ * `C` is the context `score` and `deriveFeedback` read: `BrowserLabScoringContext` for a scorer
15
+ * written for computer use and shared world, `TerminalProductScoringContext` for one written for
16
+ * terminal runs, or the default union for one that narrows at runtime.
13
17
  */
14
- export interface AdapterScorerModule {
15
- score?: (ctx: AdapterScoringContext) => RunAdapterScore | Promise<RunAdapterScore>;
16
- deriveFeedback?: (ctx: AdapterScoringContext) => RunFeedbackCandidate[] | Promise<RunFeedbackCandidate[]>;
17
- /** Browser-route only; inert on the terminal route (TerminalProductLabHooks carries no artifacts seam). */
18
+ export interface AdapterScorerModule<C extends AdapterScoringContext = AdapterScoringContext> {
19
+ score?: (ctx: C) => RunAdapterScore | Promise<RunAdapterScore>;
20
+ deriveFeedback?: (ctx: C) => RunFeedbackCandidate[] | Promise<RunFeedbackCandidate[]>;
21
+ /** Browser-route only; inert on the terminal route, whose TerminalScorer has no artifacts seam. */
18
22
  deriveArtifacts?: (ctx: BrowserLabScoringContext) => RunAdapterArtifact[] | Promise<RunAdapterArtifact[]>;
19
23
  }
24
+ /**
25
+ * A scorer written for computer use and shared world, as `RunLabOptions.scorer` takes it. Those
26
+ * routes pass the browser context; another route that calls it passes a context it was not written
27
+ * for. The call states the kind, so the module itself needs no cast.
28
+ */
29
+ export declare function browserScorer(scorer: AdapterScorerModule<BrowserLabScoringContext>): AdapterScorerModule;
30
+ /** A scorer written for terminal runs, as `RunLabOptions.scorer` takes it (see browserScorer). */
31
+ export declare function terminalScorer(scorer: AdapterScorerModule<TerminalProductScoringContext>): AdapterScorerModule;
32
+ /**
33
+ * The scorer as a computer-use or shared-world run calls it, with the browser context. The caller
34
+ * chose the context it wrote the scorer for; only the route knows which context it passes, so the
35
+ * narrowing is here. A terminal-typed scorer on a browser route reads fields the context lacks.
36
+ */
37
+ export declare function browserRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<BrowserLabScoringContext>;
38
+ /** The scorer as a terminal run calls it, with the terminal context (see browserRouteScorer). */
39
+ export declare function terminalRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<TerminalProductScoringContext>;
20
40
  type AdapterScorerLoadErrorCode = "HUMANISH_LAB_SCORER_BAD_REF" | "HUMANISH_LAB_SCORER_NOT_FOUND" | "HUMANISH_LAB_SCORER_LOAD_FAILED" | "HUMANISH_LAB_SCORER_NO_HOOKS" | "HUMANISH_LAB_SCORER_UNSUPPORTED_BACKEND";
21
41
  export type AdapterScorerLoadResult = {
22
42
  ok: true;
@@ -19,6 +19,30 @@ import path from "node:path";
19
19
  import { pathToFileURL } from "node:url";
20
20
  import { digestText, redactText } from "../evidence/redaction.js";
21
21
  import { prepareSelectedOutputDirectory, readContainedRegularFile, } from "../run/contained-output.js";
22
+ /**
23
+ * A scorer written for computer use and shared world, as `RunLabOptions.scorer` takes it. Those
24
+ * routes pass the browser context; another route that calls it passes a context it was not written
25
+ * for. The call states the kind, so the module itself needs no cast.
26
+ */
27
+ export function browserScorer(scorer) {
28
+ return scorer;
29
+ }
30
+ /** A scorer written for terminal runs, as `RunLabOptions.scorer` takes it (see browserScorer). */
31
+ export function terminalScorer(scorer) {
32
+ return scorer;
33
+ }
34
+ /**
35
+ * The scorer as a computer-use or shared-world run calls it, with the browser context. The caller
36
+ * chose the context it wrote the scorer for; only the route knows which context it passes, so the
37
+ * narrowing is here. A terminal-typed scorer on a browser route reads fields the context lacks.
38
+ */
39
+ export function browserRouteScorer(scorer) {
40
+ return scorer;
41
+ }
42
+ /** The scorer as a terminal run calls it, with the terminal context (see browserRouteScorer). */
43
+ export function terminalRouteScorer(scorer) {
44
+ return scorer;
45
+ }
22
46
  /** The routes whose hooks bag can carry the loaded scorer. A declared scorer on ANY other route
23
47
  * (scripted or preview) aborts at load — a gate that cannot run must never green-pass. */
24
48
  const SCORER_CAPABLE_ROUTES = new Set([
@@ -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.
24
+ // Independent computer-use participants: the roster contract on every route that resolves to cua.
25
25
  (isComputerUseComposition(config) ? cuaLaneValidationReason(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) ??
@@ -45,12 +45,12 @@ 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
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
54
  // it fails closed in runCuaActorLab with HUMANISH_CUA_LAB_LOCAL_APP_NO_EXECUTOR.
55
55
  function localAppValidationReason(config) {
56
56
  if (config.subject.source === "local-app") {
@@ -73,7 +73,7 @@ function localAppValidationReason(config) {
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 lane
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) {
@@ -108,9 +108,9 @@ 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)];
@@ -178,7 +178,7 @@ function scriptedBrowserValidationReason(config) {
178
178
  return null;
179
179
  }
180
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
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" &&
@@ -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) {
@@ -218,7 +218,7 @@ function localTreeValidationReason(config) {
218
218
  }
219
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
221
+ // distinction is the population: terminal-product sends an autonomous agent
222
222
  // through a pipe with stdin disabled, which is the honest way to study what an agent meets and
223
223
  // structurally cannot study an interactive surface. This route sends someone who can see it.
224
224
  //
@@ -248,11 +248,11 @@ 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
251
+ // terminal-product route: a real autonomous agent studies a CLI/product from public surfaces
252
252
  // inside an E2B shell. Fail-closed (invariant 6 — a field that cannot act on this route is an
253
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.
254
+ // (absent defaults to e2b-terminal — the only honest target for an in-sandbox agent), one
255
+ // participant until fan-out lands.
256
256
  function terminalValidationReason(config) {
257
257
  if (config.subject.source === "terminal-product") {
258
258
  const type = config.actors[0]?.type ?? "";
@@ -267,7 +267,7 @@ 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
270
+ // e2b-terminal is the terminal-product substrate only. Any other source declaring it is a
271
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
  }
@@ -1,59 +1,61 @@
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
2
  //
3
- // HONEST SCOPE (read before trusting field names): the engine routes by
3
+ // Scope (read before trusting field names): the engine routes by
4
4
  // subject.source × execution.target (disambiguated by the actor lane where both axes
5
5
  // collide) and consumes a deliberately small set of fields:
6
6
  // subject.source/repos/appUrl/serve/env/state/clone.{depth,fanout,keep}, actors[0].count,
7
7
  // execution.target + execution.desktop.codexAppServer, scenario.mode,
8
8
  // policies.redactRepos, defaults.open.
9
9
  // 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
10
+ // computer-use actor), `actors[0].type` is load-bearing: it must resolve to a registered
11
11
  // computer-use actor, and that descriptor runs the session. Those routes also consume
12
12
  // actors[0].{mission,persona,laneFocus.instruction,model,reasoningEffort}, execution.timeoutMs,
13
13
  // execution.desktop.{browser,resolution,sandboxTimeoutMs}, and (clone)
14
14
  // subject.{serve,env,state,clone.depth}.
15
15
  // On the scripted-browser route (app-url × local-or-absent, or clone × e2b-desktop, with a
16
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
17
+ // consumes scenario.ref (required there, because the committed scenario's browser steps are what the
18
18
  // actor executes), actors[0].{persona,count}, and execution.timeoutMs. On the provisioned
19
19
  // clone slice it also consumes subject.{repos,serve,env,state,exposure,clone.depth} and
20
20
  // execution.desktop.template. actors[0].{mission,laneFocus,model} are inert on that route
21
21
  // because no model runs, and most execution.desktop.* fields remain forward-declared (device
22
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 —
23
+ // viewports where isMobile/DSF genuinely render via playwright emulation).
24
+ // On the other routes those fields remain forward-declared and are not yet consumed:
25
25
  // parseLabConfig emits a warning listing any such field that is set, so `lab inspect` shows
26
26
  // the truth.
27
27
  //
28
28
  // NOTE on actors[0].count: it now carries ROUTE-SPECIFIC meanings — synthetic route: simCount;
29
29
  // 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).
30
+ // defaults-table single-participant row governs; count: 2 is the declared override); computer-use
31
+ // E2B route: the homogeneous fan-out participant count (N identical participants, each its own E2B
32
+ // desktop), capped at 16; the in-process/local-app cua route stays single-participant (no E2B to
33
+ // fan out).
33
34
  //
34
35
  // 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
36
+ // differentiated fan-out roster: each `{ id?, persona?, device?, instruction?, target? }` becomes one
37
+ // independent E2B desktop (`per-lane-worlds`, the default topology). `roster[]` is parser sugar for
37
38
  // 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
39
+ // `count` (declare a differentiated roster or a homogeneous count, never both); `lanes|roster`
40
+ // XOR `actors[0].laneFocus` (each entry's `instruction` is the roster's steer); `lanes[].device` XOR
41
+ // raw `execution.desktop.resolution`. `execution.concurrency` bounds in-flight participants (default:
42
+ // the participant count, all at once; env HUMANISH_CUA_MAX_CONCURRENCY may only lower it, per invariant
42
43
  // 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
44
+ // rejected on the cua route. `lanes[].target` is app-url × computer-use only: an absolute browser
45
+ // URL this participant opens instead of `subject.appUrl`; it is the generic setup-produced-target
45
46
  // handoff, not a service topology primitive.
46
47
  //
47
- // There is deliberately NO v1 compatibility: v1 had zero real users. Breaking schema changes
48
+ // There is deliberately no v1 compatibility: v1 had zero real users. Breaking schema changes
48
49
  // bump the version honestly.
49
50
  import { isLocalBrowserLab, localBrowserDefaults, localBrowserUnsupportedReason, } from "../substrates/local/runtime-config.js";
51
+ import { isRecord } from "../run/type-guards.js";
50
52
  import { compositionReason } from "./composition-rules.js";
51
53
  import { findUnknownLabKey } from "./keys.js";
52
54
  import { parseActors, rosterOf } from "./parse/actors.js";
53
55
  import { parseComms, recipientParticipantId } from "./parse/comms.js";
54
56
  import { parseDefaults, parseExecution, parsePersonas, parsePolicies, parseReview, parseScenario, } from "./parse/execution.js";
55
57
  import { parseSubject } from "./parse/subject.js";
56
- import { invalid, isRecord, optionalStr, str } from "./parse/values.js";
58
+ import { invalid, optionalStr, str } from "./parse/values.js";
57
59
  import { isComputerUseComposition, isSharedWorldComposition } from "./routing.js";
58
60
  import { declaredParticipantIds } from "./plan-participants.js";
59
61
  import { ID_PATTERN, LAB_CONFIG_SCHEMA, } from "./types.js";
@@ -150,7 +152,7 @@ export function parseLabConfig(raw) {
150
152
  return invalid(scenarioCapsReason);
151
153
  // All-parallel default (#350): a multi-seat lab that does not declare execution.concurrency runs
152
154
  // 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
155
+ // computer-use participants resolve that default from the final participant count when they plan, after any
154
156
  // --count override, so the parser leaves it unset for them. A shared world's roster is fixed, so
155
157
  // its default is filled here for the envelopes and warnings that read the parsed config.
156
158
  {
@@ -161,12 +163,12 @@ export function parseLabConfig(raw) {
161
163
  config.execution = { ...config.execution, concurrency: participantCount };
162
164
  }
163
165
  }
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).
166
+ // Email that just works (#351): the funnel's only handoff to an actor is the per-participant
167
+ // inbox instruction, gated on recipients[]. Guessed participant ids broke a field run —
168
+ // recipients copied from a single-participant example matched nothing, so every actor was left inbox-blind with zero
169
+ // signal. Omitted recipients are therefore filled (one deterministic address per participant);
170
+ // a recipient naming an unknown participant is a hard error listing the real ids; declared
171
+ // recipients covering zero participants are a hard error (a guaranteed-dead funnel).
170
172
  const receivingReason = receivingEmailValidationReason(config);
171
173
  if (receivingReason)
172
174
  return invalid(receivingReason);
@@ -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
  /**
@@ -7,6 +7,7 @@ import { parse } from "yaml";
7
7
  import { parseLabConfig } from "./config.js";
8
8
  import {} from "./types.js";
9
9
  import { assertPreparedSelectedOutputDirectory, assertSafeOutputPathSegment, prepareSelectedOutputDirectory, readContainedRegularFile, } from "../run/contained-output.js";
10
+ import { isNodeError } from "../run/type-guards.js";
10
11
  const LAB_LIST_SCHEMA = "humanish.lab-list.v1";
11
12
  const LAB_INSPECT_SCHEMA = "humanish.lab-inspect.v1";
12
13
  const committedLabsDir = path.join("humanish", "labs");
@@ -417,6 +418,3 @@ function relativeToCwd(cwd, filePath) {
417
418
  const relative = path.relative(cwd, filePath);
418
419
  return relative && !relative.startsWith("..") ? relative : filePath;
419
420
  }
420
- function isNodeError(error) {
421
- return error instanceof Error && "code" in error;
422
- }