humanish 0.107.0 → 0.109.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 (671) hide show
  1. package/ARCHITECTURE.md +73 -69
  2. package/CHANGELOG.md +27 -0
  3. package/CONTEXT.md +51 -44
  4. package/README.md +148 -175
  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-trace.js +2 -1
  14. package/dist/actors/codex/app-server-ui.js +1 -1
  15. package/dist/actors/codex/codex-admission.d.ts +91 -0
  16. package/dist/actors/codex/codex-admission.js +150 -0
  17. package/dist/actors/codex/restricted-executable.d.ts +4 -4
  18. package/dist/actors/codex/restricted-executable.js +8 -8
  19. package/dist/actors/codex/restricted-launch.d.ts +2 -1
  20. package/dist/actors/codex/restricted-launch.js +1 -1
  21. package/dist/actors/codex/restricted-participant.js +20 -18
  22. package/dist/actors/codex/restricted-policy.d.ts +2 -2
  23. package/dist/actors/codex/restricted-policy.js +2 -2
  24. package/dist/actors/codex/restricted-session.d.ts +3 -3
  25. package/dist/actors/codex/restricted-session.js +10 -5
  26. package/dist/actors/computer-use/actor.d.ts +18 -18
  27. package/dist/actors/computer-use/actor.js +4 -4
  28. package/dist/actors/computer-use/admission-limit.d.ts +3 -3
  29. package/dist/actors/computer-use/admission-limit.js +4 -4
  30. package/dist/actors/computer-use/executor-error.d.ts +2 -2
  31. package/dist/actors/computer-use/executor-error.js +3 -3
  32. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  33. package/dist/actors/computer-use/loop/actions.js +15 -15
  34. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  35. package/dist/actors/computer-use/loop/backstop.js +14 -12
  36. package/dist/actors/computer-use/loop/debrief.js +2 -2
  37. package/dist/actors/computer-use/loop/ending.d.ts +6 -6
  38. package/dist/actors/computer-use/loop/ending.js +18 -17
  39. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  40. package/dist/actors/computer-use/loop/observation.js +15 -14
  41. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  42. package/dist/actors/computer-use/loop/provider-call.js +12 -12
  43. package/dist/actors/computer-use/loop/session.d.ts +4 -4
  44. package/dist/actors/computer-use/loop/session.js +4 -4
  45. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  46. package/dist/actors/computer-use/loop/spend.js +1 -1
  47. package/dist/actors/computer-use/loop/trace.js +11 -9
  48. package/dist/actors/computer-use/loop/types.d.ts +47 -45
  49. package/dist/actors/computer-use/loop/usage.d.ts +2 -2
  50. package/dist/actors/computer-use/loop/usage.js +2 -2
  51. package/dist/actors/computer-use/loop.d.ts +6 -1
  52. package/dist/actors/computer-use/loop.js +26 -4
  53. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  54. package/dist/actors/computer-use/openai-context.js +214 -0
  55. package/dist/actors/computer-use/openai-provider.d.ts +13 -10
  56. package/dist/actors/computer-use/openai-provider.js +52 -41
  57. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  58. package/dist/actors/computer-use/openai-requests.js +82 -15
  59. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  60. package/dist/actors/computer-use/openai-wire.js +36 -34
  61. package/dist/actors/computer-use/provider-error.d.ts +4 -4
  62. package/dist/actors/computer-use/provider-error.js +6 -6
  63. package/dist/actors/contract.d.ts +82 -47
  64. package/dist/actors/contract.js +30 -24
  65. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  66. package/dist/actors/local-agent/claude-session.js +13 -12
  67. package/dist/actors/local-agent/cli.d.ts +9 -7
  68. package/dist/actors/local-agent/cli.js +24 -28
  69. package/dist/actors/local-agent/readiness.d.ts +2 -2
  70. package/dist/actors/local-agent/readiness.js +4 -4
  71. package/dist/actors/reasoning-effort.js +8 -8
  72. package/dist/actors/registry.d.ts +12 -12
  73. package/dist/actors/registry.js +21 -20
  74. package/dist/actors/scripted-browser/actor.d.ts +10 -10
  75. package/dist/actors/scripted-browser/actor.js +17 -17
  76. package/dist/actors/scripted-browser/browser-command.js +1 -1
  77. package/dist/actors/scripted-browser/steps.js +1 -1
  78. package/dist/actors/scripted-browser/types.d.ts +1 -1
  79. package/dist/actors/stop-conditions.d.ts +1 -1
  80. package/dist/analysis/automatic-completion.d.ts +7 -7
  81. package/dist/analysis/automatic-completion.js +1 -1
  82. package/dist/analysis/automatic-config.d.ts +6 -6
  83. package/dist/analysis/automatic-config.js +1 -1
  84. package/dist/analysis/codex-config.d.ts +6 -2
  85. package/dist/analysis/codex-config.js +22 -14
  86. package/dist/analysis/execute.d.ts +1 -1
  87. package/dist/analysis/execute.js +1 -1
  88. package/dist/analysis/service.js +5 -5
  89. package/dist/analysis/types.d.ts +6 -0
  90. package/dist/browser-control/client.js +16 -16
  91. package/dist/browser-control/dispatcher.js +4 -4
  92. package/dist/browser-control/protocol.js +14 -14
  93. package/dist/browser-control/recording-transfer.js +4 -4
  94. package/dist/browser-control/transport.js +7 -7
  95. package/dist/cli/commands/analysis-signals.d.ts +2 -2
  96. package/dist/cli/commands/analyze.js +19 -16
  97. package/dist/cli/commands/codex.js +9 -9
  98. package/dist/cli/commands/comms.js +48 -35
  99. package/dist/cli/commands/feedback.js +20 -21
  100. package/dist/cli/commands/migrate.d.ts +4 -0
  101. package/dist/cli/commands/migrate.js +65 -0
  102. package/dist/cli/commands/observe.d.ts +0 -1
  103. package/dist/cli/commands/observe.js +136 -112
  104. package/dist/cli/commands/run-command.d.ts +10 -0
  105. package/dist/cli/commands/run-command.js +85 -0
  106. package/dist/cli/commands/runs.js +136 -139
  107. package/dist/cli/commands/setup.d.ts +2 -2
  108. package/dist/cli/commands/setup.js +27 -24
  109. package/dist/cli/commands/study-format.d.ts +9 -0
  110. package/dist/cli/commands/{lab-format.js → study-format.js} +39 -27
  111. package/dist/cli/commands/{lab-route-computer-use.d.ts → study-route-computer-use.d.ts} +6 -6
  112. package/dist/cli/commands/{lab-route-computer-use.js → study-route-computer-use.js} +17 -18
  113. package/dist/cli/commands/{lab-route-open.d.ts → study-route-open.d.ts} +4 -4
  114. package/dist/cli/commands/{lab-route-open.js → study-route-open.js} +2 -2
  115. package/dist/cli/commands/{lab-route-preview.d.ts → study-route-preview.d.ts} +7 -7
  116. package/dist/cli/commands/{lab-route-preview.js → study-route-preview.js} +7 -6
  117. package/dist/cli/commands/study-route-run.d.ts +19 -0
  118. package/dist/cli/commands/{lab-route-run.js → study-route-run.js} +6 -6
  119. package/dist/cli/commands/study-route-scripted.d.ts +17 -0
  120. package/dist/cli/commands/{lab-route-scripted.js → study-route-scripted.js} +4 -4
  121. package/dist/cli/commands/{lab-route-shared-world.d.ts → study-route-shared-world.d.ts} +5 -5
  122. package/dist/cli/commands/{lab-route-shared-world.js → study-route-shared-world.js} +10 -10
  123. package/dist/cli/commands/study-route-terminal.d.ts +17 -0
  124. package/dist/cli/commands/{lab-route-terminal.js → study-route-terminal.js} +4 -4
  125. package/dist/cli/commands/study-run.d.ts +9 -0
  126. package/dist/cli/commands/{lab-run.js → study-run.js} +44 -45
  127. package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +7 -7
  128. package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +2 -2
  129. package/dist/cli/commands/study.d.ts +3 -0
  130. package/dist/cli/commands/study.js +146 -0
  131. package/dist/cli/commands/tui.d.ts +4 -4
  132. package/dist/cli/commands/tui.js +31 -31
  133. package/dist/cli/commands/watch.js +71 -121
  134. package/dist/cli/deprecations.d.ts +6 -0
  135. package/dist/cli/deprecations.js +18 -0
  136. package/dist/cli/doctor.d.ts +18 -8
  137. package/dist/cli/doctor.js +114 -59
  138. package/dist/cli/first-run-path.d.ts +15 -13
  139. package/dist/cli/first-run-path.js +35 -33
  140. package/dist/cli/io.d.ts +44 -9
  141. package/dist/cli/io.js +98 -23
  142. package/dist/cli/observer-follow.d.ts +3 -3
  143. package/dist/cli/observer-follow.js +6 -7
  144. package/dist/cli/orientation.d.ts +10 -7
  145. package/dist/cli/orientation.js +89 -47
  146. package/dist/cli/product-sentence.d.ts +6 -0
  147. package/dist/cli/product-sentence.js +6 -0
  148. package/dist/cli/program.d.ts +6 -1
  149. package/dist/cli/program.js +111 -43
  150. package/dist/cli/telemetry.d.ts +16 -16
  151. package/dist/cli/telemetry.js +46 -44
  152. package/dist/cli.js +1 -1
  153. package/dist/comms/capture-surface.d.ts +13 -12
  154. package/dist/comms/capture-surface.js +23 -22
  155. package/dist/comms/catch-host.d.ts +7 -7
  156. package/dist/comms/catch-host.js +17 -17
  157. package/dist/comms/connections.d.ts +1 -1
  158. package/dist/comms/connections.js +2 -2
  159. package/dist/comms/email-catch.d.ts +3 -3
  160. package/dist/comms/email-catch.js +8 -8
  161. package/dist/comms/external-evidence.d.ts +5 -5
  162. package/dist/comms/external-evidence.js +5 -4
  163. package/dist/comms/extract.js +2 -2
  164. package/dist/comms/fake-inbox.d.ts +3 -3
  165. package/dist/comms/fake-inbox.js +3 -3
  166. package/dist/comms/receiving-render.d.ts +1 -1
  167. package/dist/comms/receiving-render.js +2 -2
  168. package/dist/comms/receiving-runtime.d.ts +4 -4
  169. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  170. package/dist/comms/sandbox-catch-script.js +6 -6
  171. package/dist/comms/sandbox-catch.d.ts +38 -39
  172. package/dist/comms/sandbox-catch.js +36 -37
  173. package/dist/comms/setup.d.ts +2 -2
  174. package/dist/comms/setup.js +56 -25
  175. package/dist/comms/thread-evidence.d.ts +1 -1
  176. package/dist/comms/thread-evidence.js +6 -6
  177. package/dist/comms/types.d.ts +6 -6
  178. package/dist/comms/types.js +3 -3
  179. package/dist/evidence/frame-signature.d.ts +1 -1
  180. package/dist/evidence/frame-signature.js +4 -4
  181. package/dist/evidence/redaction.d.ts +3 -3
  182. package/dist/evidence/redaction.js +4 -4
  183. package/dist/feedback/draft.js +38 -80
  184. package/dist/feedback/export-bundle.js +1 -1
  185. package/dist/feedback/export.d.ts +5 -1
  186. package/dist/feedback/export.js +10 -10
  187. package/dist/feedback/feedback.d.ts +2 -2
  188. package/dist/feedback/feedback.js +21 -3
  189. package/dist/feedback/proof.d.ts +1 -1
  190. package/dist/feedback/proof.js +2 -2
  191. package/dist/guest/bootstrap.js +6 -6
  192. package/dist/guest/browser-tools.js +8 -8
  193. package/dist/guest/chromium-text.js +19 -19
  194. package/dist/guest/desktop-executor.d.ts +2 -2
  195. package/dist/guest/desktop-executor.js +20 -20
  196. package/dist/guest/desktop-keys.js +4 -4
  197. package/dist/guest/desktop-media.d.ts +2 -2
  198. package/dist/guest/desktop-media.js +16 -16
  199. package/dist/guest/desktop-native.d.ts +1 -1
  200. package/dist/guest/desktop-native.js +10 -10
  201. package/dist/guest/runtime-desktop.js +2 -2
  202. package/dist/guest/runtime-processes.d.ts +2 -2
  203. package/dist/guest/runtime-processes.js +2 -2
  204. package/dist/guest/runtime.js +6 -6
  205. package/dist/index.d.ts +14 -14
  206. package/dist/index.js +8 -8
  207. package/dist/keys/key-resolution.d.ts +5 -5
  208. package/dist/keys/key-resolution.js +23 -23
  209. package/dist/observer/artifact.d.ts +2 -2
  210. package/dist/observer/artifact.js +7 -7
  211. package/dist/observer/data.d.ts +6 -6
  212. package/dist/observer/data.js +5 -4
  213. package/dist/observer/exposure.d.ts +1 -1
  214. package/dist/observer/exposure.js +11 -11
  215. package/dist/observer/http.js +1 -1
  216. package/dist/observer/library.d.ts +3 -1
  217. package/dist/observer/library.js +8 -3
  218. package/dist/observer/listen.js +5 -4
  219. package/dist/observer/render.d.ts +1 -1
  220. package/dist/observer/render.js +17 -6
  221. package/dist/observer/run-routes.d.ts +4 -3
  222. package/dist/observer/run-routes.js +38 -13
  223. package/dist/observer/serve.d.ts +1 -1
  224. package/dist/observer/serve.js +7 -3
  225. package/dist/observer/tunnel.js +1 -1
  226. package/dist/observer-app.html +4 -4
  227. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  228. package/dist/routes/computer-use/bundle-parts.js +18 -17
  229. package/dist/routes/computer-use/bundle.d.ts +2 -2
  230. package/dist/routes/computer-use/bundle.js +10 -9
  231. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +6 -6
  232. package/dist/routes/computer-use/e2b-desktop/comms.js +18 -17
  233. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
  234. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +5 -4
  235. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
  236. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
  237. package/dist/routes/computer-use/e2b-desktop/prepare.js +10 -10
  238. package/dist/routes/computer-use/e2b-desktop/start.js +7 -7
  239. package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
  240. package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -2
  241. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  242. package/dist/routes/computer-use/external-comms.js +1 -1
  243. package/dist/routes/computer-use/fanout-bundle.js +27 -26
  244. package/dist/routes/computer-use/fanout-records.js +12 -13
  245. package/dist/routes/computer-use/live-flush.d.ts +4 -4
  246. package/dist/routes/computer-use/live-flush.js +6 -6
  247. package/dist/routes/computer-use/live-phase.d.ts +5 -4
  248. package/dist/routes/computer-use/live-phase.js +8 -8
  249. package/dist/routes/computer-use/local-tree-pack.d.ts +5 -5
  250. package/dist/routes/computer-use/local-tree-pack.js +1 -1
  251. package/dist/routes/computer-use/local-vm.d.ts +8 -8
  252. package/dist/routes/computer-use/local-vm.js +3 -3
  253. package/dist/routes/computer-use/participant-desktop.d.ts +7 -7
  254. package/dist/routes/computer-use/participant-desktop.js +5 -5
  255. package/dist/routes/computer-use/participant-execution.d.ts +4 -4
  256. package/dist/routes/computer-use/participant-execution.js +10 -10
  257. package/dist/routes/computer-use/participant-model.d.ts +6 -0
  258. package/dist/routes/computer-use/participant-model.js +33 -15
  259. package/dist/routes/computer-use/participant-prompt.d.ts +15 -15
  260. package/dist/routes/computer-use/participant-prompt.js +9 -9
  261. package/dist/routes/computer-use/participant-runs.d.ts +16 -16
  262. package/dist/routes/computer-use/participant-runs.js +26 -25
  263. package/dist/routes/computer-use/plan.d.ts +12 -12
  264. package/dist/routes/computer-use/plan.js +42 -42
  265. package/dist/routes/computer-use/preflight.d.ts +5 -5
  266. package/dist/routes/computer-use/preflight.js +25 -25
  267. package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
  268. package/dist/routes/computer-use/rerun-selection.js +4 -3
  269. package/dist/routes/computer-use/result.d.ts +4 -4
  270. package/dist/routes/computer-use/result.js +22 -21
  271. package/dist/routes/computer-use/route.d.ts +12 -11
  272. package/dist/routes/computer-use/route.js +31 -30
  273. package/dist/routes/computer-use/self-report.d.ts +7 -7
  274. package/dist/routes/computer-use/self-report.js +32 -32
  275. package/dist/routes/computer-use/setup.d.ts +23 -23
  276. package/dist/routes/computer-use/setup.js +28 -29
  277. package/dist/routes/computer-use/single-bundle.d.ts +11 -11
  278. package/dist/routes/computer-use/single-bundle.js +40 -41
  279. package/dist/routes/computer-use/subject-projection.d.ts +4 -4
  280. package/dist/routes/computer-use/subject-projection.js +6 -6
  281. package/dist/routes/computer-use/types.d.ts +71 -73
  282. package/dist/routes/computer-use/types.js +12 -12
  283. package/dist/routes/preview.d.ts +13 -7
  284. package/dist/routes/preview.js +11 -7
  285. package/dist/routes/scripted/bundle.d.ts +7 -7
  286. package/dist/routes/scripted/bundle.js +20 -18
  287. package/dist/routes/scripted/plan.d.ts +8 -8
  288. package/dist/routes/scripted/plan.js +13 -13
  289. package/dist/routes/scripted/result.d.ts +3 -3
  290. package/dist/routes/scripted/result.js +13 -13
  291. package/dist/routes/scripted/route.d.ts +9 -9
  292. package/dist/routes/scripted/route.js +15 -16
  293. package/dist/routes/scripted/scenario.d.ts +1 -1
  294. package/dist/routes/scripted/scenario.js +5 -5
  295. package/dist/routes/scripted/setup.d.ts +6 -6
  296. package/dist/routes/scripted/setup.js +8 -8
  297. package/dist/routes/scripted/subject.d.ts +5 -5
  298. package/dist/routes/scripted/subject.js +4 -4
  299. package/dist/routes/scripted/surface-records.d.ts +1 -1
  300. package/dist/routes/scripted/surface-records.js +4 -4
  301. package/dist/routes/scripted/surface-sessions.d.ts +3 -3
  302. package/dist/routes/scripted/types.d.ts +18 -20
  303. package/dist/routes/scripted/types.js +2 -2
  304. package/dist/routes/shared-world/bundle-records.js +11 -10
  305. package/dist/routes/shared-world/bundle.d.ts +5 -5
  306. package/dist/routes/shared-world/bundle.js +46 -43
  307. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  308. package/dist/routes/shared-world/checkpoints.js +2 -2
  309. package/dist/routes/shared-world/comms.d.ts +14 -14
  310. package/dist/routes/shared-world/comms.js +19 -18
  311. package/dist/routes/shared-world/external-public.d.ts +4 -3
  312. package/dist/routes/shared-world/external-public.js +16 -12
  313. package/dist/routes/shared-world/handoff.d.ts +7 -6
  314. package/dist/routes/shared-world/handoff.js +65 -57
  315. package/dist/routes/shared-world/lobby-code.d.ts +2 -2
  316. package/dist/routes/shared-world/lobby-code.js +9 -9
  317. package/dist/routes/shared-world/participant-specs.d.ts +10 -9
  318. package/dist/routes/shared-world/participant-specs.js +38 -31
  319. package/dist/routes/shared-world/plan.d.ts +9 -9
  320. package/dist/routes/shared-world/plan.js +16 -16
  321. package/dist/routes/shared-world/provenance.d.ts +2 -2
  322. package/dist/routes/shared-world/provenance.js +2 -2
  323. package/dist/routes/shared-world/provisioned.d.ts +8 -8
  324. package/dist/routes/shared-world/provisioned.js +18 -17
  325. package/dist/routes/shared-world/result.d.ts +6 -6
  326. package/dist/routes/shared-world/result.js +29 -29
  327. package/dist/routes/shared-world/route.d.ts +11 -11
  328. package/dist/routes/shared-world/route.js +40 -39
  329. package/dist/routes/shared-world/setup.d.ts +16 -16
  330. package/dist/routes/shared-world/setup.js +23 -23
  331. package/dist/routes/shared-world/types.d.ts +55 -53
  332. package/dist/routes/shared-world/types.js +4 -4
  333. package/dist/routes/terminal/adapter.d.ts +5 -5
  334. package/dist/routes/terminal/adapter.js +9 -9
  335. package/dist/routes/terminal/bundle.d.ts +13 -13
  336. package/dist/routes/terminal/bundle.js +28 -27
  337. package/dist/routes/terminal/credentials.d.ts +8 -8
  338. package/dist/routes/terminal/credentials.js +12 -12
  339. package/dist/routes/terminal/dry-run.d.ts +4 -4
  340. package/dist/routes/terminal/dry-run.js +12 -12
  341. package/dist/routes/terminal/encoding.js +2 -2
  342. package/dist/routes/terminal/ledger.d.ts +5 -5
  343. package/dist/routes/terminal/ledger.js +14 -14
  344. package/dist/routes/terminal/lifetime.d.ts +1 -1
  345. package/dist/routes/terminal/lifetime.js +1 -1
  346. package/dist/routes/terminal/live-finish.d.ts +2 -2
  347. package/dist/routes/terminal/live-finish.js +10 -10
  348. package/dist/routes/terminal/live-sandbox.d.ts +2 -2
  349. package/dist/routes/terminal/live-sandbox.js +15 -15
  350. package/dist/routes/terminal/participant-text.js +2 -1
  351. package/dist/routes/terminal/persona.d.ts +2 -2
  352. package/dist/routes/terminal/persona.js +3 -3
  353. package/dist/routes/terminal/plan.d.ts +7 -7
  354. package/dist/routes/terminal/plan.js +15 -15
  355. package/dist/routes/terminal/recorder.js +2 -2
  356. package/dist/routes/terminal/result.d.ts +5 -5
  357. package/dist/routes/terminal/result.js +14 -14
  358. package/dist/routes/terminal/route.d.ts +9 -9
  359. package/dist/routes/terminal/route.js +19 -20
  360. package/dist/routes/terminal/sandbox.d.ts +1 -1
  361. package/dist/routes/terminal/sandbox.js +1 -1
  362. package/dist/routes/terminal/session.d.ts +5 -5
  363. package/dist/routes/terminal/session.js +14 -13
  364. package/dist/routes/terminal/token-usage.d.ts +1 -1
  365. package/dist/routes/terminal/token-usage.js +7 -8
  366. package/dist/routes/terminal/trace.d.ts +4 -4
  367. package/dist/routes/terminal/trace.js +2 -2
  368. package/dist/routes/terminal/types.d.ts +48 -50
  369. package/dist/routes/terminal/types.js +5 -5
  370. package/dist/run/bundle-shape.js +3 -3
  371. package/dist/run/bundle.d.ts +49 -49
  372. package/dist/run/bundle.js +3 -2
  373. package/dist/run/cost-summary.js +3 -3
  374. package/dist/run/costs.d.ts +23 -0
  375. package/dist/run/costs.js +79 -44
  376. package/dist/run/detail.d.ts +6 -6
  377. package/dist/run/detail.js +4 -4
  378. package/dist/run/dry-run-inputs.d.ts +1 -1
  379. package/dist/run/dry-run-inputs.js +2 -2
  380. package/dist/run/dry-run.js +20 -20
  381. package/dist/run/judge.d.ts +19 -13
  382. package/dist/run/judge.js +18 -8
  383. package/dist/run/outcomes.d.ts +1 -1
  384. package/dist/run/participant.d.ts +1 -1
  385. package/dist/run/paths.d.ts +1 -1
  386. package/dist/run/paths.js +1 -1
  387. package/dist/run/preflight-receipts.js +1 -1
  388. package/dist/run/pricing.d.ts +11 -6
  389. package/dist/run/pricing.js +22 -15
  390. package/dist/run/projection.d.ts +46 -46
  391. package/dist/run/projection.js +57 -57
  392. package/dist/run/reclaim.d.ts +1 -1
  393. package/dist/run/reclaim.js +3 -3
  394. package/dist/run/results.d.ts +5 -5
  395. package/dist/run/run-cost.d.ts +53 -0
  396. package/dist/run/run-cost.js +105 -0
  397. package/dist/run/run-index-analysis.d.ts +15 -0
  398. package/dist/run/run-index-analysis.js +77 -0
  399. package/dist/run/run-index.d.ts +19 -7
  400. package/dist/run/run-index.js +77 -64
  401. package/dist/run/run-not-found.d.ts +5 -0
  402. package/dist/run/run-not-found.js +15 -0
  403. package/dist/run/run.d.ts +6 -5
  404. package/dist/run/run.js +3 -3
  405. package/dist/run/sandbox-receipts.d.ts +2 -2
  406. package/dist/run/sandbox-receipts.js +3 -3
  407. package/dist/run/shared-world-evidence.d.ts +37 -36
  408. package/dist/run/shared-world-evidence.js +4 -4
  409. package/dist/run/shared-world-shape.d.ts +1 -1
  410. package/dist/run/shared-world-shape.js +7 -7
  411. package/dist/run/stats.d.ts +14 -8
  412. package/dist/run/stats.js +121 -63
  413. package/dist/run/status.d.ts +16 -29
  414. package/dist/run/status.js +10 -29
  415. package/dist/run/stored-runs.js +2 -1
  416. package/dist/run/stream-shape.js +1 -1
  417. package/dist/run/streams.d.ts +7 -7
  418. package/dist/run/study-provenance.d.ts +49 -0
  419. package/dist/run/study-provenance.js +66 -0
  420. package/dist/run/study-result.d.ts +11 -0
  421. package/dist/run/study-result.js +9 -0
  422. package/dist/run/text.d.ts +2 -0
  423. package/dist/run/text.js +4 -0
  424. package/dist/run-study.d.ts +112 -0
  425. package/dist/{run-lab.js → run-study.js} +52 -47
  426. package/dist/{lab → study}/adapter-extension.d.ts +15 -27
  427. package/dist/{lab → study}/adapter-extension.js +10 -45
  428. package/dist/{lab → study}/adapter-scorer-loader.d.ts +17 -17
  429. package/dist/{lab → study}/adapter-scorer-loader.js +34 -34
  430. package/dist/study/composition-rules.d.ts +7 -0
  431. package/dist/{lab → study}/composition-rules.js +53 -53
  432. package/dist/study/config.d.ts +15 -0
  433. package/dist/{lab → study}/config.js +98 -41
  434. package/dist/study/convert.d.ts +33 -0
  435. package/dist/study/convert.js +432 -0
  436. package/dist/{lab → study}/device-presets.d.ts +10 -10
  437. package/dist/{lab → study}/device-presets.js +11 -11
  438. package/dist/study/discover.d.ts +75 -0
  439. package/dist/{lab → study}/discover.js +134 -95
  440. package/dist/{lab → study}/doctor.d.ts +19 -12
  441. package/dist/{lab → study}/doctor.js +58 -20
  442. package/dist/study/field-paths.d.ts +12 -0
  443. package/dist/study/field-paths.js +126 -0
  444. package/dist/study/files.d.ts +26 -0
  445. package/dist/study/files.js +44 -0
  446. package/dist/{lab → study}/init-templates.d.ts +2 -2
  447. package/dist/study/init-templates.js +421 -0
  448. package/dist/{lab → study}/init.d.ts +2 -2
  449. package/dist/{lab → study}/init.js +46 -11
  450. package/dist/study/keys.d.ts +4 -0
  451. package/dist/{lab → study}/keys.js +46 -12
  452. package/dist/study/migrate.d.ts +48 -0
  453. package/dist/study/migrate.js +408 -0
  454. package/dist/study/owned-files.d.ts +38 -0
  455. package/dist/study/owned-files.js +182 -0
  456. package/dist/{lab → study}/parse/actors.d.ts +5 -5
  457. package/dist/{lab → study}/parse/actors.js +14 -14
  458. package/dist/study/parse/comms.d.ts +12 -0
  459. package/dist/{lab → study}/parse/comms.js +5 -5
  460. package/dist/study/parse/execution.d.ts +19 -0
  461. package/dist/{lab → study}/parse/execution.js +13 -13
  462. package/dist/study/parse/study-v3.d.ts +21 -0
  463. package/dist/study/parse/study-v3.js +259 -0
  464. package/dist/study/parse/subject-state.d.ts +30 -0
  465. package/dist/{lab → study}/parse/subject-state.js +19 -19
  466. package/dist/{lab → study}/parse/subject.d.ts +3 -3
  467. package/dist/{lab → study}/parse/subject.js +34 -34
  468. package/dist/{lab → study}/parse/values.d.ts +3 -3
  469. package/dist/{lab → study}/parse/values.js +3 -3
  470. package/dist/{lab → study}/persona-resolve.d.ts +8 -8
  471. package/dist/{lab → study}/persona-resolve.js +6 -6
  472. package/dist/{lab → study}/plan-base.d.ts +7 -7
  473. package/dist/{lab → study}/plan-base.js +1 -1
  474. package/dist/{lab → study}/plan-participants.d.ts +12 -12
  475. package/dist/{lab → study}/plan-participants.js +4 -4
  476. package/dist/{lab → study}/plan-types.d.ts +31 -31
  477. package/dist/{lab → study}/plan-types.js +2 -2
  478. package/dist/study/plan.d.ts +13 -0
  479. package/dist/study/plan.js +101 -0
  480. package/dist/study/preflight-probes.d.ts +3 -0
  481. package/dist/{lab → study}/preflight-probes.js +20 -19
  482. package/dist/study/preflight-result.d.ts +8 -0
  483. package/dist/{lab → study}/preflight-result.js +5 -4
  484. package/dist/study/preflight.d.ts +94 -0
  485. package/dist/{lab → study}/preflight.js +12 -12
  486. package/dist/{lab → study}/requirements.d.ts +3 -3
  487. package/dist/{lab → study}/requirements.js +1 -1
  488. package/dist/study/route-inputs.d.ts +28 -0
  489. package/dist/{lab → study}/route-inputs.js +1 -1
  490. package/dist/{lab → study}/routing.d.ts +39 -33
  491. package/dist/{lab → study}/routing.js +60 -29
  492. package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -13
  493. package/dist/{lab/run-lab-events.js → study/run-study-events.js} +3 -9
  494. package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +21 -18
  495. package/dist/{lab/run-lab-homes.js → study/run-study-homes.js} +1 -1
  496. package/dist/study/run-study-options.d.ts +28 -0
  497. package/dist/{lab/run-lab-options.js → study/run-study-options.js} +29 -25
  498. package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +8 -13
  499. package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
  500. package/dist/{lab → study}/summary.d.ts +16 -15
  501. package/dist/{lab → study}/summary.js +21 -21
  502. package/dist/{lab → study}/tasks.d.ts +18 -18
  503. package/dist/{lab → study}/tasks.js +14 -14
  504. package/dist/{lab → study}/types.d.ts +202 -196
  505. package/dist/{lab → study}/types.js +3 -1
  506. package/dist/{lab → study}/validation.d.ts +27 -27
  507. package/dist/{lab → study}/validation.js +53 -51
  508. package/dist/study/warnings.d.ts +12 -0
  509. package/dist/{lab → study}/warnings.js +62 -34
  510. package/dist/subject/clone.d.ts +7 -7
  511. package/dist/subject/clone.js +2 -2
  512. package/dist/subject/desktop-cli.d.ts +1 -1
  513. package/dist/subject/desktop-cli.js +2 -2
  514. package/dist/subject/local-tree-archive.d.ts +2 -2
  515. package/dist/subject/local-tree-archive.js +4 -4
  516. package/dist/subject/local-tree.d.ts +4 -4
  517. package/dist/subject/node-bootstrap.js +1 -1
  518. package/dist/subject/runtime.js +9 -10
  519. package/dist/subject/serve.d.ts +5 -5
  520. package/dist/subject/serve.js +3 -3
  521. package/dist/subject/state.d.ts +4 -4
  522. package/dist/subject/state.js +1 -1
  523. package/dist/subject/steps.d.ts +6 -6
  524. package/dist/subject/steps.js +5 -5
  525. package/dist/substrates/command-failure.d.ts +3 -3
  526. package/dist/substrates/command-failure.js +3 -3
  527. package/dist/substrates/desktop-session.js +2 -2
  528. package/dist/substrates/detached.d.ts +6 -6
  529. package/dist/substrates/detached.js +7 -7
  530. package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
  531. package/dist/substrates/e2b/cdp-probe.js +14 -17
  532. package/dist/substrates/e2b/desktop-browser.d.ts +6 -6
  533. package/dist/substrates/e2b/desktop-browser.js +9 -9
  534. package/dist/substrates/e2b/desktop-cdp.d.ts +10 -10
  535. package/dist/substrates/e2b/desktop-cdp.js +9 -9
  536. package/dist/substrates/e2b/desktop-executor.d.ts +2 -2
  537. package/dist/substrates/e2b/desktop-executor.js +13 -13
  538. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  539. package/dist/substrates/e2b/desktop-geometry.js +8 -8
  540. package/dist/substrates/e2b/desktop-media.d.ts +4 -4
  541. package/dist/substrates/e2b/desktop-media.js +1 -1
  542. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  543. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  544. package/dist/substrates/e2b/lifetime.js +1 -1
  545. package/dist/substrates/e2b/sandbox.d.ts +4 -4
  546. package/dist/substrates/e2b/sandbox.js +2 -2
  547. package/dist/substrates/e2b/sdk.d.ts +12 -12
  548. package/dist/substrates/e2b/sdk.js +7 -7
  549. package/dist/substrates/local/runtime-config.d.ts +4 -4
  550. package/dist/substrates/local/runtime-config.js +4 -4
  551. package/dist/tui/actions.d.ts +1 -1
  552. package/dist/tui/actions.js +13 -13
  553. package/dist/tui/contract.d.ts +23 -23
  554. package/dist/tui/contract.js +11 -11
  555. package/dist/tui/launch.d.ts +7 -7
  556. package/dist/tui/launch.js +36 -31
  557. package/dist/tui/project.js +5 -5
  558. package/dist/tui-app.js +139 -139
  559. package/dist/verify/actor.d.ts +8 -8
  560. package/dist/verify/actor.js +36 -36
  561. package/dist/verify/artifacts.d.ts +2 -2
  562. package/dist/verify/artifacts.js +3 -3
  563. package/dist/verify/context-growth.d.ts +9 -0
  564. package/dist/verify/context-growth.js +62 -0
  565. package/dist/verify/costs.d.ts +6 -6
  566. package/dist/verify/costs.js +8 -8
  567. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  568. package/dist/verify/shared-world-concurrent.js +79 -76
  569. package/dist/verify/shared-world.d.ts +2 -2
  570. package/dist/verify/shared-world.js +16 -16
  571. package/dist/verify/subject.d.ts +5 -5
  572. package/dist/verify/subject.js +19 -19
  573. package/dist/verify/verify.js +94 -44
  574. package/docs/README.md +25 -32
  575. package/docs/architecture/actor-contract.md +60 -91
  576. package/docs/architecture/browser-control.md +1 -1
  577. package/docs/architecture/desktop-sessions.md +7 -7
  578. package/docs/architecture/external-public-shared-world.md +68 -65
  579. package/docs/architecture/github-feedback-loop.md +2 -5
  580. package/docs/architecture/guest-desktop.md +2 -2
  581. package/docs/architecture/observer.md +34 -34
  582. package/docs/architecture/restricted-codex-analysis.md +34 -28
  583. package/docs/architecture/serve.md +34 -37
  584. package/docs/architecture/state-driven-executor.md +55 -58
  585. package/docs/architecture/task-protocol-support.md +6 -6
  586. package/docs/architecture/terminal-product-route.md +70 -110
  587. package/docs/contracts/README.md +24 -0
  588. package/docs/contracts/adapter-admission.md +3 -3
  589. package/docs/contracts/adapter-fixtures.md +4 -7
  590. package/docs/contracts/core.md +1 -3
  591. package/docs/contracts/errors.md +62 -0
  592. package/docs/contracts/feedback.md +8 -9
  593. package/docs/contracts/policy.md +7 -12
  594. package/docs/contracts/run-bundle.md +42 -44
  595. package/docs/contracts/schemas.md +446 -368
  596. package/docs/contracts/study-analysis.md +7 -4
  597. package/docs/contracts/study-costs.md +28 -9
  598. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  599. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  600. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  601. package/docs/principles/actor-fidelity.md +4 -4
  602. package/docs/principles/engineering.md +3 -3
  603. package/docs/principles/invariants-and-defaults.md +38 -38
  604. package/docs/principles/self-driving-harness.md +1 -5
  605. package/docs/principles/three-roles.md +1 -1
  606. package/docs/product/automatic-analysis.md +7 -7
  607. package/examples/README.md +1 -1
  608. package/examples/participant/README.md +5 -5
  609. package/examples/participant/run.mjs +11 -10
  610. package/examples/scorer/README.md +3 -3
  611. package/examples/scorer/run.mjs +11 -12
  612. package/examples/scorer/scorer.mjs +3 -3
  613. package/package.json +16 -17
  614. package/skills/humanish/SKILL.md +64 -60
  615. package/skills/humanish/agents/openai.yaml +1 -1
  616. package/AGENTS.md +0 -99
  617. package/CONTRIBUTING.md +0 -148
  618. package/dist/actors/codex/qualified-versions.d.ts +0 -72
  619. package/dist/actors/codex/qualified-versions.js +0 -132
  620. package/dist/cli/commands/lab-format.d.ts +0 -8
  621. package/dist/cli/commands/lab-route-run.d.ts +0 -19
  622. package/dist/cli/commands/lab-route-scripted.d.ts +0 -17
  623. package/dist/cli/commands/lab-route-terminal.d.ts +0 -17
  624. package/dist/cli/commands/lab-run.d.ts +0 -9
  625. package/dist/cli/commands/lab.d.ts +0 -3
  626. package/dist/cli/commands/lab.js +0 -199
  627. package/dist/cli/renamed-options.d.ts +0 -11
  628. package/dist/cli/renamed-options.js +0 -18
  629. package/dist/lab/composition-rules.d.ts +0 -7
  630. package/dist/lab/config.d.ts +0 -7
  631. package/dist/lab/discover.d.ts +0 -65
  632. package/dist/lab/init-templates.js +0 -416
  633. package/dist/lab/keys.d.ts +0 -2
  634. package/dist/lab/parse/comms.d.ts +0 -12
  635. package/dist/lab/parse/execution.d.ts +0 -19
  636. package/dist/lab/parse/subject-state.d.ts +0 -30
  637. package/dist/lab/plan.d.ts +0 -19
  638. package/dist/lab/plan.js +0 -132
  639. package/dist/lab/preflight-probes.d.ts +0 -3
  640. package/dist/lab/preflight-result.d.ts +0 -7
  641. package/dist/lab/preflight.d.ts +0 -92
  642. package/dist/lab/route-inputs.d.ts +0 -28
  643. package/dist/lab/run-lab-options.d.ts +0 -28
  644. package/dist/lab/warnings.d.ts +0 -2
  645. package/dist/observer/static.d.ts +0 -39
  646. package/dist/observer/static.js +0 -369
  647. package/dist/run-lab.d.ts +0 -112
  648. package/docs/architecture/comms-inbox.md +0 -122
  649. package/docs/architecture/desktop-recording.md +0 -80
  650. package/docs/architecture/local-browser-runtime.md +0 -178
  651. package/docs/architecture/observer-review.md +0 -144
  652. package/docs/architecture/participant-media.md +0 -90
  653. package/docs/architecture/project-layout.md +0 -62
  654. package/docs/architecture/real-email-receiving.md +0 -136
  655. package/docs/assets/humanish-drawdb-hero.png +0 -0
  656. package/docs/assets/humanish-observer-hero.png +0 -0
  657. package/docs/goals/current.md +0 -207
  658. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  659. package/docs/product/open-source-install-experience.md +0 -240
  660. package/docs/ramp/README.md +0 -295
  661. package/docs/release/open-source-readiness.md +0 -222
  662. package/docs/release/public-readiness-standard.md +0 -210
  663. package/docs/roadmap/world-class-open-source-v0.md +0 -311
  664. /package/dist/{lab → study}/init-paths.d.ts +0 -0
  665. /package/dist/{lab → study}/init-paths.js +0 -0
  666. /package/dist/{lab → study}/init-plan.d.ts +0 -0
  667. /package/dist/{lab → study}/init-plan.js +0 -0
  668. /package/dist/{lab → study}/participant-assignment.d.ts +0 -0
  669. /package/dist/{lab → study}/participant-assignment.js +0 -0
  670. /package/dist/{lab → study}/persona.d.ts +0 -0
  671. /package/dist/{lab → study}/persona.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { ParticipantIds } from "./participant-records.js";
