swarm-orchestrator 13.1.9 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/CHANGELOG.md +317 -0
  2. package/README.md +317 -27
  3. package/dist/adapters/external-agent.js +141 -0
  4. package/dist/adapters/external-agent.js.map +1 -0
  5. package/dist/agent-run.js +388 -22
  6. package/dist/agent-run.js.map +1 -1
  7. package/dist/build-version.js +9 -0
  8. package/dist/build-version.js.map +1 -0
  9. package/dist/cli-local-backend.js +23 -0
  10. package/dist/cli-local-backend.js.map +1 -0
  11. package/dist/cli-options.js +161 -43
  12. package/dist/cli-options.js.map +1 -1
  13. package/dist/cli-run-commands.js +142 -0
  14. package/dist/cli-run-commands.js.map +1 -0
  15. package/dist/cli-select.js +109 -0
  16. package/dist/cli-select.js.map +1 -0
  17. package/dist/cli.js +681 -93
  18. package/dist/cli.js.map +1 -1
  19. package/dist/config/init.js +105 -0
  20. package/dist/config/init.js.map +1 -0
  21. package/dist/config/settings.js +28 -7
  22. package/dist/config/settings.js.map +1 -1
  23. package/dist/config/swarm-toml.js +64 -15
  24. package/dist/config/swarm-toml.js.map +1 -1
  25. package/dist/core/compaction.js +64 -0
  26. package/dist/core/compaction.js.map +1 -0
  27. package/dist/core/loop.js +122 -24
  28. package/dist/core/loop.js.map +1 -1
  29. package/dist/core/model-client.js +23 -3
  30. package/dist/core/model-client.js.map +1 -1
  31. package/dist/core/termination.js.map +1 -1
  32. package/dist/durable/run-store.js +215 -0
  33. package/dist/durable/run-store.js.map +1 -0
  34. package/dist/edit-distance.js +39 -0
  35. package/dist/edit-distance.js.map +1 -0
  36. package/dist/eval/arms.js +93 -0
  37. package/dist/eval/arms.js.map +1 -0
  38. package/dist/eval/campaign-run.js +269 -0
  39. package/dist/eval/campaign-run.js.map +1 -0
  40. package/dist/eval/oracle-filter.js +31 -0
  41. package/dist/eval/oracle-filter.js.map +1 -0
  42. package/dist/eval/statistics.js +102 -0
  43. package/dist/eval/statistics.js.map +1 -0
  44. package/dist/eval/test-case-split.js +89 -0
  45. package/dist/eval/test-case-split.js.map +1 -0
  46. package/dist/evidence/attestation.js +111 -0
  47. package/dist/evidence/attestation.js.map +1 -0
  48. package/dist/evidence/blob-manifest.js +170 -0
  49. package/dist/evidence/blob-manifest.js.map +1 -0
  50. package/dist/evidence/blob-restore.js +100 -0
  51. package/dist/evidence/blob-restore.js.map +1 -0
  52. package/dist/evidence/blob-store.js +8 -3
  53. package/dist/evidence/blob-store.js.map +1 -1
  54. package/dist/evidence/bundle-manifest.js +17 -2
  55. package/dist/evidence/bundle-manifest.js.map +1 -1
  56. package/dist/evidence/bundle.js +23 -8
  57. package/dist/evidence/bundle.js.map +1 -1
  58. package/dist/evidence/dag.js +12 -3
  59. package/dist/evidence/dag.js.map +1 -1
  60. package/dist/evidence/fixtures/empty-assistant-turns.js +13 -0
  61. package/dist/evidence/fixtures/empty-assistant-turns.js.map +1 -0
  62. package/dist/evidence/ledger-record.js +12 -1
  63. package/dist/evidence/ledger-record.js.map +1 -1
  64. package/dist/evidence/ledger.js +4 -3
  65. package/dist/evidence/ledger.js.map +1 -1
  66. package/dist/evidence/model-call-recording.js +20 -1
  67. package/dist/evidence/model-call-recording.js.map +1 -1
  68. package/dist/evidence/predicate-catalogue.js +507 -0
  69. package/dist/evidence/predicate-catalogue.js.map +1 -0
  70. package/dist/evidence/record-kind.js +1 -0
  71. package/dist/evidence/record-kind.js.map +1 -1
  72. package/dist/evidence/retention.js +93 -0
  73. package/dist/evidence/retention.js.map +1 -0
  74. package/dist/evidence/review-page.js +160 -23
  75. package/dist/evidence/review-page.js.map +1 -1
  76. package/dist/evidence/run-spec.js +117 -0
  77. package/dist/evidence/run-spec.js.map +1 -0
  78. package/dist/evidence/signer-trust.js +60 -0
  79. package/dist/evidence/signer-trust.js.map +1 -0
  80. package/dist/evidence/signing.js +7 -2
  81. package/dist/evidence/signing.js.map +1 -1
  82. package/dist/evidence/store-mode.js +17 -0
  83. package/dist/evidence/store-mode.js.map +1 -0
  84. package/dist/evidence/turn-content.js +32 -0
  85. package/dist/evidence/turn-content.js.map +1 -0
  86. package/dist/evidence/verdict.js +111 -0
  87. package/dist/evidence/verdict.js.map +1 -0
  88. package/dist/evidence/verifier/rederive.d.mts +21 -0
  89. package/dist/evidence/verifier/rederive.mjs +331 -0
  90. package/dist/evidence/verifier/verify.d.mts +18 -0
  91. package/dist/evidence/verifier/verify.mjs +191 -4
  92. package/dist/evidence/verify-report.js +87 -0
  93. package/dist/evidence/verify-report.js.map +1 -0
  94. package/dist/exec/child-environment.js +120 -0
  95. package/dist/exec/child-environment.js.map +1 -0
  96. package/dist/exec/container-backend.js +58 -0
  97. package/dist/exec/container-backend.js.map +1 -0
  98. package/dist/exec/execution-envelope-record.js +31 -0
  99. package/dist/exec/execution-envelope-record.js.map +1 -0
  100. package/dist/exec/execution-mode.js +164 -0
  101. package/dist/exec/execution-mode.js.map +1 -0
  102. package/dist/exec/isolation-option.js +38 -0
  103. package/dist/exec/isolation-option.js.map +1 -0
  104. package/dist/exec/run-cancellation.js +33 -0
  105. package/dist/exec/run-cancellation.js.map +1 -0
  106. package/dist/exec/run-envelope.js +48 -0
  107. package/dist/exec/run-envelope.js.map +1 -0
  108. package/dist/exec/run-process.js +108 -0
  109. package/dist/exec/run-process.js.map +1 -0
  110. package/dist/gates/approval.js +59 -0
  111. package/dist/gates/approval.js.map +1 -0
  112. package/dist/gates/auto-resolve.js +60 -12
  113. package/dist/gates/auto-resolve.js.map +1 -1
  114. package/dist/gates/base-control.js +23 -39
  115. package/dist/gates/base-control.js.map +1 -1
  116. package/dist/gates/behaviour-probe.js +178 -0
  117. package/dist/gates/behaviour-probe.js.map +1 -0
  118. package/dist/gates/bond-runner.js +169 -0
  119. package/dist/gates/bond-runner.js.map +1 -0
  120. package/dist/gates/bonds.js +133 -0
  121. package/dist/gates/bonds.js.map +1 -0
  122. package/dist/gates/default-gates.js +115 -26
  123. package/dist/gates/default-gates.js.map +1 -1
  124. package/dist/gates/engine.js +110 -20
  125. package/dist/gates/engine.js.map +1 -1
  126. package/dist/gates/escalation.js +9 -0
  127. package/dist/gates/escalation.js.map +1 -1
  128. package/dist/gates/failure-signature.js +9 -0
  129. package/dist/gates/failure-signature.js.map +1 -0
  130. package/dist/gates/file-set.js +22 -0
  131. package/dist/gates/file-set.js.map +1 -1
  132. package/dist/gates/gate-capability.js +37 -0
  133. package/dist/gates/gate-capability.js.map +1 -0
  134. package/dist/gates/gate-definition.js.map +1 -1
  135. package/dist/gates/gate-runner.js +133 -19
  136. package/dist/gates/gate-runner.js.map +1 -1
  137. package/dist/gates/gate-set-seal.js +63 -0
  138. package/dist/gates/gate-set-seal.js.map +1 -0
  139. package/dist/gates/git-workspace.js +53 -4
  140. package/dist/gates/git-workspace.js.map +1 -1
  141. package/dist/gates/harness-reporting.js +67 -0
  142. package/dist/gates/harness-reporting.js.map +1 -0
  143. package/dist/gates/independent-verification.js +244 -0
  144. package/dist/gates/independent-verification.js.map +1 -0
  145. package/dist/gates/inherited-changes.js +26 -0
  146. package/dist/gates/inherited-changes.js.map +1 -0
  147. package/dist/gates/inspection-gates.js +140 -2
  148. package/dist/gates/inspection-gates.js.map +1 -1
  149. package/dist/gates/measure-snapshot.js +28 -3
  150. package/dist/gates/measure-snapshot.js.map +1 -1
  151. package/dist/gates/measures.js +78 -4
  152. package/dist/gates/measures.js.map +1 -1
  153. package/dist/gates/node-command-runner.js +57 -32
  154. package/dist/gates/node-command-runner.js.map +1 -1
  155. package/dist/gates/node-test-command.js +0 -34
  156. package/dist/gates/node-test-command.js.map +1 -1
  157. package/dist/gates/parsers.js +69 -2
  158. package/dist/gates/parsers.js.map +1 -1
  159. package/dist/gates/patch-paths.js +25 -0
  160. package/dist/gates/patch-paths.js.map +1 -0
  161. package/dist/gates/value-flow.js +335 -0
  162. package/dist/gates/value-flow.js.map +1 -0
  163. package/dist/install/health.js +1 -1
  164. package/dist/install/health.js.map +1 -1
  165. package/dist/machine-output.js +44 -0
  166. package/dist/machine-output.js.map +1 -0
  167. package/dist/node-floor.js +21 -0
  168. package/dist/node-floor.js.map +1 -0
  169. package/dist/providers/ai-sdk-model-client.js +85 -46
  170. package/dist/providers/ai-sdk-model-client.js.map +1 -1
  171. package/dist/providers/fixture-provider.js +18 -1
  172. package/dist/providers/fixture-provider.js.map +1 -1
  173. package/dist/providers/local-fetch.js +28 -0
  174. package/dist/providers/local-fetch.js.map +1 -0
  175. package/dist/providers/registry.js +48 -2
  176. package/dist/providers/registry.js.map +1 -1
  177. package/dist/providers/transport-trace-file.js +24 -0
  178. package/dist/providers/transport-trace-file.js.map +1 -0
  179. package/dist/providers/transport-trace.js +148 -0
  180. package/dist/providers/transport-trace.js.map +1 -0
  181. package/dist/select/calibrate.js +3 -0
  182. package/dist/select/calibrate.js.map +1 -1
  183. package/dist/select/calibration-measures.js +26 -0
  184. package/dist/select/calibration-measures.js.map +1 -1
  185. package/dist/select/calibration-report.js +15 -2
  186. package/dist/select/calibration-report.js.map +1 -1
  187. package/dist/select/calibration-run.js +61 -15
  188. package/dist/select/calibration-run.js.map +1 -1
  189. package/dist/select/calibration-summary.js +15 -3
  190. package/dist/select/calibration-summary.js.map +1 -1
  191. package/dist/select/competency-table.js +164 -0
  192. package/dist/select/competency-table.js.map +1 -0
  193. package/dist/select/reward.js +11 -0
  194. package/dist/select/reward.js.map +1 -1
  195. package/dist/select/routing-log.js +2 -2
  196. package/dist/select/routing-log.js.map +1 -1
  197. package/dist/select/routing-mode.js +73 -0
  198. package/dist/select/routing-mode.js.map +1 -0
  199. package/dist/select/routing-record.js +16 -0
  200. package/dist/select/routing-record.js.map +1 -1
  201. package/dist/select/servable-candidates.js +30 -0
  202. package/dist/select/servable-candidates.js.map +1 -0
  203. package/dist/select/task-class.js +8 -0
  204. package/dist/select/task-class.js.map +1 -1
  205. package/dist/select/ucb.js +21 -5
  206. package/dist/select/ucb.js.map +1 -1
  207. package/dist/telemetry/otel.js +130 -0
  208. package/dist/telemetry/otel.js.map +1 -0
  209. package/dist/tools/chokepoint-record.js +8 -7
  210. package/dist/tools/chokepoint-record.js.map +1 -1
  211. package/dist/tools/chokepoint.js +4 -4
  212. package/dist/tools/chokepoint.js.map +1 -1
  213. package/dist/tools/derivation.js +44 -4
  214. package/dist/tools/derivation.js.map +1 -1
  215. package/dist/tools/file-tools.js +26 -10
  216. package/dist/tools/file-tools.js.map +1 -1
  217. package/dist/tools/policy-guard.js +165 -0
  218. package/dist/tools/policy-guard.js.map +1 -0
  219. package/dist/tools/search-tool.js +16 -9
  220. package/dist/tools/search-tool.js.map +1 -1
  221. package/dist/tools/shell-canonical.js +104 -0
  222. package/dist/tools/shell-canonical.js.map +1 -0
  223. package/dist/tools/shell-command.js +154 -0
  224. package/dist/tools/shell-command.js.map +1 -0
  225. package/dist/tools/shell-tool.js +22 -17
  226. package/dist/tools/shell-tool.js.map +1 -1
  227. package/dist/tools/tool-argument-decoding.js +3 -0
  228. package/dist/tools/tool-argument-decoding.js.map +1 -1
  229. package/dist/tools/workspace-path.js +4 -4
  230. package/dist/tools/workspace-path.js.map +1 -1
  231. package/dist/tools/workspace-tools.js +13 -9
  232. package/dist/tools/workspace-tools.js.map +1 -1
  233. package/dist/tui/calibrate-interface.js +59 -0
  234. package/dist/tui/calibrate-interface.js.map +1 -0
  235. package/dist/tui/calibrate-screen-model.js +118 -0
  236. package/dist/tui/calibrate-screen-model.js.map +1 -0
  237. package/dist/tui/calibrate-screen.js +44 -0
  238. package/dist/tui/calibrate-screen.js.map +1 -0
  239. package/dist/tui/calibrate-store.js +22 -0
  240. package/dist/tui/calibrate-store.js.map +1 -0
  241. package/dist/tui/calibrate-view.js +92 -0
  242. package/dist/tui/calibrate-view.js.map +1 -0
  243. package/dist/tui/confirmation-queue.js +31 -18
  244. package/dist/tui/confirmation-queue.js.map +1 -1
  245. package/dist/tui/plain-lines.js +9 -0
  246. package/dist/tui/plain-lines.js.map +1 -1
  247. package/dist/tui/render-timings.js +22 -0
  248. package/dist/tui/render-timings.js.map +1 -0
  249. package/dist/tui/screen-model.js +35 -6
  250. package/dist/tui/screen-model.js.map +1 -1
  251. package/dist/tui/screen.js +1 -0
  252. package/dist/tui/screen.js.map +1 -1
  253. package/dist/tui/session-interface.js +14 -1
  254. package/dist/tui/session-interface.js.map +1 -1
  255. package/dist/tui/session-view.js +19 -0
  256. package/dist/tui/session-view.js.map +1 -1
  257. package/dist/tui/verify-bundle.js +2 -2
  258. package/dist/tui/verify-bundle.js.map +1 -1
  259. package/dist/tui/view-state.js +10 -2
  260. package/dist/tui/view-state.js.map +1 -1
  261. package/dist/workers/attempt-selector.js +126 -0
  262. package/dist/workers/attempt-selector.js.map +1 -0
  263. package/dist/workers/attempt-universe.js +50 -0
  264. package/dist/workers/attempt-universe.js.map +1 -0
  265. package/dist/workers/fan-out.js +35 -0
  266. package/dist/workers/fan-out.js.map +1 -0
  267. package/dist/workers/graph-record.js +109 -0
  268. package/dist/workers/graph-record.js.map +1 -0
  269. package/dist/workers/graph-tool.js +65 -0
  270. package/dist/workers/graph-tool.js.map +1 -0
  271. package/dist/workers/merge-queue.js +66 -31
  272. package/dist/workers/merge-queue.js.map +1 -1
  273. package/dist/workers/parallel-report.js +27 -0
  274. package/dist/workers/parallel-report.js.map +1 -1
  275. package/dist/workers/parallel-run.js +274 -25
  276. package/dist/workers/parallel-run.js.map +1 -1
  277. package/dist/workers/planner-run.js +80 -0
  278. package/dist/workers/planner-run.js.map +1 -0
  279. package/dist/workers/pool.js +52 -0
  280. package/dist/workers/pool.js.map +1 -0
  281. package/dist/workers/schedule.js +64 -0
  282. package/dist/workers/schedule.js.map +1 -0
  283. package/dist/workers/selection-record.js +61 -0
  284. package/dist/workers/selection-record.js.map +1 -0
  285. package/dist/workers/task-contract.js +117 -0
  286. package/dist/workers/task-contract.js.map +1 -0
  287. package/dist/workers/task-graph.js +156 -0
  288. package/dist/workers/task-graph.js.map +1 -0
  289. package/dist/workers/trail-tool.js +27 -0
  290. package/dist/workers/trail-tool.js.map +1 -0
  291. package/dist/workers/trail.js +175 -0
  292. package/dist/workers/trail.js.map +1 -0
  293. package/dist/workers/worktree.js +30 -0
  294. package/dist/workers/worktree.js.map +1 -1
  295. package/docs/README.md +49 -0
  296. package/docs/build-guide.md +25 -11
  297. package/docs/claims.md +23 -2
  298. package/docs/security-coverage.md +58 -0
  299. package/package.json +5 -1
  300. package/dist/gates/coverage-artifact.js +0 -55
  301. package/dist/gates/coverage-artifact.js.map +0 -1
  302. package/dist/tools/sandbox.js +0 -108
  303. package/dist/tools/sandbox.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,322 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 14.0.1 - 2026-09-07
