@provos/ironcurtain 0.11.0 → 0.12.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 (365) hide show
  1. package/README.md +9 -7
  2. package/dist/cli-help.d.ts +12 -0
  3. package/dist/cli-help.js +21 -0
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.js +8 -6
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config/agent-model-guard.d.ts +14 -0
  8. package/dist/config/agent-model-guard.js +24 -0
  9. package/dist/config/agent-model-guard.js.map +1 -0
  10. package/dist/config/config-command.js +116 -1
  11. package/dist/config/config-command.js.map +1 -1
  12. package/dist/config/first-start.js +2 -8
  13. package/dist/config/first-start.js.map +1 -1
  14. package/dist/config/model-provider.d.ts +9 -0
  15. package/dist/config/model-provider.js +13 -0
  16. package/dist/config/model-provider.js.map +1 -1
  17. package/dist/config/paths.d.ts +48 -6
  18. package/dist/config/paths.js +63 -8
  19. package/dist/config/paths.js.map +1 -1
  20. package/dist/config/user-config.d.ts +48 -1
  21. package/dist/config/user-config.js +49 -1
  22. package/dist/config/user-config.js.map +1 -1
  23. package/dist/daemon/daemon-command.js +14 -5
  24. package/dist/daemon/daemon-command.js.map +1 -1
  25. package/dist/daemon/ironcurtain-daemon.d.ts +18 -0
  26. package/dist/daemon/ironcurtain-daemon.js +22 -1
  27. package/dist/daemon/ironcurtain-daemon.js.map +1 -1
  28. package/dist/daemon-client/daemon-client.d.ts +123 -0
  29. package/dist/daemon-client/daemon-client.js +324 -0
  30. package/dist/daemon-client/daemon-client.js.map +1 -0
  31. package/dist/docker/adapters/codex.d.ts +9 -0
  32. package/dist/docker/adapters/codex.js +297 -0
  33. package/dist/docker/adapters/codex.js.map +1 -0
  34. package/dist/docker/agent-adapter.d.ts +5 -1
  35. package/dist/docker/agent-adapter.js +2 -0
  36. package/dist/docker/agent-adapter.js.map +1 -1
  37. package/dist/docker/agent-registry.js +5 -0
  38. package/dist/docker/agent-registry.js.map +1 -1
  39. package/dist/docker/apple-container-manager.d.ts +49 -0
  40. package/dist/docker/apple-container-manager.js +464 -0
  41. package/dist/docker/apple-container-manager.js.map +1 -0
  42. package/dist/docker/code-mode-proxy.d.ts +11 -0
  43. package/dist/docker/code-mode-proxy.js +3 -1
  44. package/dist/docker/code-mode-proxy.js.map +1 -1
  45. package/dist/docker/container-lifecycle.d.ts +2 -2
  46. package/dist/docker/container-lifecycle.js.map +1 -1
  47. package/dist/docker/container-runtime.d.ts +29 -0
  48. package/dist/docker/container-runtime.js +76 -0
  49. package/dist/docker/container-runtime.js.map +1 -0
  50. package/dist/docker/docker-agent-session.js +30 -1
  51. package/dist/docker/docker-agent-session.js.map +1 -1
  52. package/dist/docker/docker-infrastructure.d.ts +186 -9
  53. package/dist/docker/docker-infrastructure.js +521 -77
  54. package/dist/docker/docker-infrastructure.js.map +1 -1
  55. package/dist/docker/docker-manager.d.ts +25 -5
  56. package/dist/docker/docker-manager.js +262 -22
  57. package/dist/docker/docker-manager.js.map +1 -1
  58. package/dist/docker/docker-probe.d.ts +45 -0
  59. package/dist/docker/docker-probe.js +86 -0
  60. package/dist/docker/docker-probe.js.map +1 -0
  61. package/dist/docker/docker-progress-sink.d.ts +1 -1
  62. package/dist/docker/mitm-proxy.d.ts +52 -1
  63. package/dist/docker/mitm-proxy.js +234 -10
  64. package/dist/docker/mitm-proxy.js.map +1 -1
  65. package/dist/docker/network-topology.d.ts +81 -0
  66. package/dist/docker/network-topology.js +160 -0
  67. package/dist/docker/network-topology.js.map +1 -0
  68. package/dist/docker/oauth-credentials.d.ts +13 -0
  69. package/dist/docker/oauth-credentials.js +125 -0
  70. package/dist/docker/oauth-credentials.js.map +1 -1
  71. package/dist/docker/package-types.d.ts +1 -1
  72. package/dist/docker/provider-config.d.ts +29 -1
  73. package/dist/docker/provider-config.js +93 -3
  74. package/dist/docker/provider-config.js.map +1 -1
  75. package/dist/docker/provision-lock.d.ts +46 -0
  76. package/dist/docker/provision-lock.js +152 -0
  77. package/dist/docker/provision-lock.js.map +1 -0
  78. package/dist/docker/pty-session.d.ts +15 -0
  79. package/dist/docker/pty-session.js +139 -67
  80. package/dist/docker/pty-session.js.map +1 -1
  81. package/dist/docker/registry-proxy.d.ts +46 -0
  82. package/dist/docker/registry-proxy.js +255 -1
  83. package/dist/docker/registry-proxy.js.map +1 -1
  84. package/dist/docker/resource-limits.d.ts +14 -5
  85. package/dist/docker/resource-limits.js +11 -8
  86. package/dist/docker/resource-limits.js.map +1 -1
  87. package/dist/docker/trajectory-capture.d.ts +79 -0
  88. package/dist/docker/trajectory-capture.js +521 -0
  89. package/dist/docker/trajectory-capture.js.map +1 -0
  90. package/dist/docker/trajectory-reassembler.d.ts +286 -0
  91. package/dist/docker/trajectory-reassembler.js +990 -0
  92. package/dist/docker/trajectory-reassembler.js.map +1 -0
  93. package/dist/docker/trajectory-tap.d.ts +100 -0
  94. package/dist/docker/trajectory-tap.js +410 -0
  95. package/dist/docker/trajectory-tap.js.map +1 -0
  96. package/dist/docker/trajectory-types.d.ts +187 -0
  97. package/dist/docker/trajectory-types.js +43 -0
  98. package/dist/docker/trajectory-types.js.map +1 -0
  99. package/dist/docker/types.d.ts +53 -7
  100. package/dist/doctor/checks.d.ts +36 -3
  101. package/dist/doctor/checks.js +102 -15
  102. package/dist/doctor/checks.js.map +1 -1
  103. package/dist/doctor/doctor-command.js +39 -9
  104. package/dist/doctor/doctor-command.js.map +1 -1
  105. package/dist/doctor/mcp-liveness.d.ts +1 -1
  106. package/dist/doctor/mcp-liveness.js +12 -4
  107. package/dist/doctor/mcp-liveness.js.map +1 -1
  108. package/dist/index.js +30 -12
  109. package/dist/index.js.map +1 -1
  110. package/dist/mux/mux-app.d.ts +2 -0
  111. package/dist/mux/mux-app.js +1 -0
  112. package/dist/mux/mux-app.js.map +1 -1
  113. package/dist/mux/mux-command.js +19 -6
  114. package/dist/mux/mux-command.js.map +1 -1
  115. package/dist/mux/pty-bridge.d.ts +2 -0
  116. package/dist/mux/pty-bridge.js +3 -0
  117. package/dist/mux/pty-bridge.js.map +1 -1
  118. package/dist/observe/observe-command.js +112 -125
  119. package/dist/observe/observe-command.js.map +1 -1
  120. package/dist/persona/broad-policy-validator.d.ts +95 -0
  121. package/dist/persona/broad-policy-validator.js +171 -0
  122. package/dist/persona/broad-policy-validator.js.map +1 -0
  123. package/dist/persona/compile-persona-policy.d.ts +54 -2
  124. package/dist/persona/compile-persona-policy.js +29 -4
  125. package/dist/persona/compile-persona-policy.js.map +1 -1
  126. package/dist/persona/event-bus-progress-reporter.d.ts +57 -0
  127. package/dist/persona/event-bus-progress-reporter.js +66 -0
  128. package/dist/persona/event-bus-progress-reporter.js.map +1 -0
  129. package/dist/persona/persona-command.js +46 -76
  130. package/dist/persona/persona-command.js.map +1 -1
  131. package/dist/persona/persona-compile-orchestrator.d.ts +101 -0
  132. package/dist/persona/persona-compile-orchestrator.js +504 -0
  133. package/dist/persona/persona-compile-orchestrator.js.map +1 -0
  134. package/dist/persona/persona-service.d.ts +137 -0
  135. package/dist/persona/persona-service.js +263 -0
  136. package/dist/persona/persona-service.js.map +1 -0
  137. package/dist/persona/policy-mutation-audit.d.ts +109 -0
  138. package/dist/persona/policy-mutation-audit.js +179 -0
  139. package/dist/persona/policy-mutation-audit.js.map +1 -0
  140. package/dist/persona/rule-delta.d.ts +30 -0
  141. package/dist/persona/rule-delta.js +82 -0
  142. package/dist/persona/rule-delta.js.map +1 -0
  143. package/dist/persona/types.d.ts +12 -0
  144. package/dist/pipeline/annotate.js +10 -2
  145. package/dist/pipeline/annotate.js.map +1 -1
  146. package/dist/pipeline/compile.js +14 -2
  147. package/dist/pipeline/compile.js.map +1 -1
  148. package/dist/pipeline/pipeline-runner.d.ts +63 -4
  149. package/dist/pipeline/pipeline-runner.js +159 -50
  150. package/dist/pipeline/pipeline-runner.js.map +1 -1
  151. package/dist/pipeline/pipeline-shared.d.ts +32 -3
  152. package/dist/pipeline/pipeline-shared.js +76 -8
  153. package/dist/pipeline/pipeline-shared.js.map +1 -1
  154. package/dist/pipeline/refresh-lists.js +3 -5
  155. package/dist/pipeline/refresh-lists.js.map +1 -1
  156. package/dist/sandbox/index.d.ts +19 -4
  157. package/dist/sandbox/index.js +31 -18
  158. package/dist/sandbox/index.js.map +1 -1
  159. package/dist/session/index.js +10 -1
  160. package/dist/session/index.js.map +1 -1
  161. package/dist/session/preflight.d.ts +1 -30
  162. package/dist/session/preflight.js +52 -85
  163. package/dist/session/preflight.js.map +1 -1
  164. package/dist/session/types.d.ts +9 -0
  165. package/dist/signal/bot-command.js +6 -1
  166. package/dist/signal/bot-command.js.map +1 -1
  167. package/dist/signal/setup-signal.js +1 -1
  168. package/dist/signal/setup-signal.js.map +1 -1
  169. package/dist/signal/signal-container.d.ts +3 -3
  170. package/dist/signal/signal-container.js +2 -2
  171. package/dist/signal/signal-container.js.map +1 -1
  172. package/dist/trusted-process/call-circuit-breaker.d.ts +6 -0
  173. package/dist/trusted-process/call-circuit-breaker.js +22 -3
  174. package/dist/trusted-process/call-circuit-breaker.js.map +1 -1
  175. package/dist/trusted-process/container-command.d.ts +35 -0
  176. package/dist/trusted-process/container-command.js +49 -0
  177. package/dist/trusted-process/container-command.js.map +1 -0
  178. package/dist/trusted-process/mcp-proxy-server.js +35 -3
  179. package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
  180. package/dist/trusted-process/policy-engine.js +13 -2
  181. package/dist/trusted-process/policy-engine.js.map +1 -1
  182. package/dist/trusted-process/tcp-server-transport.d.ts +12 -1
  183. package/dist/trusted-process/tcp-server-transport.js +9 -1
  184. package/dist/trusted-process/tcp-server-transport.js.map +1 -1
  185. package/dist/trusted-process/tool-call-coordinator.d.ts +22 -8
  186. package/dist/trusted-process/tool-call-coordinator.js +149 -65
  187. package/dist/trusted-process/tool-call-coordinator.js.map +1 -1
  188. package/dist/trusted-process/tool-call-pipeline.d.ts +8 -0
  189. package/dist/trusted-process/tool-call-pipeline.js +68 -34
  190. package/dist/trusted-process/tool-call-pipeline.js.map +1 -1
  191. package/dist/util/atomic-write.d.ts +31 -0
  192. package/dist/util/atomic-write.js +43 -0
  193. package/dist/util/atomic-write.js.map +1 -0
  194. package/dist/web-ui/conn-registry.d.ts +14 -0
  195. package/dist/web-ui/conn-registry.js +25 -0
  196. package/dist/web-ui/conn-registry.js.map +1 -0
  197. package/dist/web-ui/dispatch/persona-dispatch.d.ts +46 -2
  198. package/dist/web-ui/dispatch/persona-dispatch.js +209 -56
  199. package/dist/web-ui/dispatch/persona-dispatch.js.map +1 -1
  200. package/dist/web-ui/dispatch/session-dispatch.js +22 -4
  201. package/dist/web-ui/dispatch/session-dispatch.js.map +1 -1
  202. package/dist/web-ui/dispatch/types.d.ts +23 -0
  203. package/dist/web-ui/dispatch/types.js +4 -0
  204. package/dist/web-ui/dispatch/types.js.map +1 -1
  205. package/dist/web-ui/dispatch/workflow-dispatch.js +116 -5
  206. package/dist/web-ui/dispatch/workflow-dispatch.js.map +1 -1
  207. package/dist/web-ui/json-rpc-dispatch.js +1 -1
  208. package/dist/web-ui/json-rpc-dispatch.js.map +1 -1
  209. package/dist/web-ui/web-event-bus.d.ts +25 -1
  210. package/dist/web-ui/web-event-bus.js.map +1 -1
  211. package/dist/web-ui/web-ui-server.d.ts +14 -0
  212. package/dist/web-ui/web-ui-server.js +16 -0
  213. package/dist/web-ui/web-ui-server.js.map +1 -1
  214. package/dist/web-ui/web-ui-types.d.ts +133 -5
  215. package/dist/web-ui/web-ui-types.js.map +1 -1
  216. package/dist/web-ui-static/assets/index-BD5U6ILh.css +1 -0
  217. package/dist/web-ui-static/assets/index-FMsHWEfK.js +79 -0
  218. package/dist/web-ui-static/index.html +2 -2
  219. package/dist/workflow/cli-shared.d.ts +62 -0
  220. package/dist/workflow/cli-shared.js +117 -0
  221. package/dist/workflow/cli-shared.js.map +1 -0
  222. package/dist/workflow/cli-support.js +0 -2
  223. package/dist/workflow/cli-support.js.map +1 -1
  224. package/dist/workflow/container-snapshots.d.ts +29 -0
  225. package/dist/workflow/container-snapshots.js +137 -0
  226. package/dist/workflow/container-snapshots.js.map +1 -0
  227. package/dist/workflow/daemon-gate-commands.d.ts +21 -0
  228. package/dist/workflow/daemon-gate-commands.js +599 -0
  229. package/dist/workflow/daemon-gate-commands.js.map +1 -0
  230. package/dist/workflow/discovery.d.ts +29 -0
  231. package/dist/workflow/discovery.js +67 -7
  232. package/dist/workflow/discovery.js.map +1 -1
  233. package/dist/workflow/lane-template.d.ts +89 -0
  234. package/dist/workflow/lane-template.js +141 -0
  235. package/dist/workflow/lane-template.js.map +1 -0
  236. package/dist/workflow/lint.d.ts +7 -1
  237. package/dist/workflow/lint.js +186 -3
  238. package/dist/workflow/lint.js.map +1 -1
  239. package/dist/workflow/machine-builder.d.ts +90 -2
  240. package/dist/workflow/machine-builder.js +222 -29
  241. package/dist/workflow/machine-builder.js.map +1 -1
  242. package/dist/workflow/message-log.d.ts +15 -1
  243. package/dist/workflow/message-log.js.map +1 -1
  244. package/dist/workflow/orchestrator.d.ts +505 -1
  245. package/dist/workflow/orchestrator.js +1722 -69
  246. package/dist/workflow/orchestrator.js.map +1 -1
  247. package/dist/workflow/prompt-builder.js +2 -1
  248. package/dist/workflow/prompt-builder.js.map +1 -1
  249. package/dist/workflow/run-state-command.js +1 -1
  250. package/dist/workflow/run-state-command.js.map +1 -1
  251. package/dist/workflow/status-parser.js +19 -4
  252. package/dist/workflow/status-parser.js.map +1 -1
  253. package/dist/workflow/types.d.ts +123 -23
  254. package/dist/workflow/types.js +2 -0
  255. package/dist/workflow/types.js.map +1 -1
  256. package/dist/workflow/validate.d.ts +23 -1
  257. package/dist/workflow/validate.js +311 -22
  258. package/dist/workflow/validate.js.map +1 -1
  259. package/dist/workflow/workflow-command.d.ts +0 -17
  260. package/dist/workflow/workflow-command.js +110 -88
  261. package/dist/workflow/workflow-command.js.map +1 -1
  262. package/dist/workflow/workflow-discovery.d.ts +2 -0
  263. package/dist/workflow/workflow-discovery.js +22 -1
  264. package/dist/workflow/workflow-discovery.js.map +1 -1
  265. package/dist/workflow/workflow-manager.d.ts +34 -0
  266. package/dist/workflow/workflow-manager.js +52 -1
  267. package/dist/workflow/workflow-manager.js.map +1 -1
  268. package/dist/workflow/workflows/design-and-code/README.md +50 -0
  269. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/format_report.js +29 -0
  270. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/package.json +5 -0
  271. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/requirements.txt +1 -0
  272. package/dist/workflow/workflows/deterministic-eval-smoke/scripts/run_eval.py +41 -0
  273. package/dist/workflow/workflows/deterministic-eval-smoke/workflow.yaml +57 -0
  274. package/dist/workflow/workflows/deterministic-verdict-smoke/scripts/classify.py +18 -0
  275. package/dist/workflow/workflows/deterministic-verdict-smoke/workflow.yaml +51 -0
  276. package/dist/workflow/workflows/evolve/scripts/LICENSE +201 -0
  277. package/dist/workflow/workflows/evolve/scripts/README.md +314 -0
  278. package/dist/workflow/workflows/evolve/scripts/evolve-brief +16 -0
  279. package/dist/workflow/workflows/evolve/scripts/evolve-cognition +16 -0
  280. package/dist/workflow/workflows/evolve/scripts/evolve-db +16 -0
  281. package/dist/workflow/workflows/evolve/scripts/evolve-eval +16 -0
  282. package/dist/workflow/workflows/evolve/scripts/evolve-files +16 -0
  283. package/dist/workflow/workflows/evolve/scripts/evolve-summary +16 -0
  284. package/dist/workflow/workflows/evolve/scripts/evolve_core/__init__.py +14 -0
  285. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/__init__.py +17 -0
  286. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/base.py +21 -0
  287. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/factory.py +90 -0
  288. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/greedy.py +17 -0
  289. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/island.py +316 -0
  290. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/random.py +18 -0
  291. package/dist/workflow/workflows/evolve/scripts/evolve_core/algorithms/ucb1.py +55 -0
  292. package/dist/workflow/workflows/evolve/scripts/evolve_core/best_snapshot.py +62 -0
  293. package/dist/workflow/workflows/evolve/scripts/evolve_core/cli.py +752 -0
  294. package/dist/workflow/workflows/evolve/scripts/evolve_core/cognition.py +127 -0
  295. package/dist/workflow/workflows/evolve/scripts/evolve_core/database.py +218 -0
  296. package/dist/workflow/workflows/evolve/scripts/evolve_core/diff.py +57 -0
  297. package/dist/workflow/workflows/evolve/scripts/evolve_core/embedding.py +84 -0
  298. package/dist/workflow/workflows/evolve/scripts/evolve_core/file_lock.py +45 -0
  299. package/dist/workflow/workflows/evolve/scripts/evolve_core/run_state.py +343 -0
  300. package/dist/workflow/workflows/evolve/scripts/evolve_core/sampling_config.py +173 -0
  301. package/dist/workflow/workflows/evolve/scripts/evolve_core/structures.py +93 -0
  302. package/dist/workflow/workflows/evolve/scripts/evolve_core/vector_index.py +191 -0
  303. package/dist/workflow/workflows/evolve/scripts/evolve_result.py +1503 -0
  304. package/dist/workflow/workflows/evolve/scripts/requirements.txt +2 -0
  305. package/dist/workflow/workflows/evolve/workflow.yaml +646 -0
  306. package/dist/workflow/workflows/test-email-summary/workflow.yaml +1 -0
  307. package/dist/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +6 -1
  308. package/dist/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +1 -0
  309. package/dist/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +4 -0
  310. package/dist/workflow/workflows/vuln-discovery/workflow.yaml +13 -8
  311. package/docker/Dockerfile.base +22 -0
  312. package/docker/Dockerfile.base.arm64 +18 -0
  313. package/docker/Dockerfile.claude-code +3 -1
  314. package/docker/Dockerfile.codex +17 -0
  315. package/docker/Dockerfile.goose +3 -1
  316. package/docker/entrypoint-claude-code.sh +6 -45
  317. package/docker/entrypoint-codex.sh +42 -0
  318. package/docker/entrypoint-goose.sh +5 -24
  319. package/docker/entrypoint-uid-remap.sh +93 -0
  320. package/package.json +9 -4
  321. package/src/workflow/workflows/design-and-code/README.md +50 -0
  322. package/src/workflow/workflows/deterministic-eval-smoke/scripts/format_report.js +29 -0
  323. package/src/workflow/workflows/deterministic-eval-smoke/scripts/package.json +5 -0
  324. package/src/workflow/workflows/deterministic-eval-smoke/scripts/requirements.txt +1 -0
  325. package/src/workflow/workflows/deterministic-eval-smoke/scripts/run_eval.py +41 -0
  326. package/src/workflow/workflows/deterministic-eval-smoke/workflow.yaml +57 -0
  327. package/src/workflow/workflows/deterministic-verdict-smoke/scripts/classify.py +18 -0
  328. package/src/workflow/workflows/deterministic-verdict-smoke/workflow.yaml +51 -0
  329. package/src/workflow/workflows/evolve/scripts/LICENSE +201 -0
  330. package/src/workflow/workflows/evolve/scripts/README.md +314 -0
  331. package/src/workflow/workflows/evolve/scripts/evolve-brief +16 -0
  332. package/src/workflow/workflows/evolve/scripts/evolve-cognition +16 -0
  333. package/src/workflow/workflows/evolve/scripts/evolve-db +16 -0
  334. package/src/workflow/workflows/evolve/scripts/evolve-eval +16 -0
  335. package/src/workflow/workflows/evolve/scripts/evolve-files +16 -0
  336. package/src/workflow/workflows/evolve/scripts/evolve-summary +16 -0
  337. package/src/workflow/workflows/evolve/scripts/evolve_core/__init__.py +14 -0
  338. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/__init__.py +17 -0
  339. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/base.py +21 -0
  340. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/factory.py +90 -0
  341. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/greedy.py +17 -0
  342. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/island.py +316 -0
  343. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/random.py +18 -0
  344. package/src/workflow/workflows/evolve/scripts/evolve_core/algorithms/ucb1.py +55 -0
  345. package/src/workflow/workflows/evolve/scripts/evolve_core/best_snapshot.py +62 -0
  346. package/src/workflow/workflows/evolve/scripts/evolve_core/cli.py +752 -0
  347. package/src/workflow/workflows/evolve/scripts/evolve_core/cognition.py +127 -0
  348. package/src/workflow/workflows/evolve/scripts/evolve_core/database.py +218 -0
  349. package/src/workflow/workflows/evolve/scripts/evolve_core/diff.py +57 -0
  350. package/src/workflow/workflows/evolve/scripts/evolve_core/embedding.py +84 -0
  351. package/src/workflow/workflows/evolve/scripts/evolve_core/file_lock.py +45 -0
  352. package/src/workflow/workflows/evolve/scripts/evolve_core/run_state.py +343 -0
  353. package/src/workflow/workflows/evolve/scripts/evolve_core/sampling_config.py +173 -0
  354. package/src/workflow/workflows/evolve/scripts/evolve_core/structures.py +93 -0
  355. package/src/workflow/workflows/evolve/scripts/evolve_core/vector_index.py +191 -0
  356. package/src/workflow/workflows/evolve/scripts/evolve_result.py +1503 -0
  357. package/src/workflow/workflows/evolve/scripts/requirements.txt +2 -0
  358. package/src/workflow/workflows/evolve/workflow.yaml +646 -0
  359. package/src/workflow/workflows/test-email-summary/workflow.yaml +1 -0
  360. package/src/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +6 -1
  361. package/src/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +1 -0
  362. package/src/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +4 -0
  363. package/src/workflow/workflows/vuln-discovery/workflow.yaml +13 -8
  364. package/dist/web-ui-static/assets/index-BFO5z1js.js +0 -76
  365. package/dist/web-ui-static/assets/index-CCUwrkIL.css +0 -1
