humanish 0.108.0 → 0.109.1

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 (461) hide show
  1. package/ARCHITECTURE.md +58 -59
  2. package/CHANGELOG.md +22 -0
  3. package/CONTEXT.md +44 -44
  4. package/README.md +3 -3
  5. package/TELEMETRY.md +2 -2
  6. package/dist/actors/codex/app-server-trace.js +2 -1
  7. package/dist/actors/codex/restricted-participant.js +12 -12
  8. package/dist/actors/codex/restricted-session.d.ts +2 -2
  9. package/dist/actors/computer-use/actor.d.ts +6 -6
  10. package/dist/actors/computer-use/actor.js +2 -2
  11. package/dist/actors/computer-use/admission-limit.d.ts +2 -2
  12. package/dist/actors/computer-use/admission-limit.js +3 -3
  13. package/dist/actors/computer-use/executor-error.d.ts +2 -2
  14. package/dist/actors/computer-use/executor-error.js +3 -3
  15. package/dist/actors/computer-use/loop/actions.js +5 -5
  16. package/dist/actors/computer-use/loop/debrief.js +2 -2
  17. package/dist/actors/computer-use/loop/ending.d.ts +1 -1
  18. package/dist/actors/computer-use/loop/ending.js +12 -11
  19. package/dist/actors/computer-use/loop/observation.js +6 -5
  20. package/dist/actors/computer-use/loop/provider-call.js +11 -11
  21. package/dist/actors/computer-use/loop/session.d.ts +4 -4
  22. package/dist/actors/computer-use/loop/session.js +2 -2
  23. package/dist/actors/computer-use/loop/trace.js +3 -2
  24. package/dist/actors/computer-use/loop/types.d.ts +24 -24
  25. package/dist/actors/computer-use/loop/usage.d.ts +2 -2
  26. package/dist/actors/computer-use/loop.d.ts +6 -1
  27. package/dist/actors/computer-use/loop.js +26 -4
  28. package/dist/actors/computer-use/openai-provider.d.ts +2 -2
  29. package/dist/actors/computer-use/openai-provider.js +8 -8
  30. package/dist/actors/computer-use/provider-error.d.ts +4 -4
  31. package/dist/actors/computer-use/provider-error.js +6 -6
  32. package/dist/actors/contract.d.ts +4 -4
  33. package/dist/actors/contract.js +1 -1
  34. package/dist/actors/local-agent/claude-session.js +3 -3
  35. package/dist/actors/local-agent/cli.d.ts +1 -1
  36. package/dist/actors/local-agent/cli.js +1 -1
  37. package/dist/actors/reasoning-effort.js +3 -3
  38. package/dist/actors/registry.d.ts +2 -2
  39. package/dist/actors/registry.js +3 -3
  40. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  41. package/dist/actors/scripted-browser/actor.js +1 -1
  42. package/dist/analysis/automatic-completion.d.ts +7 -7
  43. package/dist/analysis/automatic-completion.js +1 -1
  44. package/dist/analysis/automatic-config.d.ts +6 -6
  45. package/dist/analysis/automatic-config.js +1 -1
  46. package/dist/analysis/execute.d.ts +1 -1
  47. package/dist/analysis/execute.js +1 -1
  48. package/dist/analysis/types.d.ts +6 -0
  49. package/dist/browser-control/client.js +16 -16
  50. package/dist/browser-control/dispatcher.js +4 -4
  51. package/dist/browser-control/protocol.js +14 -14
  52. package/dist/browser-control/recording-transfer.js +4 -4
  53. package/dist/browser-control/transport.js +7 -7
  54. package/dist/cli/commands/analysis-signals.d.ts +2 -2
  55. package/dist/cli/commands/comms.js +14 -22
  56. package/dist/cli/commands/migrate.js +15 -4
  57. package/dist/cli/commands/observe.d.ts +0 -1
  58. package/dist/cli/commands/observe.js +0 -15
  59. package/dist/cli/commands/run-command.d.ts +2 -2
  60. package/dist/cli/commands/run-command.js +3 -3
  61. package/dist/cli/commands/runs.js +9 -7
  62. package/dist/cli/commands/setup.js +5 -7
  63. package/dist/cli/commands/study-format.d.ts +9 -0
  64. package/dist/cli/commands/{lab-format.js → study-format.js} +5 -5
  65. package/dist/cli/commands/{lab-route-computer-use.d.ts → study-route-computer-use.d.ts} +6 -6
  66. package/dist/cli/commands/{lab-route-computer-use.js → study-route-computer-use.js} +12 -12
  67. package/dist/cli/commands/{lab-route-open.d.ts → study-route-open.d.ts} +4 -4
  68. package/dist/cli/commands/{lab-route-open.js → study-route-open.js} +2 -2
  69. package/dist/cli/commands/{lab-route-preview.d.ts → study-route-preview.d.ts} +7 -7
  70. package/dist/cli/commands/{lab-route-preview.js → study-route-preview.js} +3 -3
  71. package/dist/cli/commands/study-route-run.d.ts +19 -0
  72. package/dist/cli/commands/{lab-route-run.js → study-route-run.js} +6 -6
  73. package/dist/cli/commands/study-route-scripted.d.ts +17 -0
  74. package/dist/cli/commands/{lab-route-scripted.js → study-route-scripted.js} +4 -4
  75. package/dist/cli/commands/{lab-route-shared-world.d.ts → study-route-shared-world.d.ts} +5 -5
  76. package/dist/cli/commands/{lab-route-shared-world.js → study-route-shared-world.js} +7 -7
  77. package/dist/cli/commands/study-route-terminal.d.ts +17 -0
  78. package/dist/cli/commands/{lab-route-terminal.js → study-route-terminal.js} +4 -4
  79. package/dist/cli/commands/study-run.d.ts +9 -0
  80. package/dist/cli/commands/{lab-run.js → study-run.js} +34 -34
  81. package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +5 -5
  82. package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +1 -1
  83. package/dist/cli/commands/study.js +13 -49
  84. package/dist/cli/commands/tui.js +12 -12
  85. package/dist/cli/commands/watch.js +30 -65
  86. package/dist/cli/deprecations.d.ts +1 -13
  87. package/dist/cli/deprecations.js +0 -30
  88. package/dist/cli/doctor.d.ts +3 -3
  89. package/dist/cli/doctor.js +16 -16
  90. package/dist/cli/first-run-path.d.ts +4 -4
  91. package/dist/cli/first-run-path.js +7 -7
  92. package/dist/cli/io.d.ts +3 -3
  93. package/dist/cli/io.js +2 -2
  94. package/dist/cli/observer-follow.d.ts +2 -2
  95. package/dist/cli/observer-follow.js +2 -2
  96. package/dist/cli/orientation.d.ts +4 -4
  97. package/dist/cli/orientation.js +58 -20
  98. package/dist/cli/program.js +3 -4
  99. package/dist/cli/telemetry.d.ts +1 -1
  100. package/dist/cli/telemetry.js +14 -20
  101. package/dist/comms/catch-host.d.ts +1 -1
  102. package/dist/comms/catch-host.js +3 -3
  103. package/dist/comms/connections.d.ts +1 -1
  104. package/dist/comms/connections.js +2 -2
  105. package/dist/comms/external-evidence.d.ts +5 -5
  106. package/dist/comms/external-evidence.js +4 -3
  107. package/dist/comms/fake-inbox.d.ts +2 -2
  108. package/dist/comms/fake-inbox.js +2 -2
  109. package/dist/comms/receiving-runtime.d.ts +4 -4
  110. package/dist/comms/sandbox-catch.d.ts +2 -2
  111. package/dist/comms/sandbox-catch.js +2 -2
  112. package/dist/comms/setup.d.ts +2 -2
  113. package/dist/comms/setup.js +29 -32
  114. package/dist/evidence/redaction.d.ts +11 -0
  115. package/dist/evidence/redaction.js +43 -0
  116. package/dist/feedback/draft.js +2 -2
  117. package/dist/feedback/export-bundle.js +5 -4
  118. package/dist/feedback/export.js +3 -2
  119. package/dist/feedback/proof.d.ts +1 -1
  120. package/dist/feedback/proof.js +2 -2
  121. package/dist/guest/bootstrap.js +6 -6
  122. package/dist/guest/browser-tools.js +8 -8
  123. package/dist/guest/chromium-text.js +17 -17
  124. package/dist/guest/desktop-executor.d.ts +2 -2
  125. package/dist/guest/desktop-executor.js +20 -20
  126. package/dist/guest/desktop-keys.js +4 -4
  127. package/dist/guest/desktop-media.d.ts +2 -2
  128. package/dist/guest/desktop-media.js +16 -16
  129. package/dist/guest/desktop-native.js +10 -10
  130. package/dist/guest/runtime-desktop.js +2 -2
  131. package/dist/guest/runtime-processes.d.ts +2 -2
  132. package/dist/guest/runtime-processes.js +2 -2
  133. package/dist/guest/runtime.js +5 -5
  134. package/dist/index.d.ts +13 -15
  135. package/dist/index.js +6 -8
  136. package/dist/observer/artifact.d.ts +1 -1
  137. package/dist/observer/artifact.js +1 -1
  138. package/dist/observer/data.d.ts +1 -1
  139. package/dist/observer/library.d.ts +2 -0
  140. package/dist/observer/library.js +4 -1
  141. package/dist/observer/render.js +7 -1
  142. package/dist/observer/run-routes.d.ts +1 -0
  143. package/dist/observer/run-routes.js +37 -12
  144. package/dist/observer/serve.d.ts +1 -1
  145. package/dist/observer-app.html +1 -1
  146. package/dist/routes/computer-use/bundle-parts.js +3 -2
  147. package/dist/routes/computer-use/bundle.d.ts +2 -2
  148. package/dist/routes/computer-use/bundle.js +7 -6
  149. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +5 -5
  150. package/dist/routes/computer-use/e2b-desktop/comms.js +5 -4
  151. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +1 -1
  152. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
  153. package/dist/routes/computer-use/e2b-desktop/prepare.js +3 -3
  154. package/dist/routes/computer-use/e2b-desktop/start.js +3 -4
  155. package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
  156. package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -3
  157. package/dist/routes/computer-use/external-comms.d.ts +3 -3
  158. package/dist/routes/computer-use/fanout-bundle.js +11 -10
  159. package/dist/routes/computer-use/fanout-records.js +2 -2
  160. package/dist/routes/computer-use/in-process-desktop.js +1 -1
  161. package/dist/routes/computer-use/live-flush.d.ts +3 -3
  162. package/dist/routes/computer-use/live-phase.d.ts +2 -3
  163. package/dist/routes/computer-use/live-phase.js +3 -3
  164. package/dist/routes/computer-use/local-tree-pack.d.ts +5 -5
  165. package/dist/routes/computer-use/local-tree-pack.js +1 -1
  166. package/dist/routes/computer-use/local-vm.d.ts +8 -8
  167. package/dist/routes/computer-use/local-vm.js +2 -2
  168. package/dist/routes/computer-use/participant-desktop.d.ts +3 -3
  169. package/dist/routes/computer-use/participant-desktop.js +1 -1
  170. package/dist/routes/computer-use/participant-execution.js +1 -1
  171. package/dist/routes/computer-use/participant-model.js +3 -3
  172. package/dist/routes/computer-use/participant-prompt.d.ts +5 -5
  173. package/dist/routes/computer-use/participant-prompt.js +3 -3
  174. package/dist/routes/computer-use/participant-runs.d.ts +10 -10
  175. package/dist/routes/computer-use/participant-runs.js +14 -13
  176. package/dist/routes/computer-use/plan.d.ts +12 -12
  177. package/dist/routes/computer-use/plan.js +27 -27
  178. package/dist/routes/computer-use/preflight.d.ts +5 -5
  179. package/dist/routes/computer-use/preflight.js +5 -5
  180. package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
  181. package/dist/routes/computer-use/rerun-selection.js +3 -2
  182. package/dist/routes/computer-use/result.d.ts +4 -4
  183. package/dist/routes/computer-use/result.js +13 -12
  184. package/dist/routes/computer-use/route.d.ts +12 -12
  185. package/dist/routes/computer-use/route.js +19 -19
  186. package/dist/routes/computer-use/self-report.js +1 -1
  187. package/dist/routes/computer-use/setup.d.ts +22 -22
  188. package/dist/routes/computer-use/setup.js +15 -15
  189. package/dist/routes/computer-use/single-bundle.d.ts +4 -4
  190. package/dist/routes/computer-use/single-bundle.js +14 -13
  191. package/dist/routes/computer-use/subject-projection.d.ts +3 -3
  192. package/dist/routes/computer-use/types.d.ts +34 -34
  193. package/dist/routes/computer-use/types.js +3 -3
  194. package/dist/routes/preview.d.ts +6 -6
  195. package/dist/routes/preview.js +5 -5
  196. package/dist/routes/scripted/bundle.d.ts +6 -6
  197. package/dist/routes/scripted/bundle.js +10 -9
  198. package/dist/routes/scripted/plan.d.ts +7 -7
  199. package/dist/routes/scripted/plan.js +6 -6
  200. package/dist/routes/scripted/result.d.ts +3 -3
  201. package/dist/routes/scripted/result.js +9 -9
  202. package/dist/routes/scripted/route.d.ts +9 -9
  203. package/dist/routes/scripted/route.js +11 -11
  204. package/dist/routes/scripted/scenario.d.ts +1 -1
  205. package/dist/routes/scripted/scenario.js +3 -3
  206. package/dist/routes/scripted/setup.d.ts +6 -6
  207. package/dist/routes/scripted/setup.js +4 -4
  208. package/dist/routes/scripted/subject.d.ts +5 -5
  209. package/dist/routes/scripted/subject.js +3 -3
  210. package/dist/routes/scripted/surface-records.d.ts +1 -1
  211. package/dist/routes/scripted/surface-records.js +2 -2
  212. package/dist/routes/scripted/surface-sessions.d.ts +3 -3
  213. package/dist/routes/scripted/types.d.ts +17 -17
  214. package/dist/routes/scripted/types.js +1 -1
  215. package/dist/routes/shared-world/bundle-records.js +3 -3
  216. package/dist/routes/shared-world/bundle.js +15 -14
  217. package/dist/routes/shared-world/checkpoints.d.ts +3 -3
  218. package/dist/routes/shared-world/checkpoints.js +1 -1
  219. package/dist/routes/shared-world/comms.d.ts +9 -9
  220. package/dist/routes/shared-world/comms.js +6 -5
  221. package/dist/routes/shared-world/participant-specs.d.ts +3 -3
  222. package/dist/routes/shared-world/participant-specs.js +7 -7
  223. package/dist/routes/shared-world/plan.d.ts +9 -9
  224. package/dist/routes/shared-world/plan.js +9 -9
  225. package/dist/routes/shared-world/provisioned.d.ts +8 -8
  226. package/dist/routes/shared-world/provisioned.js +4 -4
  227. package/dist/routes/shared-world/result.d.ts +6 -6
  228. package/dist/routes/shared-world/result.js +11 -10
  229. package/dist/routes/shared-world/route.d.ts +11 -11
  230. package/dist/routes/shared-world/route.js +19 -19
  231. package/dist/routes/shared-world/setup.d.ts +13 -13
  232. package/dist/routes/shared-world/setup.js +19 -19
  233. package/dist/routes/shared-world/types.d.ts +27 -27
  234. package/dist/routes/terminal/adapter.d.ts +2 -2
  235. package/dist/routes/terminal/adapter.js +4 -4
  236. package/dist/routes/terminal/bundle.d.ts +11 -11
  237. package/dist/routes/terminal/bundle.js +12 -12
  238. package/dist/routes/terminal/credentials.d.ts +4 -4
  239. package/dist/routes/terminal/credentials.js +5 -5
  240. package/dist/routes/terminal/dry-run.d.ts +4 -4
  241. package/dist/routes/terminal/dry-run.js +9 -9
  242. package/dist/routes/terminal/ledger.d.ts +2 -2
  243. package/dist/routes/terminal/lifetime.d.ts +1 -1
  244. package/dist/routes/terminal/lifetime.js +1 -1
  245. package/dist/routes/terminal/live-finish.d.ts +2 -2
  246. package/dist/routes/terminal/live-finish.js +7 -7
  247. package/dist/routes/terminal/live-sandbox.d.ts +2 -2
  248. package/dist/routes/terminal/live-sandbox.js +3 -2
  249. package/dist/routes/terminal/participant-text.js +2 -1
  250. package/dist/routes/terminal/persona.d.ts +2 -2
  251. package/dist/routes/terminal/persona.js +2 -2
  252. package/dist/routes/terminal/plan.d.ts +7 -7
  253. package/dist/routes/terminal/plan.js +5 -5
  254. package/dist/routes/terminal/result.d.ts +5 -5
  255. package/dist/routes/terminal/result.js +7 -7
  256. package/dist/routes/terminal/route.d.ts +9 -9
  257. package/dist/routes/terminal/route.js +14 -14
  258. package/dist/routes/terminal/session.d.ts +5 -5
  259. package/dist/routes/terminal/session.js +7 -7
  260. package/dist/routes/terminal/trace.d.ts +2 -2
  261. package/dist/routes/terminal/types.d.ts +24 -24
  262. package/dist/routes/terminal/types.js +2 -2
  263. package/dist/run/bundle.d.ts +7 -7
  264. package/dist/run/bundle.js +2 -2
  265. package/dist/run/costs.d.ts +23 -0
  266. package/dist/run/costs.js +72 -43
  267. package/dist/run/dry-run-inputs.d.ts +1 -1
  268. package/dist/run/dry-run-inputs.js +1 -1
  269. package/dist/run/dry-run.js +2 -2
  270. package/dist/run/outcomes.d.ts +1 -1
  271. package/dist/run/participant.d.ts +1 -1
  272. package/dist/run/preflight-receipts.js +1 -1
  273. package/dist/run/pricing.js +2 -2
  274. package/dist/run/projection.d.ts +32 -32
  275. package/dist/run/projection.js +44 -44
  276. package/dist/run/reclaim.d.ts +1 -1
  277. package/dist/run/reclaim.js +1 -1
  278. package/dist/run/results.d.ts +2 -2
  279. package/dist/run/run-cost.d.ts +53 -0
  280. package/dist/run/run-cost.js +105 -0
  281. package/dist/run/run-index-analysis.d.ts +15 -0
  282. package/dist/run/run-index-analysis.js +77 -0
  283. package/dist/run/run-index.d.ts +11 -1
  284. package/dist/run/run-index.js +63 -49
  285. package/dist/run/run.d.ts +3 -3
  286. package/dist/run/run.js +2 -2
  287. package/dist/run/shared-world-evidence.d.ts +1 -1
  288. package/dist/run/shared-world-shape.js +1 -1
  289. package/dist/run/stats.d.ts +3 -3
  290. package/dist/run/stats.js +14 -14
  291. package/dist/run/status.d.ts +10 -2
  292. package/dist/run/status.js +6 -3
  293. package/dist/run/streams.d.ts +2 -2
  294. package/dist/run/study-provenance.d.ts +4 -2
  295. package/dist/run/study-provenance.js +7 -4
  296. package/dist/run/study-result.d.ts +0 -5
  297. package/dist/run/study-result.js +1 -1
  298. package/dist/run-study.d.ts +112 -0
  299. package/dist/{run-lab.js → run-study.js} +52 -45
  300. package/dist/{lab → study}/adapter-extension.d.ts +8 -20
  301. package/dist/{lab → study}/adapter-extension.js +2 -14
  302. package/dist/{lab → study}/adapter-scorer-loader.d.ts +10 -10
  303. package/dist/{lab → study}/adapter-scorer-loader.js +3 -3
  304. package/dist/study/composition-rules.d.ts +7 -0
  305. package/dist/{lab → study}/composition-rules.js +12 -12
  306. package/dist/study/config.d.ts +15 -0
  307. package/dist/{lab → study}/config.js +37 -20
  308. package/dist/study/convert.d.ts +1 -1
  309. package/dist/study/convert.js +15 -15
  310. package/dist/{lab → study}/device-presets.d.ts +2 -2
  311. package/dist/{lab → study}/discover.d.ts +29 -23
  312. package/dist/{lab → study}/discover.js +97 -118
  313. package/dist/{lab → study}/doctor.d.ts +11 -11
  314. package/dist/{lab → study}/doctor.js +18 -18
  315. package/dist/study/files.d.ts +2 -2
  316. package/dist/study/files.js +6 -5
  317. package/dist/{lab → study}/init-templates.d.ts +2 -2
  318. package/dist/{lab → study}/init-templates.js +16 -11
  319. package/dist/{lab → study}/init.d.ts +1 -1
  320. package/dist/{lab → study}/init.js +7 -4
  321. package/dist/{lab → study}/keys.d.ts +2 -2
  322. package/dist/{lab → study}/keys.js +10 -10
  323. package/dist/study/migrate.d.ts +8 -3
  324. package/dist/study/migrate.js +60 -4
  325. package/dist/{lab → study}/parse/actors.d.ts +5 -5
  326. package/dist/{lab → study}/parse/actors.js +5 -5
  327. package/dist/study/parse/comms.d.ts +12 -0
  328. package/dist/study/parse/execution.d.ts +19 -0
  329. package/dist/{lab → study}/parse/study-v3.d.ts +3 -5
  330. package/dist/{lab → study}/parse/study-v3.js +3 -3
  331. package/dist/{lab → study}/parse/subject-state.d.ts +8 -8
  332. package/dist/{lab → study}/parse/subject-state.js +4 -4
  333. package/dist/{lab → study}/parse/subject.d.ts +3 -3
  334. package/dist/{lab → study}/parse/subject.js +8 -8
  335. package/dist/{lab → study}/parse/values.d.ts +2 -2
  336. package/dist/{lab → study}/persona-resolve.d.ts +4 -4
  337. package/dist/{lab → study}/persona-resolve.js +2 -2
  338. package/dist/{lab → study}/plan-base.d.ts +7 -7
  339. package/dist/{lab → study}/plan-base.js +1 -1
  340. package/dist/{lab → study}/plan-participants.d.ts +10 -10
  341. package/dist/{lab → study}/plan-participants.js +4 -4
  342. package/dist/{lab → study}/plan-types.d.ts +28 -28
  343. package/dist/{lab → study}/plan-types.js +2 -2
  344. package/dist/study/plan.d.ts +13 -0
  345. package/dist/{lab → study}/plan.js +20 -20
  346. package/dist/study/preflight-probes.d.ts +3 -0
  347. package/dist/{lab → study}/preflight-probes.js +9 -8
  348. package/dist/study/preflight-result.d.ts +8 -0
  349. package/dist/{lab → study}/preflight-result.js +3 -3
  350. package/dist/{lab → study}/preflight.d.ts +31 -31
  351. package/dist/{lab → study}/preflight.js +8 -8
  352. package/dist/{lab → study}/requirements.d.ts +3 -3
  353. package/dist/{lab → study}/requirements.js +1 -1
  354. package/dist/study/route-inputs.d.ts +28 -0
  355. package/dist/{lab → study}/route-inputs.js +1 -1
  356. package/dist/{lab → study}/routing.d.ts +12 -12
  357. package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -10
  358. package/dist/{lab/run-lab-events.js → study/run-study-events.js} +4 -4
  359. package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +8 -17
  360. package/dist/study/run-study-homes.js +3 -0
  361. package/dist/study/run-study-options.d.ts +28 -0
  362. package/dist/{lab/run-lab-options.js → study/run-study-options.js} +16 -15
  363. package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +2 -2
  364. package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
  365. package/dist/{lab → study}/summary.d.ts +10 -10
  366. package/dist/{lab → study}/summary.js +15 -15
  367. package/dist/{lab → study}/tasks.d.ts +3 -3
  368. package/dist/{lab → study}/tasks.js +1 -1
  369. package/dist/{lab → study}/types.d.ts +104 -104
  370. package/dist/{lab → study}/types.js +1 -1
  371. package/dist/{lab → study}/validation.d.ts +19 -19
  372. package/dist/{lab → study}/validation.js +13 -13
  373. package/dist/{lab → study}/warnings.d.ts +4 -4
  374. package/dist/{lab → study}/warnings.js +1 -1
  375. package/dist/subject/clone.d.ts +6 -6
  376. package/dist/subject/clone.js +2 -2
  377. package/dist/subject/local-tree-archive.d.ts +2 -2
  378. package/dist/subject/local-tree-archive.js +3 -3
  379. package/dist/subject/local-tree.d.ts +3 -3
  380. package/dist/subject/runtime.js +2 -2
  381. package/dist/subject/serve.d.ts +4 -4
  382. package/dist/subject/state.d.ts +3 -3
  383. package/dist/subject/state.js +1 -1
  384. package/dist/subject/steps.d.ts +1 -1
  385. package/dist/subject/steps.js +1 -1
  386. package/dist/substrates/desktop-session.js +2 -2
  387. package/dist/substrates/detached.d.ts +1 -1
  388. package/dist/substrates/e2b/desktop-browser.d.ts +4 -4
  389. package/dist/substrates/e2b/desktop-browser.js +1 -1
  390. package/dist/substrates/e2b/desktop-cdp.d.ts +1 -1
  391. package/dist/substrates/e2b/desktop-cdp.js +1 -1
  392. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  393. package/dist/substrates/e2b/desktop-executor.js +12 -12
  394. package/dist/substrates/e2b/desktop-geometry.d.ts +1 -1
  395. package/dist/substrates/e2b/desktop-geometry.js +1 -1
  396. package/dist/substrates/e2b/desktop-media.d.ts +3 -3
  397. package/dist/substrates/e2b/lifetime.js +1 -1
  398. package/dist/substrates/e2b/sandbox.d.ts +3 -3
  399. package/dist/substrates/e2b/sandbox.js +1 -1
  400. package/dist/substrates/e2b/sdk.d.ts +1 -1
  401. package/dist/substrates/e2b/sdk.js +1 -1
  402. package/dist/substrates/local/runtime-config.d.ts +4 -4
  403. package/dist/substrates/local/runtime-config.js +4 -4
  404. package/dist/tui/contract.d.ts +8 -8
  405. package/dist/tui/contract.js +2 -2
  406. package/dist/tui/launch.d.ts +3 -3
  407. package/dist/tui/launch.js +22 -16
  408. package/dist/tui-app.js +139 -139
  409. package/dist/verify/subject.d.ts +1 -1
  410. package/dist/verify/subject.js +1 -1
  411. package/dist/verify/verify.js +2 -1
  412. package/docs/architecture/actor-contract.md +5 -5
  413. package/docs/architecture/browser-control.md +1 -1
  414. package/docs/architecture/external-public-shared-world.md +8 -7
  415. package/docs/architecture/github-feedback-loop.md +1 -1
  416. package/docs/architecture/task-protocol-support.md +1 -1
  417. package/docs/architecture/terminal-product-route.md +18 -18
  418. package/docs/contracts/adapter-fixtures.md +2 -2
  419. package/docs/contracts/errors.md +8 -8
  420. package/docs/contracts/run-bundle.md +6 -4
  421. package/docs/contracts/schemas.md +61 -42
  422. package/docs/contracts/study-analysis.md +4 -1
  423. package/docs/contracts/study-costs.md +17 -2
  424. package/examples/README.md +1 -1
  425. package/examples/scorer/scorer.mjs +3 -3
  426. package/package.json +2 -1
  427. package/skills/humanish/SKILL.md +8 -6
  428. package/skills/humanish/agents/openai.yaml +1 -1
  429. package/dist/cli/commands/lab-format.d.ts +0 -9
  430. package/dist/cli/commands/lab-route-run.d.ts +0 -19
  431. package/dist/cli/commands/lab-route-scripted.d.ts +0 -17
  432. package/dist/cli/commands/lab-route-terminal.d.ts +0 -17
  433. package/dist/cli/commands/lab-run.d.ts +0 -9
  434. package/dist/lab/composition-rules.d.ts +0 -7
  435. package/dist/lab/config.d.ts +0 -7
  436. package/dist/lab/deprecated-fields.d.ts +0 -10
  437. package/dist/lab/deprecated-fields.js +0 -24
  438. package/dist/lab/parse/comms.d.ts +0 -12
  439. package/dist/lab/parse/execution.d.ts +0 -19
  440. package/dist/lab/plan.d.ts +0 -13
  441. package/dist/lab/preflight-probes.d.ts +0 -3
  442. package/dist/lab/preflight-result.d.ts +0 -8
  443. package/dist/lab/route-inputs.d.ts +0 -28
  444. package/dist/lab/run-lab-homes.js +0 -7
  445. package/dist/lab/run-lab-options.d.ts +0 -28
  446. package/dist/library-aliases.d.ts +0 -56
  447. package/dist/library-aliases.js +0 -22
  448. package/dist/run-lab.d.ts +0 -112
  449. /package/dist/{lab → study}/device-presets.js +0 -0
  450. /package/dist/{lab → study}/init-paths.d.ts +0 -0
  451. /package/dist/{lab → study}/init-paths.js +0 -0
  452. /package/dist/{lab → study}/init-plan.d.ts +0 -0
  453. /package/dist/{lab → study}/init-plan.js +0 -0
  454. /package/dist/{lab → study}/parse/comms.js +0 -0
  455. /package/dist/{lab → study}/parse/execution.js +0 -0
  456. /package/dist/{lab → study}/parse/values.js +0 -0
  457. /package/dist/{lab → study}/participant-assignment.d.ts +0 -0
  458. /package/dist/{lab → study}/participant-assignment.js +0 -0
  459. /package/dist/{lab → study}/persona.d.ts +0 -0
  460. /package/dist/{lab → study}/persona.js +0 -0
  461. /package/dist/{lab → study}/routing.js +0 -0
