swarm-orchestrator 14.1.0 → 14.3.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 +750 -0
- package/README.md +97 -355
- package/dist/action/artifacts.js +72 -0
- package/dist/action/artifacts.js.map +1 -0
- package/dist/action/comment.js +139 -0
- package/dist/action/comment.js.map +1 -0
- package/dist/action/environment.js +106 -0
- package/dist/action/environment.js.map +1 -0
- package/dist/action/verdict.js +103 -0
- package/dist/action/verdict.js.map +1 -0
- package/dist/action/verify.js +424 -0
- package/dist/action/verify.js.map +1 -0
- package/dist/agent-escalation.js +74 -0
- package/dist/agent-escalation.js.map +1 -0
- package/dist/agent-prompt.js +3 -1
- package/dist/agent-prompt.js.map +1 -1
- package/dist/agent-run.js +68 -10
- package/dist/agent-run.js.map +1 -1
- package/dist/cli-action.js +117 -0
- package/dist/cli-action.js.map +1 -0
- package/dist/cli-bundle.js +0 -23
- package/dist/cli-bundle.js.map +1 -1
- package/dist/cli-calibrate.js +2 -1
- package/dist/cli-calibrate.js.map +1 -1
- package/dist/cli-check.js +341 -0
- package/dist/cli-check.js.map +1 -0
- package/dist/cli-ci.js +82 -34
- package/dist/cli-ci.js.map +1 -1
- package/dist/cli-command-definitions.js +49 -4
- package/dist/cli-command-definitions.js.map +1 -1
- package/dist/cli-evidence-summary.js +25 -0
- package/dist/cli-evidence-summary.js.map +1 -0
- package/dist/cli-gates.js +147 -0
- package/dist/cli-gates.js.map +1 -0
- package/dist/cli-init.js +114 -1
- package/dist/cli-init.js.map +1 -1
- package/dist/cli-integrations.js +145 -0
- package/dist/cli-integrations.js.map +1 -0
- package/dist/cli-model-default.js +107 -0
- package/dist/cli-model-default.js.map +1 -0
- package/dist/cli-options.js +95 -126
- package/dist/cli-options.js.map +1 -1
- package/dist/cli-parallel.js +9 -3
- package/dist/cli-parallel.js.map +1 -1
- package/dist/cli-preflight.js +33 -0
- package/dist/cli-preflight.js.map +1 -0
- package/dist/cli-provider-settings.js +21 -0
- package/dist/cli-provider-settings.js.map +1 -0
- package/dist/cli-run-settings.js +0 -15
- package/dist/cli-run-settings.js.map +1 -1
- package/dist/cli-select.js +10 -4
- package/dist/cli-select.js.map +1 -1
- package/dist/cli-session.js +48 -8
- package/dist/cli-session.js.map +1 -1
- package/dist/cli-strengthen.js +527 -0
- package/dist/cli-strengthen.js.map +1 -0
- package/dist/cli-task-contract.js +24 -0
- package/dist/cli-task-contract.js.map +1 -0
- package/dist/cli-task-goal.js +163 -0
- package/dist/cli-task-goal.js.map +1 -0
- package/dist/cli-terminal.js +5 -0
- package/dist/cli-terminal.js.map +1 -1
- package/dist/cli-verdict.js +144 -0
- package/dist/cli-verdict.js.map +1 -0
- package/dist/cli-verification-evidence.js +51 -0
- package/dist/cli-verification-evidence.js.map +1 -0
- package/dist/cli-verify-options.js +231 -0
- package/dist/cli-verify-options.js.map +1 -0
- package/dist/cli-verify.js +18 -0
- package/dist/cli-verify.js.map +1 -0
- package/dist/cli.js +247 -160
- package/dist/cli.js.map +1 -1
- package/dist/config/approval-mode.js +26 -0
- package/dist/config/approval-mode.js.map +1 -0
- package/dist/config/init.js +67 -5
- package/dist/config/init.js.map +1 -1
- package/dist/config/interface-settings.js +7 -0
- package/dist/config/interface-settings.js.map +1 -0
- package/dist/config/node-harness.js +34 -0
- package/dist/config/node-harness.js.map +1 -0
- package/dist/config/package-discovery.js +96 -0
- package/dist/config/package-discovery.js.map +1 -0
- package/dist/config/settings.js +7 -0
- package/dist/config/settings.js.map +1 -1
- package/dist/config/swarm-toml.js +16 -3
- package/dist/config/swarm-toml.js.map +1 -1
- package/dist/core/degenerate-output.js +44 -0
- package/dist/core/degenerate-output.js.map +1 -0
- package/dist/core/loop.js +88 -8
- package/dist/core/loop.js.map +1 -1
- package/dist/core/termination.js.map +1 -1
- package/dist/durable/recovery-context.js +77 -1
- package/dist/durable/recovery-context.js.map +1 -1
- package/dist/eval/agent-session.js +146 -0
- package/dist/eval/agent-session.js.map +1 -0
- package/dist/eval/arms.js +13 -5
- package/dist/eval/arms.js.map +1 -1
- package/dist/eval/campaign-run.js +2 -1
- package/dist/eval/campaign-run.js.map +1 -1
- package/dist/eval/empty-patch-attribution.js +9 -5
- package/dist/eval/empty-patch-attribution.js.map +1 -1
- package/dist/eval/endpoint-health.js +126 -0
- package/dist/eval/endpoint-health.js.map +1 -0
- package/dist/eval/feedback-study-analysis.js +747 -0
- package/dist/eval/feedback-study-analysis.js.map +1 -0
- package/dist/eval/feedback-study-report.js +156 -0
- package/dist/eval/feedback-study-report.js.map +1 -0
- package/dist/eval/feedback-study.js +854 -0
- package/dist/eval/feedback-study.js.map +1 -0
- package/dist/eval/frozen-campaign.js.map +1 -1
- package/dist/eval/known-total.js +7 -0
- package/dist/eval/known-total.js.map +1 -0
- package/dist/eval/patch-metrics.js +74 -0
- package/dist/eval/patch-metrics.js.map +1 -0
- package/dist/eval/pr-task-judge.js +241 -0
- package/dist/eval/pr-task-judge.js.map +1 -0
- package/dist/eval/reach-pressure-analysis.js +507 -0
- package/dist/eval/reach-pressure-analysis.js.map +1 -0
- package/dist/eval/reach-pressure-derivation.js +201 -0
- package/dist/eval/reach-pressure-derivation.js.map +1 -0
- package/dist/eval/reach-pressure-report.js +266 -0
- package/dist/eval/reach-pressure-report.js.map +1 -0
- package/dist/eval/reach-pressure.js +645 -0
- package/dist/eval/reach-pressure.js.map +1 -0
- package/dist/eval/repair-progress.js +109 -0
- package/dist/eval/repair-progress.js.map +1 -0
- package/dist/eval/sealed-workspace.js +61 -0
- package/dist/eval/sealed-workspace.js.map +1 -0
- package/dist/eval/statistics.js +168 -0
- package/dist/eval/statistics.js.map +1 -1
- package/dist/evidence/behavior-check.js +93 -0
- package/dist/evidence/behavior-check.js.map +1 -0
- package/dist/evidence/blob-manifest.js +14 -1
- package/dist/evidence/blob-manifest.js.map +1 -1
- package/dist/evidence/browser-execution.js +12 -0
- package/dist/evidence/browser-execution.js.map +1 -0
- package/dist/evidence/bundle.js +36 -4
- package/dist/evidence/bundle.js.map +1 -1
- package/dist/evidence/challenge-lines.js +21 -0
- package/dist/evidence/challenge-lines.js.map +1 -0
- package/dist/evidence/ci-summary.js +62 -0
- package/dist/evidence/ci-summary.js.map +1 -0
- package/dist/evidence/goal-contract.js +140 -1
- package/dist/evidence/goal-contract.js.map +1 -1
- package/dist/evidence/ledger-record.js +2 -0
- package/dist/evidence/ledger-record.js.map +1 -1
- package/dist/evidence/model-call-recording.js +3 -0
- package/dist/evidence/model-call-recording.js.map +1 -1
- package/dist/evidence/predicate-catalogue.js +22 -0
- package/dist/evidence/predicate-catalogue.js.map +1 -1
- package/dist/evidence/run-assessment.js +65 -1
- package/dist/evidence/run-assessment.js.map +1 -1
- package/dist/evidence/run-spec.js +6 -3
- package/dist/evidence/run-spec.js.map +1 -1
- package/dist/evidence/signing.js +13 -1
- package/dist/evidence/signing.js.map +1 -1
- package/dist/evidence/task-preset.js +52 -0
- package/dist/evidence/task-preset.js.map +1 -0
- package/dist/evidence/verdict.js +36 -1
- package/dist/evidence/verdict.js.map +1 -1
- package/dist/evidence/verifier/behavior.d.mts +5 -0
- package/dist/evidence/verifier/behavior.mjs +161 -0
- package/dist/evidence/verifier/challenges.d.mts +19 -0
- package/dist/evidence/verifier/challenges.mjs +203 -0
- package/dist/evidence/verifier/rederive.d.mts +7 -1
- package/dist/evidence/verifier/rederive.mjs +32 -61
- package/dist/evidence/verifier/status.d.mts +11 -0
- package/dist/evidence/verifier/status.mjs +757 -0
- package/dist/evidence/verifier/strengthening.d.mts +18 -0
- package/dist/evidence/verifier/strengthening.mjs +200 -0
- package/dist/evidence/verifier/upgrade.d.mts +6 -0
- package/dist/evidence/verifier/upgrade.mjs +81 -0
- package/dist/evidence/verifier/verify.mjs +165 -6
- package/dist/exec/child-environment.js +34 -0
- package/dist/exec/child-environment.js.map +1 -1
- package/dist/exec/container-backend.js +141 -12
- package/dist/exec/container-backend.js.map +1 -1
- package/dist/exec/container-image.js +7 -0
- package/dist/exec/container-image.js.map +1 -0
- package/dist/exec/controlled-network.js +20 -1
- package/dist/exec/controlled-network.js.map +1 -1
- package/dist/exec/execution-mode.js +25 -13
- package/dist/exec/execution-mode.js.map +1 -1
- package/dist/exec/isolation-option.js +3 -1
- package/dist/exec/isolation-option.js.map +1 -1
- package/dist/exec/run-process.js +5 -1
- package/dist/exec/run-process.js.map +1 -1
- package/dist/exec/runtime-resource.js +6 -1
- package/dist/exec/runtime-resource.js.map +1 -1
- package/dist/gates/auto-resolve.js +18 -0
- package/dist/gates/auto-resolve.js.map +1 -1
- package/dist/gates/base-control.js +7 -2
- package/dist/gates/base-control.js.map +1 -1
- package/dist/gates/behavior-artifacts.js +88 -0
- package/dist/gates/behavior-artifacts.js.map +1 -0
- package/dist/gates/behavior-check.js +144 -0
- package/dist/gates/behavior-check.js.map +1 -0
- package/dist/gates/browser-instrument-runner.mjs +80 -0
- package/dist/gates/browser-instrument.js +33 -0
- package/dist/gates/browser-instrument.js.map +1 -0
- package/dist/gates/browser-results.js +75 -0
- package/dist/gates/browser-results.js.map +1 -0
- package/dist/gates/certification.js +4 -0
- package/dist/gates/certification.js.map +1 -1
- package/dist/gates/change-source.js +150 -0
- package/dist/gates/change-source.js.map +1 -0
- package/dist/gates/check-admission.js +218 -0
- package/dist/gates/check-admission.js.map +1 -0
- package/dist/gates/check-network-probe.js +42 -0
- package/dist/gates/check-network-probe.js.map +1 -0
- package/dist/gates/check-plan.js +269 -0
- package/dist/gates/check-plan.js.map +1 -0
- package/dist/gates/checkout-environment.js +119 -0
- package/dist/gates/checkout-environment.js.map +1 -0
- package/dist/gates/contract-executor.js +7 -4
- package/dist/gates/contract-executor.js.map +1 -1
- package/dist/gates/default-gates.js +20 -153
- package/dist/gates/default-gates.js.map +1 -1
- package/dist/gates/deferred-setup.js +250 -0
- package/dist/gates/deferred-setup.js.map +1 -0
- package/dist/gates/dependency-install.js +212 -41
- package/dist/gates/dependency-install.js.map +1 -1
- package/dist/gates/engine.js +19 -2
- package/dist/gates/engine.js.map +1 -1
- package/dist/gates/environment-preflight.js +108 -0
- package/dist/gates/environment-preflight.js.map +1 -0
- package/dist/gates/failure-attribution.js +444 -0
- package/dist/gates/failure-attribution.js.map +1 -0
- package/dist/gates/file-set-tool.js +57 -13
- package/dist/gates/file-set-tool.js.map +1 -1
- package/dist/gates/file-set.js +78 -11
- package/dist/gates/file-set.js.map +1 -1
- package/dist/gates/gate-command.js +69 -0
- package/dist/gates/gate-command.js.map +1 -0
- package/dist/gates/gate-definition.js.map +1 -1
- package/dist/gates/gate-runner.js +70 -49
- package/dist/gates/gate-runner.js.map +1 -1
- package/dist/gates/gate-set-seal.js +11 -1
- package/dist/gates/gate-set-seal.js.map +1 -1
- package/dist/gates/git-workspace.js +54 -7
- package/dist/gates/git-workspace.js.map +1 -1
- package/dist/gates/github-source.js +44 -0
- package/dist/gates/github-source.js.map +1 -0
- package/dist/gates/goal-acceptance.js +79 -11
- package/dist/gates/goal-acceptance.js.map +1 -1
- package/dist/gates/goal-challenge-runner.js +99 -0
- package/dist/gates/goal-challenge-runner.js.map +1 -0
- package/dist/gates/goal-challenges.js +337 -0
- package/dist/gates/goal-challenges.js.map +1 -0
- package/dist/gates/goal-checkout.js +40 -4
- package/dist/gates/goal-checkout.js.map +1 -1
- package/dist/gates/goal-effects.js +38 -0
- package/dist/gates/goal-effects.js.map +1 -0
- package/dist/gates/harness-reporting.js +7 -3
- package/dist/gates/harness-reporting.js.map +1 -1
- package/dist/gates/http-check-runner.mjs +96 -0
- package/dist/gates/independent-checks.js +95 -0
- package/dist/gates/independent-checks.js.map +1 -0
- package/dist/gates/independent-verification.js +771 -105
- package/dist/gates/independent-verification.js.map +1 -1
- package/dist/gates/inspection-gates.js +30 -8
- package/dist/gates/inspection-gates.js.map +1 -1
- package/dist/gates/instrument-dependencies.js +249 -0
- package/dist/gates/instrument-dependencies.js.map +1 -0
- package/dist/gates/instrument-identity.js +794 -0
- package/dist/gates/instrument-identity.js.map +1 -0
- package/dist/gates/measure-snapshot.js +5 -0
- package/dist/gates/measure-snapshot.js.map +1 -1
- package/dist/gates/mutant-parse.js +23 -0
- package/dist/gates/mutant-parse.js.map +1 -1
- package/dist/gates/node-command-runner.js +32 -4
- package/dist/gates/node-command-runner.js.map +1 -1
- package/dist/gates/node-gates.js +122 -0
- package/dist/gates/node-gates.js.map +1 -0
- package/dist/gates/node-test-command.js +22 -4
- package/dist/gates/node-test-command.js.map +1 -1
- package/dist/gates/noninteractive-runner.js +106 -0
- package/dist/gates/noninteractive-runner.js.map +1 -0
- package/dist/gates/oracle-instrumentation.js +6 -2
- package/dist/gates/oracle-instrumentation.js.map +1 -1
- package/dist/gates/oracle-mutants.js +14 -4
- package/dist/gates/oracle-mutants.js.map +1 -1
- package/dist/gates/oracle-reach.js +58 -5
- package/dist/gates/oracle-reach.js.map +1 -1
- package/dist/gates/package-scope.js +115 -0
- package/dist/gates/package-scope.js.map +1 -0
- package/dist/gates/parsers.js +113 -4
- package/dist/gates/parsers.js.map +1 -1
- package/dist/gates/patch-paths.js +304 -14
- package/dist/gates/patch-paths.js.map +1 -1
- package/dist/gates/prepare-dependencies.js +37 -0
- package/dist/gates/prepare-dependencies.js.map +1 -0
- package/dist/gates/prepared-python.js +92 -0
- package/dist/gates/prepared-python.js.map +1 -0
- package/dist/gates/prepared-tools.js +18 -0
- package/dist/gates/prepared-tools.js.map +1 -0
- package/dist/gates/preset-verification.js +65 -0
- package/dist/gates/preset-verification.js.map +1 -0
- package/dist/gates/project-environment.js +60 -0
- package/dist/gates/project-environment.js.map +1 -0
- package/dist/gates/project-type.js +170 -14
- package/dist/gates/project-type.js.map +1 -1
- package/dist/gates/python-gates.js +93 -0
- package/dist/gates/python-gates.js.map +1 -0
- package/dist/gates/python-mutants.js +176 -0
- package/dist/gates/python-mutants.js.map +1 -0
- package/dist/gates/python-offline-build.js +274 -0
- package/dist/gates/python-offline-build.js.map +1 -0
- package/dist/gates/ratchet.js +6 -1
- package/dist/gates/ratchet.js.map +1 -1
- package/dist/gates/repair-policy.js +64 -0
- package/dist/gates/repair-policy.js.map +1 -0
- package/dist/gates/runner-results.js +150 -0
- package/dist/gates/runner-results.js.map +1 -0
- package/dist/gates/scratch-index.js +124 -2
- package/dist/gates/scratch-index.js.map +1 -1
- package/dist/gates/setup-effect.js +16 -0
- package/dist/gates/setup-effect.js.map +1 -0
- package/dist/gates/setup-follow-up.js +113 -0
- package/dist/gates/setup-follow-up.js.map +1 -0
- package/dist/gates/structured-runner.js +66 -0
- package/dist/gates/structured-runner.js.map +1 -0
- package/dist/gates/unified-diff.js +39 -9
- package/dist/gates/unified-diff.js.map +1 -1
- package/dist/gates/upgrade-contract.js +82 -0
- package/dist/gates/upgrade-contract.js.map +1 -0
- package/dist/gates/upgrade-resolution.js +63 -0
- package/dist/gates/upgrade-resolution.js.map +1 -0
- package/dist/install/health.js +26 -0
- package/dist/install/health.js.map +1 -1
- package/dist/integrations/claude-hook.js +200 -0
- package/dist/integrations/claude-hook.js.map +1 -0
- package/dist/integrations/launcher.js +17 -0
- package/dist/integrations/launcher.js.map +1 -0
- package/dist/integrations/mcp-server.js +270 -0
- package/dist/integrations/mcp-server.js.map +1 -0
- package/dist/integrations/pre-commit.js +169 -0
- package/dist/integrations/pre-commit.js.map +1 -0
- package/dist/machine-output.js +1 -0
- package/dist/machine-output.js.map +1 -1
- package/dist/node-floor-check.js +12 -0
- package/dist/node-floor-check.js.map +1 -0
- package/dist/node-floor.js +61 -13
- package/dist/node-floor.js.map +1 -1
- package/dist/select/calibration-measures.js +17 -3
- package/dist/select/calibration-measures.js.map +1 -1
- package/dist/select/calibration-run.js +1 -1
- package/dist/select/calibration-run.js.map +1 -1
- package/dist/select/recommendation.js +10 -0
- package/dist/select/recommendation.js.map +1 -1
- package/dist/select/routing-candidates.js +29 -0
- package/dist/select/routing-candidates.js.map +1 -0
- package/dist/select/served-pick.js +36 -0
- package/dist/select/served-pick.js.map +1 -0
- package/dist/swarm-verify.js +75 -0
- package/dist/swarm-verify.js.map +1 -0
- package/dist/tools/chokepoint-record.js +14 -1
- package/dist/tools/chokepoint-record.js.map +1 -1
- package/dist/tools/chokepoint.js +41 -2
- package/dist/tools/chokepoint.js.map +1 -1
- package/dist/tools/policy-guard.js +7 -0
- package/dist/tools/policy-guard.js.map +1 -1
- package/dist/tui/confirmation-queue.js +6 -6
- package/dist/tui/confirmation-queue.js.map +1 -1
- package/dist/tui/elapsed.js +13 -0
- package/dist/tui/elapsed.js.map +1 -1
- package/dist/tui/evidence-panel.js +72 -12
- package/dist/tui/evidence-panel.js.map +1 -1
- package/dist/tui/glyphs.js +23 -0
- package/dist/tui/glyphs.js.map +1 -0
- package/dist/tui/hyperlink.js +38 -0
- package/dist/tui/hyperlink.js.map +1 -0
- package/dist/tui/key-bindings.js +2 -0
- package/dist/tui/key-bindings.js.map +1 -1
- package/dist/tui/key-dispatcher.js +5 -2
- package/dist/tui/key-dispatcher.js.map +1 -1
- package/dist/tui/layout.js +3 -1
- package/dist/tui/layout.js.map +1 -1
- package/dist/tui/screen-model.js +127 -24
- package/dist/tui/screen-model.js.map +1 -1
- package/dist/tui/screen.js +5 -3
- package/dist/tui/screen.js.map +1 -1
- package/dist/tui/session-interface.js +20 -5
- package/dist/tui/session-interface.js.map +1 -1
- package/dist/tui/session-store.js +3 -3
- package/dist/tui/session-store.js.map +1 -1
- package/dist/tui/session-view.js +10 -0
- package/dist/tui/session-view.js.map +1 -1
- package/dist/workers/bootstrap-history.js +4 -3
- package/dist/workers/bootstrap-history.js.map +1 -1
- package/dist/workers/controller-configuration.js +3 -1
- package/dist/workers/controller-configuration.js.map +1 -1
- package/dist/workers/controller-jobs.js +1 -1
- package/dist/workers/controller-jobs.js.map +1 -1
- package/dist/workers/controller-state.js +2 -0
- package/dist/workers/controller-state.js.map +1 -1
- package/dist/workers/merge-queue.js +1 -0
- package/dist/workers/merge-queue.js.map +1 -1
- package/dist/workers/planner-run.js +1 -1
- package/dist/workers/planner-run.js.map +1 -1
- package/dist/workers/worktree.js +72 -30
- package/dist/workers/worktree.js.map +1 -1
- package/docs/README.md +8 -1
- package/docs/build-guide.md +10 -2
- package/docs/claims.md +20 -0
- package/docs/security-coverage.md +24 -1
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,755 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.0 - 2026-09-29
|
|
4
|
+
|
|
5
|
+
Defects found by the sixteen-repository rollout of 1.2.0, each reproduced from a recorded run
|
|
6
|
+
and fixed at the root. The verdicts that change are named below. The minor version is for the
|
|
7
|
+
new attribution rule, `failure-identity-v3`, which new records carry; a record written under
|
|
8
|
+
`failure-identity-v2` or v1 re-derives under the rule that wrote it.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Build runs before every check that can read its output.** 1.2.0 moved the build ahead of
|
|
13
|
+
tests only. A pnpm workspace whose per-package `tsc --noEmit` resolves its siblings through the
|
|
14
|
+
`dist/index.d.ts` that `tsc --build` writes, as its own CI builds first, read a failed typecheck
|
|
15
|
+
on a clean tree. The build now runs first, then typecheck, lint, format and tests. **Verdict
|
|
16
|
+
change:** such a project reads its real typecheck and lint results instead of a failure caused
|
|
17
|
+
by the order.
|
|
18
|
+
- **A failed check records what its runner printed.** Node checks ran as `npm run --silent`,
|
|
19
|
+
and npm hands that log level to the script as `npm_config_loglevel=silent`. pnpm reads it, so a
|
|
20
|
+
failed `pnpm -r run typecheck` recorded an exit code with empty output. Checks now run as
|
|
21
|
+
`npm run --loglevel=error`, which keeps npm's notices out of the record and every tool's errors
|
|
22
|
+
in it; `swarm init` writes the same form. No verdict changes: the failure is still a failure,
|
|
23
|
+
now with its reason.
|
|
24
|
+
- **The base control sees nothing the patched tree's run produced.** The base was measured in
|
|
25
|
+
the same checkout after a forced checkout and a clean that keeps ignored files, so the base's
|
|
26
|
+
checks ran beside the patched tree's build output. depose's base typecheck passed on the `dist/`
|
|
27
|
+
the patched build wrote, and a workflow-only patch read **Regression: fail**; a module only the
|
|
28
|
+
patched build emitted stayed in `dist/` and failed the base's suite the same way, so a real
|
|
29
|
+
regression read as inherited. The ignored tree is now recorded once dependencies are prepared,
|
|
30
|
+
and every switch between the two sides removes what was added since; a prepared entry a run
|
|
31
|
+
changed refuses the comparison. Where the patch changes a lockfile, nothing installed is shared:
|
|
32
|
+
the base installs its own dependencies from its own lockfile. **Verdict changes:** such a
|
|
33
|
+
workflow-only patch reads its real regression result, and a patch whose build output or
|
|
34
|
+
dependency change broke the suite reads **Regression: fail** instead of an inherited failure.
|
|
35
|
+
- **A failure that differs only in a temporary directory's random name is inherited.** The base
|
|
36
|
+
and the patch failed the same three tests, and two causes differed only in pre-commit's random
|
|
37
|
+
repository directory (`...eponyx5xidu` against `...epoc90ac5y6`), so the failures could not be
|
|
38
|
+
matched and the regression read unmeasured. Causes and outputs are now compared with generated
|
|
39
|
+
names set aside: platform temporary roots, digit-bearing directory names under them, and a
|
|
40
|
+
generated name's tail where a reporter elided the rest. A file's own name, a path outside a
|
|
41
|
+
temporary root and every other word still count, so a changed message still reads as changed.
|
|
42
|
+
New records carry `failure-identity-v3`; a record written under v2 re-derives under v2. The
|
|
43
|
+
advice for an unmatched failure now says why it could not be matched, instead of saying the
|
|
44
|
+
output names no tests when it names them. **Verdict change:** such inherited failures read
|
|
45
|
+
inherited, so the regression dimension is measured instead of unmeasured.
|
|
46
|
+
- **A base control whose worker crashed on exit still shows a regression.** quantproof's base
|
|
47
|
+
ran its whole suite, failed no test, and exited 1 when a Vitest worker aborted on exit (a
|
|
48
|
+
better-sqlite3 assertion under Node 24), leaving one file's tests pending. Its report no longer
|
|
49
|
+
reconciled, so the two tests the patch broke, which that report names as passing, read
|
|
50
|
+
unmeasured. Where the base names no failure and was not killed by the harness, a test it names
|
|
51
|
+
passing once and the patch fails is now newly failing. A test the base never finished, a killed
|
|
52
|
+
or cut run, or a base that names a failure of its own stays unmeasured, and nothing is ever
|
|
53
|
+
inherited this way. **Verdict change:** such a run reads **Regression: fail** instead of
|
|
54
|
+
unmeasured.
|
|
55
|
+
- **The advice for a run that measured nothing says the right thing.** Where the install already
|
|
56
|
+
ran (the Action's `install: true` is passed as `--install`), a runner still missing was followed
|
|
57
|
+
by "pass --install"; it now says the environment does not carry that toolchain and names the
|
|
58
|
+
image setting for each route. Where it did not run, it names both routes' setting. A run that
|
|
59
|
+
planned no check printed "every check stood down ()"; it now says no check was planned and why,
|
|
60
|
+
and no longer suggests a `--command` flag the verifier does not have. No verdict changes.
|
|
61
|
+
|
|
62
|
+
## 1.2.0 - 2026-09-29
|
|
63
|
+
|
|
64
|
+
Fixes found by running the published 1.1.0 where a stranger would: fresh virtual machines, the
|
|
65
|
+
real pre-commit framework, hooks installed through `npx`, and a sixteen-repository rollout.
|
|
66
|
+
The verdicts that change are named below. The minor version is for two additive outputs: an `excludedEnvironments` field in the
|
|
67
|
+
`check` JSON report and an `excluded-environments-v1` record; no existing record field, exit code
|
|
68
|
+
or rule name changes meaning.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- **Build runs before tests.** Checks ran a Node project's `test` script before its `build`
|
|
73
|
+
script. A suite that reads build output (a Vite and Workers project whose test script reads the
|
|
74
|
+
built asset directory, found in a fresh-VM onboarding run) failed on a clean tree, where its own
|
|
75
|
+
CI, which builds first, passes. The build check now runs first. **Verdict change:** such a
|
|
76
|
+
project reads its real test result instead of a failure caused by the order.
|
|
77
|
+
- **The pre-commit framework hook works.** The distribution declared a `node` language hook. The
|
|
78
|
+
framework installs that from git, which npm 11 refuses (`EALLOWGIT`), blocking every commit,
|
|
79
|
+
good or bad; under npm 10 the install linked no `swarm-verify` binary, so whichever binary was
|
|
80
|
+
on `PATH` answered. The hook now runs `npx --yes swarm-verify@<version> pre-commit`. Exercised
|
|
81
|
+
against the framework on npm 11.12.1 and 10.9.8: a bad staged change is refused and a good one
|
|
82
|
+
committed. Use `rev: v1.2.0` or later.
|
|
83
|
+
- **Installed hooks survive npm clearing its npx cache.** Run as `npx swarm-verify hook install`
|
|
84
|
+
or `npx swarm-verify pre-commit install`, the installers wrote an absolute path inside the npx
|
|
85
|
+
cache. From there they now write the pinned `npx` invocation; a project or global install is
|
|
86
|
+
still called directly.
|
|
87
|
+
- **The Claude Code hook routes a piped test command.** `npm test 2>&1 | tail -5` and the same
|
|
88
|
+
through `head` or `grep` with plain arguments are routed through `check` with the filters kept;
|
|
89
|
+
any other pipeline stage or shell syntax is still left alone.
|
|
90
|
+
- **A bundle whose required challenge refused verifies.** The bundle's own verifier failed the
|
|
91
|
+
"independent goal bound" check of a `--challenges required` run that refused for
|
|
92
|
+
`challenges-unmet`, although the refusal was correct.
|
|
93
|
+
- **A formatter check runs only where the project declares that formatter.** Any `[tool.ruff]`
|
|
94
|
+
table used to add `ruff format --check .`, so projects that lint with ruff and format with black
|
|
95
|
+
or not at all read `fail` on a clean checkout (four real repositories, 4 to 151 files each). The
|
|
96
|
+
format check now runs `ruff format --check .` only for a `[tool.ruff.format]` table or a
|
|
97
|
+
`ruff-format` pre-commit hook, and `black --check .` for a `[tool.black]` table or a `black`
|
|
98
|
+
hook, unavailable with the tool named when the project's environment does not hold it. Verdict
|
|
99
|
+
change: a project with ruff lint configuration and no declared formatter no longer fails `check`
|
|
100
|
+
on formatting; its format check reads not run, with the reason.
|
|
101
|
+
- **mypy keeps the scope the project's mypy configuration names.** Only `pyproject.toml` and
|
|
102
|
+
`setup.cfg` `files` were read, so a project scoping mypy in `mypy.ini` (`files = src`) was
|
|
103
|
+
checked with `mypy .` and failed on 180 errors in tests it never type-checks. Targets are now
|
|
104
|
+
read from `files`, `packages` or `modules` in the one file mypy itself reads, in its documented
|
|
105
|
+
order (`mypy.ini`, `.mypy.ini`, `pyproject.toml` with `[tool.mypy]`, `setup.cfg` with
|
|
106
|
+
`[mypy]`). Verdict change: such a project's typecheck runs plain `mypy` and can pass; a project
|
|
107
|
+
whose `pyproject.toml` names targets while a `mypy.ini` without them takes precedence now runs
|
|
108
|
+
`mypy .` instead of a bare `mypy` that exited asking for a target.
|
|
109
|
+
- **An untracked virtual environment is not the change `check` measures.** A `.venv` made by
|
|
110
|
+
`python3 -m venv` before Python 3.13 carries no `.gitignore`, and in a project that does not
|
|
111
|
+
ignore `.venv/` its every file counted as changed: a clean tavern checkout read 81 changed files
|
|
112
|
+
and failed the placeholder, secret and diff-budget checks on the environment's own files. An
|
|
113
|
+
untracked directory whose root holds a `pyvenv.cfg` with a `home` key is now left out of the
|
|
114
|
+
change and named (`excluded` in the output, `excludedEnvironments` in the JSON report, an
|
|
115
|
+
`excluded-environments-v1` record in the evidence). A tracked or staged `pyvenv.cfg`, a
|
|
116
|
+
directory holding anything tracked, and every file a `ci` patch adds are still checked. Verdict
|
|
117
|
+
change: such a tree no longer fails `check` on its environment's files.
|
|
118
|
+
- **A dependency whose install script builds its native binding is measurable under
|
|
119
|
+
`--install`.** With scripts off, `better-sqlite3` never had its binding, so every test that
|
|
120
|
+
opened a database failed at base and head alike and the verdict read incomplete. The install
|
|
121
|
+
scripts `npm ci --ignore-scripts` skipped now run as a deferred phase with `npm rebuild`, where
|
|
122
|
+
the checks run, only after a probe shows a check-time command cannot connect, and with
|
|
123
|
+
node-gyp pointed at the running node's own headers so the build needs no download. Registry
|
|
124
|
+
code still never runs with network access: on the host, or wherever the probe cannot show the
|
|
125
|
+
network is off, the deferred scripts do not run and the install detail says why. A script
|
|
126
|
+
that tries the network there is refused and its output is reported.
|
|
127
|
+
- **A uv project in src layout is installed before its tests run.** `uv sync
|
|
128
|
+
--no-install-project` left the project itself out, so tests could not import the package or
|
|
129
|
+
call its console scripts. The project is now installed editable in the deferred offline phase:
|
|
130
|
+
the build backend's requirements are fetched as wheels without being run, the backend builds
|
|
131
|
+
the editable wheel offline, and uv installs it offline.
|
|
132
|
+
- **A script that calls pnpm finds the pnpm that installed.** Where the image has no pnpm and
|
|
133
|
+
the install fetched the declared version for its own command, a script such as
|
|
134
|
+
`pnpm -r run typecheck` read `pnpm: not found` and the check was unmeasured. The same version
|
|
135
|
+
is kept in the checkout's `node_modules` and put first on the checks' PATH through the built
|
|
136
|
+
environment.
|
|
137
|
+
- **The uv install no longer builds anything while the registry is reachable.** `uv sync
|
|
138
|
+
--no-install-project` still built every dependency that ships only a source archive (the
|
|
139
|
+
real `docopt==0.6.2` is one) and every workspace member, which runs that package's setup.py
|
|
140
|
+
or build backend with the network on: a fixture archive whose setup.py tries a connection got
|
|
141
|
+
through and wrote into the checkout. The install now runs with `--no-build` and leaves those
|
|
142
|
+
packages out by name; in the deferred offline phase a source archive's bytes are fetched and
|
|
143
|
+
checked against the lockfile's sha256 (`stage: source-archive`, nothing executed), unpacked
|
|
144
|
+
and built offline, and a workspace member or local directory is built offline from the
|
|
145
|
+
checkout, each step recorded. A setup.py that tries the network there is refused and its
|
|
146
|
+
output reported. A git source or an archive whose hash cannot be checked is left out of the
|
|
147
|
+
install with its reason named, so a check that needs it reads what it is rather than a pass.
|
|
148
|
+
|
|
149
|
+
Each deferred step is its own intent and completion on the `dependency-install` record, naming
|
|
150
|
+
its stage and its network (`none` with the probe's result for offline work), so a reader sees
|
|
151
|
+
which scripts ran offline and which fetch reached the registry. A deferred step that fails is
|
|
152
|
+
reported and the checks still run; one that changes source files fails setup.
|
|
153
|
+
|
|
154
|
+
### Documentation
|
|
155
|
+
|
|
156
|
+
- Every documented Action workflow shows `install: true`, without which a repository with
|
|
157
|
+
dependencies reads incomplete.
|
|
158
|
+
|
|
159
|
+
## 1.1.0 - 2026-09-29
|
|
160
|
+
|
|
161
|
+
Two false passes reported against the published 1.0.7, reproduced on it and fixed at the root,
|
|
162
|
+
and four more found while building real controls for every attack family. Some verdicts change
|
|
163
|
+
because of these repairs: each change is named below, a pass that was not shown now reads
|
|
164
|
+
incomplete or unmeasured rather than passed, and none of them turns an old refusal into a pass.
|
|
165
|
+
Additive record fields and one additive flag take the minor version; no field, exit code or rule
|
|
166
|
+
name changes meaning, and records written before a rule keep re-deriving under the rule that
|
|
167
|
+
wrote them.
|
|
168
|
+
|
|
169
|
+
### Fixed
|
|
170
|
+
|
|
171
|
+
- **A pass the candidate's own instrument reported is not a pass.** On 1.0.7 a
|
|
172
|
+
`vitest.config.mjs` that wrote a passing report to Vitest's `--outputFile` and exited before
|
|
173
|
+
any test ran read `result: pass` from `check`, and a `test` script replaced by an `echo` of a
|
|
174
|
+
passing summary read as a pass from `check` and as a regression pass from `ci`. The 1.0.6 fix
|
|
175
|
+
read a list of configuration file names; it could not see a configuration importing a changed
|
|
176
|
+
helper, a setup file named another way, the package scripts npm reads from the working tree,
|
|
177
|
+
or a runner substituted through the manifest, the lockfile or `node_modules/.bin`. Each
|
|
178
|
+
command check now observes its instrument (`instrument-identity-v1`): the scripts its command
|
|
179
|
+
reaches, each tool's configuration by the names the tool discovers, every file those import or
|
|
180
|
+
name, where the tool's packages come from, and the runner as installed, compared with the
|
|
181
|
+
reference commit before and after the run. A pass reported under an instrument the change
|
|
182
|
+
altered is withheld: `check` reads incomplete (exit 4) naming the altered files, and `ci`
|
|
183
|
+
reruns the check with the base's instrument restored, where only that reading can let the pass
|
|
184
|
+
stand. The observation is on the `gate-run` record and the offline verifier applies the same
|
|
185
|
+
rule. A registry release of a tool at another version is recorded and trusted; a tool from a
|
|
186
|
+
path, URL, git source or another package's name is not.
|
|
187
|
+
- **Two failing tests with the same title are two failures.** On 1.0.7 two node tests both named
|
|
188
|
+
`works`, the first already failing at the base, collapsed to one TAP identity, so a patch that
|
|
189
|
+
broke the second read as the first's inherited failure: `inheritedFromBase: true`,
|
|
190
|
+
`regression: pass`, and the Action's `regression-only`. Under `failure-identity-v2` a node
|
|
191
|
+
failure is named by its TAP location, depth and title, a Vitest test by file and full name, a
|
|
192
|
+
pytest test by node id; failures are counted, compared with their cause, and never inherited
|
|
193
|
+
from a run that was cancelled, truncated, cut short of its plan, contradicts its own counters,
|
|
194
|
+
or repeats an identity. Checks carry `attributionRule`; a record without it re-derives under
|
|
195
|
+
the title-only rule that wrote it.
|
|
196
|
+
- **A patch cannot pass `ci` by editing the test that would catch it.** A patch that broke the
|
|
197
|
+
code and marked the catching test `skip`, deleted its file or rewrote its assertion read as a
|
|
198
|
+
regression pass. Where a patch changes or deletes test files, the checks run again with the
|
|
199
|
+
base's versions of those files over the patch's source; a test the base passed that fails
|
|
200
|
+
there is named (`weakenedTests`) and the pass is withheld. A correct change that edits, renames
|
|
201
|
+
or adds tests still passes.
|
|
202
|
+
- **A node suite whose every test was skipped measured nothing.** It read as passed.
|
|
203
|
+
- **The pre-commit hook measured the staged commit against itself**, so the change read as empty
|
|
204
|
+
and a staged configuration was its own reference. It is now measured against `HEAD`.
|
|
205
|
+
- **A workspace pattern from a checked repository's package.json is no longer compiled into a
|
|
206
|
+
regular expression**; a crafted pattern made discovery take exponential time. Patterns keep
|
|
207
|
+
`*` and `**`; any other shape is refused with the fix named.
|
|
208
|
+
|
|
209
|
+
### Added
|
|
210
|
+
|
|
211
|
+
- `verdict --head <sha>` refuses a verdict made for another head than the one being decided.
|
|
212
|
+
- Quoted and space-bearing Git patch paths (`my file.js`, `café "x".js`, renames and copies
|
|
213
|
+
between them) are read instead of refused, with every unsafe path still refused after decoding.
|
|
214
|
+
- The ci report and the Markdown summary name the failing tests beside every attribution, so a
|
|
215
|
+
failure excused as inherited stays in view.
|
|
216
|
+
|
|
217
|
+
### Changed
|
|
218
|
+
|
|
219
|
+
- The front door, package README and claims index say what the command runs and records and
|
|
220
|
+
what it does not judge, and correct three statements: `check` briefly writes its own
|
|
221
|
+
falsification-bond fixtures into the repository and removes them; `regression: pass` can include
|
|
222
|
+
a proven inherited failure; locally commands run on the host under a built environment, and
|
|
223
|
+
containers are the Action's default. The 1.0.0 release note's statement that the basic command
|
|
224
|
+
runs in a container when one is available was wrong and is corrected on that release.
|
|
225
|
+
|
|
226
|
+
## 1.0.7 - 2026-09-28
|
|
227
|
+
|
|
228
|
+
### Fixed
|
|
229
|
+
|
|
230
|
+
- **An inherited failure in Vitest's text reporters can be proven.** A project whose test
|
|
231
|
+
script adds flags the structured runner does not take (`vitest run --coverage
|
|
232
|
+
--reporter=verbose`) prints a coverage table that differs between the base and the patch
|
|
233
|
+
whenever the patch changes code, so 1.0.6 could never show its failures were inherited and left
|
|
234
|
+
the dimension unmeasured: cronproof#2, which 1.0.4 and 1.0.5 passed on an unproven inheritance.
|
|
235
|
+
Vitest names every failed test and every file that failed to load on a `FAIL` line beside its
|
|
236
|
+
`Test Files` summary; those lines are now the failure identities, in the verifier and in the
|
|
237
|
+
offline re-deriver alike. They name failures only, so they can prove an inheritance or a new
|
|
238
|
+
failure and never a pass. cronproof#2 now reads a proven inheritance and a regression pass.
|
|
239
|
+
|
|
240
|
+
## 1.0.6 - 2026-09-28
|
|
241
|
+
|
|
242
|
+
Two false passes reported against 1.0.5 and reproduced on it, and a third defect found while
|
|
243
|
+
fixing them. Each is fixed at the root.
|
|
244
|
+
|
|
245
|
+
### Fixed
|
|
246
|
+
|
|
247
|
+
- **A patch cannot pass its own suite by changing the runner's configuration.** A patch that
|
|
248
|
+
broke `sum.js` and added a `vitest.config.js` read the report path from `process.argv`, wrote a
|
|
249
|
+
passing report there and exited before any test ran, and 1.0.5 read a regression pass. The
|
|
250
|
+
commands already came from the base commit; the rest of the instrument now does too. Where a
|
|
251
|
+
patch changes runner configuration (Vitest, Jest, Mocha, Babel, ESLint, Prettier, Biome,
|
|
252
|
+
TypeScript, pytest and their setup files), every check runs a second time with the base's
|
|
253
|
+
configuration restored. A check that passes only under the patch's configuration fails where
|
|
254
|
+
the base's configuration fails a test the base itself passed, and measures nothing otherwise.
|
|
255
|
+
Both readings are kept on the check (`configurationObservation`, `configurationStatus`,
|
|
256
|
+
`configurationFiles`, `regressedUnderBaseConfiguration`). A configuration that imports a
|
|
257
|
+
helper module the patch changed, or a setup file named outside the listed patterns, is not
|
|
258
|
+
caught by this and is named as a residual.
|
|
259
|
+
- **A newly broken test behind an old failure is a regression.** A check that failed both with
|
|
260
|
+
and without the patch was read as inherited whatever else failed inside it: a base with one
|
|
261
|
+
failing test and a patch that broke a second read as a regression pass wherever another check
|
|
262
|
+
passed. A failure is now inherited only where every test the patched run failed also failed at
|
|
263
|
+
the base (read from a structured report or TAP), or where both runs printed the same output
|
|
264
|
+
once times and durations are set aside. A patched run that fails a test the base did not is a
|
|
265
|
+
regression, and the new failures are named (`newFailures`). A failure that can be shown neither
|
|
266
|
+
way (`attribution: "unattributed"`) leaves the regression dimension unmeasured, never passed.
|
|
267
|
+
- **The offline verifier re-derives these rules with its own implementation.** Since 1.0.3 the
|
|
268
|
+
live verdict read an inherited failure beside a passing check as a regression pass, while the
|
|
269
|
+
offline re-deriver still read it as unmeasured, so every such bundle failed its own
|
|
270
|
+
"independent regression re-derived" check. The re-deriver now recomputes each failed check's
|
|
271
|
+
attribution and each base-configuration reading from the recorded observations, requires them
|
|
272
|
+
to match, and applies the new rule to records that carry them. Records from 1.0.3 to 1.0.5 that
|
|
273
|
+
read an unproven inheritance as a pass still do not re-derive; that pass was not shown.
|
|
274
|
+
- **Vitest test names are relative to the checkout**, so a test is named the same wherever the
|
|
275
|
+
checkout sits and a verdict posted publicly does not carry the machine's session path.
|
|
276
|
+
|
|
277
|
+
## 1.0.5 - 2026-09-28
|
|
278
|
+
|
|
279
|
+
What Comparison B and the study's replay on 1.0.4 found, fixed at the root: an oracle that ran
|
|
280
|
+
outside the project environment and left no record of why it refused, a container removal
|
|
281
|
+
judged on one sample, and two test-check details that named nothing to fix.
|
|
282
|
+
|
|
283
|
+
### Changed
|
|
284
|
+
|
|
285
|
+
- **The oracle runs in the project environment the verifier prepared.** `.venv/bin` and
|
|
286
|
+
`node_modules/.bin` come first on PATH for the oracle, as `uv run` and `npm exec` would. The
|
|
287
|
+
repository's own checks already call those interpreters by path. An oracle written
|
|
288
|
+
`python -m pytest ...` otherwise reached the container image's interpreter, which has none of
|
|
289
|
+
the project's packages, and a patch read as rejected. A directory that does not exist changes
|
|
290
|
+
nothing.
|
|
291
|
+
- **Every oracle run is kept in the verdict** (`oracleRuns`: the tree it ran on, the command,
|
|
292
|
+
its exit code, duration and the last 4000 characters of its output). The task dimension was
|
|
293
|
+
decided from runs whose output was not recorded anywhere.
|
|
294
|
+
|
|
295
|
+
### Fixed
|
|
296
|
+
|
|
297
|
+
- **A late container removal no longer refuses the run.** Removal is asked for and observed up
|
|
298
|
+
to three times with a growing pause before cleanup is called unconfirmed. Under load the
|
|
299
|
+
runtime finished removals after its 15-second client deadline, and a container gone moments
|
|
300
|
+
later refused twelve study rows in a row. A container still present after the last round, or
|
|
301
|
+
one whose creation was uncertain, still refuses.
|
|
302
|
+
|
|
303
|
+
- **A failed TAP run names the tests that failed**, up to five, quoted as the runner printed
|
|
304
|
+
them, after the counts. "2 failed" alone named nothing a repair could act on: in Comparison B
|
|
305
|
+
the model changed nothing in six invocations fed that line for three koa patches.
|
|
306
|
+
- **A failed test check says why when no counted test failed.** jest and vitest summaries count
|
|
307
|
+
tests, so a file that fails to load or exits the process, or a command the test script runs
|
|
308
|
+
after the runner, left a failed check reading "978 passed, 978 total". The detail now quotes
|
|
309
|
+
the runner's test-file line and names the files it marked FAIL, or says the exit came from
|
|
310
|
+
outside the counted tests. Found on commander.js#1671 in Comparison B.
|
|
311
|
+
|
|
312
|
+
## 1.0.4 - 2026-09-28
|
|
313
|
+
|
|
314
|
+
Two findings from the 1.0.3 rollout and the study's replay on 1.0.3, fixed at the root: an
|
|
315
|
+
Action headline that contradicted its own regression dimension, and one more install gap.
|
|
316
|
+
|
|
317
|
+
### Changed
|
|
318
|
+
|
|
319
|
+
- **The Action's result follows the regression dimension when every failed check is
|
|
320
|
+
inherited.** Three of sixteen dogfood repositories read "Not verified" while their verdict
|
|
321
|
+
said "Regression: pass": their only failures were ones the base commit already had. Such a
|
|
322
|
+
run is now a regression-only pass with exit status 0; the reason line still says the failure
|
|
323
|
+
is inherited. A failure the base did not have still refuses. The verdict document's format is
|
|
324
|
+
unchanged.
|
|
325
|
+
|
|
326
|
+
### Fixed
|
|
327
|
+
|
|
328
|
+
- **A uv project's extras are installed too** by the authorized lockfile install
|
|
329
|
+
(`uv sync --locked --all-groups --all-extras --no-install-project`). 1.0.3 left extras out on
|
|
330
|
+
the reasoning that they are runtime features. The study's replay on 1.0.3 showed that reasoning
|
|
331
|
+
wrong for the older layout that keeps pytest, ruff and mypy in a `dev` extra: every row from
|
|
332
|
+
those projects read "no test ran", and the held-back check was reported as failing on heads
|
|
333
|
+
where it passes once pytest is present. A lockfile declaring conflicting extras makes uv refuse,
|
|
334
|
+
and that is reported as a failed install.
|
|
335
|
+
|
|
336
|
+
## 1.0.3 - 2026-09-28
|
|
337
|
+
|
|
338
|
+
What the AI-authored pull request study's first complete run through 1.0.2 established, fixed
|
|
339
|
+
at the root: one change of verdict semantics, named as such, and one install gap.
|
|
340
|
+
|
|
341
|
+
### Changed
|
|
342
|
+
|
|
343
|
+
- **A failure the base already had no longer leaves the regression dimension unmeasured.**
|
|
344
|
+
The base control ran the same check at the base commit and found it failing there, which
|
|
345
|
+
is a measurement about the base, not about the patch; with the patch's other checks
|
|
346
|
+
passing, the regression dimension now passes and the inherited failure is named beside it.
|
|
347
|
+
In the AI-authored pull request study, ten of twenty-two adjudicated-correct pull requests
|
|
348
|
+
had read as refused for a lint or format failure their base carried. A failure the base did
|
|
349
|
+
not have is still a regression, and a required check that measured nothing still leaves the
|
|
350
|
+
dimension unmeasured.
|
|
351
|
+
|
|
352
|
+
### Fixed
|
|
353
|
+
|
|
354
|
+
- **A uv project's every dependency group is installed** by the authorized lockfile install
|
|
355
|
+
(`uv sync --locked --all-groups --no-install-project`). Groups are development-only by
|
|
356
|
+
definition, and a project that keeps pytest in a `test` group rather than `dev` had no
|
|
357
|
+
runner after a default sync, so its suite read as not run. Extras stay uninstalled.
|
|
358
|
+
|
|
359
|
+
## 1.0.2 - 2026-09-28
|
|
360
|
+
|
|
361
|
+
Two more findings from the study's run through 1.0.1, fixed at the root.
|
|
362
|
+
|
|
363
|
+
### Fixed
|
|
364
|
+
|
|
365
|
+
- **The container's scratch space is a directory on the host, not a tmpfs.** A tmpfs is
|
|
366
|
+
charged to the container's memory limit, so with the cap at 2 GB every large lockfile
|
|
367
|
+
install was killed (exit 137) once its cache passed the cap; sizing the tmpfs in 1.0.1 could
|
|
368
|
+
not help. Each run now mounts its own directory under the person's `~/.swarm/scratch` at
|
|
369
|
+
`/tmp`, executable, removed when the run ends, and removed by runtime repair for a run that
|
|
370
|
+
died between creating and removing it.
|
|
371
|
+
- **A base commit that exists but cannot be checked out is reported with git's own line.**
|
|
372
|
+
Two paths differing only in case, on a case-insensitive filesystem, leave the fresh checkout
|
|
373
|
+
dirty and git refuses to switch; the refusal read as "the base commit is not in the checkout",
|
|
374
|
+
which was false. The last line git printed is now the reason.
|
|
375
|
+
|
|
376
|
+
## 1.0.1 - 2026-09-28
|
|
377
|
+
|
|
378
|
+
Four gaps the AI-authored pull request study exposed on its first run through the stable
|
|
379
|
+
release, each on real repositories, each fixed at the root.
|
|
380
|
+
|
|
381
|
+
### Fixed
|
|
382
|
+
|
|
383
|
+
- **The container's scratch space holds a real install.** HOME and TMPDIR inside the container
|
|
384
|
+
are the `/tmp` tmpfs, so npm's and uv's caches live there, and its 256 MB left a lockfile
|
|
385
|
+
with a native wheel or a large dependency tree failing with "no space left on device". It
|
|
386
|
+
is now 4 GB, of which only what is written is used.
|
|
387
|
+
- **A pnpm lockfile with no `packageManager` pin installs.** The image carries no pnpm; the
|
|
388
|
+
lockfile's own format now names the major that reads it (9.0: pnpm 10, 6.0: pnpm 8, 5.x:
|
|
389
|
+
pnpm 7), that major's latest is fetched through npm for the install command, and the
|
|
390
|
+
command records which.
|
|
391
|
+
- **A configured Python tool the environment does not hold reads as a check that measured
|
|
392
|
+
nothing.** `ci` assembles its checks before the install, so the environment could not be
|
|
393
|
+
read then; when the interpreter itself refuses to start a module, exits 1, and prints only
|
|
394
|
+
its one-line "No module named", the gate is not applicable with the module named. A test's
|
|
395
|
+
own output beside those words is a test's words, and the exit code decides as before.
|
|
396
|
+
- **pytest absent from the environment is said as such.** The runner script says so and exits
|
|
397
|
+
127, and the reading is "measured nothing" with the reason, not "malformed runner output".
|
|
398
|
+
|
|
399
|
+
## 1.0.0 - 2026-09-28
|
|
400
|
+
|
|
401
|
+
The first stable release of `swarm-verify`. Everything below shipped through nine prerelease
|
|
402
|
+
candidates, each rolled out across sixteen owned repositories and three README-only onboarding
|
|
403
|
+
simulations, with every defect they found fixed at its root and named here.
|
|
404
|
+
|
|
405
|
+
### Added
|
|
406
|
+
|
|
407
|
+
- **`swarm-verify` with no subcommand is `check`**: discover the declared checks from the
|
|
408
|
+
manifests, run them unattended (no terminal on stdin, `CI=true` in the child environment),
|
|
409
|
+
and report five conclusions apart: whether the command ran, what the checks found, how
|
|
410
|
+
commands were contained, whether any requirement was judged, whether any check was
|
|
411
|
+
challenged. Exit codes: 0 regression-only pass, 1 a failed check, 2 an unreadable command
|
|
412
|
+
line, 3 cancelled, 4 incomplete. `--explain` previews, `--json` emits `swarm.check.v1`.
|
|
413
|
+
- **Requirement-level challenges** for goal contracts: `ci --challenges off|report|required`
|
|
414
|
+
runs a base control per requirement, mechanical mutations of the changed lines witnessed by
|
|
415
|
+
the repository suite, sealed fixtures the contract declares, and names missing obligations.
|
|
416
|
+
Records `challenge-plan-v1`, `challenge-run-v1` and `challenge-verdict-v1`; the bundle's own
|
|
417
|
+
verifier re-derives every verdict independently. `required` refuses with `challenges-unmet`.
|
|
418
|
+
- **Python changes are challenged too**: the mutation set reads Python's statement forms
|
|
419
|
+
(comparison inversion, condition negation, operand swap, `return None`, `= None`), masks
|
|
420
|
+
literals and comments, sets test files aside, and every Python mutant is shown to parse with
|
|
421
|
+
Python's own parser before it runs.
|
|
422
|
+
- **The GitHub Action as a client of the installed verifier**: `swarm-verify action
|
|
423
|
+
verify|comment|retain`. The verdict document is signed as a GitHub artifact attestation, the
|
|
424
|
+
pull request comment is one per PR, updated in place, bound to the head, escaped and
|
|
425
|
+
mention-free, and a delayed run for an older head posts nothing.
|
|
426
|
+
- **Coverage on Node 22.8 and newer**: the coverage arm names process isolation in the spelling
|
|
427
|
+
the running Node takes; the floor moves from 24 to 22.8.
|
|
428
|
+
- A verifier platform matrix workflow installs the packed package on Linux, macOS and Windows
|
|
429
|
+
under Node 22.0.0, 22 and 24.
|
|
430
|
+
- **`swarm-verify verdict`** binds a signed verdict document to the report, summary and bundle
|
|
431
|
+
beside it and hands the signer question to `gh attestation verify`.
|
|
432
|
+
- **Three integrations, each a client of the installed verifier**: a Claude Code hook that
|
|
433
|
+
rewrites the agent's recognised test command to `swarm-verify check` (`hook install`,
|
|
434
|
+
`uninstall`, `run`); a local MCP server over stdio with three bounded tools (`mcp`); and a
|
|
435
|
+
pre-commit hook that verifies the staged tree in a detached worktree without touching the
|
|
436
|
+
working tree (`pre-commit`, `pre-commit install`, `uninstall`). Documented in
|
|
437
|
+
`docs/integrations.md`, each with real positive and negative runs in its tests.
|
|
438
|
+
|
|
439
|
+
- An authorized lockfile install inside a container reaches the registry for that one
|
|
440
|
+
command, with lifecycle scripts off, recorded with `network: registry`; the checks that
|
|
441
|
+
follow run with the network off. Where the image carries no pnpm and the manifest pins
|
|
442
|
+
`packageManager: pnpm@X`, that exact pnpm is fetched through npm for the install command.
|
|
443
|
+
The install record is written whether or not a goal contract was supplied.
|
|
444
|
+
- The twelve attack families of the verifier-first assignment are bound to executed controls
|
|
445
|
+
in `docs/verifier-first/attack-controls.md`, with four new ones: an outside-package change
|
|
446
|
+
refused by name, a mismatched goal tree refused before any record, an unfinished challenge
|
|
447
|
+
intent refusing the next challenge, and a revised contract deriving a fresh verdict.
|
|
448
|
+
- The stable 1.x contract is written down in `docs/verifier-first/contract.md`.
|
|
449
|
+
|
|
450
|
+
### Fixed
|
|
451
|
+
|
|
452
|
+
- **A container image that is not on the machine is pulled once, before the first container.**
|
|
453
|
+
`docker create` against an absent image pulled it inside the command's own deadline, and a
|
|
454
|
+
probe's deadline is seconds, so on a fresh machine (a GitHub runner with the Action) every
|
|
455
|
+
container timed out while the image downloaded and the run stopped as "cleanup could not be
|
|
456
|
+
confirmed" without saying why. The backend now inspects the image and pulls it with its own
|
|
457
|
+
ten-minute allowance before the command's deadline starts (a pull inside the deadline left a
|
|
458
|
+
containment probe no time at all and the run refused as "isolation unknown"), names a pull
|
|
459
|
+
that fails, and a creation that timed out or did not start is named in the cleanup message
|
|
460
|
+
with the runtime's last line. A probe that timed out is named as such rather than as one
|
|
461
|
+
that "could not start (null)".
|
|
462
|
+
- **The vitest runner reports to a file and prints only that file.** Four of sixteen rollout
|
|
463
|
+
repositories had their whole suite read as "malformed runner output" because their tests
|
|
464
|
+
logged, or their test script printed its own verdicts, into the stdout the JSON reporter
|
|
465
|
+
used. Stdout is muted while the suite runs; the report's bytes are all that is printed,
|
|
466
|
+
whole: the first cut of this wrote at exit and lost everything past the pipe's 64 KiB
|
|
467
|
+
buffer, so every large suite read as malformed instead.
|
|
468
|
+
- **Manifest scripts run through npm whichever manager installed the lockfile.** pnpm is
|
|
469
|
+
fetched for the install command alone and is not in a trusted image, so every pnpm
|
|
470
|
+
project's typecheck, lint and build read "the command is not installed" in a container. A
|
|
471
|
+
script that itself calls pnpm still needs pnpm and says so. Both the `check` plan and the
|
|
472
|
+
`ci` gate set compose the scripts this way.
|
|
473
|
+
- **When every check stood down, the advice lists why each did**, and distinguishes a runner
|
|
474
|
+
that is not installed (install the dependencies) from a toolchain the verifier does not
|
|
475
|
+
drive (unmeasured, not a pass) and from a manifest that declares no check.
|
|
476
|
+
- **Containment probes are shell scripts.** An image built for a Python project carries no
|
|
477
|
+
node, so every probe "could not start" and the run refused with isolation unknown. The read
|
|
478
|
+
and write probes use `cat` and `printf`; the network probe attempts the connection with node,
|
|
479
|
+
else python3, else bash's `/dev/tcp`, and an image with none of them is recorded as
|
|
480
|
+
unmeasured, never as contained.
|
|
481
|
+
- **The verdict's advice names what happened.** A failed or unmeasured required check was
|
|
482
|
+
advised as "the repository's own suite passed"; it now names the check that failed on the
|
|
483
|
+
patch and passed at the base, or the required check that measured nothing.
|
|
484
|
+
- **A configured Python tool the environment does not hold is an unavailable check, not a
|
|
485
|
+
failed one.** tavern configures mypy, its synced environment holds none, and `python -m
|
|
486
|
+
mypy` exited 1 with "No module named mypy", read as the typecheck failing on a clean
|
|
487
|
+
checkout. Presence is read from `.venv`'s site-packages without running anything; the
|
|
488
|
+
check then says which tool to add and sync. Without a `.venv` nothing is claimed.
|
|
489
|
+
- **A failed check shows the last lines the command printed**, in `check`'s report and its
|
|
490
|
+
JSON (`output`), so "the command exited 1" comes with what a terminal would have shown.
|
|
491
|
+
- **Two messages a stranger met on a first run say what they mean.** The file-set check in a
|
|
492
|
+
run with no declared file set no longer speaks of "no planner" and "no agent"; it says no
|
|
493
|
+
file set was declared and what changed. The per-run signing key notice says what a per-run
|
|
494
|
+
key means and that it is ordinary on a headless machine.
|
|
495
|
+
- **A vitest file that repeats a test title no longer makes the whole suite unmeasured.**
|
|
496
|
+
The second occurrence is named by its position; the runner accepted the title and so does
|
|
497
|
+
the reading. Found on depose, where one repeated `it` hid 383 tests.
|
|
498
|
+
- **The tests reading says what its counts are and are not** in words a first-time reader
|
|
499
|
+
can follow, instead of "ratchet counts" and "base-control attribution".
|
|
500
|
+
- **An image pull is attempted three times** before the run stops, since a hosted runner saw
|
|
501
|
+
Docker Hub reset the connection once; the last failure's own line is what the error names.
|
|
502
|
+
- **A Python checkout whose ignored caches exist no longer fails to stage.** The scratch
|
|
503
|
+
index named `__pycache__`, `.pytest_cache`, `.mypy_cache` and `.ruff_cache` as exclude
|
|
504
|
+
pathspecs on `git add -A`, which git refuses with "paths are ignored" (exit 1) as soon as one
|
|
505
|
+
of them exists and is gitignored, the ordinary state after one test run; the verifier then
|
|
506
|
+
told the reader the repository "is not a git working tree". Everything is staged and the
|
|
507
|
+
caches are removed from the index afterwards. Found by the README-only python simulation.
|
|
508
|
+
- **A git failure inside a repository quotes git's own last line** rather than the command
|
|
509
|
+
line, and no longer sends the reader to `git init` unless git said the directory is not a
|
|
510
|
+
repository.
|
|
511
|
+
- **A uv project without a synced environment is a missing prerequisite, not four failed
|
|
512
|
+
checks.** `uv run --no-sync` exits at once without a `.venv`; `check` now names
|
|
513
|
+
`uv sync --locked` as the remedy and exits 4, as it does for a missing `node_modules`.
|
|
514
|
+
|
|
515
|
+
### Changed
|
|
516
|
+
|
|
517
|
+
- Both binaries exit 2 for a command line they cannot read, as the exit code taxonomy said.
|
|
518
|
+
- The container's scratch mount is executable, so a fetched package manager can run from it.
|
|
519
|
+
- The README leads with the verifier; the coding agent's page is `docs/agent.md`.
|
|
520
|
+
|
|
521
|
+
## 14.3.0 - 2026-09-30
|
|
522
|
+
|
|
523
|
+
The coding agent, `swarm-orchestrator`, released for the first time since the verifier-first
|
|
524
|
+
work began. The `swarm` binary shares its verifier with `swarm-verify`, so every change published
|
|
525
|
+
for `swarm-verify` 1.0.0 through 1.3.0 above is in this release too. What follows is what the
|
|
526
|
+
agent itself gained; the verifier stays the primary product and the agent its advanced mode.
|
|
527
|
+
|
|
528
|
+
### Added
|
|
529
|
+
|
|
530
|
+
- **The verifier's commands in the `swarm` binary**: `swarm check`, `verdict`, `hook`, `mcp`,
|
|
531
|
+
`pre-commit` and `action`, as published for `swarm-verify` and documented there.
|
|
532
|
+
- **Requirement-level challenges on the agent's preset path.** `--challenges off|report|required`
|
|
533
|
+
(with `--preset` and `--goal-contract`) runs the base control, mechanical mutations of the
|
|
534
|
+
changed lines witnessed by the repository's suite, and the contract's sealed fixtures against
|
|
535
|
+
the agent's own change; `required` refuses a run whose checks demonstrated no detection. The
|
|
536
|
+
challenge conclusions are stated the same way in the terminal, the summary and the comment.
|
|
537
|
+
- **Check strengthening and repair.** `--strengthen` (with `--strengthen-rounds` and
|
|
538
|
+
`--strengthen-per-requirement`, which can only lower the defaults of two rounds and one check
|
|
539
|
+
per requirement) answers a witnessed gap: the model proposes one additive check, the harness
|
|
540
|
+
admits it only where it rejects the counterexample and accepts every sealed reference, the
|
|
541
|
+
admitted checks revise the contract with their lineage, and the implementation is repaired
|
|
542
|
+
under the same seal with a bounded brief. The JSON result carries `strengthening` (rounds,
|
|
543
|
+
admitted checks, why it stopped, contract digest). Nothing is asked of the model before the
|
|
544
|
+
criteria are sealed or after cancellation; a run killed mid-admission resumes with that
|
|
545
|
+
admission named once and never repeated. The bundle's verifier re-derives every admission and
|
|
546
|
+
revision offline.
|
|
547
|
+
|
|
548
|
+
### Fixed
|
|
549
|
+
|
|
550
|
+
- **Check strengthening reads the token budget before every proposal, and asks for no more than
|
|
551
|
+
is left.** The controller checked the budget once at the start of a round, then asked one
|
|
552
|
+
proposal per requirement with a floor of 256 output tokens: with 128 tokens left it asked for
|
|
553
|
+
256, and after that call it asked the next requirement's proposal against nothing. The budget,
|
|
554
|
+
the task's allowance less every recorded model call, is now read before each proposal and
|
|
555
|
+
before the repair; a proposal is asked for at most what is left, never a floor; and a spent
|
|
556
|
+
budget stops the loop where it stands, with the reason recorded (`budget-spent`) and any check
|
|
557
|
+
admitted before the stop kept on the revised contract for the final verification. Usage a
|
|
558
|
+
provider did not report still spends the whole budget, and an uncapped run is unchanged. The
|
|
559
|
+
cap is on requested output; a provider's actual usage, input included, is what the chain
|
|
560
|
+
records and the next check reads. Found by review before the feature was published; no
|
|
561
|
+
released version carried the defect.
|
|
562
|
+
- **Dispatched workers no longer break each other's worktree add**: one worktree command runs at
|
|
563
|
+
a time against a repository. An unrelated worker counts as running from the moment the
|
|
564
|
+
controller admits it, not from its first model call.
|
|
565
|
+
- **The Claude Code hook routes a test command piped through `tail`, `head` or `grep`** (such
|
|
566
|
+
as `npm test 2>&1 | tail -5`) through the verifier and keeps the filters, so the run is
|
|
567
|
+
recorded rather than left alone; any other pipeline or shell syntax is still untouched.
|
|
568
|
+
- **The goal run's final verification is bound to the worker's own recorded diff**, held by a
|
|
569
|
+
regression test.
|
|
570
|
+
|
|
571
|
+
## 14.2.0 - 2026-09-27
|
|
572
|
+
|
|
573
|
+
### Fixed
|
|
574
|
+
|
|
575
|
+
- Rejected acceptance authority for candidate-controlled Playwright JSON. Sealed browser
|
|
576
|
+
instruments use harness configuration, immutable image dependencies and exact test identities.
|
|
577
|
+
- Retained unavailable package checks through sealing, final assessment and reviewer reports,
|
|
578
|
+
separating absent optional tools from unavailable required checks.
|
|
579
|
+
- Provisioned Chromium and the isolated browser runtime in clean Linux gate workflows;
|
|
580
|
+
nightly failure notifications no longer require an optional repository label.
|
|
581
|
+
- Reopened the prior completion claim after the independent audit. Corrective delivery and
|
|
582
|
+
release status are tracked in [audit corrections](docs/upgrade-audit-corrections.md).
|
|
583
|
+
|
|
584
|
+
### Added
|
|
585
|
+
|
|
586
|
+
- Shared model-free branch/PR snapshot verification, reviewer Markdown and versioned JSON source
|
|
587
|
+
identities alongside patch mode. Standalone source tarballs build and install without providers.
|
|
588
|
+
- Declared npm/pnpm and uv/existing-venv initialization, explicit package scopes, structured
|
|
589
|
+
Vitest/pytest outcomes, and sealed CLI, local HTTP and optional Playwright behavior checks.
|
|
590
|
+
- Bugfix, refactor and dependency-upgrade presets on the existing engine, with base controls,
|
|
591
|
+
narrow manifest authorization, locked preparation and recorded installed versions.
|
|
592
|
+
- One explicitly authorized capability escalation with deterministic failure classification,
|
|
593
|
+
original budget limits and recovery reconciliation. A configured cloud key grants no consent.
|
|
594
|
+
- Trusted-source Action infrastructure and separate good/bad behavioral workflow controls.
|
|
595
|
+
Source delivery and package publication remain separate; exact validation is tracked in
|
|
596
|
+
[the upgrade ledger](docs/upgrade-completion.md).
|
|
597
|
+
|
|
598
|
+
- **An approval mode, asked once per workspace.** The first terminal run asks whether commands
|
|
599
|
+
off the shell allowlist may be approved automatically and writes the answer to `swarm.toml`
|
|
600
|
+
as `[tools] approval`; `--approve ask|auto` and `SWARM_APPROVAL` override it. Under `auto` the
|
|
601
|
+
run answers an allowlist prompt itself and records it as pre-approved; a derivation-heuristic
|
|
602
|
+
prompt, the injection defence, asks under either mode. Every prompt gains `a`, always: the
|
|
603
|
+
call runs and its off-list programs are allowed for the rest of that run, recorded as a
|
|
604
|
+
`run-allowance` ledger record. The screen's header shows the mode.
|
|
605
|
+
- **The default model is the best served local model for this hardware.** With nothing pinned
|
|
606
|
+
and no calibration, a run discovers the local backends, ranks what they serve by the
|
|
607
|
+
shortlist's tier for the probed hardware, prints the choice and its reason before the session
|
|
608
|
+
opens, and records it as a `model-default` ledger record. A frontier key is used only where
|
|
609
|
+
nothing local is served; with neither, the run stops and names the remedies instead of
|
|
610
|
+
defaulting to a provider it has no key for.
|
|
611
|
+
- **A preflight card, and a screen that says what became of each step.** Before the screen goes
|
|
612
|
+
up, `swarm run` and `swarm session` print four lines to stderr naming the repository and base
|
|
613
|
+
commit, the manifest, the model with the reason it was chosen, and the approval mode. On the
|
|
614
|
+
screen, the header's second line reads elapsed, step, tokens, attempt, ratchet, model,
|
|
615
|
+
approval and workspace, and stays at every width; each timeline row starts with a status
|
|
616
|
+
mark and the clock time it landed; the gate strip counts passed, failed and not-applicable.
|
|
617
|
+
A finished run ends on a finish card: the verdict, duration, steps, tokens and cost, then the
|
|
618
|
+
review page and the bundle as rows a terminal that understands OSC 8 shows as clickable
|
|
619
|
+
links. Marks fall back to ASCII where the locale is not UTF-8. The plain-line stream that CI
|
|
620
|
+
and pipes read is byte-identical to before.
|
|
621
|
+
- **`swarm-verify`, the verification path as its own package.** `packages/swarm-verify` builds a
|
|
622
|
+
binary carrying `verify`, `ci` and `gates` from the same modules `swarm` runs under those names,
|
|
623
|
+
parsed by the same parser, so an invocation reads the same through either. It carries no
|
|
624
|
+
provider, worker or screen module and none of the agent's run assembly: a test walks its import
|
|
625
|
+
closure and the build refuses to emit a crossing. A test verifies a committed bundle through
|
|
626
|
+
both binaries and compares the bytes. Version 0.2.0 has a separate release workflow; the packaged check
|
|
627
|
+
packs it, installs it beside the full CLI, and runs the tamper demo through it.
|
|
628
|
+
- **An agent can record a file as temporary, and is held to removing it.** `declare_file_set`
|
|
629
|
+
and `amend_file_set` take `temporary`: paths created only to investigate, such as a probe
|
|
630
|
+
script. The blocking `file-set` gate fails while one is still in the change and names it. An
|
|
631
|
+
amendment can keep one on purpose with `retain`, and its reason then shows on the ledger, in the
|
|
632
|
+
reviewer's claim and in the gate's output on every pass. Nothing is deleted behind the model's
|
|
633
|
+
back and nothing reads a filename. Two repairs in the reach-pressure run left a scratch script
|
|
634
|
+
in their final patch, and membership alone had passed both.
|
|
635
|
+
- **Derived evidence packs losslessly inside the tree.** `scripts/evidence-pack.mjs` packs tracked
|
|
636
|
+
review pages and run transcripts under a root into one `utf8-file-map-brotli` archive with a
|
|
637
|
+
digest for every original, removes originals only after the written archive has been unpacked
|
|
638
|
+
and compared, and `npm run checks` verifies every committed pack. Ledgers, DAGs, manifests and
|
|
639
|
+
verifiers can never be packed. The tracked tree went from 99.8 MB to about 90.5 MB with every
|
|
640
|
+
cited bundle still verifying, and the weight check now also requires 6 MB of headroom so the next
|
|
641
|
+
experiment's evidence has somewhere to go.
|
|
642
|
+
- **A repair is read as what it did to the verifier's findings.** Experiment rows record, per
|
|
643
|
+
invocation, one of `patch-unchanged`, `findings-identical`, `findings-moved`, `findings-shrank`,
|
|
644
|
+
`findings-grew` or `satisfied`, with both finding sets, both patch digests and the files that
|
|
645
|
+
entered or left the patch, plus the same from the fork to the final patch. No score is computed.
|
|
646
|
+
Generation 3's nine "repairs exhausted" split into six unchanged patches, two that grew the
|
|
647
|
+
findings by leaving a scratch file, and one that changed bytes and no finding.
|
|
648
|
+
|
|
649
|
+
### Fixed
|
|
650
|
+
|
|
651
|
+
- **Reach reports `unmeasured`, not `reached`, for a change it could not measure at all.** A
|
|
652
|
+
change made only of documentation, types and its own tests skipped every file, left nothing
|
|
653
|
+
unreached and read as a measurement. Certification treats the two alike; a reader does not.
|
|
654
|
+
The verdict now carries every file reach set aside with its reason (`setAsideByReach`) and
|
|
655
|
+
`swarm ci` prints them. One path rule serves reach, the mutant planner, the patch metrics and
|
|
656
|
+
the PR miner, which had each spelled it separately: the miner still read a tsd type test as
|
|
657
|
+
source. tsd's `test-d/` directory and the `_test` suffix are recognized, and scratch scripts and
|
|
658
|
+
JavaScript tool configuration stay judged.
|
|
659
|
+
- **Three campaign runners asked whether the model lists, not whether it generates.** A wedged
|
|
660
|
+
local server answers `/models` and completes nothing. `pr-task-pass` probed `/models`, and only
|
|
661
|
+
when a patch was empty, so a partial patch left by a server that died was judged as the model's;
|
|
662
|
+
the pilot campaign's health effect returned the literal `healthy: true`; `run-campaign` had no
|
|
663
|
+
probe. All three ask the configured model for a bounded completion after every invocation. The
|
|
664
|
+
probes are `endpointListsModels` and `endpointGenerates` in a module of their own, the second
|
|
665
|
+
names why it failed, and `pr-task-pass` keeps an infrastructure attempt apart from `runs`, where
|
|
666
|
+
it used to mark its task done and get re-judged.
|
|
667
|
+
- **A failed model call records whether the harness cancelled it.** A call cut off at the wall
|
|
668
|
+
budget and a provider that raised were both `call-failed`. Every unknown-usage invocation of the
|
|
669
|
+
reach-pressure run was the first kind, and nothing on the ledger said so.
|
|
670
|
+
- **Unknown usage is no longer added in as zero.** The experiment analysis summed a null model-call
|
|
671
|
+
count as 0; arm scoring priced a crashed run at $0 and printed dollars per accepted patch off the
|
|
672
|
+
sum; calibration divided all tokens by all time, so a model with one call cut off measured
|
|
673
|
+
slower than it is. A total is a number only where every part was measured, and the known part
|
|
674
|
+
is kept under its own name. The core loop's token total is unchanged and now travels with
|
|
675
|
+
`callsWithUnknownUsage`.
|
|
676
|
+
- **The experiment analyzer cannot overwrite what a run published.** `analyze` wrote its summary
|
|
677
|
+
and page in place. It now refuses where the bytes differ and writes to `--out` with a
|
|
678
|
+
`derivation.json` naming the acquisition identity, the identities it was derived with, and every
|
|
679
|
+
value changed, added or removed. `run` and `score` refuse to write beside rows of another
|
|
680
|
+
protocol identity, which only `analyze` had checked, and identity is read before a row is
|
|
681
|
+
parsed. Generation 3's published summary re-derives with no value changed.
|
|
682
|
+
- **The router considers every model the table has measured, not only the last sweep's pair.**
|
|
683
|
+
The calibration pick's candidates were the models the last sweep ran together, so a model with
|
|
684
|
+
the best evidence of all on a class was never in the running when a later sweep happened not
|
|
685
|
+
to include it: on one machine qwen3.6 held the best edit share across two sweeps and the router
|
|
686
|
+
chose between gemma4 and mistral. The candidates are now the pick's own plus every model the
|
|
687
|
+
competency table has measured on the task's class, on the same golden set, at or above the
|
|
688
|
+
floor, restricted as before to what the backend serves.
|
|
689
|
+
- **A turn cut off at the output cap is not a completion.** A live run's only turn was the
|
|
690
|
+
marker `<channel|>` repeated to the 8192-token cap around a fragment of a plan, with no tool
|
|
691
|
+
called; the loop read the cut-off text as the model's account of finishing, the gates ran
|
|
692
|
+
green over an unchanged workspace, and the run ended "work accepted" with nothing written.
|
|
693
|
+
Two of five samples of the same request against gemma4:31b behind Ollama spiral the same way.
|
|
694
|
+
A turn cut off at the cap before it called a tool is now sampled again, its text never becomes
|
|
695
|
+
the plan or the claim, and a run whose every sample is cut off stops as `output-cap`. A stream
|
|
696
|
+
that repeats one short unit 96 times in a row is cut off there and sampled again, rather than
|
|
697
|
+
running minutes to the cap. The finish card over an unchanged workspace says nothing was done
|
|
698
|
+
instead of repeating the assessment, and the header's elapsed counter stops when the card
|
|
699
|
+
goes up.
|
|
700
|
+
- **A run stops before the session where it could never go green.** A directory that is not a
|
|
701
|
+
repository, a `--base` that does not resolve, and a repository with no manifest each used to be
|
|
702
|
+
found out after the model had worked: eight steps in one case, three attempts and 112,000
|
|
703
|
+
tokens in another, then a first gate saying "add the manifest". `run` and `session` now check
|
|
704
|
+
the base commit and the manifest first. With no manifest, `swarm` on a terminal offers to add
|
|
705
|
+
a Node harness (`package.json` running `node --test`, and `.gitignore`) and commit it; off a
|
|
706
|
+
terminal, or declined, it stops with the remedy named.
|
|
707
|
+
- **An interpreter cache is not a change.** Running a Python test writes `__pycache__`, and the
|
|
708
|
+
file-set gate charged that as an edit outside the declared set, after which the ratchet
|
|
709
|
+
rejected the attempt for a gate that had passed before and discarded the work. `__pycache__`,
|
|
710
|
+
`.pytest_cache`, `.mypy_cache` and `.ruff_cache` are excluded from the change set by name.
|
|
711
|
+
- **A stopped run says what stopped it.** A cancellation during a model call reported "model
|
|
712
|
+
error: This operation was aborted", the transport's words. The signal now carries the reason
|
|
713
|
+
(cancelled from the keyboard, or the run's wall budget spent) and the loop reports it.
|
|
714
|
+
- **A refused assessment names only what refused.** The status line read "work refused: work
|
|
715
|
+
refused: required checks passed, lifecycle interrupted, ..." beside four failed gates. It now
|
|
716
|
+
reads, for example, "work refused: the gates settled escalated; the run was cancelled".
|
|
717
|
+
- **The macOS keychain is asked whether a default keychain exists before a signing key is
|
|
718
|
+
added.** `security add-generic-password` with no default keychain raises a dialog and blocks
|
|
719
|
+
until the store kills it; the probe fails cleanly instead and the run signs with a per-run key.
|
|
720
|
+
|
|
721
|
+
### Measured
|
|
722
|
+
|
|
723
|
+
- **Enforcing changed-line reach after visible acceptance changed no held-back verdict in 79
|
|
724
|
+
mined tasks.** A pre-registered shared-prefix experiment ran each task until the visible half of
|
|
725
|
+
its oracle first accepted, took that patch as the control, and forked a reach condition from the
|
|
726
|
+
same workspace that was told which added lines the oracle never executed. Thirteen tasks reached
|
|
727
|
+
visible acceptance, reach triggered on nine, no repair satisfied it, and the held-back half
|
|
728
|
+
agreed on every pair: 12 pass both, 67 fail both, zero discordant, exact McNemar p = 1, paired
|
|
729
|
+
difference 0.0 points, 95% CI [-4.0, +4.0]. Three repairs changed bytes, none narrowed the
|
|
730
|
+
implementation, two left scratch files behind. Six of the nine refusals named a tsd type-test
|
|
731
|
+
file no runner executes. The protocol, rows, patches and a report that re-derives from the rows
|
|
732
|
+
are in [`docs/evidence/2026-09-17/reach-pressure-experiment/`](docs/evidence/2026-09-17/reach-pressure-experiment/report.md).
|
|
733
|
+
Two earlier generations were stopped on instrument defects and are kept beside it. The instrument
|
|
734
|
+
defects it exposed, and what closed each without touching a row, are in
|
|
735
|
+
[`docs/evidence/2026-09-18/reach-pressure-hardening/`](docs/evidence/2026-09-18/reach-pressure-hardening/README.md).
|
|
736
|
+
|
|
737
|
+
### Changed
|
|
738
|
+
|
|
739
|
+
- **The verify-only commands are command definition data.** `verify`, `ci` and `gates` are marked
|
|
740
|
+
as needing no model, and a test runs each through the real CLI with no provider key and the
|
|
741
|
+
local endpoint pinned to a closed port. `docs/verify-only.md` walks all three through on
|
|
742
|
+
committed artifacts, with every transcript captured from the command it sits under.
|
|
743
|
+
|
|
744
|
+
- **Node 22 runs the tool; Node 24 is needed only for the coverage measurement.** The whole CLI
|
|
745
|
+
refused to start below Node 24 because the changed-line coverage arm spawns node's test runner
|
|
746
|
+
with `--test-isolation=process`, which Node 22 rejects. Now `engines.node` is `>=22`, every
|
|
747
|
+
command runs there, and on a Node below 24 the tests gate runs the project's own test command
|
|
748
|
+
while the coverage arm reports `unmeasured` with the reason named in the gate-run record and in
|
|
749
|
+
the ratchet's abstention. Unmeasured never renders as a pass, so a change touching covered
|
|
750
|
+
lines fails the ratchet on that runtime rather than passing quietly. `swarm doctor` reports
|
|
751
|
+
which Node it found and what that disables.
|
|
752
|
+
|
|
3
753
|
## 14.1.0 - 2026-09-14
|
|
4
754
|
|
|
5
755
|
### Added
|