@@ -27,6 +27,7 @@ import type { ResolvedSkill } from '../skills/types.js';
27
27
  * location.
28
28
  */
29
29
  export declare function stageWorkflowSkillsAtStart(packageDir: string, runMetaDir: string): string | undefined;
30
+ export declare function stageWorkflowScriptsAtStart(packageDir: string, runMetaDir: string): string | undefined;
30
31
  /** Handle for writing to a workflow tab in the mux. */
31
32
  export interface WorkflowTabHandle {
32
33
  write(text: string): void;
@@ -88,6 +89,10 @@ export interface CreateWorkflowInfrastructureInput {
88
89
  * Persona skills are layered in per-state via `bundle.restageSkills`.
89
90
  */
90
91
  readonly resolvedSkills?: readonly ResolvedSkill[];
92
+ /** Per-run staged workflow scripts directory to mount read-only in the bundle. */
93
+ readonly workflowScriptsDir?: string;
94
+ /** Optional immutable snapshot image digest to use for the main container. */
95
+ readonly baseImageOverride?: string;
91
96
  }
92
97
  /** Inputs for starting the coordinator's HTTP control server on a workflow bundle. */
93
98
  export interface StartWorkflowControlServerInput {
@@ -157,6 +162,17 @@ export interface WorkflowOrchestratorDeps {
157
162
  * to assert on the RPC shape without standing up a real socket.
158
163
  */
159
164
  readonly loadPolicyRpc?: (input: LoadPolicyRpcInput) => Promise<void>;
165
+ /**
166
+ * Raw trajectory-capture override for this workflow run (CLI
167
+ * `--capture-traces` flag). Passed UNRESOLVED to the infrastructure
168
+ * factory, which is the single place that resolves it against
169
+ * `userConfig.capture?.enabled`. When resolution yields true, the
170
+ * factory constructs a writer for each bundle and `executeAgentState`
171
+ * brackets each agent's session with `bundle.beginCaptureSession` /
172
+ * `bundle.endCaptureSession`. Undefined falls through to config.
173
+ * See docs/designs/mitm-token-trajectory-capture.md §10.
174
+ */
175
+ readonly captureTracesOverride?: boolean;
160
176
  }
161
177
  /** Lifecycle events emitted by the orchestrator. */
162
178
  export type WorkflowLifecycleEvent = {
@@ -356,6 +372,20 @@ export declare class WorkflowOrchestrator implements WorkflowController {
356
372
  * test or CLI layer), which is the intended signal.
357
373
  */
358
374
  private destroyWorkflowInfrastructure;
375
+ /** Body of the bundle teardown; only ever started once per instance. */
376
+ private runBundleTeardown;
377
+ private shouldSnapshotOnStop;
378
+ private snapshotResumableScopes;
379
+ private dockerForSnapshotCleanup;
380
+ private removeSnapshotImagesAfterTeardown;
381
+ /**
382
+ * Builds and persists the terminal checkpoint, preserving the prior on-disk
383
+ * machineState/context (which point at the last non-terminal save point) so
384
+ * resume re-enters that state instead of the terminal snapshot. Shared by the
385
+ * abort() and handleWorkflowComplete() stop paths.
386
+ */
387
+ private saveTerminalCheckpoint;
388
+ private snapshotsSupersededBy;
359
389
  /**
360
390
  * Lazy-loads the default `createDockerInfrastructure` wrapper. The real
361
391
  * helper requires Docker dependencies and the session config, so we
@@ -399,7 +429,14 @@ export declare class WorkflowOrchestrator implements WorkflowController {
399
429
  abort(id: WorkflowId): Promise<void>;
400
430
  onEvent(callback: (event: WorkflowLifecycleEvent) => void): void;
401
431
  shutdownAll(): Promise<void>;
402
- /** Injects concrete agent/deterministic service implementations into the machine. */
432
+ /**
433
+ * Injects concrete service implementations into the machine: `agentService`
434
+ * and `deterministicService` for executable states, plus `fanOutService` —
435
+ * the invoke body of a `workers` fan-out state, which runs
436
+ * {@link runFanOutSegment} and is re-provided onto each child round machine
437
+ * (the children reuse the same agent/deterministic actors, lane-scoped via
438
+ * input).
439
+ */
403
440
  private provideActors;
404
441
  /** Subscribes to actor snapshot changes for lifecycle events, gates, and checkpointing. */
405
442
  private subscribeToActor;
@@ -414,7 +451,474 @@ export declare class WorkflowOrchestrator implements WorkflowController {
414
451
  private buildCheckpoint;
415
452
  private saveCheckpoint;
416
453
  private executeAgentState;
454
+ /**
455
+ * Runs one fan-out batch: the invoke body of the real `workers` state,
456
+ * registered as the `fanOutService` actor (see {@link provideActors}). For
457
+ * each worker it creates a free-standing child round actor, starts it, and
458
+ * barrier-joins on every child reaching a `final` state, then folds the lane
459
+ * verdicts into a single parent-edge result (§6.2).
460
+ *
461
+ * WHY free-standing `createActor` + `.start()` and NOT in-context `spawn`:
462
+ * this is a `fromPromise` invoke body (plain async TS), not an XState entry
463
+ * action — `spawn` is only callable from inside an action. A free-standing
464
+ * actor is its OWN root, so the parent's `snapshot.value` stays the string
465
+ * `"workers"` (single-active-state spine preserved, §6.4); the children's
466
+ * snapshots are their own, read here via {@link waitForRoundChild}. A
467
+ * `type:'parallel'` region would instead fold into the parent's `value` and
468
+ * make it an object — fatal to checkpoint/terminal/gate serialization (§6.4).
469
+ *
470
+ * WHY mint the scope bundle BEFORE fan-out: {@link preMintFanOutScopeBundle}
471
+ * runs `ensureBundleForScope` serially up front so the single shared
472
+ * container exists before any child's first `container:true` step. N children
473
+ * racing their first container step would each see an empty `bundlesByScope`
474
+ * and mint a SEPARATE container, defeating `sharedContainer` (§6.2 / §8.1;
475
+ * cross-ref the `ensureBundleForScope` check-then-act race comment).
476
+ *
477
+ * Never throws: every failure path — workflow gone, misconfigured segment,
478
+ * unsupported worker count, missing child machine — funnels through
479
+ * {@link fanOutErrorResult}, which yields a `result_file_error` verdict that
480
+ * the parent `workers` state routes to its `failed` edge. (The `fanOutService`
481
+ * wrapper in {@link provideActors} would also catch a thrown error, but the
482
+ * uniform result keeps the parent transition table verdict-driven.)
483
+ */
484
+ private runFanOutSegment;
485
+ /**
486
+ * Promotes recorded lane lessons once, serially, at the fan-out barrier. This
487
+ * is the workers>1 cognition single-writer point (§9): lane `attach_analysis`
488
+ * calls only record durable nodes; the parent invokes `promote_cognition`
489
+ * after every child has recorded and before re-entering `orchestrator`.
490
+ *
491
+ * Only `recorded` lanes are promoted — blocked/errored children are filtered
492
+ * out because they contributed no durable node to seed a lesson from.
493
+ *
494
+ * Returns one of three shapes:
495
+ * - `{ error }` — the promotion ran but did not pass (the bridge returned a
496
+ * non-`cognition_promoted` verdict / `needs_repair`), OR — a hard error —
497
+ * `lanes.length === 0` for a workers>1 recorded batch (every recorded child
498
+ * should carry a lane id, so an empty set means the join is inconsistent).
499
+ * - `{ result }` — the promotion passed; the caller folds the payload into the
500
+ * batch result under `cognition_promotion`.
501
+ * - `{}` — a no-op, when {@link buildEvolvePromoteCognitionInput} returns
502
+ * undefined (non-evolve segment, or a segment with nothing to promote).
503
+ *
504
+ * Mixed-verdict deferral (within §9, intended): this only runs when the batch
505
+ * verdict is `recorded`. When a batch instead escalates/fails, recorded lanes'
506
+ * lessons are NOT promoted that turn — on APPROVE→resume the recorded lanes
507
+ * idempotent-skip then barrier-promote (the ledger dedups), but an
508
+ * ABORT/FORCE_REVISION never promotes them, by design: an aborted batch must
509
+ * not seed cognition.
510
+ */
511
+ private promoteBarrierCognition;
512
+ /**
513
+ * Locates the segment's `attach_analysis` deterministic state and its evolve
514
+ * command (the segment member that carries the `evolve_result.py` path and
515
+ * `--run-dir`). Returns `undefined` when the segment has no such state — a
516
+ * non-evolve fan-out has no cognition to promote.
517
+ */
518
+ private findEvolveAttachAnalysisState;
519
+ /**
520
+ * Derives the `promote_cognition` invoke input from the segment's already-
521
+ * resolved `attach_analysis` command: reuses the bridge path, `--run-dir`,
522
+ * container scope, and timeout; rewrites the subcommand; passes the recorded
523
+ * lane ids; and writes one barrier-owned result at
524
+ * `current/cognition_promotion.json`. Returns `undefined` when the command
525
+ * lacks the bridge path, a `--run-dir`, or a resolvable workspace-relative
526
+ * result path (the caller then treats promotion as a no-op).
527
+ */
528
+ private buildEvolvePromoteCognitionInput;
529
+ /**
530
+ * Computes the single canonical `current/stop_signals.json` ONCE at the
531
+ * barrier join by running the bridge's `compute_stop_signals` subcommand over
532
+ * the batch-grown `nodes.json`. The bridge writes the bare canonical file
533
+ * atomically (temp+rename); per-lane `attach_analysis` only ever wrote
534
+ * lane-scoped copies, so this is the sole writer of the routing input the
535
+ * orchestrator reads each batch (SHOULD-FIX-1).
536
+ *
537
+ * Derived from the segment head's declared `sample` command (the only segment
538
+ * member guaranteed to carry the `evolve_result.py` path and `--run-dir`), so
539
+ * it inherits the same container scope / timeout. Returns an error string on
540
+ * failure (the caller folds it into a `result_file_error`), or `undefined` on
541
+ * success — including the benign case where the segment has no recognizable
542
+ * evolve sample command (a non-evolve fan-out has no stop signals to compute).
543
+ */
544
+ private computeBarrierStopSignals;
545
+ /**
546
+ * Derives the `compute_stop_signals` invoke input from the segment head's
547
+ * `sample` command: reuses its `evolve_result.py` path and `--run-dir`,
548
+ * rewrites the subcommand to `compute_stop_signals`, and points
549
+ * `--result-file` at the shared `current/stop_signals_compute.json` barrier
550
+ * artifact. Returns `undefined` when the command lacks the bridge path, a
551
+ * `--run-dir`, or a resolvable workspace-relative result path.
552
+ */
553
+ private buildEvolveStopSignalsInput;
554
+ /**
555
+ * Mints the fan-out segment's shared-container bundle ONCE, before any child
556
+ * actor starts (the load-bearing precondition of {@link runFanOutSegment}).
557
+ *
558
+ * The mint precondition: only when the workflow actually uses a shared
559
+ * container (`shouldUseSharedContainer`) AND at least one segment member runs
560
+ * in-container. A segment with no container members needs no bundle and
561
+ * returns early.
562
+ *
563
+ * `ensureBundleForScope` is an unguarded check-then-act across awaits (its own
564
+ * doc flags the lazy-mint race): N children each hitting their first
565
+ * `container:true` step would each see `bundlesByScope.get(scope)` undefined
566
+ * and mint a SEPARATE container. Calling it once here, serially, closes that
567
+ * window — every child then borrows the already-minted bundle. Cross-ref the
568
+ * race comment on `ensureBundleForScope`.
569
+ *
570
+ * The multi-scope throw is a guardrail, not a supported path: this slice
571
+ * keeps the whole segment under one `containerScope` (single-policy
572
+ * homogeneity, §8.2). A segment spanning >1 scope is out of slice scope and
573
+ * fails fast rather than minting the wrong bundle.
574
+ */
575
+ private preMintFanOutScopeBundle;
576
+ private buildFanOutLaneContext;
577
+ /**
578
+ * Reconstructs an in-flight evolve fan-out batch from the durable engine DB.
579
+ *
580
+ * This intentionally does NOT use XState child persistence. The checkpoint
581
+ * stores `{ machineState, context }` and `resolveState()` re-enters `workers`
582
+ * without live child ActorRefs; free-standing child actors created in the old
583
+ * process are gone. First-cut crash-resume therefore treats `nodes.json` as the
584
+ * source of truth: a recorded `step_<batch>_lane_<k>` means lane k is already
585
+ * done and must be synthesized, while every missing lane is re-spawned fresh
586
+ * from `sample`. That fresh re-run can produce a different verdict (§11.2
587
+ * verdict drift), which is acceptable for node-integrity but not a promise of
588
+ * batch-outcome reproducibility.
589
+ *
590
+ * Cross-language seam (deliberate, NOT accidental duplication). The batch-index
591
+ * reuse rule below re-implements Python `_next_batch_index(run_dir, workers)`.
592
+ * We re-derive it here rather than consume the bridge's `sample_batch_prepared`
593
+ * echo because the index is needed BEFORE `sample_batch` runs: TS must know it
594
+ * to decide synthesize-vs-respawn per lane AND to pin `--batch-index` into the
595
+ * very `sample_batch` call whose output would otherwise echo it. Having the
596
+ * bridge be authoritative would invert that ordering. So the two derivations
597
+ * MUST move together — TS pins `--batch-index` whenever any lane is recorded (so
598
+ * the bridge cannot diverge), and recomputes the identical number when none is.
599
+ * Both sides cite the shared `step_<batch>_lane_<k>` format (`evolveStepName` /
600
+ * the Python f-string) as the contract.
601
+ */
602
+ private reconstructFanOutBatchFromDb;
603
+ /**
604
+ * The evolve `--run-dir` for this fan-out segment's `sample` head, or
605
+ * `undefined` when the segment head is not a deterministic evolve sample
606
+ * command. `undefined` makes {@link reconstructFanOutBatchFromDb} return
607
+ * `unavailable`, so resume falls back to re-spawning all lanes fresh.
608
+ */
609
+ private evolveRunDirForFanOutSegment;
610
+ /**
611
+ * Reads the engine `nodes.json` node map. Missing file ⇒ `{ entries: [] }`
612
+ * with NO error — a fresh batch (or a run that has not recorded any node yet)
613
+ * is a normal pre-crash state and must reconstruct as "nothing recorded". A
614
+ * read or JSON-parse failure ⇒ an `error`, which aborts the fan-out: a corrupt
615
+ * DB is NOT safe to treat as empty (we would re-run lanes that may already be
616
+ * recorded), so the missing-vs-corrupt distinction is load-bearing.
617
+ */
618
+ private readEvolveNodes;
619
+ private asRecord;
620
+ private nodeIdFromRecord;
621
+ /**
622
+ * The node's parent lineage as a tri-state: `undefined` when the record has no
623
+ * `parent` array at all (omit the field from the synthesized payload — lineage
624
+ * unknown), `[]` for a root node (an explicit empty array — root, not omitted),
625
+ * and `[...ids]` for a child's parent ids. The empty-vs-undefined distinction
626
+ * is preserved deliberately so {@link synthesizeRecordedFanOutOutcome} can omit
627
+ * an unknown parent while still echoing an explicit root.
628
+ */
629
+ private nodeParentFromRecord;
630
+ /**
631
+ * Builds the barrier outcome for a lane that already recorded before a crash.
632
+ * The durable node proves the lane advanced; the volatile child actor context
633
+ * (visit counts, token spend, in-flight state) is not recoverable without the
634
+ * deferred `getPersistedSnapshot()` + in-context spawn migration, so this is a
635
+ * minimal recorded context sufficient for join, promotion, and duplicate stats.
636
+ *
637
+ * Edge cases (the contract callers rely on):
638
+ * - Called ONLY for a lane the engine DB already recorded — i.e. the
639
+ * just-before-crash case where the node landed but the process died before
640
+ * the join. Every NOT-recorded lane is re-spawned instead (see the fork in
641
+ * {@link runFanOutSegment}).
642
+ * - Does NOT rebuild on-disk artifacts. The lane's `analysis.md` /
643
+ * `analysis_record.json` may be absent post-crash, but the durable node is
644
+ * authoritative, so a fabricated `lastDeterministicResult` with
645
+ * `{ verdict: 'recorded', idempotent_skip: true }` is sufficient — nothing
646
+ * downstream re-reads those files for a recorded lane.
647
+ * - `idempotent_skip: true` is the marker that this outcome was synthesized
648
+ * (vs produced by a live re-run); the returned `recorded` outcome is
649
+ * otherwise indistinguishable to {@link joinFanOutBatch} from a live-recorded
650
+ * lane, so the join, promotion, and duplicate-rate paths need no special case.
651
+ */
652
+ private synthesizeRecordedFanOutOutcome;
653
+ /**
654
+ * Runs the ONE barrier-side `sample_batch(n=workers)` before fan-out and
655
+ * partitions its result into per-lane pre-computed `sample` results (keyed by
656
+ * lane id) that {@link executeDeterministicState} replays as each child's
657
+ * `sample` step.
658
+ *
659
+ * WHY one barrier-side `sample_batch(n=N)` and NOT N independent `sample()`
660
+ * calls: the divergence between lanes is INJECTED at sampling (§7.4). N
661
+ * independent `sample()` calls each reload the same `nodes.json` and, with a
662
+ * diversity-maintaining sampler, could draw the SAME parent into multiple
663
+ * lanes — collapsing the N-wide frontier into "N samples of one distribution"
664
+ * and producing near-duplicate candidates. A single `sample_batch` over the
665
+ * whole DB partitions N DISTINCT parents (one per lane) in one serialized,
666
+ * read-only DB touch, guaranteeing disjoint parent sets up front. The bridge
667
+ * uses a per-lane seed offset (`base_seed + laneId`) to decorrelate the lanes
668
+ * while keeping the partition reproducible, with a deterministic hash tiebreak
669
+ * so the assignment is stable across resume (§7.4).
670
+ *
671
+ * `workers === 1` short-circuits: the single lane uses the legacy inline
672
+ * `sample` step (byte-identical backward compat, gate item 1), so there is no
673
+ * batch to prepare. A non-deterministic or unrecognized sample state likewise
674
+ * returns an empty map (the child runs its own `sample`).
675
+ */
676
+ private prepareFanOutLaneResults;
677
+ /**
678
+ * Derives the deterministic invoke input for the barrier-side `sample_batch`
679
+ * from the segment head's declared `sample` command: rewrites the `sample`
680
+ * subcommand to `sample_batch`, adds `--workers <N>`, carries over the
681
+ * query/top-k flags, and points `--result-file` at the shared
682
+ * `current/sample_batch.json` (the batch artifact is barrier-owned, not
683
+ * lane-scoped). Returns `undefined` (the caller then lets each child sample on
684
+ * its own) when the segment head is not a recognizable evolve `sample`
685
+ * command, has no `evolve_result.py` entry, or lacks a `--run-dir` / resolvable
686
+ * workspace-relative result path.
687
+ */
688
+ private buildEvolveSampleBatchInput;
689
+ /**
690
+ * Shared skeleton for the three barrier-side `evolve_result.py` invocations
691
+ * (`sample_batch`, `promote_cognition`, `compute_stop_signals`). Given an
692
+ * already-resolved `sourceCommand` (the caller does the `state.run.find`), it
693
+ * locates the bridge path, carries over `--run-dir`, rewrites the subcommand,
694
+ * splices in the per-caller `extraArgs`, and points `--result-file` at the
695
+ * shared barrier artifact `current/<resultBasename>`. Returns `undefined` when
696
+ * the source command lacks the bridge path, a `--run-dir`, or a resolvable
697
+ * workspace-relative result path — the caller's documented no-op signal.
698
+ */
699
+ private buildEvolveBarrierInput;
700
+ private isEvolveSampleCommand;
701
+ private isEvolveAttachAnalysisCommand;
702
+ private commandFlagValue;
703
+ private sampleQueryArgs;
704
+ private sampleTopKArgs;
705
+ private containerPathToWorkspaceRelative;
706
+ /**
707
+ * Barrier primitive for one lane. Returns a {@link RoundChildWaiter} (NOT a
708
+ * bare Promise): a two-phase handle whose `promise` resolves by EITHER of two
709
+ * routes, and whose `drain`/`isSettled` members let the fan-out pump stop and
710
+ * inspect the lane externally.
711
+ *
712
+ * The two resolution routes and the discriminator {@link joinFanOutBatch} reads:
713
+ * - NATURAL SETTLE — the child's own snapshot reaches a `final` state
714
+ * (`status === 'done'`), resolving with `recorded`/`blocked`/`errored` and
715
+ * `drainedBy: undefined`. A free-standing child fires no parent-visible
716
+ * `onDone`, so the parent watches the child's OWN snapshot (§6.2) via
717
+ * subscribe-until-done rather than an `xstate.done.actor` event.
718
+ * - DRAIN — an external `drain(trigger)` call (a peer blocked/errored) stops
719
+ * the actor and resolves with status `drained` and a populated `drainedBy`.
720
+ * `drainedBy` being set vs `undefined` is exactly how the join distinguishes
721
+ * a drained peer from a naturally-settled lane.
722
+ *
723
+ * `isSettled` is first-wins: whichever route fires first latches `settled`, so
724
+ * a lane that RECORDED before the drain reached it keeps its real `recorded`
725
+ * outcome (the drain is a no-op on an already-settled lane).
726
+ *
727
+ * After the child `onError` -> `errored` fix, a segment-member service
728
+ * rejection becomes a normal `errored` TERMINAL (status `done`, value
729
+ * `errored`) and resolves here; the `status === 'error'` branch is the
730
+ * residual safety net for an actor-level throw the `errored` terminal did not
731
+ * catch (e.g. an entry-action throw), which resolves as an `errored` lane so
732
+ * drain-on-escalation can still stop peers and the join can report the full
733
+ * batch.
734
+ *
735
+ * WHY a hand-rolled subscribe loop and NOT `xstate`'s `waitFor`: `waitFor`
736
+ * resolves only when the actor's OWN snapshot stream matches a predicate. The
737
+ * drain route resolves the SAME promise from OUTSIDE that stream (the pump
738
+ * synthesizes a `drained` outcome the instant it stops the actor, without
739
+ * waiting for any in-flight external service call to settle, FSM-M3). `waitFor`
740
+ * cannot express that external resolver, so the two-phase waiter is kept.
741
+ *
742
+ * The trailing `observe(actor.getSnapshot())` after `subscribe` guards the
743
+ * synchronous-settle-before-subscribe race: a child whose first state
744
+ * settles synchronously (e.g. a sync entry-action throw) can already be
745
+ * `done`/`error` by the time `.subscribe` returns, so the subscription would
746
+ * never deliver that final snapshot. Observing the current snapshot once,
747
+ * immediately, closes the lane in that case.
748
+ */
749
+ private waitForRoundChild;
750
+ /**
751
+ * Folds the settled lane outcomes into a single parent-edge result, applying
752
+ * a fixed verdict precedence (worst lane wins):
753
+ * 1. any rejected settle -> `result_file_error` (a residual actor-level
754
+ * throw that did not resolve as an `errored` lane);
755
+ * 2. else any `blocked` lane -> `escalate` (route once to human review,
756
+ * with every blocked/errored lane reason aggregated);
757
+ * 3. else any `errored` lane -> `result_file_error` (explicit fail mapping);
758
+ * 4. else any `drained` lane without an issue trigger -> `result_file_error`;
759
+ * 5. else all `recorded` -> `recorded` (the batch advanced).
760
+ *
761
+ * WHY `Promise.allSettled` (not `Promise.all`) upstream: one lane's rejection
762
+ * must not abandon its N-1 in-flight peers (FSM-S5). `all` would reject on the
763
+ * first throw and lose the other lanes' outcomes; `allSettled` lets the join
764
+ * see the full batch, including parent-synthesized `drained` peer outcomes.
765
+ *
766
+ * For `workers: 1`, the recorded path still promotes the single child context
767
+ * exactly. For N>1, the recorded path folds lane contexts into a parent batch
768
+ * context: child artifacts/conversations merge, parent visit counts remain
769
+ * authoritative for the single-active-state spine, and total tokens fan in
770
+ * from the orchestrator's workflow-level token accumulator.
771
+ */
772
+ private joinFanOutBatch;
773
+ /**
774
+ * Projects the blocked/errored lanes (the offenders) into the {@link FanOutIssue}
775
+ * payload that lands in the aggregated gate. Drained peers are intentionally
776
+ * excluded — they are the drain-first collateral, not independent issues (§ the
777
+ * reason list is the blocked-at-drain set, not all-would-have-blocked).
778
+ */
779
+ private fanOutIssues;
780
+ /**
781
+ * Surfaces a one-line human-readable cause for a blocked/errored lane, with an
782
+ * ASYMMETRIC fallback order per status — THE footgun this method guards:
783
+ *
784
+ * - `errored` prefers `lastError` then `previousAgentOutput`: an errored lane
785
+ * DID trip `storeError`, so `lastError` is the populated, authoritative cause.
786
+ * - `blocked` prefers `previousAgentOutput` then `lastError`: a blocked lane
787
+ * (evaluator_blocked) never trips `storeError`, so its `lastError` is null and
788
+ * the real reason lives on `previousAgentOutput` (the evaluator's message).
789
+ *
790
+ * Do NOT collapse the two branches into one fallback chain: a unified order
791
+ * would surface a stale/null field for one of the two statuses. This rationale
792
+ * was deleted from the old call sites and is re-homed here on purpose.
793
+ */
794
+ private roundChildReason;
795
+ /** Renders an issue list as a header line plus one `- lane <i> <status>: <reason>` bullet per offending lane. */
796
+ private formatFanOutIssues;
797
+ /**
798
+ * Builds the parent-spine context for a blocked/errored BATCH (the escalate and
799
+ * errored-only join branches). WHAT it folds:
800
+ * - the worst lane's context (`source`) promoted back onto the spine via
801
+ * {@link promoteFanOutContext} (lane marker stripped, parent visit counts
802
+ * restored, tokens from the accumulator);
803
+ * - an AGGREGATED multi-lane summary of every blocked/errored lane written to
804
+ * `previousAgentOutput` (this is what the orchestrator reads on APPROVE→resume
805
+ * and the human reads in the gate banner);
806
+ * - the same lanes as the structured `issues` payload on
807
+ * `lastDeterministicResult` for the gate.
808
+ *
809
+ * WHY ONE gate, not one per offending lane: all blocked/errored reasons fold
810
+ * into a single payload so the human reviews the batch ONCE. The two verdict
811
+ * shapes differ only in `lastError`: `escalate` leaves `lastError` null (a
812
+ * blocked lane is recoverable, not an error), while the errored-only verdict
813
+ * mirrors the summary into `lastError` (the batch failed).
814
+ *
815
+ * SCRATCH-SHAPE TAG (workers:1 vs workers>1 disambiguator): the orchestrator's
816
+ * recovery prompt has two mutually-exclusive recoveries — legacy `evaluate`-
817
+ * resume of the one written-but-unscored candidate (bare `current/`) vs discard
818
+ * the lane scratch and start a fresh `design` batch (lane-scoped
819
+ * `current/lane_<k>/`). At `workers:1` the lane carries NO `lane` marker and the
820
+ * scratch is the BARE `current/`, so the legacy resume is the correct recovery;
821
+ * at `workers>1` the lane scratch is under `current/lane_<k>/` and must be
822
+ * discarded. The summary message alone ("Fan-out batch escalated…") would push
823
+ * the LLM toward discard in BOTH cases, so we append an explicit scratch-shape
824
+ * sentence derived from `source.context.lane` to steer the prompt's branch.
825
+ */
826
+ private promoteFanOutIssueContext;
827
+ /**
828
+ * Promotes a SINGLE lane's context back onto the parent spine (the
829
+ * blocked/errored drain paths, and the `workers: 1` recorded path where there
830
+ * is exactly one lane). Strips the per-lane `lane` marker so the parent never
831
+ * carries a lane identity, restores the parent's authoritative `visitCounts`
832
+ * (the single-active-state spine owns visit accounting; a lane's own counts
833
+ * are a within-batch detail, §7.5), and reads `totalTokens` from the
834
+ * instance-level token accumulator (the aggregate over all lanes' registered
835
+ * sessionIds, which is the budget-authoritative figure, NOT the lane's local
836
+ * sum). The `lane === undefined` branch is the no-fan-out / `workers: 1` case:
837
+ * there is no lane marker to strip, so only the token figure is refreshed.
838
+ */
839
+ private promoteFanOutContext;
840
+ /**
841
+ * Folds the N recorded lane contexts back into ONE parent-spine context at the
842
+ * barrier join (the recorded happy path for `workers > 1`). This is the
843
+ * highest-stakes merge in the fan-out: the parent FSM is single-active-state,
844
+ * so after the batch it must hold a single coherent context even though N
845
+ * child actors each evolved their own copy in parallel. Each field is merged
846
+ * by a rule chosen for WHY it is correct on the spine, NOT by a uniform
847
+ * strategy:
848
+ *
849
+ * - `visitCounts`: the PARENT's counts are authoritative and copied verbatim.
850
+ * The spine has a single active state (`workers`), entered once per batch;
851
+ * the children's per-lane visit counts are a within-batch bookkeeping detail
852
+ * (§7.5) that must not leak onto the parent, or the global round-limit
853
+ * backstop would see N× inflated counts.
854
+ * - `round`: SUM of each lane's POSITIVE delta over the parent baseline
855
+ * (`max(0, child.round - parent.round)`). A batch advanced the search by as
856
+ * many rounds as lanes that progressed; summing positive deltas counts each
857
+ * advancing lane once and ignores any lane that did not move forward.
858
+ * - `reviewHistory`: SUFFIX-append only — each lane's entries BEYOND the shared
859
+ * parent baseline are appended. Lanes start from the same parent
860
+ * reviewHistory, so a naive concat would replay the baseline N times; taking
861
+ * only the suffix past `parentContext.reviewHistory.length` avoids that N×
862
+ * duplication while still capturing every lane's new review notes.
863
+ * - `humanPrompt`: NULLED. A human prompt is a single-turn directive consumed
864
+ * by one state entry; it has no meaning fanned across N lanes and must not
865
+ * survive the batch (a stale prompt would mis-route the next orchestrator
866
+ * turn).
867
+ * - `totalTokens`: read from the instance-level accumulator (the aggregate over
868
+ * all lanes' registered MITM sessionIds), NOT summed from the children here —
869
+ * the accumulator is the budget-authoritative figure and already includes
870
+ * every lane's spend.
871
+ * - `artifacts` / `previousOutputHashes` / `agentConversationsByState`: shallow
872
+ * last-writer-wins merge over the parent baseline (lanes write disjoint,
873
+ * lane-scoped keys, so collisions are not expected; the parent baseline is
874
+ * the floor). The remaining scalar fields come from `last` (the
875
+ * highest-index lane), an arbitrary-but-deterministic representative.
876
+ */
877
+ private mergeRecordedFanOutContext;
878
+ private withoutLaneContext;
879
+ private logFanOutJoin;
880
+ /**
881
+ * Measures effective lane diversity for one recorded batch by content-hashing
882
+ * each lane's candidate source and counting byte-identical collisions.
883
+ *
884
+ * WHY content-hash at fan-in (not assume effective-N = N): distinct sampled
885
+ * parents do NOT guarantee distinct candidates (§7.4). Convergent lanes — the
886
+ * researcher LLM collapsing two different parents into the same edit, or a
887
+ * degenerate sampler handing out overlapping parents — can produce
888
+ * byte-identical candidates, so "N lanes" can have an effective diversity
889
+ * below N. Hashing the recorded `steps/<step>/code` files surfaces that as an
890
+ * observable duplicate rate instead of pretending every lane added a distinct
891
+ * candidate; the operator reads it as a signal to tune the diversity knobs.
892
+ * It is a diagnostic, NOT a gate — duplicates are still recorded as distinct
893
+ * nodes (the engine assigns each its own id, §7.6).
894
+ *
895
+ * Every skip is best-effort, NOT an error: a missing step_name, a candidate
896
+ * file that does not exist yet, or a non-recorded lane is simply omitted from
897
+ * the sample rather than failing the join — a diagnostic must never block a
898
+ * batch that otherwise recorded cleanly. The `undefined` return is the
899
+ * "nothing measurable" contract: when no lane yielded a hashable candidate
900
+ * (every lane skipped), there is no diversity to report and the caller logs no
901
+ * duplicate stats at all (distinct from a measured `duplicateRate: 0`).
902
+ */
903
+ private computeFanOutCandidateDuplicateStats;
904
+ /**
905
+ * The single terminal error channel from {@link runFanOutSegment} to the
906
+ * parent: a `result_file_error` verdict carrying `message`, which the parent
907
+ * `workers` state routes to its `failed` edge.
908
+ */
909
+ private fanOutErrorResult;
417
910
  private executeDeterministicState;
911
+ private applyResultFile;
912
+ /**
913
+ * Shared reduction for both deterministic execution paths: skip empty command
914
+ * arrays, mine the `N tests pass` heuristic from stdout, accumulate per-command
915
+ * failures, and shape the `{ passed, testCount, errors }` result. Host vs.
916
+ * container execution differ only in `runCommand` — keep that the only fork so
917
+ * the pass/fail and test-count semantics cannot drift between the two paths.
918
+ */
919
+ private reduceDeterministicCommands;
920
+ private runDeterministicHost;
921
+ private runDeterministicInContainer;
418
922
  private handleGateEntry;
419
923
  private buildGateRequest;
420
924
  private handleWorkflowComplete;