@@ -10,7 +10,7 @@
10
10
  // against a real app (it fills forms and clicks buttons). A dry run parses and digest-pins the
11
11
  // scenario and writes the contract bundle without touching anything.
12
12
  //
13
- // Subject provenance: an app-url run declares that the lab did not provision the
13
+ // Subject provenance: an app-url run declares that humanish did not provision the
14
14
  // subject, so its build provenance is unpinned and the evidence binds to the scenario digest. A
15
15
  // clone run records commit, env names, state provenance and a host digest, never the raw getHost
16
16
  // URL or a secret value.
@@ -24,7 +24,7 @@ import { buildRunSource } from "../../run/bundle.js";
24
24
  import { prepareSelectedOutputDirectory } from "../../run/contained-output.js";
25
25
  import { runScope } from "../../run/run.js";
26
26
  import { renderScriptedReviewMarkdown } from "./bundle.js";
27
- import { injectedBrowser, planScriptedLab } from "./plan.js";
27
+ import { injectedBrowser, planScriptedStudy } from "./plan.js";
28
28
  import { finishScriptedRun } from "./result.js";
29
29
  import { UnsafeScriptedSessionResultError } from "./session-result.js";
30
30
  import { prepareScriptedRun } from "./setup.js";
@@ -36,22 +36,22 @@ import { studyResultIdentity } from "../../run/study-result.js";
36
36
  * The config-taking entry point. It plans, returns a refusal with the envelope the route has always
