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