humanish 0.107.0 → 0.108.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/ARCHITECTURE.md +22 -17
  2. package/CHANGELOG.md +14 -0
  3. package/CONTEXT.md +51 -44
  4. package/README.md +145 -172
  5. package/SECURITY.md +16 -26
  6. package/TELEMETRY.md +8 -6
  7. package/dist/actors/affordance.d.ts +4 -4
  8. package/dist/actors/affordance.js +12 -12
  9. package/dist/actors/agent-session.d.ts +2 -2
  10. package/dist/actors/agent-session.js +7 -7
  11. package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
  12. package/dist/actors/codex/app-server-actor-trace.js +1 -1
  13. package/dist/actors/codex/app-server-ui.js +1 -1
  14. package/dist/actors/codex/codex-admission.d.ts +91 -0
  15. package/dist/actors/codex/codex-admission.js +150 -0
  16. package/dist/actors/codex/restricted-executable.d.ts +4 -4
  17. package/dist/actors/codex/restricted-executable.js +8 -8
  18. package/dist/actors/codex/restricted-launch.d.ts +2 -1
  19. package/dist/actors/codex/restricted-launch.js +1 -1
  20. package/dist/actors/codex/restricted-participant.js +8 -6
  21. package/dist/actors/codex/restricted-policy.d.ts +2 -2
  22. package/dist/actors/codex/restricted-policy.js +2 -2
  23. package/dist/actors/codex/restricted-session.d.ts +2 -2
  24. package/dist/actors/codex/restricted-session.js +10 -5
  25. package/dist/actors/computer-use/actor.d.ts +16 -16
  26. package/dist/actors/computer-use/actor.js +2 -2
  27. package/dist/actors/computer-use/admission-limit.d.ts +1 -1
  28. package/dist/actors/computer-use/admission-limit.js +1 -1
  29. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  30. package/dist/actors/computer-use/loop/actions.js +10 -10
  31. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  32. package/dist/actors/computer-use/loop/backstop.js +14 -12
  33. package/dist/actors/computer-use/loop/ending.d.ts +5 -5
  34. package/dist/actors/computer-use/loop/ending.js +7 -7
  35. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/observation.js +9 -9
  37. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/provider-call.js +1 -1
  39. package/dist/actors/computer-use/loop/session.js +3 -3
  40. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  41. package/dist/actors/computer-use/loop/spend.js +1 -1
  42. package/dist/actors/computer-use/loop/trace.js +9 -8
  43. package/dist/actors/computer-use/loop/types.d.ts +25 -23
  44. package/dist/actors/computer-use/loop/usage.js +2 -2
  45. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  46. package/dist/actors/computer-use/openai-context.js +214 -0
  47. package/dist/actors/computer-use/openai-provider.d.ts +11 -8
  48. package/dist/actors/computer-use/openai-provider.js +45 -34
  49. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  50. package/dist/actors/computer-use/openai-requests.js +82 -15
  51. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  52. package/dist/actors/computer-use/openai-wire.js +36 -34
  53. package/dist/actors/contract.d.ts +78 -43
  54. package/dist/actors/contract.js +29 -23
  55. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  56. package/dist/actors/local-agent/claude-session.js +10 -9
  57. package/dist/actors/local-agent/cli.d.ts +8 -6
  58. package/dist/actors/local-agent/cli.js +24 -28
  59. package/dist/actors/local-agent/readiness.d.ts +2 -2
  60. package/dist/actors/local-agent/readiness.js +4 -4
  61. package/dist/actors/reasoning-effort.js +6 -6
  62. package/dist/actors/registry.d.ts +10 -10
  63. package/dist/actors/registry.js +18 -17
  64. package/dist/actors/scripted-browser/actor.d.ts +8 -8
  65. package/dist/actors/scripted-browser/actor.js +16 -16
  66. package/dist/actors/scripted-browser/browser-command.js +1 -1
  67. package/dist/actors/scripted-browser/steps.js +1 -1
  68. package/dist/actors/scripted-browser/types.d.ts +1 -1
  69. package/dist/actors/stop-conditions.d.ts +1 -1
  70. package/dist/analysis/codex-config.d.ts +6 -2
  71. package/dist/analysis/codex-config.js +22 -14
  72. package/dist/analysis/service.js +5 -5
  73. package/dist/cli/commands/analyze.js +19 -16
  74. package/dist/cli/commands/codex.js +9 -9
  75. package/dist/cli/commands/comms.js +54 -33
  76. package/dist/cli/commands/feedback.js +20 -21
  77. package/dist/cli/commands/lab-format.d.ts +5 -4
  78. package/dist/cli/commands/lab-format.js +35 -23
  79. package/dist/cli/commands/lab-route-computer-use.js +6 -7
  80. package/dist/cli/commands/lab-route-preview.js +4 -3
  81. package/dist/cli/commands/lab-route-shared-world.js +3 -3
  82. package/dist/cli/commands/lab-run.js +10 -11
  83. package/dist/cli/commands/lab-scorer.d.ts +2 -2
  84. package/dist/cli/commands/lab-scorer.js +1 -1
  85. package/dist/cli/commands/migrate.d.ts +4 -0
  86. package/dist/cli/commands/migrate.js +65 -0
  87. package/dist/cli/commands/observe.js +147 -108
  88. package/dist/cli/commands/run-command.d.ts +10 -0
  89. package/dist/cli/commands/run-command.js +85 -0
  90. package/dist/cli/commands/runs.js +137 -138
  91. package/dist/cli/commands/setup.d.ts +2 -2
  92. package/dist/cli/commands/setup.js +26 -21
  93. package/dist/cli/commands/study.d.ts +3 -0
  94. package/dist/cli/commands/study.js +182 -0
  95. package/dist/cli/commands/tui.d.ts +4 -4
  96. package/dist/cli/commands/tui.js +21 -21
  97. package/dist/cli/commands/watch.js +60 -75
  98. package/dist/cli/deprecations.d.ts +18 -0
  99. package/dist/cli/deprecations.js +48 -0
  100. package/dist/cli/doctor.d.ts +15 -5
  101. package/dist/cli/doctor.js +103 -48
  102. package/dist/cli/first-run-path.d.ts +12 -10
  103. package/dist/cli/first-run-path.js +30 -28
  104. package/dist/cli/io.d.ts +41 -6
  105. package/dist/cli/io.js +97 -22
  106. package/dist/cli/observer-follow.d.ts +2 -2
  107. package/dist/cli/observer-follow.js +5 -6
  108. package/dist/cli/orientation.d.ts +6 -3
  109. package/dist/cli/orientation.js +43 -39
  110. package/dist/cli/product-sentence.d.ts +6 -0
  111. package/dist/cli/product-sentence.js +6 -0
  112. package/dist/cli/program.d.ts +6 -1
  113. package/dist/cli/program.js +109 -40
  114. package/dist/cli/telemetry.d.ts +15 -15
  115. package/dist/cli/telemetry.js +48 -40
  116. package/dist/cli.js +1 -1
  117. package/dist/comms/capture-surface.d.ts +13 -12
  118. package/dist/comms/capture-surface.js +23 -22
  119. package/dist/comms/catch-host.d.ts +7 -7
  120. package/dist/comms/catch-host.js +14 -14
  121. package/dist/comms/email-catch.d.ts +3 -3
  122. package/dist/comms/email-catch.js +8 -8
  123. package/dist/comms/external-evidence.js +2 -2
  124. package/dist/comms/extract.js +2 -2
  125. package/dist/comms/fake-inbox.d.ts +2 -2
  126. package/dist/comms/fake-inbox.js +2 -2
  127. package/dist/comms/receiving-render.d.ts +1 -1
  128. package/dist/comms/receiving-render.js +2 -2
  129. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  130. package/dist/comms/sandbox-catch-script.js +6 -6
  131. package/dist/comms/sandbox-catch.d.ts +36 -37
  132. package/dist/comms/sandbox-catch.js +34 -35
  133. package/dist/comms/setup.js +42 -8
  134. package/dist/comms/thread-evidence.d.ts +1 -1
  135. package/dist/comms/thread-evidence.js +6 -6
  136. package/dist/comms/types.d.ts +6 -6
  137. package/dist/comms/types.js +3 -3
  138. package/dist/evidence/frame-signature.d.ts +1 -1
  139. package/dist/evidence/frame-signature.js +4 -4
  140. package/dist/evidence/redaction.d.ts +3 -3
  141. package/dist/evidence/redaction.js +4 -4
  142. package/dist/feedback/draft.js +36 -78
  143. package/dist/feedback/export-bundle.js +1 -1
  144. package/dist/feedback/export.d.ts +5 -1
  145. package/dist/feedback/export.js +7 -8
  146. package/dist/feedback/feedback.d.ts +2 -2
  147. package/dist/feedback/feedback.js +21 -3
  148. package/dist/guest/chromium-text.js +2 -2
  149. package/dist/guest/desktop-native.d.ts +1 -1
  150. package/dist/guest/runtime.js +1 -1
  151. package/dist/index.d.ts +12 -10
  152. package/dist/index.js +8 -6
  153. package/dist/keys/key-resolution.d.ts +5 -5
  154. package/dist/keys/key-resolution.js +23 -23
  155. package/dist/lab/adapter-extension.d.ts +7 -7
  156. package/dist/lab/adapter-extension.js +13 -36
  157. package/dist/lab/adapter-scorer-loader.d.ts +7 -7
  158. package/dist/lab/adapter-scorer-loader.js +32 -32
  159. package/dist/lab/composition-rules.js +42 -42
  160. package/dist/lab/config.js +65 -25
  161. package/dist/lab/deprecated-fields.d.ts +10 -0
  162. package/dist/lab/deprecated-fields.js +24 -0
  163. package/dist/lab/device-presets.d.ts +8 -8
  164. package/dist/lab/device-presets.js +11 -11
  165. package/dist/lab/discover.d.ts +13 -9
  166. package/dist/lab/discover.js +117 -57
  167. package/dist/lab/doctor.d.ts +10 -3
  168. package/dist/lab/doctor.js +47 -9
  169. package/dist/lab/init-templates.js +147 -147
  170. package/dist/lab/init.d.ts +1 -1
  171. package/dist/lab/init.js +41 -9
  172. package/dist/lab/keys.d.ts +2 -0
  173. package/dist/lab/keys.js +42 -8
  174. package/dist/lab/lab-deps.d.ts +7 -12
  175. package/dist/lab/parse/actors.js +9 -9
  176. package/dist/lab/parse/comms.js +5 -5
  177. package/dist/lab/parse/execution.js +13 -13
  178. package/dist/lab/parse/study-v3.d.ts +23 -0
  179. package/dist/lab/parse/study-v3.js +259 -0
  180. package/dist/lab/parse/subject-state.d.ts +7 -7
  181. package/dist/lab/parse/subject-state.js +16 -16
  182. package/dist/lab/parse/subject.js +28 -28
  183. package/dist/lab/parse/values.d.ts +1 -1
  184. package/dist/lab/parse/values.js +3 -3
  185. package/dist/lab/persona-resolve.d.ts +4 -4
  186. package/dist/lab/persona-resolve.js +4 -4
  187. package/dist/lab/plan-participants.d.ts +2 -2
  188. package/dist/lab/plan-types.d.ts +4 -4
  189. package/dist/lab/plan.d.ts +1 -7
  190. package/dist/lab/plan.js +10 -41
  191. package/dist/lab/preflight-probes.js +11 -11
  192. package/dist/lab/preflight-result.d.ts +2 -1
  193. package/dist/lab/preflight-result.js +5 -4
  194. package/dist/lab/preflight.d.ts +7 -5
  195. package/dist/lab/preflight.js +5 -5
  196. package/dist/lab/routing.d.ts +31 -25
  197. package/dist/lab/routing.js +60 -29
  198. package/dist/lab/run-lab-events.d.ts +0 -3
  199. package/dist/lab/run-lab-events.js +0 -6
  200. package/dist/lab/run-lab-homes.d.ts +22 -10
  201. package/dist/lab/run-lab-homes.js +5 -1
  202. package/dist/lab/run-lab-options.d.ts +1 -1
  203. package/dist/lab/run-lab-options.js +16 -13
  204. package/dist/lab/summary.d.ts +7 -6
  205. package/dist/lab/summary.js +10 -10
  206. package/dist/lab/tasks.d.ts +15 -15
  207. package/dist/lab/tasks.js +14 -14
  208. package/dist/lab/types.d.ts +101 -95
  209. package/dist/lab/types.js +2 -0
  210. package/dist/lab/validation.d.ts +13 -13
  211. package/dist/lab/validation.js +44 -42
  212. package/dist/lab/warnings.d.ts +10 -0
  213. package/dist/lab/warnings.js +61 -33
  214. package/dist/library-aliases.d.ts +56 -0
  215. package/dist/library-aliases.js +22 -0
  216. package/dist/observer/artifact.d.ts +1 -1
  217. package/dist/observer/artifact.js +6 -6
  218. package/dist/observer/data.d.ts +6 -6
  219. package/dist/observer/data.js +5 -4
  220. package/dist/observer/exposure.d.ts +1 -1
  221. package/dist/observer/exposure.js +11 -11
  222. package/dist/observer/http.js +1 -1
  223. package/dist/observer/library.d.ts +1 -1
  224. package/dist/observer/library.js +4 -2
  225. package/dist/observer/listen.js +5 -4
  226. package/dist/observer/render.d.ts +1 -1
  227. package/dist/observer/render.js +10 -5
  228. package/dist/observer/run-routes.d.ts +3 -3
  229. package/dist/observer/run-routes.js +1 -1
  230. package/dist/observer/serve.js +7 -3
  231. package/dist/observer/tunnel.js +1 -1
  232. package/dist/observer-app.html +4 -4
  233. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  234. package/dist/routes/computer-use/bundle-parts.js +15 -15
  235. package/dist/routes/computer-use/bundle.js +3 -3
  236. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
  237. package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
  238. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
  239. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
  240. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
  241. package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
  242. package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
  243. package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
  244. package/dist/routes/computer-use/external-comms.d.ts +1 -1
  245. package/dist/routes/computer-use/external-comms.js +1 -1
  246. package/dist/routes/computer-use/fanout-bundle.js +18 -18
  247. package/dist/routes/computer-use/fanout-records.js +10 -11
  248. package/dist/routes/computer-use/live-flush.d.ts +1 -1
  249. package/dist/routes/computer-use/live-flush.js +6 -6
  250. package/dist/routes/computer-use/live-phase.d.ts +4 -2
  251. package/dist/routes/computer-use/live-phase.js +6 -6
  252. package/dist/routes/computer-use/local-vm.js +1 -1
  253. package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
  254. package/dist/routes/computer-use/participant-desktop.js +4 -4
  255. package/dist/routes/computer-use/participant-execution.d.ts +4 -4
  256. package/dist/routes/computer-use/participant-execution.js +9 -9
  257. package/dist/routes/computer-use/participant-model.d.ts +6 -0
  258. package/dist/routes/computer-use/participant-model.js +31 -13
  259. package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
  260. package/dist/routes/computer-use/participant-prompt.js +6 -6
  261. package/dist/routes/computer-use/participant-runs.d.ts +7 -7
  262. package/dist/routes/computer-use/participant-runs.js +13 -13
  263. package/dist/routes/computer-use/plan.js +22 -22
  264. package/dist/routes/computer-use/preflight.js +21 -21
  265. package/dist/routes/computer-use/rerun-selection.js +1 -1
  266. package/dist/routes/computer-use/result.js +11 -11
  267. package/dist/routes/computer-use/route.d.ts +2 -1
  268. package/dist/routes/computer-use/route.js +15 -14
  269. package/dist/routes/computer-use/self-report.d.ts +7 -7
  270. package/dist/routes/computer-use/self-report.js +31 -31
  271. package/dist/routes/computer-use/setup.d.ts +1 -1
  272. package/dist/routes/computer-use/setup.js +17 -18
  273. package/dist/routes/computer-use/single-bundle.d.ts +7 -7
  274. package/dist/routes/computer-use/single-bundle.js +28 -30
  275. package/dist/routes/computer-use/subject-projection.d.ts +1 -1
  276. package/dist/routes/computer-use/subject-projection.js +6 -6
  277. package/dist/routes/computer-use/types.d.ts +40 -42
  278. package/dist/routes/computer-use/types.js +10 -10
  279. package/dist/routes/preview.d.ts +8 -2
  280. package/dist/routes/preview.js +8 -4
  281. package/dist/routes/scripted/bundle.d.ts +2 -2
  282. package/dist/routes/scripted/bundle.js +13 -12
  283. package/dist/routes/scripted/plan.d.ts +1 -1
  284. package/dist/routes/scripted/plan.js +9 -9
  285. package/dist/routes/scripted/result.js +5 -5
  286. package/dist/routes/scripted/route.js +5 -6
  287. package/dist/routes/scripted/scenario.js +2 -2
  288. package/dist/routes/scripted/setup.js +7 -7
  289. package/dist/routes/scripted/subject.js +1 -1
  290. package/dist/routes/scripted/surface-records.js +3 -3
  291. package/dist/routes/scripted/types.d.ts +3 -5
  292. package/dist/routes/scripted/types.js +1 -1
  293. package/dist/routes/shared-world/bundle-records.js +9 -8
  294. package/dist/routes/shared-world/bundle.d.ts +5 -5
  295. package/dist/routes/shared-world/bundle.js +40 -38
  296. package/dist/routes/shared-world/checkpoints.d.ts +1 -1
  297. package/dist/routes/shared-world/checkpoints.js +1 -1
  298. package/dist/routes/shared-world/comms.d.ts +5 -5
  299. package/dist/routes/shared-world/comms.js +14 -14
  300. package/dist/routes/shared-world/external-public.d.ts +4 -3
  301. package/dist/routes/shared-world/external-public.js +16 -12
  302. package/dist/routes/shared-world/handoff.d.ts +7 -6
  303. package/dist/routes/shared-world/handoff.js +65 -57
  304. package/dist/routes/shared-world/lobby-code.d.ts +2 -2
  305. package/dist/routes/shared-world/lobby-code.js +9 -9
  306. package/dist/routes/shared-world/participant-specs.d.ts +7 -6
  307. package/dist/routes/shared-world/participant-specs.js +31 -24
  308. package/dist/routes/shared-world/plan.js +7 -7
  309. package/dist/routes/shared-world/provenance.d.ts +2 -2
  310. package/dist/routes/shared-world/provenance.js +2 -2
  311. package/dist/routes/shared-world/provisioned.js +14 -13
  312. package/dist/routes/shared-world/result.js +20 -21
  313. package/dist/routes/shared-world/route.js +23 -22
  314. package/dist/routes/shared-world/setup.d.ts +3 -3
  315. package/dist/routes/shared-world/setup.js +4 -4
  316. package/dist/routes/shared-world/types.d.ts +30 -28
  317. package/dist/routes/shared-world/types.js +4 -4
  318. package/dist/routes/terminal/adapter.d.ts +3 -3
  319. package/dist/routes/terminal/adapter.js +5 -5
  320. package/dist/routes/terminal/bundle.d.ts +3 -3
  321. package/dist/routes/terminal/bundle.js +22 -21
  322. package/dist/routes/terminal/credentials.d.ts +4 -4
  323. package/dist/routes/terminal/credentials.js +7 -7
  324. package/dist/routes/terminal/dry-run.js +4 -4
  325. package/dist/routes/terminal/encoding.js +2 -2
  326. package/dist/routes/terminal/ledger.d.ts +3 -3
  327. package/dist/routes/terminal/ledger.js +14 -14
  328. package/dist/routes/terminal/live-finish.js +3 -3
  329. package/dist/routes/terminal/live-sandbox.js +12 -13
  330. package/dist/routes/terminal/persona.js +1 -1
  331. package/dist/routes/terminal/plan.js +11 -11
  332. package/dist/routes/terminal/recorder.js +2 -2
  333. package/dist/routes/terminal/result.js +8 -8
  334. package/dist/routes/terminal/route.js +6 -7
  335. package/dist/routes/terminal/sandbox.d.ts +1 -1
  336. package/dist/routes/terminal/sandbox.js +1 -1
  337. package/dist/routes/terminal/session.js +8 -7
  338. package/dist/routes/terminal/token-usage.d.ts +1 -1
  339. package/dist/routes/terminal/token-usage.js +7 -8
  340. package/dist/routes/terminal/trace.d.ts +2 -2
  341. package/dist/routes/terminal/trace.js +2 -2
  342. package/dist/routes/terminal/types.d.ts +26 -28
  343. package/dist/routes/terminal/types.js +3 -3
  344. package/dist/run/bundle-shape.js +3 -3
  345. package/dist/run/bundle.d.ts +46 -46
  346. package/dist/run/bundle.js +2 -1
  347. package/dist/run/cost-summary.js +3 -3
  348. package/dist/run/costs.js +7 -1
  349. package/dist/run/detail.d.ts +6 -6
  350. package/dist/run/detail.js +4 -4
  351. package/dist/run/dry-run-inputs.js +1 -1
  352. package/dist/run/dry-run.js +18 -18
  353. package/dist/run/judge.d.ts +19 -13
  354. package/dist/run/judge.js +18 -8
  355. package/dist/run/paths.d.ts +1 -1
  356. package/dist/run/paths.js +1 -1
  357. package/dist/run/pricing.d.ts +11 -6
  358. package/dist/run/pricing.js +20 -13
  359. package/dist/run/projection.d.ts +14 -14
  360. package/dist/run/projection.js +15 -15
  361. package/dist/run/reclaim.js +2 -2
  362. package/dist/run/results.d.ts +5 -5
  363. package/dist/run/run-index.d.ts +8 -6
  364. package/dist/run/run-index.js +15 -16
  365. package/dist/run/run-not-found.d.ts +5 -0
  366. package/dist/run/run-not-found.js +15 -0
  367. package/dist/run/run.d.ts +5 -4
  368. package/dist/run/run.js +1 -1
  369. package/dist/run/sandbox-receipts.d.ts +2 -2
  370. package/dist/run/sandbox-receipts.js +3 -3
  371. package/dist/run/shared-world-evidence.d.ts +36 -35
  372. package/dist/run/shared-world-evidence.js +4 -4
  373. package/dist/run/shared-world-shape.d.ts +1 -1
  374. package/dist/run/shared-world-shape.js +6 -6
  375. package/dist/run/stats.d.ts +12 -6
  376. package/dist/run/stats.js +116 -58
  377. package/dist/run/status.d.ts +8 -29
  378. package/dist/run/status.js +5 -27
  379. package/dist/run/stored-runs.js +2 -1
  380. package/dist/run/stream-shape.js +1 -1
  381. package/dist/run/streams.d.ts +6 -6
  382. package/dist/run/study-provenance.d.ts +47 -0
  383. package/dist/run/study-provenance.js +63 -0
  384. package/dist/run/study-result.d.ts +16 -0
  385. package/dist/run/study-result.js +9 -0
  386. package/dist/run/text.d.ts +2 -0
  387. package/dist/run/text.js +4 -0
  388. package/dist/run-lab.d.ts +7 -7
  389. package/dist/run-lab.js +1 -3
  390. package/dist/study/convert.d.ts +33 -0
  391. package/dist/study/convert.js +432 -0
  392. package/dist/study/field-paths.d.ts +12 -0
  393. package/dist/study/field-paths.js +126 -0
  394. package/dist/study/files.d.ts +26 -0
  395. package/dist/study/files.js +43 -0
  396. package/dist/study/migrate.d.ts +48 -0
  397. package/dist/study/migrate.js +408 -0
  398. package/dist/study/owned-files.d.ts +38 -0
  399. package/dist/study/owned-files.js +182 -0
  400. package/dist/subject/clone.d.ts +1 -1
  401. package/dist/subject/desktop-cli.d.ts +1 -1
  402. package/dist/subject/desktop-cli.js +2 -2
  403. package/dist/subject/local-tree-archive.js +1 -1
  404. package/dist/subject/local-tree.d.ts +1 -1
  405. package/dist/subject/node-bootstrap.js +1 -1
  406. package/dist/subject/runtime.js +8 -9
  407. package/dist/subject/serve.d.ts +1 -1
  408. package/dist/subject/serve.js +3 -3
  409. package/dist/subject/state.d.ts +1 -1
  410. package/dist/subject/steps.d.ts +5 -5
  411. package/dist/subject/steps.js +4 -4
  412. package/dist/substrates/command-failure.d.ts +3 -3
  413. package/dist/substrates/command-failure.js +3 -3
  414. package/dist/substrates/detached.d.ts +6 -6
  415. package/dist/substrates/detached.js +7 -7
  416. package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
  417. package/dist/substrates/e2b/cdp-probe.js +14 -17
  418. package/dist/substrates/e2b/desktop-browser.d.ts +2 -2
  419. package/dist/substrates/e2b/desktop-browser.js +8 -8
  420. package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
  421. package/dist/substrates/e2b/desktop-cdp.js +8 -8
  422. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  423. package/dist/substrates/e2b/desktop-executor.js +1 -1
  424. package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
  425. package/dist/substrates/e2b/desktop-geometry.js +7 -7
  426. package/dist/substrates/e2b/desktop-media.d.ts +1 -1
  427. package/dist/substrates/e2b/desktop-media.js +1 -1
  428. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  429. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  430. package/dist/substrates/e2b/sandbox.d.ts +1 -1
  431. package/dist/substrates/e2b/sandbox.js +1 -1
  432. package/dist/substrates/e2b/sdk.d.ts +11 -11
  433. package/dist/substrates/e2b/sdk.js +6 -6
  434. package/dist/tui/actions.d.ts +1 -1
  435. package/dist/tui/actions.js +13 -13
  436. package/dist/tui/contract.d.ts +16 -16
  437. package/dist/tui/contract.js +10 -10
  438. package/dist/tui/launch.d.ts +4 -4
  439. package/dist/tui/launch.js +18 -19
  440. package/dist/tui/project.js +5 -5
  441. package/dist/tui-app.js +82 -82
  442. package/dist/verify/actor.d.ts +8 -8
  443. package/dist/verify/actor.js +36 -36
  444. package/dist/verify/artifacts.d.ts +2 -2
  445. package/dist/verify/artifacts.js +3 -3
  446. package/dist/verify/context-growth.d.ts +9 -0
  447. package/dist/verify/context-growth.js +62 -0
  448. package/dist/verify/costs.d.ts +6 -6
  449. package/dist/verify/costs.js +8 -8
  450. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  451. package/dist/verify/shared-world-concurrent.js +79 -76
  452. package/dist/verify/shared-world.d.ts +2 -2
  453. package/dist/verify/shared-world.js +16 -16
  454. package/dist/verify/subject.d.ts +4 -4
  455. package/dist/verify/subject.js +18 -18
  456. package/dist/verify/verify.js +92 -43
  457. package/docs/README.md +25 -32
  458. package/docs/architecture/actor-contract.md +56 -87
  459. package/docs/architecture/desktop-sessions.md +7 -7
  460. package/docs/architecture/external-public-shared-world.md +61 -59
  461. package/docs/architecture/github-feedback-loop.md +1 -4
  462. package/docs/architecture/guest-desktop.md +2 -2
  463. package/docs/architecture/observer.md +34 -34
  464. package/docs/architecture/restricted-codex-analysis.md +34 -28
  465. package/docs/architecture/serve.md +34 -37
  466. package/docs/architecture/state-driven-executor.md +55 -58
  467. package/docs/architecture/task-protocol-support.md +5 -5
  468. package/docs/architecture/terminal-product-route.md +67 -107
  469. package/docs/contracts/README.md +24 -0
  470. package/docs/contracts/adapter-admission.md +3 -3
  471. package/docs/contracts/adapter-fixtures.md +2 -5
  472. package/docs/contracts/core.md +1 -3
  473. package/docs/contracts/errors.md +62 -0
  474. package/docs/contracts/feedback.md +8 -9
  475. package/docs/contracts/policy.md +7 -12
  476. package/docs/contracts/run-bundle.md +45 -44
  477. package/docs/contracts/schemas.md +421 -362
  478. package/docs/contracts/study-analysis.md +3 -3
  479. package/docs/contracts/study-costs.md +11 -7
  480. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  481. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  482. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  483. package/docs/principles/actor-fidelity.md +4 -4
  484. package/docs/principles/engineering.md +3 -3
  485. package/docs/principles/invariants-and-defaults.md +38 -38
  486. package/docs/principles/self-driving-harness.md +1 -5
  487. package/docs/principles/three-roles.md +1 -1
  488. package/docs/product/automatic-analysis.md +7 -7
  489. package/examples/participant/README.md +5 -5
  490. package/examples/participant/run.mjs +11 -10
  491. package/examples/scorer/README.md +3 -3
  492. package/examples/scorer/run.mjs +11 -12
  493. package/package.json +16 -17
  494. package/skills/humanish/SKILL.md +60 -58
  495. package/skills/humanish/agents/openai.yaml +1 -1
  496. package/AGENTS.md +0 -99
  497. package/CONTRIBUTING.md +0 -148
  498. package/dist/actors/codex/qualified-versions.d.ts +0 -72
  499. package/dist/actors/codex/qualified-versions.js +0 -132
  500. package/dist/cli/commands/lab.d.ts +0 -3
  501. package/dist/cli/commands/lab.js +0 -199
  502. package/dist/cli/renamed-options.d.ts +0 -11
  503. package/dist/cli/renamed-options.js +0 -18
  504. package/dist/observer/static.d.ts +0 -39
  505. package/dist/observer/static.js +0 -369
  506. package/docs/architecture/comms-inbox.md +0 -122
  507. package/docs/architecture/desktop-recording.md +0 -80
  508. package/docs/architecture/local-browser-runtime.md +0 -178
  509. package/docs/architecture/observer-review.md +0 -144
  510. package/docs/architecture/participant-media.md +0 -90
  511. package/docs/architecture/project-layout.md +0 -62
  512. package/docs/architecture/real-email-receiving.md +0 -136
  513. package/docs/assets/humanish-drawdb-hero.png +0 -0
  514. package/docs/assets/humanish-observer-hero.png +0 -0
  515. package/docs/goals/current.md +0 -207
  516. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  517. package/docs/product/open-source-install-experience.md +0 -240
  518. package/docs/ramp/README.md +0 -295
  519. package/docs/release/open-source-readiness.md +0 -222
  520. package/docs/release/public-readiness-standard.md +0 -210
  521. package/docs/roadmap/world-class-open-source-v0.md +0 -311