2
2
  export declare const SHARED_WORLD_SCHEMA = "humanish.shared-world.v1";
3
- /** The shared service-plane provenance for a shared-world run (#164): single commit + a
3
+ /** The shared service-plane provenance for a shared-world run: single commit + a
4
4
  * seed-recipe digest + the provisioned env names (never values). */
5
5
  export interface SharedWorldPlane {
6
6
  /** The cloned commit SHA of the shared plane (when the clone resolved one). */
@@ -11,13 +11,13 @@ export interface SharedWorldPlane {
11
11
  /** Declared env names provisioned for the shared plane (values never surface). */
12
12
  envNames: string[];
13
13
  /**
14
- * Concurrent route only (#164 phase 2): sha256-16 of the harness-minted `getHost` URL's origin
15
- * (the first-class provisioned-subject target every actor drove, per invariant 2). A digest replaces the
14
+ * Concurrent route only: sha256-16 of the harness-minted `getHost` URL's origin
15
+ * (the first-class provisioned-subject target every actor drove). A digest replaces the
16
16
  * raw URL: a getHost URL embeds the (live) sandbox id and matches the publish-safety e2b-URL
17
- * redaction, so — like the stream URL and like sandbox ids — it never lands raw in a published
18
- * bundle (the raw tokenless URL is surfaced only on the ephemeral lab result). The orchestrator
19
- * confirms the URL is tokenless (no authKey, per invariant 1) before digesting. verify proves every
20
- * actor drove this host by digest equality. Absent on the sequential route.
17
+ * redaction, so, like the stream URL and sandbox ids, it never lands raw in a published
18
+ * bundle (the raw tokenless URL is surfaced only on the ephemeral study result). The orchestrator
19
+ * confirms the URL is tokenless (no authKey, so no secret reaches the bundle) before digesting.
20
+ * verify proves every actor drove this host by digest equality. Absent on the sequential route.
21
21
  */
22
22
  hostDigest?: string;
23
23
  /**
@@ -30,17 +30,17 @@ export interface SharedWorldPlane {
30
30
  */
31
31
  exposure?: "synthetic";
32
32
  /**
33
- * External-public plane class only (#164 phase 2): sha256-16 of the observed origin the seats
33
+ * External-public plane class only: sha256-16 of the observed origin the participants
34
34
  * converged on. It is the counterpart of hostDigest with a weaker, disclosed claim: the harness only
35
- * observes that each seat reached this origin and never minted it. It is derived from what the
36
- * seats actually reached; the declared appUrl does not feed it. verify proves every laneWindow.routeHostDigest
37
- * (that seat's CDP-observed final URL origin) equals it, which shows inter-seat convergence on one observed
38
- * origin, not harness control of the plane. A digest, not the raw origin (kept consistent with
39
- * hostDigest hygiene). Absent on getHost.
35
+ * observes that each participant reached this origin and never minted it. It is derived from what
36
+ * the participants actually reached; the declared appUrl does not feed it. verify proves every
37
+ * laneWindow.routeHostDigest (that participant's CDP-observed final URL origin) equals it, which
38
+ * shows cross-participant convergence on one observed origin, not harness control of the plane. A
39
+ * digest, not the raw origin (kept consistent with hostDigest hygiene). Absent on getHost.
40
40
  */
41
41
  publicOriginDigest?: string;
42
42
  /**
43
- * EXTERNAL-PUBLIC plane class only: sha256-16 of the operator-DECLARED origin (from subject.appUrl),
43
+ * External-public plane class only: sha256-16 of the operator-declared origin (from subject.appUrl),
44
44
  * recorded for reference/evidence only. It is never asserted equal to publicOriginDigest: a normal
45
45
  * cross-origin redirect (apex->www, http->https) makes the observed origin differ from the declared
46
46
  * one, which is expected. Operator ownership rests on the subject.publicTarget.authorized attestation
@@ -49,7 +49,7 @@ export interface SharedWorldPlane {
49
49
  declaredOriginDigest?: string;
50
50
  }
51
51
  /**
52
- * Concurrent shape (#164 phase 2): one actor's harness-clocked activity window against the one
52
+ * Concurrent shape: one actor's harness-clocked activity window against the one
53
53
  * shared plane. Overlapping windows mechanically prove ≥2 personas were active simultaneously.
54
54
  * `laneWindows` and `stateSeries` are independent series. There is deliberately no per-delta→actor
55
55
  * field, because under concurrency the evidence cannot say which actor caused a state change.
@@ -68,9 +68,9 @@ export interface SharedWorldParticipantWindow {
68
68
  endedAt: number;
69
69
  /** The actor's terminal session verdict (per-persona). */
70
70
  verdict: string;
71
- /** sha256-16 of the origin of the getHost seat URL this actor drove. verify confirms it equals
72
- * plane.hostDigest, so the actor drove exactly the harness-minted host (invariant 2).
73
- * A digest, not the raw URL (a getHost URL is not publish-safe — see SharedWorldPlane.hostDigest). */
71
+ /** sha256-16 of the origin of the getHost participant URL this actor drove. verify confirms it
72
+ * equals plane.hostDigest, so the actor drove exactly the harness-minted host. A digest, not the
73
+ * raw URL (a getHost URL is not publish-safe; see SharedWorldPlane.hostDigest). */
74
74
  routeHostDigest: string;
75
75
  /** The shared plane's commit this actor observed (omitted when unresolved). */
76
76
  commit?: string;
@@ -109,19 +109,19 @@ export declare function sharedWorldParticipantKeys(ids: ParticipantIds, particip
109
109
  readonly caseGroup?: string;
110
110
  }): Pick<SharedWorldOutcome, "roleId" | "actorType" | "surface" | "caseGroup" | "simId" | "streamId">;
111
111
  /** A timeline checkpoint: a read-only digest probe of the shared plane at one moment. Persisted
112
- * DIGEST-ONLY — `digest` is sha256-16(scrub+redact(stdout)); no raw value ever lands. */
112
+ * digest-only: `digest` is sha256-16(scrub+redact(stdout)); no raw value ever lands. */
113
113
  export interface SharedWorldCheckpoint {
114
114
  kind: "checkpoint";
115
115
  /** "cp-baseline" for the baseline snapshot; "cp-after-<roleId>" after each role's turn. */
116
116
  name: string;
117
117
  /** sha256-16 of the (scrubbed, redacted) combined probe output at this snapshot. */
118
118
  digest: string;
119
- /** True when this snapshot's digest differs from the previous checkpoint's — the observed
119
+ /** True when this snapshot's digest differs from the previous checkpoint's, meaning the observed
120
120
  * state changed across the intervening turn (the delta is attributed to the whole turn). */
121
121
  deltaFromPrev: boolean;
122
122
  }
123
- /** A timeline turn: one role's seat session against the shared plane. Carries the plane
124
- * provenance it observed (identical across turns by construction — the single-plane proof). */
123
+ /** A timeline turn: one participant's session against the shared plane. Carries the plane
124
+ * provenance it observed (identical across turns by construction: the single-plane proof). */
125
125
  interface SharedWorldTurn {
126
126
  kind: "turn";
127
127
  roleId: string;
@@ -135,8 +135,8 @@ interface SharedWorldTurn {
135
135
  seedDigest: string;
136
136
  }
137
137
  type SharedWorldTimelineEntry = SharedWorldCheckpoint | SharedWorldTurn;
138
- /** Declared seats that were never started after one executed sequential role stopped the run.
139
- * The executed timeline plus this ordered tail must account for every declared sim/stream. */
138
+ /** Declared participants that were never started after one executed sequential role stopped the
139
+ * run. The executed timeline plus this ordered tail must account for every declared sim/stream. */
140
140
  interface SharedWorldSkippedTail {
141
141
  afterRoleId: string;
142
142
  roles: Array<{
@@ -156,10 +156,10 @@ interface SharedWorldSkippedTail {
156
156
  * - Sequential (`topologyMode: "sequential"`): `sequence` + an alternating `timeline`
157
157
  * (cp-baseline → turn → cp → … → cp); limits `sequential-only` etc. No route writes it since
158
158
  * 0.106.0; verify still reads it so older bundles keep verifying.
159
- * - Concurrent (`topologyMode: "concurrent"`, #164 phase 2): `laneWindows` + `stateSeries` +
159
+ * - Concurrent (`topologyMode: "concurrent"`): `laneWindows` + `stateSeries` +
160
160
  * `outcomes`; limits `concurrent` etc. No `timeline`.
161
161
  *
162
- * Additive + optional on `humanish.run-bundle.v1` — absent on every non-shared-world bundle.
162
+ * Additive + optional on `humanish.run-bundle.v1`: absent on every non-shared-world bundle.
163
163
  * The mandatory `attributionLimits` are verify-enforced (fail closed on a missing required or a
164
164
  * present forbidden limit).
165
165
  */
@@ -169,26 +169,27 @@ export interface SharedWorldEvidence {
169
169
  /** The substrate discriminator. Branched on first by sharedWorldEvidenceFindings. */
170
170
  topologyMode: "sequential" | "concurrent";
171
171
  /**
172
- * Concurrent route only (#164 phase 2): the plane-class discriminator. Absent == the historical
173
- * "provisioned-getHost" plane (a clone/local-tree subject served + getHost-exposed in-sandbox — the
172
+ * Concurrent route only: the plane-class discriminator. Absent == the historical
173
+ * "provisioned-getHost" plane (a clone/local-tree subject served + getHost-exposed in-sandbox; the
174
174
  * harness minted the host; synthetic-seeded attestation + authoritative in-sandbox checkpoint
175
175
  * stateSeries). "external-public" == a real operator-owned public deployment used directly as the
176
176
  * plane (no getHost/clone/seed; the operator attests it and the harness does not control it; no authoritative
177
- * shared-state proof — concurrency evidenced by temporal co-occupancy + observed lobby convergence).
177
+ * shared-state proof: concurrency evidenced by temporal co-occupancy + observed lobby convergence).
178
178
  * verify gates every getHost-specific assertion on this discriminator; existing bundles omit it and
179
179
  * default to provisioned-getHost, byte-stable.
180
180
  */
181
181
  planeClass?: "provisioned-getHost" | "external-public";
182
- /** The declared number of role seats. */
182
+ /** The declared number of participants. */
183
183
  roleCount: number;
184
184
  plane: SharedWorldPlane;
185
185
  /** The pinned, verify-enforced attribution ceiling (the set differs per topologyMode/planeClass). */
186
186
  attributionLimits: string[];
187
187
  /**
188
- * EXTERNAL-PUBLIC plane class only (#164 phase 2, optional-but-strong): sha256-16 of the shared
189
- * `/lobby/CODE` path every seat's CDP-observed URL converged on: the concrete "they were in one
190
- * shared world" proof, observation-derived and needing no subject change. Digest-only (the raw
191
- * 6-char lobby code and full URLs are runtime-only and never land). Absent when seats did not converge.
188
+ * External-public plane class only (optional-but-strong): sha256-16 of the shared
189
+ * `/lobby/CODE` path every participant's CDP-observed URL converged on: the concrete "they were
190
+ * in one shared world" proof, observation-derived and needing no subject change. Digest-only (the
191
+ * raw 6-char lobby code and full URLs are runtime-only and never land). Absent when participants
192
+ * did not converge.
192
193
  */
193
194
  lobbyConvergenceDigest?: string;
194
195
  /** The role ids that actually took a turn, in declared order. */
@@ -210,8 +211,8 @@ interface ParticipantWindow {
210
211
  }
211
212
  /**
212
213
  * What a shared-world run shows about concurrency, as verify's pass gate and the judge both read
213
- * it: whether two or more seats were live at once, and, when the plane keeps a state series (the
214
- * provisioned plane), whether the state changed at or after the first overlap started.
214
+ * it: whether two or more participants were live at once, and, when the plane keeps a state series
215
+ * (the provisioned plane), whether the state changed at or after the first overlap started.
215
216
  */
216
217
  export declare function concurrencyFacts(windows: readonly ParticipantWindow[], stateSeries: readonly SharedWorldStateSnapshot[] | undefined): {
217
218
  overlap: boolean;
@@ -1,5 +1,5 @@
1
- // The sharedWorld block of run.json (humanish.shared-world.v1): the one shared plane, each seat's
2
- // window, state snapshots and the interleaved timeline of checkpoints and turns.
1
+ // The sharedWorld block of run.json (humanish.shared-world.v1): the one shared plane, each
2
+ // participant's window, state snapshots and the interleaved timeline of checkpoints and turns.
3
3
  export const SHARED_WORLD_SCHEMA = "humanish.shared-world.v1";
4
4
  /**
5
5
  * The fields a window and an outcome start with, in the saved order: the participant id saved as
@@ -30,8 +30,8 @@ function overlapStarts(windows) {
30
30
  }
31
31
  /**
32
32
  * What a shared-world run shows about concurrency, as verify's pass gate and the judge both read
33
- * it: whether two or more seats were live at once, and, when the plane keeps a state series (the
34
- * provisioned plane), whether the state changed at or after the first overlap started.
33
+ * it: whether two or more participants were live at once, and, when the plane keeps a state series
34
+ * (the provisioned plane), whether the state changed at or after the first overlap started.
35
35
  */
36
36
  export function concurrencyFacts(windows, stateSeries) {
37
37
  const starts = overlapStarts(windows);
@@ -18,7 +18,7 @@ export declare function planeProvenanceFindings(items: readonly Record<string, u
18
18
  /** Common shape findings shared by both topologyMode branches. */
19
19
  export declare function sharedWorldCommonFindings(bundle: RunBundle, sw: SharedWorldEvidence): string[];
20
20
  /**
21
- * Tolerant shape guard for the shared-world evidence block (#164). Validates required fields +
21
+ * Tolerant shape guard for the shared-world evidence block. Validates required fields +
22
22
  * types and tolerates extra keys (additive): the strict value-shape/timeline checks are
23
23
  * sharedWorldEvidenceFindings' job (an injected value-shaped checkpoint field must pass the shape
24
24
  * guard so verify can catch it fail-closed, not silently bounce off isRunBundle).
@@ -4,18 +4,18 @@ import { isNonNegativeSafeInteger, isRecord } from "./type-guards.js";
4
4
  // The promptDigest convention: sha256 hex, first 16 chars. A "seeded" record without a real
5
5
  // digest cannot pin "same recipe" across bundles, so verify treats it as a hollow claim.
6
6
  export const COMMAND_DIGEST_PATTERN = /^[0-9a-f]{16}$/;
7
- // Env var name shape (mirrors ENV_NAME_PATTERN in src/lab/parse/values.ts). externalEnvNames
7
+ // Env var name shape (mirrors ENV_NAME_PATTERN in src/study/parse/values.ts). externalEnvNames
8
8
  // must hold names only: a value sneaking into the list trips this check (a free secret tripwire).
9
9
  export const SUBJECT_ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
10
10
  // Sequential: the three disclosures a sequential shared-world bundle must pin (verify fails closed
11
- // if any is absent — omission overclaims): sequential turns only, no concurrency/races handled, and
11
+ // if any is absent, because omission overclaims): sequential turns only, no concurrency/races handled, and
12
12
  // a checkpoint delta is attributed to the turn it followed, never a specific action (correlation).
13
13
  export const MANDATORY_ATTRIBUTION_LIMITS = [
14
14
  "sequential-only",
15
15
  "no-concurrent-races",
16
16
  "delta-attributed-to-turn-not-action",
17
17
  ];
18
- // A shared-world checkpoint record persists DIGEST-ONLY: exactly these keys, nothing value-shaped.
18
+ // A shared-world checkpoint record persists digest-only: exactly these keys, nothing value-shaped.
19
19
  export const SHARED_WORLD_CHECKPOINT_KEYS = new Set(["kind", "name", "digest", "deltaFromPrev"]);
20
20
  // A concurrent stateSeries record is digest-only too: it permits a numeric timestamp + the
21
21
  // sha256-16 digest; any other key is a value-shaped leak / a smuggled per-delta→actor field.
@@ -30,7 +30,7 @@ export function planeProvenanceFindings(items, plane, labels) {
30
30
  const findings = [];
31
31
  const keys = new Set(items.map((item) => `${text(item.commit)}::${text(item.seedDigest)}`));
32
32
  if (keys.size > 1) {
33
- findings.push(`${labels.items} reference divergent plane provenance (commit/seedDigest) — a ${labels.run} run drives ONE plane`);
33
+ findings.push(`${labels.items} reference different plane provenance (commit or seedDigest), but a ${labels.run} run uses one plane`);
34
34
  }
35
35
  if (!isRecord(plane))
36
36
  return findings;
@@ -63,14 +63,14 @@ export function sharedWorldCommonFindings(bundle, sw) {
63
63
  for (const name of plane.envNames) {
64
64
  if (typeof name !== "string" || !SUBJECT_ENV_NAME_PATTERN.test(name)) {
65
65
  // Never echoes the entry: a malformed entry may be a value.
66
- findings.push("sharedWorld.plane.envNames carries an entry that is not an env var NAME shape (values must never appear in evidence)");
66
+ findings.push("sharedWorld.plane.envNames has an entry that is not an environment variable name; evidence may hold names only, never values");
67
67
  }
68
68
  }
69
69
  }
70
70
  return findings;
71
71
  }
72
72
  /**
73
- * Tolerant shape guard for the shared-world evidence block (#164). Validates required fields +
73
+ * Tolerant shape guard for the shared-world evidence block. Validates required fields +
74
74
  * types and tolerates extra keys (additive): the strict value-shape/timeline checks are
75
75
  * sharedWorldEvidenceFindings' job (an injected value-shaped checkpoint field must pass the shape
76
76
  * guard so verify can catch it fail-closed, not silently bounce off isRunBundle).
@@ -110,7 +110,7 @@ export function isSharedWorldEvidence(value) {
110
110
  value.attributionLimits.every((limit) => typeof limit === "string")))
111
111
  return false;
112
112
  // Tolerant: validate the type of each present field only (the coherence + topologyMode dispatch
113
- // are the job of sharedWorldEvidenceFindings — an injected value-shaped field must pass this
113
+ // are the job of sharedWorldEvidenceFindings; an injected value-shaped field must pass this
114
114
  // guard so verify catches it fail-closed). A bundle must carry at least one of the two shapes.
115
115
  if (value.sequence !== undefined &&
116
116
  !(Array.isArray(value.sequence) && value.sequence.every((id) => typeof id === "string")))
@@ -1,12 +1,13 @@
1
1
  import { type CostTotals, type CostRow } from "./costs.js";
2
- declare const STATS_SCHEMA = "humanish.stats.v1";
2
+ declare const STATS_SCHEMA = "humanish.stats.v2";
3
3
  interface StatsParticipants {
4
4
  total: number;
5
5
  reachedGoal: number;
6
6
  reportedFriction: number;
7
7
  }
8
- interface StatsLabRow {
9
- lab: string;
8
+ interface StatsStudyRow {
9
+ /** The study's `id`. */
10
+ study: string;
10
11
  runs: number;
11
12
  live: number;
12
13
  dryRun: number;
@@ -40,7 +41,8 @@ export interface StatsResult {
40
41
  ok: true;
41
42
  cwd: string;
42
43
  since?: string;
43
- lab?: string;
44
+ /** The study the stats are limited to, when one was given. */
45
+ study?: string;
44
46
  totals: {
45
47
  runs: number;
46
48
  live: number;
@@ -53,11 +55,11 @@ export interface StatsResult {
53
55
  verdicts: Record<string, number>;
54
56
  costs: CostTotals;
55
57
  };
56
- labs: StatsLabRow[];
58
+ studies: StatsStudyRow[];
57
59
  days: StatsDayRow[];
58
60
  /** Same selected runs; individual accounting gaps are inspectable without reading private evidence. */
59
61
  costsByRun: CostRow[];
60
- /** Directories that could not be read, by name — surfaced, never silently dropped. */
62
+ /** Directories that could not be read, by name: surfaced, never silently dropped. */
61
63
  unreadable: string[];
62
64
  note: string;
63
65
  }
@@ -65,7 +67,7 @@ export interface StatsOptions {
65
67
  /** ISO date or datetime; runs that started before it are excluded. */
66
68
  since?: string;
67
69
  /** Lab id; runs from other labs are excluded. */
68
- lab?: string;
70
+ study?: string;
69
71
  nowMs?: number;
70
72
  }
71
73
  export interface StatsFailure {
@@ -78,5 +80,9 @@ export interface StatsFailure {
78
80
  };
79
81
  }
80
82
  export declare function computeStats(cwdInput: string, options?: StatsOptions): Promise<StatsResult | StatsFailure>;
81
- export declare function formatStatsHuman(result: StatsResult | StatsFailure): string;
83
+ /** Human output; a failure is an error the CLI prints on stderr (HumanOutput in src/cli/io.ts). */
84
+ export declare function formatStatsHuman(result: StatsResult): string;
85
+ export declare function formatStatsHuman(result: StatsResult | StatsFailure): string | {
86
+ error: StatsFailure["error"];
87
+ };
82
88
  export {};
package/dist/run/stats.js CHANGED
@@ -5,12 +5,10 @@ import path from "node:path";
5
5
  import { readRunIndex } from "./run-index.js";
6
6
  import { addCostTotals, emptyCostTotals, readCostTotals, } from "./costs.js";
7
7
  import { round6 } from "./pricing.js";
8
- const STATS_SCHEMA = "humanish.stats.v1";
9
- const STATS_NOTE = "Every dollar figure is a retained rate-table estimate, never a provider charge. " +
10
- "Known spend includes participant/desktop estimates and all distinct recorded analysis attempts; reuse is counted once. " +
11
- "Unknown amounts are excluded, not $0. Missing historical attempts cannot be reconstructed. " +
12
- "Analysis is attributed to its run's start date, including later reruns. " +
13
- "JSON estimatedSpendUsd and medianCostUsd retain their participant/desktop-only meaning; costs includes analysis.";
8
+ import { plural } from "./text.js";
9
+ const STATS_SCHEMA = "humanish.stats.v2";
10
+ // docs/contracts/study-costs.md holds the accounting rules this sentence summarizes.
11
+ const STATS_NOTE = "Dollar figures are estimates from humanish's rate table, never provider charges, and a cost humanish does not know is left out of every total.";
14
12
  function median(values) {
15
13
  if (values.length === 0)
16
14
  return undefined;
@@ -28,15 +26,26 @@ function addParticipants(into, entry) {
28
26
  into.reachedGoal += entry.participants.reachedGoal;
29
27
  into.reportedFriction += entry.participants.reportedFriction ?? 0;
30
28
  }
29
+ /**
30
+ * A run's participant and desktop estimate: its recorded figure, or $0 for a dry run that records
31
+ * none, since a dry run makes no model request and creates no desktop. Undefined when the cost is
32
+ * unknown, including a dry run that records an unknown (null) figure.
33
+ */
34
+ function runEstimateUsd(entry) {
35
+ const usd = entry.estimatedCostUsd;
36
+ if (typeof usd === "number" && Number.isFinite(usd) && usd >= 0)
37
+ return usd;
38
+ return usd === undefined && entry.mode === "dry-run" ? 0 : undefined;
39
+ }
31
40
  function entryTime(entry) {
32
41
  return entry.startedAt ?? entry.completedAt ?? entry.updatedAt;
33
42
  }
34
- function addToLabRow(labs, entry, priced, costs) {
35
- const labId = entry.lab?.id ?? "(no lab)";
36
- let row = labs.get(labId);
43
+ function addToStudyRow(studies, entry, runUsd, costs) {
44
+ const studyId = entry.study?.id ?? "(no study)";
45
+ let row = studies.get(studyId);
37
46
  if (row === undefined) {
38
47
  row = {
39
- lab: labId,
48
+ study: studyId,
40
49
  runs: 0,
41
50
  live: 0,
42
51
  dryRun: 0,
@@ -50,7 +59,7 @@ function addToLabRow(labs, entry, priced, costs) {
50
59
  costs: emptyCostTotals(),
51
60
  runCosts: [],
52
61
  };
53
- labs.set(labId, row);
62
+ studies.set(studyId, row);
54
63
  }
55
64
  row.runs += 1;
56
65
  if (entry.mode === "live")
@@ -64,14 +73,14 @@ function addToLabRow(labs, entry, priced, costs) {
64
73
  }
65
74
  if (entry.mode === "live" && entry.durationMs !== undefined)
66
75
  row.durations.push(entry.durationMs);
67
- if (priced)
68
- row.runCosts.push(entry.estimatedCostUsd);
69
- else
76
+ if (runUsd === undefined)
70
77
  row.unpricedRuns += 1;
78
+ else
79
+ row.runCosts.push(runUsd);
71
80
  addParticipants(row.participants, entry);
72
81
  addCostTotals(row.costs, costs);
73
82
  }
74
- function addToDayRow(days, entry, priced, costs) {
83
+ function addToDayRow(days, entry, runUsd, costs) {
75
84
  const at = entryTime(entry);
76
85
  const day = at === undefined ? "(undated)" : at.slice(0, 10);
77
86
  let dayRow = days.get(day);
@@ -89,10 +98,10 @@ function addToDayRow(days, entry, priced, costs) {
89
98
  dayRow.runs += 1;
90
99
  if (entry.mode === "live")
91
100
  dayRow.live += 1;
92
- if (priced)
93
- dayRow.estimatedSpendUsd += entry.estimatedCostUsd;
94
- else
101
+ if (runUsd === undefined)
95
102
  dayRow.unpricedRuns += 1;
103
+ else
104
+ dayRow.estimatedSpendUsd += runUsd;
96
105
  addCostTotals(dayRow.costs, costs);
97
106
  }
98
107
  export async function computeStats(cwdInput, options = {}) {
@@ -114,7 +123,7 @@ export async function computeStats(cwdInput, options = {}) {
114
123
  }
115
124
  const index = await readRunIndex(cwd, options.nowMs === undefined ? {} : { nowMs: options.nowMs });
116
125
  // Corrupt source metadata must not hide separately retained paid analysis receipts.
117
- // These directories cannot be attributed to a lab/date, so scoped filters exclude them.
126
+ // These directories cannot be attributed to a study or date, so scoped filters exclude them.
118
127
  const indexedIds = new Set(index.runs.map((entry) => entry.runId));
119
128
  const entries = [
120
129
  ...index.runs,
@@ -127,7 +136,7 @@ export async function computeStats(cwdInput, options = {}) {
127
136
  })),
128
137
  ];
129
138
  const selected = entries.filter((entry) => {
130
- if (options.lab !== undefined && entry.lab?.id !== options.lab)
139
+ if (options.study !== undefined && entry.study?.id !== options.study)
131
140
  return false;
132
141
  if (sinceMs !== undefined) {
133
142
  const at = entryTime(entry);
@@ -150,7 +159,7 @@ export async function computeStats(cwdInput, options = {}) {
150
159
  verdicts: {},
151
160
  costs: emptyCostTotals(),
152
161
  };
153
- const labs = new Map();
162
+ const studies = new Map();
154
163
  const days = new Map();
155
164
  const costsByRun = [];
156
165
  for (const entry of selected) {
@@ -164,20 +173,18 @@ export async function computeStats(cwdInput, options = {}) {
164
173
  totals.dryRun += 1;
165
174
  if (entry.liveness === "running")
166
175
  totals.running += 1;
167
- const priced = typeof entry.estimatedCostUsd === "number" &&
168
- Number.isFinite(entry.estimatedCostUsd) &&
169
- entry.estimatedCostUsd >= 0;
170
- if (priced)
171
- totals.estimatedSpendUsd += entry.estimatedCostUsd;
172
- else
176
+ const runUsd = runEstimateUsd(entry);
177
+ if (runUsd === undefined)
173
178
  totals.unpricedRuns += 1;
179
+ else
180
+ totals.estimatedSpendUsd += runUsd;
174
181
  addParticipants(totals.participants, entry);
175
182
  if (entry.verdict !== undefined)
176
183
  totals.verdicts[entry.verdict] = (totals.verdicts[entry.verdict] ?? 0) + 1;
177
- addToLabRow(labs, entry, priced, accounting.costs);
178
- addToDayRow(days, entry, priced, accounting.costs);
184
+ addToStudyRow(studies, entry, runUsd, accounting.costs);
185
+ addToDayRow(days, entry, runUsd, accounting.costs);
179
186
  }
180
- const labRows = [...labs.values()]
187
+ const studyRows = [...studies.values()]
181
188
  .map(({ durations, runCosts, ...row }) => ({
182
189
  ...row,
183
190
  ...(row.judged === 0 ? {} : { passRate: round6(row.passed / row.judged) }),
@@ -186,15 +193,15 @@ export async function computeStats(cwdInput, options = {}) {
186
193
  ...(runCosts.length === 0 ? {} : { medianCostUsd: round6(median(runCosts)) }),
187
194
  costSamples: runCosts.length,
188
195
  }))
189
- .sort((a, b) => b.runs - a.runs || a.lab.localeCompare(b.lab));
196
+ .sort((a, b) => b.runs - a.runs || a.study.localeCompare(b.study));
190
197
  return {
191
198
  schema: STATS_SCHEMA,
192
199
  ok: true,
193
200
  cwd,
194
201
  ...(options.since === undefined ? {} : { since: options.since }),
195
- ...(options.lab === undefined ? {} : { lab: options.lab }),
202
+ ...(options.study === undefined ? {} : { study: options.study }),
196
203
  totals: { ...totals, estimatedSpendUsd: round6(totals.estimatedSpendUsd) },
197
- labs: labRows,
204
+ studies: studyRows,
198
205
  days: [...days.values()]
199
206
  .map((row) => ({ ...row, estimatedSpendUsd: round6(row.estimatedSpendUsd) }))
200
207
  .sort((a, b) => a.day.localeCompare(b.day)),
@@ -212,47 +219,98 @@ function knownMoney(value) {
212
219
  function minutes(ms) {
213
220
  return `${(ms / 60_000).toFixed(1)}m`;
214
221
  }
222
+ /**
223
+ * Whether every selected run is a dry run whose accounting is a complete $0: no recorded figure,
224
+ * no incomplete estimate and no analysis attempt. Only then does the one-line report hold.
225
+ */
226
+ function onlyFreeDryRuns(t) {
227
+ return (t.runs > 0 &&
228
+ t.runs === t.dryRun &&
229
+ t.costs.estimatedTotalUsd === 0 &&
230
+ t.costs.incompleteRunEstimates === 0 &&
231
+ t.costs.analysisAttempts === 0);
232
+ }
233
+ /** The run counts, with dry runs on their own line. */
234
+ function runCountLines(t) {
235
+ if (t.runs === 0)
236
+ return ["no runs yet; start one with humanish run first-run"];
237
+ if (onlyFreeDryRuns(t))
238
+ return [`${plural(t.dryRun, "dry run")} ($0); no live runs yet`];
239
+ const running = t.running > 0 ? ` (${t.running} still running)` : "";
240
+ return [`live runs: ${t.live}${running}`, ...(t.dryRun > 0 ? [`dry runs: ${t.dryRun}`] : [])];
241
+ }
242
+ /** Spend, analysis, participants and verdicts across the selected live runs. */
243
+ function totalsLines(t) {
244
+ const c = t.costs;
245
+ const incomplete = c.incompleteRunEstimates > 0
246
+ ? `; ${plural(c.incompleteRunEstimates, "run")} with incomplete accounting`
247
+ : "";
248
+ const unpriced = c.analysisUnpricedAttempts > 0 || c.analysisUnresolvedAttempts > 0
249
+ ? `; ${c.analysisUnpricedAttempts} unpriced, ${c.analysisUnresolvedAttempts} unresolved`
250
+ : "";
251
+ const verdicts = Object.entries(t.verdicts).map(([verdict, count]) => `${verdict} ${count}`);
252
+ return [
253
+ `known estimated spend: ${knownMoney(c.estimatedTotalUsd)}`,
254
+ `participants and desktops: ${knownMoney(c.runEstimatedUsd)}${incomplete}`,
255
+ c.analysisAttempts === 0
256
+ ? "analysis: none recorded"
257
+ : `analysis: ${knownMoney(c.analysisEstimatedUsd)} over ${plural(c.analysisAttempts, "recorded attempt")}${unpriced}`,
258
+ ...(c.analysisHistoryUncertainRuns > 0
259
+ ? [
260
+ `analysis history: ${plural(c.analysisHistoryUncertainRuns, "run")} missing or uncertain; --json lists each run`,
261
+ ]
262
+ : []),
263
+ ...(t.participants.total > 0
264
+ ? [
265
+ `participants: ${t.participants.reachedGoal} of ${t.participants.total} reached the goal, ${t.participants.reportedFriction} reported friction`,
266
+ ]
267
+ : []),
268
+ ...(verdicts.length > 0 ? [`verdicts: ${verdicts.join(", ")}`] : []),
269
+ ];
270
+ }
271
+ function dayLine(row) {
272
+ return `- ${row.day}: ${plural(row.runs, "run")}, ${row.live} live, known study spend ${knownMoney(row.costs.estimatedTotalUsd)}${unpricedTail(row.unpricedRuns, row.costs.analysisUnpricedAttempts)}`;
273
+ }
274
+ /** "; 2 unpriced runs, 1 unpriced analysis", or nothing when both are zero. */
275
+ function unpricedTail(runs, analyses) {
276
+ if (runs === 0 && analyses === 0)
277
+ return "";
278
+ return `; ${plural(runs, "unpriced run")}, ${plural(analyses, "unpriced analysis", "unpriced analyses")}`;
279
+ }
215
280
  export function formatStatsHuman(result) {
216
281
  if (!result.ok)
217
- return `${result.error.code}: ${result.error.message}\n`;
282
+ return { error: result.error };
218
283
  const t = result.totals;
219
284
  const scope = [
220
- result.lab === undefined ? undefined : `lab ${result.lab}`,
285
+ result.study === undefined ? undefined : `study ${result.study}`,
221
286
  result.since === undefined ? undefined : `since ${result.since}`,
222
287
  ].filter((part) => part !== undefined);
223
288
  const lines = [
224
289
  `humanish stats${scope.length === 0 ? "" : ` (${scope.join(", ")})`}`,
225
- `runs: ${t.runs} (${t.live} live, ${t.dryRun} dry-run${t.running > 0 ? `, ${t.running} running` : ""})`,
226
- `known estimated spend: ${knownMoney(t.costs.estimatedTotalUsd)}`,
227
- `participants + desktops: ${knownMoney(t.costs.runEstimatedUsd)}; ${t.costs.incompleteRunEstimates} run(s) with incomplete accounting`,
228
- `analysis: ${knownMoney(t.costs.analysisEstimatedUsd)} over ${t.costs.analysisAttempts} recorded attempt(s); ${t.costs.analysisUnpricedAttempts} unpriced, ${t.costs.analysisUnresolvedAttempts} unresolved`,
229
- `analysis history: ${t.costs.analysisHistoryUncertainRuns} run(s) missing or uncertain; use --json for per-run accounting`,
230
- `participants: ${t.participants.reachedGoal}/${t.participants.total} recorded goal completions, ${t.participants.reportedFriction} reported friction`,
231
- `verdicts: ${Object.entries(t.verdicts)
232
- .map(([verdict, count]) => `${verdict} ${count}`)
233
- .join(", ") || "none recorded"}`,
290
+ ...runCountLines(t),
234
291
  ];
235
- if (result.labs.length > 0) {
236
- lines.push("", "per lab:");
237
- for (const row of result.labs) {
238
- const rate = row.passRate === undefined ? "no verdicts" : `${row.passed}/${row.judged} pass`;
239
- const duration = row.medianDurationMs === undefined
240
- ? "no timed live runs"
241
- : `median ${minutes(row.medianDurationMs)} over ${row.durationSamples}`;
242
- const cost = row.medianCostUsd === undefined
243
- ? "no priced participant/desktop runs"
244
- : `participant/desktop median ${money(row.medianCostUsd)} over ${row.costSamples}`;
245
- lines.push(`- ${row.lab}: ${row.runs} run(s), ${row.live} live; ${rate}; ${duration}; known study spend ${knownMoney(row.costs.estimatedTotalUsd)}; ${cost}; ${row.unpricedRuns} unpriced runs, ${row.costs.analysisUnpricedAttempts} unpriced analyses`);
246
- }
247
- }
248
- if (result.days.length > 0) {
249
- lines.push("", "by day:");
250
- for (const row of result.days) {
251
- lines.push(`- ${row.day}: ${row.runs} run(s), ${row.live} live, known study spend ${knownMoney(row.costs.estimatedTotalUsd)}, ${row.unpricedRuns} unpriced runs, ${row.costs.analysisUnpricedAttempts} unpriced analyses`);
252
- }
292
+ // Free dry runs alone have no spend, outcome or duration to report. Anything else, an unreadable
293
+ // directory or a dry run that records a cost included, gets the full report.
294
+ const reportable = t.runs > 0 && !onlyFreeDryRuns(t);
295
+ if (reportable) {
296
+ lines.push(...totalsLines(t));
297
+ if (result.studies.length > 0)
298
+ lines.push("", "per study:", ...result.studies.map((row) => {
299
+ const rate = row.passRate === undefined ? "no verdicts" : `${row.passed} of ${row.judged} passed`;
300
+ const duration = row.medianDurationMs === undefined
301
+ ? "no timed live runs"
302
+ : `median ${minutes(row.medianDurationMs)} over ${row.durationSamples}`;
303
+ const cost = row.medianCostUsd === undefined
304
+ ? "no priced participant/desktop runs"
305
+ : `participant/desktop median ${money(row.medianCostUsd)} over ${row.costSamples}`;
306
+ return `- ${row.study}: ${plural(row.runs, "run")}, ${row.live} live; ${rate}; ${duration}; known study spend ${knownMoney(row.costs.estimatedTotalUsd)}; ${cost}${unpricedTail(row.unpricedRuns, row.costs.analysisUnpricedAttempts)}`;
307
+ }));
308
+ if (result.days.length > 0)
309
+ lines.push("", "by day:", ...result.days.map(dayLine));
253
310
  }
254
311
  if (result.unreadable.length > 0)
255
312
  lines.push("", `unreadable run directories: ${result.unreadable.join(", ")}`);
256
- lines.push("", result.note);
313
+ if (reportable)
314
+ lines.push("", result.note);
257
315
  return `${lines.join("\n")}\n`;
258
316
  }