6
+
7
+ ### Fixed
8
+
9
+ - **`swarm ci` no longer charges a patch for a failure the base already had.** Dependencies are
10
+ installed with `--ignore-scripts`, because install scripts run whatever the registry serves, so
11
+ a project that builds on `prepare` was verified without its build output and the tests that
12
+ import it failed. koa routes `import 'koa'` to `./dist/koa.mjs`: 437 passed and 2 failed without
13
+ the build, 439 and 0 with it, and the two were reported as a regression the patch caused. A
14
+ failing check is now re-run with the patch reverted on the same checkout, and one that fails
15
+ both ways is recorded as inherited rather than as a regression, with the build-on-install cause
16
+ named in the advice. A clean run pays nothing for this, since the base is measured only to
17
+ explain a failure.
18
+
19
+ ### Added
20
+
21
+ - **Tasks with two oracles, mined from merged pull requests.** `scripts/mine-pr-tasks.mjs`,
22
+ `scripts/check-pr-task-viability.mjs` and `scripts/pr-task-pass.mjs`: a merged pull request
23
+ supplies a base commit, a task, and a specification its own maintainers wrote, whose cases are
24
+ dealt alternately into a sealed oracle and a held-back one. A candidate is kept only where its
25
+ tests provably fail on the base source and pass on the merged tree, so nothing is labelled by
26
+ hand. False-green rate now 0 of 15 across two corpora, 95% CI [0.0, 20.4].
27
+
28
+ ## 14.0.0 - 2026-09-06
29
+
30
+ ### Breaking
31
+
32
+ - **`swarm ci` no longer reports a patch verified because the project's suite passed.** A suite
33
+ says nothing broke; it does not say the task was done, because it tests the behaviour the
34
+ project already had and a task adds behaviour it did not. `verified` now requires both a
35
+ passing suite and a task oracle that accepts, so a run without `--oracle <command>` exits
36
+ non-zero with `task: unjudged` and the reason printed. Anything scripted against `swarm ci`
37
+ exiting 0 needs an oracle passed to it. This is the fix for a measured 22.2% false-green rate,
38
+ not a tightening for its own sake.
39
+ - **The major version moves because of that one change.** Everything else below is additive.
40
+
41
+ ### Added
42
+
43
+ - **`swarm ci` reports whether anything broke and whether the task was done, separately.**
44
+ `regression` says the project's own suite still passes; `task` says a trusted oracle agrees the
45
+ work was done, and reads `unjudged` where none was given. `verified` requires both, so a run
46
+ with no oracle is unverified with the reason printed rather than verified by omission. This
47
+ closed a real 22.2% false-green rate: a repository's suite tests the behaviour the project
48
+ already had, and a task adds behaviour it did not, so a patch that adds a feature badly still
49
+ passes it.
50
+ - **`--oracle <command>` supplies that task check.** Nothing infers one. It runs in the fresh
51
+ checkout after the suite, whether or not the suite passed, so its verdict is readable either
52
+ way.
53
+ - **`--install` installs the fresh checkout's dependencies from its lockfile**, with install
54
+ scripts off. Off by default, because installing runs whatever the registry serves. Without it a
55
+ real project has no test runner in a fresh clone, every check stands down, and the honest
56
+ answer is that nothing was measured rather than that nothing passed. Reporting the second was a
57
+ defect, and it is why this exists.
58
+ - **`--isolation <runtime[:image]>` runs commands behind a kernel-enforced boundary**, on docker,
59
+ podman or nerdctl, with no network, a read-only root, a tmpfs, dropped capabilities, no new
60
+ privileges, and memory and pid ceilings.
61
+ - **A run measures what it actually executes under, before the first tool call.** The containment
62
+ self-test runs the escapes rather than reasoning about them: read a host file outside the
63
+ workspace, write outside it, open a socket. Whatever gets through is named in an
64
+ `execution-envelope` record and printed. With no kernel-enforced backend the answer is
65
+ `restricted`, and that is the word used. A backend that refused every escape and could not
66
+ reach its own workspace is `unknown` rather than `isolated`, since a command that sees nothing
67
+ is contained and cannot work.
68
+ - **A bundle carries a DSSE envelope over an in-toto statement**, signed over the
69
+ pre-authentication encoding rather than the payload bytes, so what a run produced can be checked
70
+ by tooling that never heard of this project.
71
+ - **Durable run state, and the commands to work with it.** `swarm list-runs`, `swarm inspect
72
+ <run-id>`, `swarm resume`, `swarm retry-step`, `swarm abort` and `swarm repair`, over a
73
+ `node:sqlite` store in WAL mode with intent recorded before effect and an idempotency key per
74
+ step, so an interrupted run is taken up rather than started again and a dead run's leases are
75
+ released rather than held forever.
76
+ - **`swarm gc [--older-than 30d] [--remove]`** says what stored evidence would be removed before
77
+ removing any of it.
78
+ - **`--json` on a run and on `swarm ci` and `swarm inspect`**: line-delimited JSON, one line per
79
+ event and one result at the end, each naming its schema.
80
+ - **`confirm_timeout_minutes` under `[interface]`**, so a confirmation nobody answers is refused
81
+ after thirty minutes rather than holding a run open indefinitely.
82
+ - **The false-green rate is measured against an oracle the tool is never given.** Each
83
+ real-repository task carries two: one sealed before the runs and handed to the tool, one written
84
+ from the task text and held back from it. 0 of 11, 95% CI [0.0, 25.9], counting the eleven
85
+ patches the tool certified. `node scripts/second-oracle-pass.mjs` reproduces it from recorded
86
+ diffs with no model calls. A single-oracle version of this number was published and withdrawn:
87
+ the same test on both sides of a comparison agrees with itself.
88
+ - **`scripts/restore-bundle-blobs.mjs` puts offloaded artifacts back**, writing a file only where
89
+ its content hashes to the digest the bundle names.
90
+
91
+ - **A run has a wall budget of its own.** `--max-wall-minutes <n>`, or `max_wall_minutes`
92
+ under `[budgets]` in swarm.toml, bounds the whole run: the first loop and every auto-resolve
93
+ attempt draw from it, the attempts stop when it is spent, and the run goes on to its final
94
+ gates and its bundle with the budget recorded on the chain as a `session-budget` record.
95
+ Before this each loop had its own half hour and the run as a whole had no bound, which is how
96
+ a run measured inside a forty-five minute container could outlast it and leave nothing: the
97
+ campaign's first arm lost seven runs that way. Unset, nothing changes: each loop keeps its
98
+ half hour.
99
+ - **The criteria a run is measured by are sealed on the chain before the model is asked for
100
+ anything.** Every gate with its severity and the rule that reads it, the budgets, the attempt
101
+ cap and the ratchet arms, as one record written before the loop, and the embedded verifier
102
+ holds every gate run to it: a gate the seal does not name, a severity or rule it did not
103
+ declare, or a sealed gate missing from the final attempt fails verification. A bundle of the
104
+ new format that carries gate runs and no seal is refused, since that is the one way to dodge
105
+ the check; a bundle that ran no gates has nothing to be held to.
106
+ - **Every passing gate is bonded.** After the fixed point, each gate that passed is handed one
107
+ added file it has to refuse, a failing test, a TODO, a credential-shaped token, a file outside
108
+ the declared set, a change over the budget, and the result is a `gate-bond` record carrying
109
+ the observation. A check that refused it held. A check that passed over a bond it demonstrably
110
+ saw is vacuous, which makes a blocking gate's run not green whatever the cycle said, and the
111
+ exit code says so. A command that passed where nothing shows it read the bond is unshown,
112
+ named as such and never promoted to held. A gate with no bond is recorded as not bonded. The
113
+ review page carries the bond beside every gate and paints a vacuous pass red.
114
+ - **A bundle carries `rederive.mjs` beside `verify.mjs`.** Where the verifier asks whether a
115
+ bundle is what it says it is, the re-deriver asks whether a third party applying this tool's
116
+ rules would reach the verdicts it records: every gate status from the recorded exit code and
117
+ output under the rule the record now names, every ratchet decision from its recorded
118
+ measures, every bond from its observation, every claim from its predicate, and the gate runs
119
+ from the seal. What it cannot re-derive from the bundle alone, it names rather than agrees
120
+ with. Dependency-free, like the verifier, and parity-tested against the parsers it mirrors.
121
+ - **Routing by a competency table, class by class, and never by interpolation.** `swarm
122
+ calibrate` now writes, beside its pick, what each model was measured to do on each class of
123
+ task: executed repeats and the ones whose gate passed, per sweep, read off the sweep's own
124
+ `calibration-run` records and folded across sweeps of the same golden set. A task's router
125
+ asks the table for its class before the reward log has enough samples to say anything, and
126
+ where a candidate has at least six executed runs on that class the best gate share stands
127
+ as the default, recorded as a `competency` assignment with the counts it was chosen on. Where
128
+ no candidate clears the floor, or none has an entry for the class at all, the table abstains
129
+ by name and the calibration pick stands as before; a model's showing on one class is never
130
+ read as evidence about another.
131
+ - **A fifty-repository campaign harness, with its criteria sealed before anything was
132
+ selected.** `campaign/criteria.md` was committed before the first GitHub query, the method in
133
+ `campaign/methodology.md` before the first run, and `campaign/harness/` sequences the rest:
134
+ the search saved raw, the candidate walk judged by rules that name the first one failed, one
135
+ seeded defect per repository accepted only where the repository's own suite passes before and
136
+ fails after, and one run per arm inside a pinned container on an internal network whose only
137
+ other member is a forwarder to the model backend. Results are read off the bundle and the
138
+ tree, never off the run's exit code.
139
+ - **The campaign was run: two local arms over fifty repositories, one hundred runs, ninety-three
140
+ bundles that verify.** Fifty seeds in five languages, each a repository whose own suite passed
141
+ before the seeded line and failed after it, run once per arm under a forty-five minute
142
+ budget. On qwen3.8:27b over rapid-mlx, forty-three runs executed and every bundle verifies,
143
+ twenty-six of them fixing the seed; seven ran out of budget without a bundle. On
144
+ qwen3.6:35b-a3b over Ollama, all fifty executed and verify, thirty-nine fixing the seed, at a
145
+ median of nine minutes against sixteen. The frontier arm was not run, because the key it
146
+ needs has no balance, and the report carries it with zero runs rather than leaving it out.
147
+ `campaign/results/report.md` is generated from the result records alone, the bundles are
148
+ under `campaign/corpus/`, and the method with its dated amendments is in
149
+ `campaign/methodology.md`. The campaign measured the CLI packed on 2026-09-02 and stayed on
150
+ it while two defects it exposed were fixed in the tree: a shell allowlist that refused every
151
+ toolchain but node's, and a model call with no deadline.
152
+ - **Two scheduled proofs on GitHub Actions.** A nightly one runs the suite and the fuzz smoke
153
+ from a clean clone, then verifies the committed reference bundle with its own verifier and
154
+ refuses a one-byte copy of it, uploading the transcript. A weekly one installs a pinned
155
+ Ollama on the runner, seeds a workspace whose test fails on a real defect, runs one task
156
+ through the built CLI, and verifies the fresh bundle in the same job; the task outcome is
157
+ recorded and never judged. Neither continues on error, and a scheduled failure of either
158
+ opens an issue with the run link.
159
+
160
+ - **A debug copy of what a local backend was actually sent and actually said.**
161
+ `SWARM_TRANSPORT_TRACE=<path>` writes the raw request body and every raw response frame of
162
+ every local call to a JSONL artifact, before anything parses them. Off with no path, which is
163
+ the default: the artifact holds whole prompts and whole completions unscrubbed, so it is not
164
+ the ledger and not a thing to leave running. It exists for one question the assembled response
165
+ cannot answer, which is whether a turn that arrived empty was empty on the wire, dropped
166
+ during stream assembly, or genuinely empty from the model. The response body is teed rather
167
+ than buffered, so streaming timing is unchanged and the first-token measurement stays real.
168
+ - **A screen for `swarm calibrate`.** A three-model sweep is 180 runs over roughly three hours,
169
+ the longest thing this tool does, and it wrote plain progress lines and nothing else. It has a
170
+ view of its own now, because a sweep has none of the things the run screen is built around: it
171
+ has a grid. Runs finished out of runs planned, the run in flight, a row per model in plan
172
+ order with green counted over executed runs rather than attempted ones, abstentions named by
173
+ the reason code the harness recorded, and the last few outcomes. No estimate of time
174
+ remaining, which would be a prediction people plan around, and no keys, because a sweep has
175
+ nothing to scroll. Off a terminal it writes one line per finished run in the same words, so
176
+ the log and the screen stay one account of the run.
177
+ - **An index over the evidence column of the review page.** Records are grouped by turn and
178
+ folded by default, the per-record digest moved into the expanded payload where the reviewer
179
+ resolving a claim through it is already looking, and the column opens with how many records
180
+ there are, how many of each type, a button per type and a search box. The 08-23 calibration
181
+ bundle is 3,716 records; before this there was no way to find anything in it. A rendering
182
+ change and nothing else: no record changed, and four existing bundles verify unaltered.
183
+ - **A behaviour probe over changed functions.** A function that answered several ways at the
184
+ base commit and answers one way now is reported by a blocking gate. Reading the text will
185
+ never tell a stub from a correct constant, and running it does not have to: the comparison is
186
+ between two measured variances rather than a judgement about what a function is for. Quiet on
187
+ a function that was always constant, one that takes no arguments, and one that now refuses
188
+ every input, which is a tighter signature rather than a missing body.
189
+
190
+ - **Workers that read what the others have already tried.** They ran side by side and saw
191
+ nothing of each other, so two could declare the same file and one could spend its whole
192
+ attempt cap on a gate that had already refused the same fix on the chain next door. They
193
+ coordinate now through the thing they were already writing: a `read_trail` tool projects
194
+ typed signals off the peers' ledgers, which files are claimed, which gates failed and how
195
+ often, which attempts the ratchet rejected, which approaches are spent. No daemon, no bus,
196
+ nothing anyone writes through, and no read of a chain but the peers' own. Nothing it returns
197
+ can render green: every signal comes from a record rather than from model text, every line
198
+ names the peer it is about, and no signal kind reports a success. A run that is not parallel
199
+ is offered none of it and sends the same tools and the same prompt, byte for byte.
200
+ - **`--redundancy <n>`: try each task several ways and land the best of them.** Attempts
201
+ diverge because each carries a seed derived from the task, the model and the attempt number,
202
+ so a report can re-derive them. The winner is chosen by a comparator over harness-measured
203
+ numbers with the precedence written down, never by asking a model which answer it likes: four
204
+ earn-it dimensions above every do-less one, a dimension nothing measured abstained on by
205
+ name, and a dimension only one side measured won by the side that measured it. Counting
206
+ happens over a file universe fixed across the attempts first, so opening a large test file
207
+ gains the opener nothing. The whole ranking goes on the chain, losers and their reasons
208
+ included. A refused winner falls to the next attempt only where the integrated gates were
209
+ what refused it.
210
+ - **`--goal <text>`: the tool breaks the goal into tasks itself.** A planner run reads the
211
+ workspace with read-only tools and declares a task graph, which is checked before anything
212
+ runs for unique ids, resolving dependencies, no cycle, and files that two unordered nodes
213
+ do not share. The graph is a ledger record written before the first worker starts. Nodes
214
+ land layer by layer, each layer branching from the tree the one before it left, and a node
215
+ whose parent did not land is recorded as blocked rather than run against a tree that lacks
216
+ it. `--tasks` also reads a JSON graph now, so a hand-written one and a declared one are the
217
+ same artifact. The claim says every declared node ran and landed and says nothing about
218
+ whether they satisfy the goal, which this tool does not check and says so.
219
+ - **`--concurrency <n>`,** capping how many workers hold a worktree at once. It defaults to
220
+ one against a local model server, because every worker in the run is asking one resident
221
+ model for tokens, so the parallelism buys nothing and costs the memory the model lives in.
222
+ Against a model served elsewhere it defaults to four and deliberately does not grow with the
223
+ hardware: what the machine is being asked for is N copies of the project's test suite, and a
224
+ bigger machine does not make those cheaper. The fan-out was unbounded before this, at any
225
+ redundancy.
226
+
227
+ ### Changed
228
+
229
+ - **Bundle format 2.** A format 2 bundle carries the sealed criteria, a bond per passing gate,
230
+ and the re-derivation script; every gate-run record names the rule that read it. Format 1
231
+ bundles are still read, replayed and verified, and the four committed ones verify unchanged
232
+ under the new verifier, which reports their lack of a seal as predating sealing rather than
233
+ as a defect.
234
+ - **The corpus replay reads the v12 falsification corpus from the `v12-final` tag.** It named
235
+ `main`, which held the v12 tree until `main` was moved onto this lineage; from then on the
236
+ three replay tests skipped under a green run, on CI and on any clone that had moved its
237
+ `main`. A tag is the one name that does not move, and the checkout test now pins that the
238
+ corpus was reached rather than allowing a skip.
239
+ - **The reports the ratchet reads come off streams the harness owns, not files.** The first fix
240
+ for the counter forgery below had the runner write reports to paths the harness named under
241
+ the session store. An adversarial pass took that apart: a destination is an argument of the
242
+ spawned process, so `ps -p $PPID -o command=` hands it to any test that asks, and the file is
243
+ writable by anything running as the same user, since the writer is the same uid. Getting the
244
+ harness to read a forgery did not work, because it reads as soon as the runner exits and won
245
+ that race every time; what did work, four times out of four, was destroying both measures, and
246
+ an abstention is not a violation. So there is no file: tap goes to stdout and lcov to stderr,
247
+ and under process isolation a test's own output is captured by the parent and folded into the
248
+ reporters' streams as escaped comments. The base-control result had the identical hole and
249
+ gets the identical fix.
250
+ - **The base a run is measured against is resolved to a commit before anything reads it.** HEAD
251
+ is a symbolic ref spent at the moment each base-side question is asked, and `git` is on the
252
+ default shell allowlist, so one unconfirmed tool call moved it. Measured on a scratch
253
+ repository with two of three tests deleted in the tree: after a `git commit -am` the base
254
+ declared 1 test instead of 3 and the change set held 0 files instead of 1, so the deletion the
255
+ ratchet exists to catch stopped being a deletion. The parallel path already resolved its base
256
+ before handing it to any worker; this is the single-run path held to the same thing.
257
+ - **The ratchet's collected and skipped test counts come from a report the runner wrote, not
258
+ from what it printed.** Node's default reporter passes a test's own `console.log("# tests
259
+ 999")` through ahead of its own counters and the counter reader took the first match, so four
260
+ print statements in one test file reported 999 collected for a suite of one. That number fed a
261
+ blocking arm. Where the harness can vouch for the invocation it now asks node for TAP at a
262
+ path of its own and counts result points there, which a test cannot print into existence.
263
+ Where it cannot vouch for the invocation both measures are null and the ratchet abstains on
264
+ them by name, which is stricter than the reading it replaces.
265
+ - **An empty assistant turn is recorded as an abstention rather than as a run of the model.**
266
+ The harness classifies every turn as it crosses into the ledger and stamps the verdict on the
267
+ record, so a repeat whose only turn arrived empty reports `abstained` with a machine-readable
268
+ reason instead of being scored against the model as a wrong answer. Two calibration bundles
269
+ had been scored with those folded in. Calibration now reads `executed` off the records rather
270
+ than off the loop's own counter, because a reviewer re-deriving that number has the records
271
+ and not the loop.
272
+ - **A seed is recorded with whether the backend took it.** Ollama and rapid-mlx both accept a
273
+ seed field and neither promises to sample from it, and the SDK reports a refused setting as a
274
+ warning. Those warnings now reach the record, so a seed in a bundle is never read as a seed
275
+ that made the run re-derivable.
276
+ - **The derivation heuristic reads a shell command as a command.** Its threshold is unchanged,
277
+ because lowering it flags ordinary commands that mention a filename someone read. What changed
278
+ is that where an argument parses as a shell command it is also compared as one, with flags
279
+ dropped and interpreters folded together, so inserting `-fsSL` and swapping `sh` for `bash`
280
+ no longer rewrites it past the match.
281
+ - **An assertion comparing a value with itself stops counting as an assertion.** The rule was a
282
+ literal against the identical literal; it now substitutes the file's own bindings first, so
283
+ `expect(v0.a).toBe(v0.a)` and the spelling that binds one side to a name are both seen. This
284
+ is arithmetic over expressions and not a judgement about meaning: deciding that two
285
+ *different* expressions mean the same thing is still refused.
286
+ - **The secret-scan gate reads a credential written in pieces.** Where a change rejoins them,
287
+ by concatenation or by a template literal, the gate rebuilds the value those lines make and
288
+ hands it to the detector that already decides about credentials, under the name the change
289
+ gave it. No second detector and no new threshold. Halves that are never rejoined build no
290
+ value and are still not caught, which build guide 7.1 says in those words.
291
+
292
+ ### Fixed
293
+
294
+ - **Every evidence bundle verifies from a clone again.** An earlier weight reduction moved record
295
+ payloads out of the tracked tree, which stopped 47 of 51 bundles passing their own verifier,
296
+ four of them cited in the README and `claims.md` in words like "verify.mjs exit 0". Payloads are
297
+ never offloaded now; only derived artifacts are, and those are regenerated from the records.
298
+ - **The README no longer cites a number the documents behind it withdrew**, and its gate tally is
299
+ counted from the table rather than from memory.
300
+
301
+ - **A parallel run now sweeps up the branches it created.** Worker branches outlive their
302
+ worktrees on purpose, because the merge queue merges from them after the working copy is
303
+ gone, and nothing outlived the queue: a repository gained a branch per worker per run, for
304
+ ever. The integration branch is never swept, since that is the result. It prunes worktrees
305
+ first, which is what stops a run killed part-way from making the next one fail on a path git
306
+ still believes in.
307
+ - **`--goal` says how the planner stopped, not just that it declared nothing.** Running out of
308
+ steps, answering in prose, and returning nothing at all want three different responses, and
309
+ the message treated them as one. It now names the stop reason and the step count and says
310
+ what to try for each.
311
+ - **Two review-page summaries that trailed off after the colon.** `worker-finished` and
312
+ `merge-attempt` both asked for a field neither writer emits, so they rendered as
313
+ `worker-1 finished:` with nothing after it. They read what is actually recorded now.
314
+ - **The weekly scan stopped filing the same 21 findings every Monday.** Data is excluded by
315
+ path, meaning the secret scrubber's own fuzz corpus and the captured shakedown logs and
316
+ nothing else; the nine findings in real source carry a suppression naming the one rule and the
317
+ reason, at the line that carries the finding. Under the workflow's own command it now reports
318
+ zero and exits 0, so the weekly issue means something arrived that nobody has looked at.
319
+
3
320
  ## 13.1.9
4
321
 
5
322
  ### Added