@@ -39,7 +39,7 @@ type BrowserScoringFacts = Omit<BrowserLabScoringContext, "backend" | "laneCount
39
39
  /** The scorer functions a computer-use or shared-world run calls: `RunLabOptions.scorer`. */
40
40
  export interface BrowserScorer {
41
41
  /**
42
- * Browser-route extension seam (#165): a thin adapter may score the assembled
42
+ * Browser-route extension seam: a thin adapter may score the assembled
43
43
  * browser/shared-world evidence without forking core. The score is stored as
44
44
  * namespaced `bundle.adapterScore`; product-specific component detail belongs
45
45
  * in `data`, not in core enums or review text.
@@ -64,9 +64,9 @@ export interface ScorerOutcome {
64
64
  /** Why the scorer failed the run, in order; empty when it did not. */
65
65
  failures: string[];
66
66
  }
67
- /** A DECLARED scorer that returned a malformed value never rendered a verdict. */
67
+ /** A declared scorer that returned a malformed value never rendered a verdict. */
68
68
  export declare 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.";
69
- /** A DECLARED scorer that threw never rendered a verdict. `detail` is already sanitized. */
69
+ /** A declared scorer that threw never rendered a verdict. `detail` is already sanitized. */
70
70
  export declare function declaredScorerThrew(detail: string): string;