37
37
  * returned at that refusal's stage, and otherwise runs the plan.
38
38
  */
39
- export async function runScriptedBrowserLab(options) {
39
+ export async function runScriptedBrowserStudy(options) {
40
40
  const { config, dryRun, ...input } = options;
41
- // planScriptedLab makes every configuration refusal, in the order this route always has.
42
- const planned = planScriptedLab(config, {
41
+ // planScriptedStudy makes every configuration refusal, in the order this route always has.
42
+ const planned = planScriptedStudy(config, {
43
43
  dryRun,
44
44
  injectedBrowser: injectedBrowser(input.deps),
45
45
  });
46
46
  if (planned.ok)
47
47
  return runScriptedPlan(planned.plan, input);
48
- return scriptedLabRefusal(options, planned.refusal);
48
+ return scriptedStudyRefusal(options, planned.refusal);
49
49
  }
50
50
  /**
51
- * A refused scripted lab's result, at the refusal's stage: a before-scope refusal has its own field
51
+ * A refused scripted study's result, at the refusal's stage: a before-scope refusal has its own field
52
52
  * order and no analysis record; the others come after the output directory checks.
53
53
  */
54
- export async function scriptedLabRefusal(options, refusal) {
54
+ export async function scriptedStudyRefusal(options, refusal) {
55
55
  const { config, dryRun } = options;
56
56
  const cwd = path.resolve(options.cwd);
57
57
  const actorType = config.actors[0]?.type ?? "";
@@ -87,7 +87,7 @@ export async function scriptedLabRefusal(options, refusal) {
87
87
  return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
88
88
  }
89
89
  /**
90
- * runLab's step for a scripted plan. It takes no scorer, and its local checks (keys, a browser)
90
+ * runStudyWith's step for a scripted plan. It takes no scorer, and its local checks (keys, a browser)
91
91
  * run inside the run, so it returns the run.
92
92
  */
93
93
  export function admitScriptedPlan(plan, input) {
@@ -102,7 +102,7 @@ export function admitScriptedPlan(plan, input) {
102
102
  /**
103
103
  * Run a scripted plan. The run scope gives a direct library caller the same status-record lifetime
104
104
  * the CLI gets: returning from this function finalizes any record the run opened, whichever of its
105
- * fail-closed exits it took. Each route opens its own scope; `runLab` opens none. Without this a
105
+ * fail-closed exits it took. Each route opens its own scope; `runStudyWith` opens none. Without this a
106
106
  * test or an adopter calling the route directly leaves
107
107
  * the 5s cadence ticking into a directory something else is deleting, which surfaces as an
108
108
  * unrelated ENOTEMPTY.
@@ -125,7 +125,7 @@ async function runScriptedPlanInScope(plan, input, scope) {
125
125
  runId: input.runId,
126
126
  mintRunId: makeScriptedRunId,
127
127
  mode: dryRun ? "dry-run" : "live",
128
- lab: plan.lab,
128
+ study: plan.study,
129
129
  renderReview: renderScriptedReviewMarkdown,
130
130
  observer: { open: input.open === true, render: setup.deps.renderObserver },
131
131
  });
@@ -11,7 +11,7 @@ interface ResolvedScriptedScenario {
11
11
  * Resolve and consume `scenario.ref`. Path-style refs (contain a separator or end .yaml/.yml)
12
12
  * resolve against cwd and are clamped inside it: a ../../ escape is rejected, never recorded
13
13
  * as repo-relative provenance. Id-style refs must be public-safe tokens and resolve to
14
- * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedLab
14
+ * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedStudy
15
15
  * has already refused a missing or blank ref.
16
16
  */
17
17
  export declare function resolveScriptedScenario(projectRoot: PreparedSelectedOutputDirectory, ref: string): Promise<ResolvedScriptedScenario | {
@@ -1,4 +1,4 @@
1
- // Resolve a scripted-browser lab's `scenario.ref` to a committed scenario file and parse its
1
+ // Resolve a scripted-browser study's `scenario.ref` to a committed scenario file and parse its
2
2
  // `browser.steps` into the journey the actor runs. The ref is an id or a repo-relative path that must
3
3
  // stay inside the project; provenance records it repo-relative with the scenario's digest.
4
4
  import { parse as parseYaml } from "yaml";
@@ -6,14 +6,14 @@ import path from "node:path";
6
6
  import { parseBrowserPersonaJourneyFromScenario } from "../../actors/scripted-browser/journey.js";
7
7
  import { digestText } from "../../evidence/redaction.js";
8
8
  import { readContainedRegularFile, } from "../../run/contained-output.js";
9
- // Same public-safe token shape the lab id uses; an id-style scenario.ref must match it before
9
+ // Same public-safe token shape the study id uses; an id-style scenario.ref must match it before
10
10
  // it is interpolated into a repo path.
11
11
  const SCENARIO_REF_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
12
12
  /**
13
13
  * Resolve and consume `scenario.ref`. Path-style refs (contain a separator or end .yaml/.yml)
14
14
  * resolve against cwd and are clamped inside it: a ../../ escape is rejected, never recorded
15
15
  * as repo-relative provenance. Id-style refs must be public-safe tokens and resolve to
16
- * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedLab
16
+ * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedStudy
17
17
  * has already refused a missing or blank ref.
18
18
  */
19
19
  export async function resolveScriptedScenario(projectRoot, ref) {
@@ -1,15 +1,15 @@
1
1
  import type { ActorPersonaRef } from "../../actors/contract.js";
2
2
  import type { BrowserPersonaJourney, ScriptedBrowserEvidenceUrlPolicy } from "../../actors/scripted-browser/types.js";
3
- import type { ScriptedPlan } from "../../lab/plan-types.js";
4
- import { type ScriptedBrowserLabResult, type ScriptedRunInput } from "./types.js";
5
- import type { LabDeps } from "../../lab/lab-deps.js";
3
+ import type { ScriptedPlan } from "../../study/plan-types.js";
4
+ import { type ScriptedBrowserStudyResult, type ScriptedRunInput } from "./types.js";
5
+ import type { StudyDeps } from "../../study/study-deps.js";
6
6
  /** What setup hands the run: the plan's subject and scenario, keys and the browser to launch. */
7
7
  export interface ScriptedRunSetup {
8
8
  cwd: string;
9
9
  physicalCwd: string;
10
- deps: LabDeps;
10
+ deps: StudyDeps;
11
11
  warnings: string[];
12
- failed: (code: NonNullable<ScriptedBrowserLabResult["error"]>["code"], message: string) => ScriptedBrowserLabResult;
12
+ failed: (code: NonNullable<ScriptedBrowserStudyResult["error"]>["code"], message: string) => ScriptedBrowserStudyResult;
13
13
  clone: Extract<ScriptedPlan["subject"], {
14
14
  readonly kind: "clone";
15
15
  }> | undefined;
@@ -39,7 +39,7 @@ export interface ScriptedRunSetup {
39
39
  */
40
40
  export declare function prepareScriptedRun(plan: ScriptedPlan, input: ScriptedRunInput): Promise<{
41
41
  ok: false;
42
- result: ScriptedBrowserLabResult;
42
+ result: ScriptedBrowserStudyResult;
43
43
  } | {
44
44
  ok: true;
45
45
  setup: ScriptedRunSetup;
@@ -2,7 +2,7 @@
2
2
  // the E2B key and subject env of a live clone, a browser to launch) and the values the run reads
3
3
  // (the evidence URL policy, the scrubber for clone values, the persona and the session budget).
4
4
  import { realpath } from "node:fs/promises";
5
- import { missingKeys, missingSubjectEnv } from "../../lab/requirements.js";
5
+ import { missingKeys, missingSubjectEnv } from "../../study/requirements.js";
6
6
  import path from "node:path";
7
7
  import { resolveBrowserCommand } from "../../actors/scripted-browser/browser-command.js";
8
8
  import { describeMissingKeys } from "../../keys/key-resolution.js";
@@ -28,7 +28,7 @@ export async function prepareScriptedRun(plan, input) {
28
28
  const clone = plan.subject.kind === "clone" ? plan.subject : undefined;
29
29
  const evidenceAppUrl = evidenceAppUrlOf(plan.subject);
30
30
  const failed = (code, message) => ({
31
- ...studyResultIdentity("scripted", plan.labId),
31
+ ...studyResultIdentity("scripted", plan.studyId),
32
32
  ok: false,
33
33
  cwd,
34
34
  actor: plan.actor,
@@ -67,14 +67,14 @@ export async function prepareScriptedRun(plan, input) {
67
67
  if (missing.length > 0) {
68
68
  return {
69
69
  ok: false,
70
- result: failed("HUMANISH_SCRIPTED_KEYS_MISSING", `Live clone scripted-browser labs require ${missing.join(" and ")} (dry-run remains $0 and does not provision a subject). ${describeMissingKeys(missing, env)}`),
70
+ result: failed("HUMANISH_SCRIPTED_KEYS_MISSING", `Live clone scripted-browser studies require ${missing.join(" and ")} (dry-run remains $0 and does not provision a subject). ${describeMissingKeys(missing, env)}`),
71
71
  };
72
72
  }
73
73
  const unsetSubjectEnv = missingSubjectEnv(plan.requirements, env);
74
74
  if (unsetSubjectEnv.length > 0) {
75
75
  return {
76
76
  ok: false,
77
- result: failed("HUMANISH_SCRIPTED_SUBJECT_ENV_MISSING", `Subject env values missing for live clone scripted-browser lab: ${unsetSubjectEnv.join(", ")}.`),
77
+ result: failed("HUMANISH_SCRIPTED_SUBJECT_ENV_MISSING", `Subject env values missing for a live clone scripted-browser study: ${unsetSubjectEnv.join(", ")}.`),
78
78
  };
79
79
  }
80
80
  const surfaces = plan.surfaces;
@@ -1,9 +1,9 @@
1
- import type { ScriptedPlan } from "../../lab/plan-types.js";
1
+ import type { ScriptedPlan } from "../../study/plan-types.js";
2
2
  import { type PreparedRunArtifactPaths } from "../../run/paths.js";
3
3
  import type { RunSubjectStateStepRecord } from "../../run/bundle.js";
4
4
  import { type DesktopResourceObservation } from "../../substrates/e2b/desktop-resources.js";
5
- import type { LabDeps } from "../../lab/lab-deps.js";
6
- import type { RunLabHomes } from "../../lab/run-lab-homes.js";
5
+ import type { StudyDeps } from "../../study/study-deps.js";
6
+ import type { RunStudyHomes } from "../../study/run-study-homes.js";
7
7
  type ScriptedCloneSubject = Extract<ScriptedPlan["subject"], {
8
8
  readonly kind: "clone";
9
9
  }>;
@@ -11,9 +11,9 @@ type ScriptedCloneSubject = Extract<ScriptedPlan["subject"], {
11
11
  export interface ScriptedSubjectInputs {
12
12
  plan: ScriptedPlan;
13
13
  clone: ScriptedCloneSubject;
14
- deps: LabDeps;
14
+ deps: StudyDeps;
15
15
  /** Runs after the subject sandbox exists and before provisioning. */
16
- prepareDesktop?: NonNullable<RunLabHomes["prepareDesktop"]>;
16
+ prepareDesktop?: NonNullable<RunStudyHomes["prepareDesktop"]>;
17
17
  env: Readonly<Record<string, string | undefined>>;
18
18
  e2bApiKey: string;
19
19
  runPaths: PreparedRunArtifactPaths;
@@ -1,4 +1,4 @@
1
- // The provisioned subject of a live clone scripted-browser lab: one E2B desktop that clones,
1
+ // The provisioned subject of a live clone scripted-browser study: one E2B desktop that clones,
2
2
  // seeds and serves the app, exposed through a tokenless getHost URL and killed by exact id at
3
3
  // teardown.
4
4
  import { commandDigestOf } from "../../subject/state.js";
@@ -74,7 +74,7 @@ export class ScriptedSubject {
74
74
  metadata: {
75
75
  mode: "scripted-browser-lab",
76
76
  tool: "humanish",
77
- labId: plan.labId,
77
+ labId: plan.studyId,
78
78
  kind: "subject",
79
79
  actor: plan.actor,
80
80
  },
@@ -115,7 +115,7 @@ export class ScriptedSubject {
115
115
  ...timers,
116
116
  });
117
117
  if (typeof subjectDesktop.getHost !== "function") {
118
- throw new Error("the installed @e2b/desktop SDK does not expose getHost(port); clone scripted-browser labs require it to reach the provisioned subject");
118
+ throw new Error("the installed @e2b/desktop SDK does not expose getHost(port); clone scripted-browser studies require it to reach the provisioned subject");
119
119
  }
120
120
  const rawHost = subjectDesktop.getHost(servePort(clone.serve.url));
121
121
  const hostUrl = /^https?:\/\//i.test(rawHost) ? rawHost : `https://${rawHost}`;
@@ -10,7 +10,7 @@ export interface ScriptedSurfaceContext {
10
10
  appUrl: string;
11
11
  createdAt: string;
12
12
  journey: BrowserPersonaJourney;
13
- labId: string;
13
+ studyId: string;
14
14
  persona: ActorPersonaRef;
15
15
  sessionError?: string;
16
16
  }
@@ -30,14 +30,14 @@ export function scriptedSurfaceRecords(context, surface, index, result, screensh
30
30
  summary: result
31
31
  ? `Scripted-browser actor (${context.actorId}) replayed ${context.journey.scenarioId} on the ${surface.id} surface; ${result.completionReason}.`
32
32
  : context.sessionError !== undefined
33
- ? `Scripted lab failed before a terminal session verdict: ${context.sessionError}`
33
+ ? `The scripted run failed before a terminal session verdict: ${context.sessionError}`
34
34
  : `Scripted-browser actor (${context.actorId}) against ${context.appUrl}; no session ran.`,
35
35
  startedAt: context.createdAt,
36
36
  updatedAt: result?.capture.capturedAt ?? context.createdAt,
37
37
  });
38
38
  const stream = participantStream(ids, {
39
39
  kind: "browser",
40
- label: `${surface.label} · ${context.labId}`,
40
+ label: `${surface.label} · ${context.studyId}`,
41
41
  status,
42
42
  transport: "snapshot",
43
43
  updatedAt: result?.capture.capturedAt ?? context.createdAt,
@@ -1,11 +1,11 @@
1
1
  import { type ScriptedBrowserSessionOptions, type ScriptedBrowserSessionResult } from "../../actors/scripted-browser/actor.js";
2
- import type { ScriptedPlan } from "../../lab/plan-types.js";
2
+ import type { ScriptedPlan } from "../../study/plan-types.js";
3
3
  import { type PreparedRunArtifactPaths } from "../../run/paths.js";
4
- import type { LabDeps } from "../../lab/lab-deps.js";
4
+ import type { StudyDeps } from "../../study/study-deps.js";
5
5
  /** One session per surface, in parallel. */
6
6
  export declare function runScriptedSessions(session: Required<Pick<ScriptedBrowserSessionOptions, "appUrl" | "evidenceAppUrl" | "urlPolicy" | "journey" | "persona" | "timeoutMs" | "artifactRoot">>, run: {
7
7
  surfaces: ScriptedPlan["surfaces"];
8
- deps: LabDeps;
8
+ deps: StudyDeps;
9
9
  browserCommand: string | undefined;
10
10
  runPaths: PreparedRunArtifactPaths;
11
11
  }): Promise<ScriptedBrowserSessionResult[]>;
@@ -1,21 +1,21 @@
1
1
  import type { ActorCompletionReason, ActorStatus } from "../../actors/contract.js";
2
- import type { LabEvent } from "../../lab/run-lab-events.js";
2
+ import type { StudyEvent } from "../../study/run-study-events.js";
3
3
  import type { AutomaticAnalysisResult } from "../../analysis/automatic-completion.js";
4
- import type { LabConfig } from "../../lab/types.js";
4
+ import type { StudyConfig } from "../../study/types.js";
5
5
  import type { ObserverResult } from "../../observer/render.js";
6
6
  import type { RunSubjectProvenance } from "../../run/bundle.js";
7
- import type { LabDeps } from "../../lab/lab-deps.js";
8
- import type { RunLabHomes } from "../../lab/run-lab-homes.js";
7
+ import type { StudyDeps } from "../../study/study-deps.js";
8
+ import type { RunStudyHomes } from "../../study/run-study-homes.js";
9
9
  import { type StudyResultIdentity } from "../../run/study-result.js";
10
- /** What a scripted run takes besides its plan. The plan carries the config, dry run and lab. */
11
- export type ScriptedRunInput = Omit<RunScriptedBrowserLabOptions, "config" | "dryRun" | "lab">;
12
- export interface RunScriptedBrowserLabOptions {
10
+ /** What a scripted run takes besides its plan. The plan carries the config, dry run and study. */
11
+ export type ScriptedRunInput = Omit<RunScriptedBrowserStudyOptions, "config" | "dryRun">;
12
+ export interface RunScriptedBrowserStudyOptions {
13
13
  /** Cancels post-run analysis only. */
14
14
  analysisSignal?: AbortSignal;
15
- /** Reports the analysis window to onEvent; built by normalizeRunLabOptions. */
16
- emit?: (event: LabEvent) => void;
15
+ /** Reports the analysis window to onEvent; built by normalizeRunStudyOptions. */
16
+ emit?: (event: StudyEvent) => void;
17
17
  cwd: string;
18
- config: LabConfig;
18
+ config: StudyConfig;
19
19
  /** Resolved upstream (scenario.mode + CLI override); defaults safe (dry-run). */
20
20
  dryRun: boolean;
21
21
  open?: boolean;
@@ -23,20 +23,20 @@ export interface RunScriptedBrowserLabOptions {
23
23
  /** Keys and subject env for the run. Defaults to process.env. Values are scrubbed; names persist. */
24
24
  env?: Readonly<Record<string, string | undefined>>;
25
25
  /** Runs after a clone subject's sandbox exists and before provisioning. */
26
- prepareDesktop?: NonNullable<RunLabHomes["prepareDesktop"]>;
26
+ prepareDesktop?: NonNullable<RunStudyHomes["prepareDesktop"]>;
27
27
  /** Test seams: the browser, the session, the E2B module, timers, the renderer and the clock. */
28
- deps?: LabDeps;
28
+ deps?: StudyDeps;
29
29
  }
30
- interface ScriptedBrowserLabSession {
30
+ interface ScriptedBrowserStudySession {
31
31
  surface: string;
32
32
  status: ActorStatus;
33
33
  completionReason: ActorCompletionReason;
34
34
  reason: string;
35
35
  screenshots: number;
36
36
  }
37
- export interface ScriptedBrowserLabResult extends AutomaticAnalysisResult, StudyResultIdentity<"scripted"> {
37
+ export interface ScriptedBrowserStudyResult extends AutomaticAnalysisResult, StudyResultIdentity<"scripted"> {
38
38
  /** True when the bundle verified and (dry-run, or every session reached a terminal verdict
39
- * without a harness error). The subject failing the script is successful evidence, and the lab
39
+ * without a harness error). The subject failing the script is successful evidence, and the run
40
40
  * does not fail for it. */
41
41
  ok: boolean;
42
42
  cwd: string;
@@ -58,11 +58,11 @@ export interface ScriptedBrowserLabResult extends AutomaticAnalysisResult, Study
58
58
  sourceDigest: string;
59
59
  steps: number;
60
60
  };
61
- sessions: ScriptedBrowserLabSession[];
61
+ sessions: ScriptedBrowserStudySession[];
62
62
  observer?: ObserverResult;
63
63
  warnings: string[];
64
64
  error?: {
65
- code: "HUMANISH_STUDY_ANALYSIS_INVALID" | "HUMANISH_STUDY_TASKS_UNSUPPORTED" | "HUMANISH_STUDY_OPTION_UNSUPPORTED" | "HUMANISH_SCRIPTED_FAILED" | "HUMANISH_SCRIPTED_ACTOR_UNSUPPORTED" | "HUMANISH_SCRIPTED_SCENARIO_INVALID" | "HUMANISH_SCRIPTED_SUBJECT_UNSAFE" | "HUMANISH_SCRIPTED_BROWSER_MISSING" | "HUMANISH_SCRIPTED_KEYS_MISSING" | "HUMANISH_SCRIPTED_SUBJECT_ENV_MISSING" | "HUMANISH_SCRIPTED_GETHOST_UNAVAILABLE" | "HUMANISH_RUN_ID_IN_USE";
65
+ code: "HUMANISH_STUDY_ANALYSIS_INVALID" | "HUMANISH_STUDY_TASKS_UNSUPPORTED" | "HUMANISH_STUDY_OPTION_UNSUPPORTED" | "HUMANISH_STUDY_V2_UNSUPPORTED" | "HUMANISH_SCRIPTED_FAILED" | "HUMANISH_SCRIPTED_ACTOR_UNSUPPORTED" | "HUMANISH_SCRIPTED_SCENARIO_INVALID" | "HUMANISH_SCRIPTED_SUBJECT_UNSAFE" | "HUMANISH_SCRIPTED_BROWSER_MISSING" | "HUMANISH_SCRIPTED_KEYS_MISSING" | "HUMANISH_SCRIPTED_SUBJECT_ENV_MISSING" | "HUMANISH_SCRIPTED_GETHOST_UNAVAILABLE" | "HUMANISH_RUN_ID_IN_USE";
66
66
  message: string;
67
67
  };
68
68
  }
@@ -1,2 +1,2 @@
1
- // The scripted-browser lab's schema constant, options and result types.
1
+ // The scripted-browser study's schema constant, options and result types.
2
2
  import {} from "../../run/study-result.js";
@@ -1,7 +1,7 @@
1
1
  // Each participant's records in a concurrent shared-world bundle: its simulation, its stream and
2
2
  // its events, projected from the actor's run result (or from the declaration on a dry run or while
3
3
  // running).
4
- import { participantAssignment } from "../../lab/participant-assignment.js";
4
+ import { participantAssignment } from "../../study/participant-assignment.js";
5
5
  import { participantEvent, participantRecord, participantStream, } from "../../run/participant-records.js";
6
6
  import { declaredScreenForRender } from "../../substrates/e2b/desktop-geometry.js";
7
7
  import { publicSafeRouteLabel } from "./provenance.js";
@@ -68,7 +68,7 @@ function sharedWorldSimulation(ctx, spec, index, view) {
68
68
  const { taxonomy, outcome, session } = view;
69
69
  return participantRecord(spec, index + 1, {
70
70
  personaId: spec.persona.id,
71
- scenarioId: `concurrent-shared-world-${args.plan.labId}`,
71
+ scenarioId: `concurrent-shared-world-${args.plan.studyId}`,
72
72
  status: view.status,
73
73
  streamKind: "browser",
74
74
  mode: "browser-sim",
@@ -93,7 +93,7 @@ function sharedWorldStream(ctx, spec, index, view) {
93
93
  ? {}
94
94
  : { assignment: participantAssignment(spec.evidenceAssignment) }),
95
95
  kind: "browser",
96
- label: `Concurrent persona ${spec.planned.id}${taxonomy} · ${args.plan.labId}`,
96
+ label: `Concurrent persona ${spec.planned.id}${taxonomy} · ${args.plan.studyId}`,
97
97
  status: view.status,
98
98
  transport: "snapshot",
99
99
  updatedAt: args.run.createdAt,
@@ -14,6 +14,7 @@ import { hostOriginDigest } from "./provenance.js";
14
14
  import { participantEvent, participantIds } from "../../run/participant-records.js";
15
15
  import { sharedWorldParticipantRecords } from "./bundle-records.js";
16
16
  import { CONCURRENT_ATTRIBUTION_LIMITS, EXTERNAL_PUBLIC_ATTRIBUTION_LIMITS, } from "./types.js";
17
+ import { plural } from "../../run/text.js";
17
18
  /** Max windows live at the same instant (sweep over start/end points). The simultaneity
18
19
  * count: the participant count says how many existed; this says how many ever ran at once. */
19
20
  export function maxSimultaneousWindows(windows) {
@@ -86,7 +87,7 @@ function formatSharedWorldActorOutcomes(outcomes, expectedCount) {
86
87
  .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
87
88
  .map(([reason, count]) => `${reason} ${count}/${expectedCount}`)
88
89
  .join(", ");
89
- return `${passedSessions}/${expectedCount} actor session(s) passed credibility checks; mission endpoint: ${goalSatisfiedSessions}/${expectedCount} ended goal_satisfied; completion reasons: ${completionReasons}`;
90
+ return `${passedSessions}/${plural(expectedCount, "actor session")} passed credibility checks; mission endpoint: ${goalSatisfiedSessions}/${expectedCount} ended goal_satisfied; completion reasons: ${completionReasons}`;
90
91
  }
91
92
  /** The run's first two events: its creation and the shared plane's provenance. */
92
93
  function planeEvents(args, external) {
@@ -97,7 +98,7 @@ function planeEvents(args, external) {
97
98
  at: createdAt,
98
99
  level: "info",
99
100
  type: "concurrent-shared-world.run.created",
100
- message: `Created a concurrent shared-world run for ${plan.labId} (actor ${descriptor.id}, ${actorSpecs.length} persona(s) on one shared app, at most ${plan.concurrency} at once).`,
101
+ message: `Created a concurrent shared-world run for ${plan.studyId} (actor ${descriptor.id}, ${plural(actorSpecs.length, "persona")} on one shared app, at most ${plan.concurrency} at once).`,
101
102
  });
102
103
  // Human-readable plane label, byte-stable for the clone route. local-tree has no repo slug: it
103
104
  // labels the packed archive instead (archiveSha256 + dirty/clean when the packed root was a git
@@ -111,7 +112,7 @@ function planeEvents(args, external) {
111
112
  // External-public plane provenance differs: an operator-declared, operator-owned public
112
113
  // deployment humanish neither provisioned nor seeded, with no getHost, no clone and no synthetic
113
114
  // attestation (claiming synthetic on a real site is a lie). The origin persists digest-only.
114
- // planSharedWorldLab refuses an external-public plane without a declared owner; the fallback
115
+ // planSharedWorldStudy refuses an external-public plane without a declared owner; the fallback
115
116
  // says so rather than naming one.
116
117
  const externalPlaneOwner = plan.plane.kind === "external-public" ? plan.plane.owner : "(undeclared)";
117
118
  events.push(participantEvent(actorSpecs[0] ?? participantIds(0), {
@@ -120,7 +121,7 @@ function planeEvents(args, external) {
120
121
  level: "info",
121
122
  type: "concurrent-shared-world.plane.provenance",
122
123
  message: external
123
- ? `Shared app: a public deployment the operator declares they own (${externalPlaneOwner}, authorized), used as it is, with no sandbox, clone or seed. humanish observed that each participant reached the declared origin (publicOriginDigest); it did not create or control the app. Ownership is the lab's declaration, and the data is not claimed to be synthetic.`
124
+ ? `Shared app: a public deployment the operator declares they own (${externalPlaneOwner}, authorized), used as it is, with no sandbox, clone or seed. humanish observed that each participant reached the declared origin (publicOriginDigest); it did not create or control the app. Ownership is the study's declaration, and the data is not claimed to be synthetic.`
124
125
  : dryRun
125
126
  ? `Shared app declared: ${dryRunPlaneLabel}, to be served in the sandbox at a public sandbox URL (dry run: nothing ${args.subject.source === "local-tree" ? "packed" : "cloned"}). Seed recipe ${args.seedDigest}; synthetic subject, as the study declares; env names: ${args.subject.envNames?.join(", ") || "none"} (values never stored).`
126
127
  : `Shared app: ${livePlaneLabel}, served at a public sandbox URL humanish created; seed recipe ${args.seedDigest}; synthetic subject, as the study declares; env names: ${args.subject.envNames?.join(", ") || "none"} (values never stored).`,
@@ -249,7 +250,7 @@ function concurrencyReview(args, external, inProgress, evidence, events, nextEve
249
250
  const deltas = (stateSeries ?? []).filter((snapshot, i) => i > 0 && snapshot.digest !== (stateSeries ?? [])[i - 1].digest).length;
250
251
  const stateSeriesLabel = external
251
252
  ? "stateSeries omitted (no authoritative shared-state proof on the external-public plane)"
252
- : `stateSeries ${(stateSeries ?? []).length} snapshot(s), ${deltas} delta(s)`;
253
+ : `stateSeries ${plural((stateSeries ?? []).length, "snapshot")}, ${plural(deltas, "delta")}`;
253
254
  const convergenceLabel = external
254
255
  ? `; lobby convergence ${args.lobbyConvergenceDigest ? "shown (all participants reached one /lobby/CODE)" : "not observed"}`
255
256
  : "";
@@ -262,7 +263,7 @@ function concurrencyReview(args, external, inProgress, evidence, events, nextEve
262
263
  at: createdAt,
263
264
  level: "info",
264
265
  type: "concurrent-shared-world.concurrency",
265
- message: `Concurrency: ${windows.length} participant(s)${dryRun ? " (dry run; $0)" : `, up to ${maxLive} live at once (cap ${capForReport}), overlap ${overlaps ? "shown" : "not observed"}`}; ${stateSeriesLabel}${convergenceLabel}. Attribution ceiling: ${sharedWorld.attributionLimits.join(", ")}. ${dryRun ? "This dry run proves nothing about live concurrency, scale, or adoption." : "This run reports only its own observed overlap and state changes; it does not prove scale, repeatability, or adopter-harness replacement."}`,
266
+ message: `Concurrency: ${plural(windows.length, "participant")}${dryRun ? " (dry run; $0)" : `, up to ${maxLive} live at once (cap ${capForReport}), overlap ${overlaps ? "shown" : "not observed"}`}; ${stateSeriesLabel}${convergenceLabel}. Attribution ceiling: ${sharedWorld.attributionLimits.join(", ")}. ${dryRun ? "This dry run proves nothing about live concurrency, scale, or adoption." : "This run reports only its own observed overlap and state changes; it does not prove scale, repeatability, or adopter-harness replacement."}`,
266
267
  });
267
268
  // The judge's verdict (judgeSharedWorld): every participant produced a terminal, engaged, passed
268
269
  // session. Mission endpoint and completion reasons are reported separately below; `outcomes[].ok`
@@ -277,13 +278,13 @@ function concurrencyReview(args, external, inProgress, evidence, events, nextEve
277
278
  // report "state delta(s) under load" (live). It reports lobby convergence instead.
278
279
  summary: dryRun
279
280
  ? external
280
- ? `Concurrent shared-world dry run: ${actorSpecs.length} persona(s) declared against one public deployment, used as it is (no sandbox, clone or seed); no sandboxes launched, $0 spent.`
281
- : `Concurrent shared-world dry run: ${actorSpecs.length} persona(s) declared against one app served at a public sandbox URL (${descriptor.id}); no sandboxes launched, $0 spent.`
281
+ ? `Concurrent shared-world dry run: ${plural(actorSpecs.length, "persona")} declared against one public deployment, used as it is (no sandbox, clone or seed); no sandboxes launched, $0 spent.`
282
+ : `Concurrent shared-world dry run: ${plural(actorSpecs.length, "persona")} declared against one app served at a public sandbox URL (${descriptor.id}); no sandboxes launched, $0 spent.`
282
283
  : inProgress
283
- ? `In-progress concurrent shared-world Observer snapshot: ${actorSpecs.length} persona(s) running against one shared app; final verification is pending.`
284
+ ? `In-progress concurrent shared-world Observer snapshot: ${plural(actorSpecs.length, "persona")} running against one shared app; final verification is pending.`
284
285
  : external
285
286
  ? `Concurrent shared-world (one public deployment, ${actorSpecs.length} personas at once): swarm ${verdict === "pass" ? "ran coherently" : "did not run coherently"}; ${actorOutcomeSummary}; overlap ${overlaps ? "proven" : "not observed"}; ${args.lobbyConvergenceDigest ? `${actorSpecs.length} participants converged on one lobby` : "lobby convergence not observed"}.`
286
- : `Concurrent shared-world (one shared app, ${actorSpecs.length} personas at once): swarm ${verdict === "pass" ? "ran coherently" : "did not run coherently"}; ${actorOutcomeSummary}; overlap ${overlaps ? "proven" : "not observed"}; ${deltas} state delta(s) under load.`,
287
+ : `Concurrent shared-world (one shared app, ${actorSpecs.length} personas at once): swarm ${verdict === "pass" ? "ran coherently" : "did not run coherently"}; ${actorOutcomeSummary}; overlap ${overlaps ? "proven" : "not observed"}; ${plural(deltas, "state delta")} under load.`,
287
288
  gaps: dryRun
288
289
  ? [
289
290
  "This dry run launched no concurrent shared-world session; it checks the evidence shape only, not live behavior, scale, or adopter-harness replacement.",
@@ -333,16 +334,16 @@ export function buildConcurrentSharedWorldBundle(args) {
333
334
  persona: {
334
335
  id: actorSpecs[0]?.persona.id ?? "concurrent-persona",
335
336
  name: `Concurrent shared-world swarm (${actorSpecs.length} personas)`,
336
- source: `study:${plan.labId}`,
337
+ source: `study:${plan.studyId}`,
337
338
  sourceDigest: actorSpecs[0]?.persona.promptDigest ?? args.seedDigest,
338
339
  },
339
340
  scenario: {
340
- id: `concurrent-shared-world-${plan.labId}`,
341
- title: plan.title ?? `Concurrent shared-world: ${plan.labId}`,
341
+ id: `concurrent-shared-world-${plan.studyId}`,
342
+ title: plan.title ?? `Concurrent shared-world: ${plan.studyId}`,
342
343
  goal: redactText(actorSpecs[0]?.evidenceInstructions ??
343
344
  actorSpecs[0]?.instructions ??
344
345
  "Concurrent shared-world interaction."),
345
- source: `study:${plan.labId}`,
346
+ source: `study:${plan.studyId}`,
346
347
  sourceDigest: actorSpecs[0]?.persona.promptDigest ?? args.seedDigest,
347
348
  },
348
349
  lifecycle: [
@@ -1,6 +1,6 @@
1
1
  import type { Shell } from "../../substrates/shell.js";
2
2
  import { type DetachedTimers } from "../../substrates/detached.js";
3
- import { type LabSubjectState, type LabSubjectStateCheckpoint } from "../../lab/types.js";
3
+ import { type StudySubjectState, type StudySubjectStateCheckpoint } from "../../study/types.js";
4
4
  import { type SharedWorldCheckpoint } from "../../run/shared-world-evidence.js";
5
5
  /** Combine a snapshot's per-probe digests into one sha256-16 (digest-only; no raw value). */
6
6
  export declare function combineCheckpointDigest(parts: string[]): string;
@@ -15,11 +15,11 @@ export declare function runCheckpointSnapshot(args: {
15
15
  shell: Shell;
16
16
  snapshotIndex: number;
17
17
  name: string;
18
- checkpoints: LabSubjectStateCheckpoint[];
18
+ checkpoints: StudySubjectStateCheckpoint[];
19
19
  prevDigest: string | undefined;
20
20
  scrub: (text: string) => string;
21
21
  requestTimeoutMs: number;
22
22
  timers: DetachedTimers;
23
23
  }): Promise<SharedWorldCheckpoint>;
24
24
  /** sha256-16 over the ordered seed-step command digests: the seeded-state recipe identity. */
25
- export declare function seedRecipeDigest(state: LabSubjectState | undefined): string;
25
+ export declare function seedRecipeDigest(state: StudySubjectState | undefined): string;
@@ -1,7 +1,7 @@
1
1
  import { commandDigestOf } from "../../subject/state.js";
2
2
  import { SUBJECT_DIR } from "../../subject/steps.js";
3
3
  import { runDetachedStep } from "../../substrates/detached.js";
4
- import {} from "../../lab/types.js";
4
+ import {} from "../../study/types.js";
5
5
  import { redactText } from "../../evidence/redaction.js";
6
6
  import {} from "../../run/shared-world-evidence.js";
7
7
  // Per-checkpoint probe budget (read-only aggregate probes are fast).
@@ -1,18 +1,18 @@
1
1
  import { type ReceivingSource } from "../../comms/receiving-runtime.js";
2
- import type { SharedWorldPlan } from "../../lab/plan-types.js";
2
+ import type { SharedWorldPlan } from "../../study/plan-types.js";
3
3
  import type { CommsReceivingRun } from "../../comms/receiving.js";
4
4
  import { type DeployedCommsCatch } from "../../comms/sandbox-catch.js";
5
- import type { LabCommsEmail, LabConfig } from "../../lab/types.js";
5
+ import type { StudyCommsEmail, StudyConfig } from "../../study/types.js";
6
6
  import type { Shell } from "../../substrates/shell.js";
7
7
  import type { ConcurrentSharedWorldPlaneClass, ExternalCommsWiring, PlaneContext } from "./types.js";
8
- /** The in-sandbox email catch a provisioned plane deploys, when the lab declares one. */
8
+ /** The in-sandbox email catch a provisioned plane deploys, when the study declares one. */
9
9
  export interface SubjectComms {
10
- email: LabCommsEmail | undefined;
10
+ email: StudyCommsEmail | undefined;
11
11
  port: number | undefined;
12
12
  /** The catch's base URL, injected into the subject sandbox's env at create. */
13
13
  env: Record<string, string>;
14
14
  }
15
- export declare function subjectCommsOf(config: Pick<LabConfig, "comms">, planeClass: ConcurrentSharedWorldPlaneClass): SubjectComms;
15
+ export declare function subjectCommsOf(config: Pick<StudyConfig, "comms">, planeClass: ConcurrentSharedWorldPlaneClass): SubjectComms;
16
16
  /**
17
17
  * Adopter-hosted ingress: on the external-public plane the harness provisions nothing, so
18
18
  * it cannot host a catch. The operator can, and then humanish still does every other part of
@@ -21,7 +21,7 @@ export declare function subjectCommsOf(config: Pick<LabConfig, "comms">, planeCl
21
21
  * the previously-inert block into a working one. Returns an error message when the declared catch
22
22
  * does not answer as a humanish catch.
23
23
  */
24
- export declare function prepareExternalComms(config: Pick<LabConfig, "comms">, planeClass: ConcurrentSharedWorldPlaneClass, dryRun: boolean, warnings: string[], env: Record<string, string | undefined>): Promise<{
24
+ export declare function prepareExternalComms(config: Pick<StudyConfig, "comms">, planeClass: ConcurrentSharedWorldPlaneClass, dryRun: boolean, warnings: string[], env: Record<string, string | undefined>): Promise<{
25
25
  ok: true;
26
26
  wiring: ExternalCommsWiring | undefined;
27
27
  } | {
@@ -36,7 +36,7 @@ export declare function prepareExternalComms(config: Pick<LabConfig, "comms">, p
36
36
  * never blocks teardown (invariant: all sandboxes torn down by id in the plane's finally). Returns
37
37
  * the thread's path when one was written.
38
38
  */
39
- export declare function drainSubjectComms(ctx: PlaneContext, commsEmail: LabCommsEmail, subjectShell: Shell, deployedComms: DeployedCommsCatch): Promise<string | undefined>;
39
+ export declare function drainSubjectComms(ctx: PlaneContext, commsEmail: StudyCommsEmail, subjectShell: Shell, deployedComms: DeployedCommsCatch): Promise<string | undefined>;
40
40
  /**
41
41
  * Adopter-hosted drain: same routing and digest-only artifact as the in-sandbox
42
42
  * catch. Only the transport differs (HTTP GET /deliveries against the catch the operator
@@ -44,10 +44,10 @@ export declare function drainSubjectComms(ctx: PlaneContext, commsEmail: LabComm
44
44
  * masks the run's own outcome. Returns the thread's path when one was written.
45
45
  */
46
46
  export declare function drainExternalComms(ctx: PlaneContext, comms: ExternalCommsWiring): Promise<string | undefined>;
47
- /** What receiving guards: the lab's email declaration and the subject env names and values. */
47
+ /** What receiving guards: the study's email declaration and the subject env names and values. */
48
48
  export declare function receivingSourceOf(residual: SharedWorldPlan["residual"], env: readonly string[]): ReceivingSource;
49
49
  /**
50
- * Real email receiving, when the lab declares it on a live run. It registers the connection's
50
+ * Real email receiving, when the study declares it on a live run. It registers the connection's
51
51
  * secrets with the run's scrub before any desktop starts. Returns the message the run fails with
52
52
  * when setup fails.
53
53
  */
@@ -7,7 +7,8 @@ import { prepareReceivingRun } from "../../comms/receiving-runtime.js";
7
7
  import { DEFAULT_SANDBOX_CATCH_PORT, collectCommsThread, externalCatchHealthy, externalInboxUrl, } from "../../comms/sandbox-catch.js";
8
8
  import { redactText, toErrorMessage } from "../../evidence/redaction.js";
9
9
  import { writeContainedOutputFile } from "../../run/contained-output.js";
10
- import { addressedRecipients } from "../../lab/parse/comms.js";
10
+ import { addressedRecipients } from "../../study/parse/comms.js";
11
+ import { plural } from "../../run/text.js";
11
12
  // Off-app comms: on the provisioned-getHost plane the harness owns the one subject sandbox, so
12
13
  // it can redirect the app's email-API sends into an in-sandbox catch and evidence them. Gated entirely
13
14
  // on config.comms: no comms declared → zero change. The base-URL env is injected into the subject
@@ -52,7 +53,7 @@ export async function prepareExternalComms(config, planeClass, dryRun, warnings,
52
53
  code: "HUMANISH_SHARED_WORLD_COMMS_TOKEN_INVALID",
53
54
  message: tokenRefusal,
54
55
  };
55
- // Fail closed before any actor sandbox is created: a comms lab whose catch is unreachable
56
+ // Fail closed before any actor sandbox is created: a comms study whose catch is unreachable
56
57
  // collects nothing while every participant still spends. The probe asserts our service marker in
57
58
  // /health, so an adopter's proxy answering 200 for everything cannot pass for a catch.
58
59
  if (!dryRun && !(await externalCatchHealthy(externalComms))) {
@@ -91,7 +92,7 @@ export async function drainSubjectComms(ctx, commsEmail, subjectShell, deployedC
91
92
  return "comms/thread.json";
92
93
  }
93
94
  else if (collected.captured > 0) {
94
- warnings.push(`The email catch captured ${collected.captured} email send(s), but none matched a declared recipient inbox, so no email evidence was written. Set comms.email.recipients[].address to the address the app sends to.`);
95
+ warnings.push(`The email catch captured ${plural(collected.captured, "email send")}, but none matched a declared recipient inbox, so no email evidence was written. Set comms.email.recipients[].address to the address the app sends to.`);
95
96
  }
96
97
  else {
97
98
  // Zero captures is the silent-broken shape: the app never posted to the catch.
@@ -120,7 +121,7 @@ export async function drainExternalComms(ctx, comms) {
120
121
  ctx.warnings.push(...warnings);
121
122
  return path;
122
123
  }
123
- /** What receiving guards: the lab's email declaration and the subject env names and values. */
124
+ /** What receiving guards: the study's email declaration and the subject env names and values. */
124
125
  export function receivingSourceOf(residual, env) {
125
126
  const { comms } = residual;
126
127
  const { envValues } = residual.subject;
@@ -130,7 +131,7 @@ export function receivingSourceOf(residual, env) {
130
131
  };
131
132
  }
132
133
  /**
133
- * Real email receiving, when the lab declares it on a live run. It registers the connection's
134
+ * Real email receiving, when the study declares it on a live run. It registers the connection's
134
135
  * secrets with the run's scrub before any desktop starts. Returns the message the run fails with
135
136
  * when setup fails.
136
137
  */