71
71
  export declare function applyBrowserScorer(args: {
72
72
  scorer: BrowserScorer | undefined;
@@ -74,9 +74,9 @@ export declare function applyBrowserScorer(args: {
74
74
  bundle: RunBundle;
75
75
  sanitize: (text: string) => string;
76
76
  warnings: string[];
77
- /** Present only when the scorer was CONFIG-DECLARED (#316); core-stamped onto the bundle as
77
+ /** Present only when the scorer was config-declared; core-stamped onto the bundle as
78
78
  * evidence of which out-of-tree module was loaded. Absent for library callers. Its presence also
79
- * makes a THROWING or MALFORMED scorer a failure — a declared gate that cannot render a pass is
79
+ * makes a throwing or malformed scorer a failure: a declared gate that cannot render a pass is
80
80
  * a fail, never a silent green. */
81
81
  scorerProvenance?: RunScorerProvenance;
82
82
  }): Promise<ScorerOutcome>;
@@ -88,10 +88,10 @@ export declare function applyBrowserScorer(args: {
88
88
  export declare function isAdapterFeedbackCandidate(value: unknown): value is RunFeedbackCandidate;
89
89
  export declare function adapterScoreFailureMessage(bundle: RunBundle): string | undefined;
90
90
  /**
91
- * Deep-freeze a structured clone so a loaded scorer sees a READ-ONLY bundle: it cannot mutate
91
+ * Deep-freeze a structured clone so a loaded scorer sees a read-only bundle: it cannot mutate
92
92
  * noSpend/cost/review in place to launder a verdict (which would defeat the costProbe-not-loadable
93
93
  * guarantee). A tamper attempt throws in the scorer's strict-mode ESM and is caught as a hook failure.
94
- * Legitimate read-only scoring is unaffected. The seam always stamps the REAL bundle, never this view.
94
+ * Legitimate read-only scoring is unaffected. The seam always stamps the real bundle, never this view.
95
95
  */
96
96
  export declare function frozenBundleView(bundle: RunBundle): RunBundle;
97
97
  export {};
@@ -1,45 +1,22 @@
1
1
  import path from "node:path";
2
2
  import { isRunAdapterScore } from "../run/bundle-shape.js";
3
+ import { withDeprecatedFields } from "./deprecated-fields.js";
3
4
  import { isRunFeedbackCandidate } from "../run/feedback-shape.js";
4
5
  import { isRecord } from "../run/type-guards.js";
5
6
  const OLDER_BACKEND = {
6
7
  "computer-use": "cua",
7
8
  "shared-world": "concurrent-shared-world",
8
9
  };
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
- */
10
+ /** The scorer's context: the facts, plus the older `backend` and `laneCount` (deprecated-fields.ts). */
22
11
  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
- },
12
+ return withDeprecatedFields({ ...facts }, { name: "BrowserLabScoringContext", code: "HUMANISH_SCORING_CONTEXT_FIELD_DEPRECATED" }, {
13
+ backend: { replacement: "route", read: () => OLDER_BACKEND[facts.route] },
14
+ laneCount: { replacement: "participantCount", read: () => facts.participantCount },
38
15
  });
39
16
  }
40
- /** A DECLARED scorer that returned a malformed value never rendered a verdict. */
17
+ /** A declared scorer that returned a malformed value never rendered a verdict. */
41
18
  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.";
42
- /** A DECLARED scorer that threw never rendered a verdict. `detail` is already sanitized. */
19
+ /** A declared scorer that threw never rendered a verdict. `detail` is already sanitized. */
43
20
  export function declaredScorerThrew(detail) {
44
21
  return `Declared product scorer threw before returning a verdict (${detail}); a crashed declared gate is recorded as a fail, never a silent pass.`;
45
22
  }
@@ -49,13 +26,13 @@ export async function applyBrowserScorer(args) {
49
26
  return { failures: [] };
50
27
  const declared = scorerProvenance !== undefined;
51
28
  // Record the loaded scorer's identity regardless of hook outcome (a throwing/invalid scorer was
52
- // still loaded and attempted). A VALID status:"fail" is a failure (library + declared, the
53
- // pre-#316 (#165) path); a DECLARED scorer that THROWS or returns MALFORMED is one too (below).
29
+ // still loaded and attempted). A valid status:"fail" is a failure (library + declared, the
30
+ // original path); a declared scorer that throws or returns a malformed value is one too (below).
54
31
  if (scorerProvenance)
55
32
  bundle.scorerProvenance = scorerProvenance;
56
- // The scorer sees a READ-ONLY view of the bundle: it cannot mutate noSpend/cost/review in place to
33
+ // The scorer sees a read-only view of the bundle: it cannot mutate noSpend/cost/review in place to
57
34
  // launder a verdict (a tamper attempt throws in the scorer's strict-mode ESM and is caught below as
58
- // a hook failure). The seam still stamps the REAL bundle.
35
+ // a hook failure). The seam still stamps the real bundle.
59
36
  const scoringContext = scorerContext({
60
37
  ...context,
61
38
  bundle: frozenBundleView(context.bundle),
@@ -142,10 +119,10 @@ export function adapterScoreFailureMessage(bundle) {
142
119
  : undefined;
143
120
  }
144
121
  /**
145
- * Deep-freeze a structured clone so a loaded scorer sees a READ-ONLY bundle: it cannot mutate
122
+ * Deep-freeze a structured clone so a loaded scorer sees a read-only bundle: it cannot mutate
146
123
  * noSpend/cost/review in place to launder a verdict (which would defeat the costProbe-not-loadable
147
124
  * guarantee). A tamper attempt throws in the scorer's strict-mode ESM and is caught as a hook failure.
148
- * Legitimate read-only scoring is unaffected. The seam always stamps the REAL bundle, never this view.
125
+ * Legitimate read-only scoring is unaffected. The seam always stamps the real bundle, never this view.
149
126
  */
150
127
  export function frozenBundleView(bundle) {
151
128
  const clone = structuredClone(bundle);
@@ -2,14 +2,14 @@ import type { BrowserLabScoringContext } from "./adapter-extension.js";
2
2
  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
- /** The read-model context a loaded scorer sees — the terminal or browser scoring context. The module
5
+ /** The read-model context a loaded scorer sees: the terminal or browser scoring context. The module
6
6
  * narrows it at runtime (`"product" in ctx` ⇒ terminal; `"route" in ctx` ⇒ browser). */
7
7
  export type AdapterScoringContext = TerminalProductScoringContext | BrowserLabScoringContext;
8
8
  /**
9
- * The adopter-facing scorer module contract (#316). Export any subset of these from a `.mjs` (or a
10
- * `.js`/`.cjs` whose package.json type matches) — named exports OR a single default object. The
11
- * loader wires ONLY these three; an exported `executor`/`env`/`provisionSubject`/`costProbe` is never
12
- * picked up (the whitelist is the scope guard). A module exporting NONE of them is a hard load error.
9
+ * The adopter-facing scorer module contract. Export any subset of these from a `.mjs` (or a
10
+ * `.js`/`.cjs` whose package.json type matches): named exports or a single default object. The
11
+ * loader wires only these three; an exported `executor`/`env`/`provisionSubject`/`costProbe` is never
12
+ * picked up (the whitelist is the scope guard). A module exporting none of them is a hard load error.
13
13
  *
14
14
  * `C` is the context `score` and `deriveFeedback` read: `BrowserLabScoringContext` for a scorer
15
15
  * written for computer use and shared world, `TerminalProductScoringContext` for one written for
@@ -37,7 +37,7 @@ export declare function terminalScorer(scorer: AdapterScorerModule<TerminalProdu
37
37
  export declare function browserRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<BrowserLabScoringContext>;
38
38
  /** The scorer as a terminal run calls it, with the terminal context (see browserRouteScorer). */
39
39
  export declare function terminalRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<TerminalProductScoringContext>;
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";
40
+ type AdapterScorerLoadErrorCode = "HUMANISH_STUDY_SCORER_BAD_REF" | "HUMANISH_STUDY_SCORER_NOT_FOUND" | "HUMANISH_STUDY_SCORER_LOAD_FAILED" | "HUMANISH_STUDY_SCORER_NO_HOOKS" | "HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND";
41
41
  export type AdapterScorerLoadResult = {
42
42
  ok: true;
43
43
  hooks: AdapterScorerModule;
@@ -52,7 +52,7 @@ export type AdapterScorerLoadResult = {
52
52
  /**
53
53
  * Resolve + load a config-declared scorer module. Resolution clones scenario.ref exactly
54
54
  * (prepareSelectedOutputDirectory → cwd-clamp → readContainedRegularFile), then `import()`s the
55
- * entry file in a BROAD try/catch. The digest is over the readContainedRegularFile ENTRY bytes.
55
+ * entry file in a broad try/catch. The digest is over the readContainedRegularFile entry bytes.
56
56
  */
57
57
  export declare function loadAdapterScorer(args: {
58
58
  cwd: string;
@@ -1,18 +1,18 @@
1
- // #316 — CLI-loadable adopter scorer. Resolve `review.scorer.ref` / `--scorer` to an out-of-tree
2
- // scorer module, load it fail-closed (typed error + exit 2, PRE-SPEND), and pick off ONLY the
1
+ // CLI-loadable adopter scorer. Resolve `review.scorer.ref` / `--scorer` to an out-of-tree
2
+ // scorer module, load it fail-closed (typed error + exit 2, before any spend), and pick off only the
3
3
  // whitelisted read-model hooks {score, deriveFeedback, deriveArtifacts}. `costProbe` is deliberately
4
- // NOT loadable — an injected provider cost line overwrites the core-measured one and can forge a
4
+ // not loadable: an injected provider cost line overwrites the core-measured one and can forge a
5
5
  // satisfied no-spend proof, so it stays library-only.
6
6
  //
7
- // TRUST MODEL (stated plainly, no overclaims): the party who writes `review.scorer.ref` is the party
8
- // who runs `humanish lab run` in their own checkout — identical trust to humanish.lab.yml or a
9
- // package.json script. #316 adds ZERO new execution capability; it relocates WHERE the reference is
10
- // declared. Containment is ENTRY-FILE-ONLY: `readContainedRegularFile` blocks abs/`..`/symlink/
7
+ // Trust model: the party who writes `review.scorer.ref` is the party
8
+ // who runs `humanish lab run` in their own checkout: identical trust to humanish.lab.yml or a
9
+ // package.json script. The loader adds no new execution capability; it relocates where the reference is
10
+ // declared. Containment is entry-file-only: `readContainedRegularFile` blocks abs/`..`/symlink/
11
11
  // hardlink/realpath-escape/TOCTOU on the entry module, but `import()` then executes the transitive
12
12
  // graph + npm deps with no clamp, and `import()` runs top-level module code before any whitelist
13
- // check. The whitelist bounds the WIRED HOOK SURFACE, not arbitrary import-time code; the
13
+ // check. The whitelist bounds the wired hook surface and does not cover import-time code; the
14
14
  // trusted-in-process boundary is the actual safety carrier. The seam's output re-scrub is a
15
- // best-effort denylist, NOT containment. `review.scorer.ref` entries are executable code — review a
15
+ // best-effort denylist that provides no containment. `review.scorer.ref` entries are executable code, so review a
16
16
  // PR that adds one as code, not config.
17
17
  import { realpath } from "node:fs/promises";
18
18
  import path from "node:path";
@@ -43,20 +43,20 @@ export function browserRouteScorer(scorer) {
43
43
  export function terminalRouteScorer(scorer) {
44
44
  return scorer;
45
45
  }
46
- /** The routes whose hooks bag can carry the loaded scorer. A declared scorer on ANY other route
47
- * (scripted or preview) aborts at load — a gate that cannot run must never green-pass. */
46
+ /** The routes that can run the loaded scorer. A declared scorer on any other route
47
+ * (scripted or preview) aborts at load: a gate that cannot run must never green-pass. */
48
48
  const SCORER_CAPABLE_ROUTES = new Set([
49
49
  "terminal",
50
50
  "computer-use",
51
51
  "shared-world",
52
52
  ]);
53
- /** `.mjs` is required-canonical; `.js`/`.cjs` accepted but the module system is the adopter repo's
54
- * package.json `type`. `.ts` is rejected — the compiled `dist/` CLI ships no TypeScript loader. */
53
+ /** `.mjs` is the recommended extension; `.js`/`.cjs` accepted but the module system is the adopter repo's
54
+ * package.json `type`. `.ts` is rejected: the compiled `dist/` CLI ships no TypeScript loader. */
55
55
  const SCORER_EXTENSIONS = new Set([".mjs", ".js", ".cjs"]);
56
56
  /**
57
57
  * Resolve + load a config-declared scorer module. Resolution clones scenario.ref exactly
58
58
  * (prepareSelectedOutputDirectory → cwd-clamp → readContainedRegularFile), then `import()`s the
59
- * entry file in a BROAD try/catch. The digest is over the readContainedRegularFile ENTRY bytes.
59
+ * entry file in a broad try/catch. The digest is over the readContainedRegularFile entry bytes.
60
60
  */
61
61
  export async function loadAdapterScorer(args) {
62
62
  const { route, source } = args;
@@ -64,25 +64,25 @@ export async function loadAdapterScorer(args) {
64
64
  ok: false,
65
65
  error: { code, message },
66
66
  });
67
- // A declared gate that cannot run on this route must ABORT (never silently green-pass).
67
+ // A declared gate that cannot run on this route must abort (never silently green-pass).
68
68
  if (!SCORER_CAPABLE_ROUTES.has(route)) {
69
- return fail("HUMANISH_LAB_SCORER_UNSUPPORTED_BACKEND", `review.scorer.ref is declared but this lab resolves to the ${route} route, which has no adopter-scorer seam. A declared scorer that cannot run must fail closed rather than pass silently — declare it on a terminal, computer-use or shared-world lab.`);
69
+ return fail("HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND", `review.scorer.ref is set, but this study runs on the ${route} route, which cannot run a scorer. The run stops here so the scorer is not silently skipped. Use it with a terminal, computer-use or shared-world study, or remove review.scorer.ref.`);
70
70
  }
71
71
  const trimmed = args.ref.trim();
72
72
  if (!trimmed) {
73
- return fail("HUMANISH_LAB_SCORER_BAD_REF", "review.scorer.ref must be a non-empty repo-relative path ending in .mjs (recommended), .js, or .cjs.");
73
+ return fail("HUMANISH_STUDY_SCORER_BAD_REF", "review.scorer.ref must be a non-empty repo-relative path ending in .mjs (recommended), .js, or .cjs.");
74
74
  }
75
- // Provenance is recorded repo-relative — an absolute ref (even one that happens to land inside cwd)
75
+ // Provenance is recorded repo-relative: an absolute ref (even one that happens to land inside cwd)
76
76
  // is rejected up front rather than silently rewritten to its in-tree relative form.
77
77
  if (path.isAbsolute(trimmed)) {
78
- return fail("HUMANISH_LAB_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a repo-relative path, not absolute — provenance is recorded repo-relative.`);
78
+ return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a path relative to the project, not an absolute path, because the run records it relative to the project.`);
79
79
  }
80
80
  const ext = path.extname(trimmed).toLowerCase();
81
81
  if (ext === ".ts") {
82
- return fail("HUMANISH_LAB_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" ends in .ts, but the shipped CLI runs compiled JS with no TypeScript loader. Precompile to .mjs (recommended) or .js/.cjs.`);
82
+ return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" ends in .ts, but the shipped CLI runs compiled JS with no TypeScript loader. Precompile to .mjs (recommended) or .js/.cjs.`);
83
83
  }
84
84
  if (!SCORER_EXTENSIONS.has(ext)) {
85
- return fail("HUMANISH_LAB_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a repo-relative PATH ending in .mjs (recommended), .js, or .cjs — an id-style ref is not supported.`);
85
+ return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a path relative to the project ending in .mjs (recommended), .js or .cjs.`);
86
86
  }
87
87
  // Root token: realpath(cwd) → prepareSelectedOutputDirectory(dirname, cwd). Mirrors scenario.ref.
88
88
  const physicalCwd = await realpath(path.resolve(args.cwd));
@@ -91,18 +91,18 @@ export async function loadAdapterScorer(args) {
91
91
  const absolutePath = path.resolve(root.physicalPath, trimmed);
92
92
  const relative = path.relative(root.physicalPath, absolutePath);
93
93
  if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
94
- return fail("HUMANISH_LAB_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must stay inside the target cwd — provenance is recorded repo-relative and an escaping/absolute path (a cwd parent, node_modules above cwd, an absolute path) cannot be.`);
94
+ return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must stay inside the project directory, because the run records it relative to the project; a path into a parent directory cannot be recorded that way.`);
95
95
  }
96
96
  const relPosix = relative.split(path.sep).join("/");
97
- // Fail-closed containment gate on the ENTRY file only: rejects symlink, nlink>1, realpath-escape,
97
+ // Fail-closed containment gate on the entry file only: rejects symlink, nlink>1, realpath-escape,
98
98
  // TOCTOU. Its returned bytes are the digest input.
99
99
  const bytes = await readContainedRegularFile(root, relPosix);
100
100
  if (!bytes) {
101
- return fail("HUMANISH_LAB_SCORER_NOT_FOUND", `review.scorer.ref "${trimmed}" could not be read as a contained regular file (${relPosix}). A scorer must be a regular file inside the target cwd — no symlink, no hardlink, no realpath escape.`);
101
+ return fail("HUMANISH_STUDY_SCORER_NOT_FOUND", `review.scorer.ref "${trimmed}" could not be read as a regular file inside the project (${relPosix}). Use a plain file there: not a symlink or a hard link, and not a path that resolves outside the project.`);
102
102
  }
103
103
  const digest = digestText(bytes.toString("utf8"));
104
- // Import the entry module in a BROAD try/catch (ERR_MODULE_NOT_FOUND / SyntaxError / ERR_REQUIRE_ESM
105
- // / top-level throw). import() executes the transitive graph — the cwd clamp guards only the ENTRY
104
+ // Import the entry module in a broad try/catch (ERR_MODULE_NOT_FOUND / SyntaxError / ERR_REQUIRE_ESM
105
+ // / top-level throw). import() executes the transitive graph, and the cwd clamp guards only the entry
106
106
  // file; out-of-tree/transitive code is acceptable only because of the trust boundary above.
107
107
  let mod;
108
108
  try {
@@ -114,12 +114,12 @@ export async function loadAdapterScorer(args) {
114
114
  const hint = /ERR_REQUIRE_ESM|import statement outside a module|Cannot use import statement|Unexpected (?:token|identifier)|SyntaxError/i.test(detail)
115
115
  ? ' Use a .mjs entry file, or set "type": "module" in the nearest package.json.'
116
116
  : "";
117
- return fail("HUMANISH_LAB_SCORER_LOAD_FAILED", `review.scorer.ref "${trimmed}" failed to load: ${redactText(detail)}.${hint}`);
117
+ return fail("HUMANISH_STUDY_SCORER_LOAD_FAILED", `review.scorer.ref "${trimmed}" failed to load: ${redactText(detail)}.${hint}`);
118
118
  }
119
- // mod.default ?? mod, then pick off ONLY the whitelist. An exported executor/env/costProbe is never
120
- // wired — the whitelist is the scope guard. `exports` records the hooks ACTUALLY WIRED for this
119
+ // mod.default ?? mod, then pick off only the whitelist. An exported executor/env/costProbe is never
120
+ // wired; the whitelist is the scope guard. `exports` records the hooks actually wired for this
121
121
  // backend: deriveArtifacts is browser-only, so on the terminal route it is neither wired nor
122
- // recorded (a scorer that exported ONLY deriveArtifacts there wires nothing and fails closed below,
122
+ // recorded (a scorer that exported only deriveArtifacts there wires nothing and fails closed below,
123
123
  // never a silent no-op).
124
124
  const picked = (mod.default ?? mod);
125
125
  const terminalRoute = route === "terminal";
@@ -139,9 +139,9 @@ export async function loadAdapterScorer(args) {
139
139
  }
140
140
  if (exports.length === 0) {
141
141
  const artifactsOnly = terminalRoute && typeof picked.deriveArtifacts === "function";
142
- return fail("HUMANISH_LAB_SCORER_NO_HOOKS", artifactsOnly
142
+ return fail("HUMANISH_STUDY_SCORER_NO_HOOKS", artifactsOnly
143
143
  ? `review.scorer.ref "${trimmed}" exported only deriveArtifacts, which is browser-only and inert on the terminal route. Export score and/or deriveFeedback for a terminal-product scorer.`
144
- : `review.scorer.ref "${trimmed}" loaded but exported none of the adopter-scorer hooks (score, deriveFeedback, deriveArtifacts). Export at least one (named, or on a single default object). costProbe is intentionally NOT loadable.`);
144
+ : `review.scorer.ref "${trimmed}" loaded but exports none of score, deriveFeedback or deriveArtifacts. Export at least one, as a named export or on a default object. costProbe cannot be loaded from a scorer file.`);
145
145
  }
146
146
  const provenance = {
147
147
  schema: "humanish.scorer-provenance.v1",
@@ -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) {
@@ -22,7 +22,7 @@ export function compositionReason(config) {
22
22
  cloneComputerUseValidationReason(config) ??
23
23
  localTreeValidationReason(config) ??
24
24
  // Independent computer-use participants: the roster contract on every route that resolves to cua.
25
- (isComputerUseComposition(config) ? cuaLaneValidationReason(config) : null) ??
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
27
  // fails with a precise reason instead of running as independent participants.
28
28
  (config.subject.topology === "shared-world" ? sharedWorldValidationReason(config) : null) ??
@@ -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") {
@@ -51,51 +51,51 @@ function thisRepoValidationReason(config) {
51
51
  // desktop), and no public-target policy (it is always loopback; the loopback shape was already
52
52
  // enforced in parseSubject). The actual "no inProcess executor supplied" case is inherently an
53
53
  // engine-time decision (the parser cannot know whether a library caller will pass one), so
54
- // it fails closed in runCuaActorLab with HUMANISH_CUA_LAB_LOCAL_APP_NO_EXECUTOR.
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.";
@@ -116,7 +116,7 @@ function appUrlValidationReason(config) {
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,41 +143,41 @@ 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
180
+ // clone × e2b-desktop disambiguates on the actor's run kind: a computer-use actor means the study
181
181
  // clones and serves the subject in-sandbox, then drives it. Scripted-browser actors were checked
182
182
  // above.
183
183
  function cloneComputerUseValidationReason(config) {
@@ -185,7 +185,7 @@ function cloneComputerUseValidationReason(config) {
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.";
@@ -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
221
  // distinction is the population: 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
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), one
255
- // participant 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}".`;
@@ -268,7 +268,7 @@ function terminalValidationReason(config) {
268
268
  }
269
269
  else if (config.execution?.target === "e2b-terminal") {
270
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).
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)) {