rapier-runtime 0.6.1__tar.gz → 0.6.2__tar.gz
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.
- rapier_runtime-0.6.2/CHANGELOG.md +208 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/PKG-INFO +5 -3
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/README.md +4 -2
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/STATUS.md +15 -1
- rapier_runtime-0.6.2/docs/chatlogs/202610162128.reconcile-false-alarms-0.6.1.md +91 -0
- rapier_runtime-0.6.2/docs/chatlogs/202611141130.inflight.accountable-agents-gaps.md +81 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/mcp-server-scope.md +12 -0
- rapier_runtime-0.6.2/docs/versioning.md +68 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/pyproject.toml +1 -1
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/cli.py +39 -6
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/mcp/tools.py +21 -2
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/onboarding.py +60 -0
- rapier_runtime-0.6.2/src/rapier/operator_policy.py +249 -0
- rapier_runtime-0.6.2/src/rapier/pipeline.py +332 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/echo.py +2 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/anchored_fix.py +2 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/author.py +2 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/compose.py +396 -12
- rapier_runtime-0.6.2/tests/test_correctness_outcome.py +303 -0
- rapier_runtime-0.6.2/tests/test_declared_vs_ran.py +240 -0
- rapier_runtime-0.6.2/tests/test_final_state.py +87 -0
- rapier_runtime-0.6.2/tests/test_method_version.py +68 -0
- rapier_runtime-0.6.2/tests/test_operator_minimum.py +264 -0
- rapier_runtime-0.6.2/tests/test_require_independent.py +111 -0
- rapier_runtime-0.6.2/tests/test_review_outcome.py +116 -0
- rapier_runtime-0.6.1/CHANGELOG.md +0 -104
- rapier_runtime-0.6.1/src/rapier/pipeline.py +0 -160
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.claude/scripts/loom-deploy-nonprod.sh +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.claude/scripts/loom-deploy-prod.sh +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.claude/scripts/loom-env-check.sh +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.claude/scripts/loom-state-docs.sh +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.githooks/pre-commit +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.github/workflows/secret-scan.yml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.gitignore +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.gitleaks.toml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.loom/audits/smuggled-virtue.done +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.loom/launcher.conf +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/.loom/project.json +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/LICENSE +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/SECURITY.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/chatlogs/.gitkeep +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/chatlogs/202607301413.checkpoint.handoff-cut-0-5-0-to-pypi.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/chatlogs/20260802-explainability-reminder.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/chatlogs/202610162038.five-releases-defaults-report-mcp2.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/docs/threat-model.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/manifests/echo.yaml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/manifests/sparring.frame.yaml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/manifests/sparring.full.yaml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/manifests/sparring.proposer.yaml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/manifests/sparring.spar.yaml +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/site/README.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/site/coming-soon.html +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/site/index.html +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/site/rapier-logo.png +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/_json.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/convergence.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/envelope.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/ledger.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/manifest.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/mcp/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/mcp/server.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/models.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/presets.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/secrets.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stage.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/frame.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/proposer/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/proposer/phase_stages.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/proposer/phases.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/proposer/traceability_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/reconcile.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/_binding.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/_extract.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/citation_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/cross_review.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/stages/resolver/definitiveness_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/__init__.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_bootstrap.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_llm_shim.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/PROVENANCE.md +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/cite_check.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/lib_llm.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/spar_cross_review.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/spar_definitiveness_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/spar_verify_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/_vendor/verify_grounding.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/rider_record.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/src/rapier/verify/service.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_cite_check_evidence_union.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_cli.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_convergence.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_envelope.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_extract_json.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_frame_stage.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_full_ceremony.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_manifest.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_mcp.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_mcp_resources.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_models_vendors.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_onboarding.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_persistence_default.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_pipeline.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_policy.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_proposer_g2.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_proposer_stages.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_proposer_traceability_gate.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_reconcile.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_resolver_stages.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_rider_record.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_secrets.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_single_vendor_report.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_vendor_policy_v4.py +0 -0
- {rapier_runtime-0.6.1 → rapier_runtime-0.6.2}/tests/test_verify_service.py +0 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to `rapier-runtime`. Earlier releases are summarized in
|
|
4
|
+
[`docs/STATUS.md`](docs/STATUS.md) and on the
|
|
5
|
+
[Releases](https://github.com/muddyone/rapier-runtime/releases) page.
|
|
6
|
+
|
|
7
|
+
## 0.6.2 — 2026-11-14
|
|
8
|
+
|
|
9
|
+
### Added: every run names its final state
|
|
10
|
+
|
|
11
|
+
The report's BOTTOM LINE opens with a final state, using the six names from the
|
|
12
|
+
Accountable Agents paper, and the same value is in the trust rider, `ceremony.json`
|
|
13
|
+
(`final_state`, `final_state_next`) and the MCP result:
|
|
14
|
+
|
|
15
|
+
- `act`: the advice cleared the checks that ran, and the report names them and any
|
|
16
|
+
that were switched off. Rapier only advises; acting on it is yours.
|
|
17
|
+
- `block`: a specific failed the correctness check, or a reference was refuted.
|
|
18
|
+
- `defer`: a declared check or the challenge review did not run on the answer
|
|
19
|
+
(crashed, no key, a reviewer error, or ran before the answer was written), or
|
|
20
|
+
the operator requires an independent review and none happened. A control that
|
|
21
|
+
did not run decided nothing, so this is never `block` and never `act`.
|
|
22
|
+
- `escalate`: a specific reads ambiguously between fact and estimate; your call.
|
|
23
|
+
- `non-decision`: the Proposer hit its round cap without agreeing on one option.
|
|
24
|
+
The report says so at the top, and in the Proposer report. The Resolver still
|
|
25
|
+
tests the strongest candidate, but choosing between the options is yours.
|
|
26
|
+
- `refuse`: the run was refused before it started (operator minimum or
|
|
27
|
+
independence requirement).
|
|
28
|
+
|
|
29
|
+
A citation check that was switched off or never declared doesn't change the
|
|
30
|
+
state, but `act` says it didn't run. A review that failed at run time (the
|
|
31
|
+
reviewer is fail-soft) is reported as not run, never as an independent challenge.
|
|
32
|
+
|
|
33
|
+
### Added: the operator can require an independent review
|
|
34
|
+
|
|
35
|
+
`"require_independent": true` in the operator policy file refuses any review
|
|
36
|
+
ceremony (spar, sparring, proposer, or a custom manifest with a review or
|
|
37
|
+
Proposer stage) when no second vendor is available. Without it, a single-vendor
|
|
38
|
+
run goes ahead and the report says the review was not independent, as before.
|
|
39
|
+
Only the operator can set this: there is no tool argument or environment
|
|
40
|
+
variable for it. The refusal names the policy file and whether it is out of the
|
|
41
|
+
caller's reach (MCP: `refused_by: "operator_require_independent"`; CLI: exit 2).
|
|
42
|
+
`rapier doctor` shows the setting and warns when only one vendor is configured.
|
|
43
|
+
|
|
44
|
+
### Added: a hash of the method that ran
|
|
45
|
+
|
|
46
|
+
`ceremony.json` gains `method_hash` and `method_resolved_hash` (plus
|
|
47
|
+
`rapier_version`), and THE RECORD shows both, shortened. `method_hash` covers
|
|
48
|
+
the Rapier version, every stage in order with its config and roles, and the
|
|
49
|
+
vendor policy. `method_resolved_hash` is the same after vendor substitution, so
|
|
50
|
+
a run on different keys shows up as the same method on different vendors. To
|
|
51
|
+
check for drift, compare runs on the same inputs under the same `method_hash`.
|
|
52
|
+
|
|
53
|
+
### Added: what the method declared, compared with what ran
|
|
54
|
+
|
|
55
|
+
- **WHAT RAN**, a new report section, lists every stage the method declared
|
|
56
|
+
and what happened to it: ran, FAILED (the run went on without it), skipped
|
|
57
|
+
(with the stage's reason) or not reached (cancelled). The pipeline records
|
|
58
|
+
this itself, so a stage that writes no trace still appears. Also in the trust
|
|
59
|
+
rider (`stages_run`) and `ceremony.json` (`stages_declared`,
|
|
60
|
+
`stages_failed_soft`, `stages_skipped`).
|
|
61
|
+
- **Checked before a run.** A pipeline that writes a report but declares no
|
|
62
|
+
correctness gate, or puts a gate after `compose` where its result can't reach
|
|
63
|
+
the report, gets a warning in the log, the report and `ceremony.json`
|
|
64
|
+
(`manifest_warnings`). `rapier doctor` checks every built-in ceremony and
|
|
65
|
+
shows the operator minimum. `rapier doctor --manifest m.yaml` checks a custom
|
|
66
|
+
manifest and exits 1 if it warns or would be refused.
|
|
67
|
+
- **Custom manifests meet the operator minimum.** `rapier run --manifest` with
|
|
68
|
+
no citation gate before `compose` counts as `verify=off` and is refused under
|
|
69
|
+
a `gate` minimum.
|
|
70
|
+
|
|
71
|
+
### Added: an operator minimum for the checks, which the caller cannot lower
|
|
72
|
+
|
|
73
|
+
Over MCP the agent whose answer is being checked chose `verify`, so it could
|
|
74
|
+
switch the citation check off. The operator can now set a floor:
|
|
75
|
+
|
|
76
|
+
- **`/etc/rapier/policy.json`** (`%PROGRAMDATA%\rapier\policy.json` on
|
|
77
|
+
Windows), `{"min_verify": "gate"}`. The path is fixed, not taken from the
|
|
78
|
+
environment, so a caller cannot point Rapier at a different file. The report
|
|
79
|
+
calls the minimum out of the calling agent's reach only when Rapier is not
|
|
80
|
+
running as root and neither owns nor can write the file or any folder above
|
|
81
|
+
it (for example, owned by root, readable by the user that runs Rapier). A
|
|
82
|
+
file that can't be checked, read or parsed fails closed.
|
|
83
|
+
- **`RAPIER_MIN_VERIFY`** also sets a floor, but whoever launches the process
|
|
84
|
+
controls its environment, so the report always calls it within the caller's
|
|
85
|
+
reach.
|
|
86
|
+
- A request below the floor is **refused**, with an error naming the floor and
|
|
87
|
+
its source (MCP: `ok: false`, `refused_by: "operator_minimum"`; CLI: exit 2).
|
|
88
|
+
A policy file that can't be read fails closed. Levels: `off` < `gate` ≤
|
|
89
|
+
`round`.
|
|
90
|
+
- **The report says who set the level:** "switched off, by caller (MCP tool
|
|
91
|
+
argument)", the default or the `--verify` flag, and whether an operator
|
|
92
|
+
minimum stood behind it. `ceremony.json` gains `verify_set_by`,
|
|
93
|
+
`verify_minimum`, `verify_minimum_source` and `verify_minimum_external`.
|
|
94
|
+
|
|
95
|
+
### Fixed: a check that did not run no longer reads like one that found nothing
|
|
96
|
+
|
|
97
|
+
The report used one sentence for "the correctness check found no specifics" and
|
|
98
|
+
"the checker was unavailable". With `verify=off` the registry section said the
|
|
99
|
+
answer "cited nothing externally checkable", though nothing had been looked up.
|
|
100
|
+
|
|
101
|
+
- **Three outcomes, kept apart**, for both the correctness check and the
|
|
102
|
+
citation check: `ran`, `nothing-to-check`, and `did-not-run: <reason>`. A
|
|
103
|
+
crash (caught fail-soft), a missing key, `verify=off`, and a check left out of
|
|
104
|
+
the pipeline are all `did-not-run`, and the report says it is not a pass.
|
|
105
|
+
- **A run with no hard specifics** now says the check found nothing to check,
|
|
106
|
+
instead of "every hard specific it states traces to a fact you gave".
|
|
107
|
+
- **Recorded everywhere the reader or a tool looks:** the report, the trust
|
|
108
|
+
rider (`correctness_check`, `citation_check`), `ceremony.json`
|
|
109
|
+
(`*_check` and `*_check_reason`) and the MCP result.
|
|
110
|
+
|
|
111
|
+
## 0.6.1 — 2026-10-16
|
|
112
|
+
|
|
113
|
+
### Fixed: "WHETHER THE NUMBERS ADD UP" no longer flags correct formulas
|
|
114
|
+
|
|
115
|
+
The arithmetic check summed the numbers in any stated result, so a correct
|
|
116
|
+
standard error, interval, sample size or difference was reported as wrong. In
|
|
117
|
+
a statistics-heavy answer that was five false alarms out of five.
|
|
118
|
+
|
|
119
|
+
- **Formulas are worked out as written.** Roots, powers, quotients and ±
|
|
120
|
+
bounds are evaluated in code, and a mismatch shows the formula it evaluated.
|
|
121
|
+
Differences are checked as differences.
|
|
122
|
+
- **"Not checked" instead of a guess.** Where the operation can't be recovered
|
|
123
|
+
from the text, or a "total" turns out to be a formula, the figure is counted
|
|
124
|
+
as not checked, never as a mismatch. The section says how many there were.
|
|
125
|
+
- **Small figures are checked properly.** The agreement margin used to be
|
|
126
|
+
measured against 1, so any figure under 1 agreed with almost anything. It is
|
|
127
|
+
now 0.5% of the figures themselves, or half a unit of the last digit the
|
|
128
|
+
text shows (`0.120` allows ±0.0005; `6×10⁻⁵` allows ±5×10⁻⁶).
|
|
129
|
+
|
|
130
|
+
## 0.6.0 — 2026-10-16
|
|
131
|
+
|
|
132
|
+
### Changed: the MCP server now runs on the mcp 2.x SDK
|
|
133
|
+
|
|
134
|
+
The `[mcp]` extra now requires `mcp>=2.3,<3` (it was `>=1.2,<2`), and the
|
|
135
|
+
server is built on the SDK's `MCPServer`. Tools, their results and the run
|
|
136
|
+
resources behave as before. Two visible differences:
|
|
137
|
+
|
|
138
|
+
- **Progress shows the stage.** Each stage's progress update now carries the
|
|
139
|
+
stage name as its message. mcp 2.x sends log messages only to clients that
|
|
140
|
+
ask for them, so the progress message is what every client will show.
|
|
141
|
+
- **`pip install -U "rapier-runtime[mcp]"` upgrades the SDK.** An environment
|
|
142
|
+
pinned to mcp 1.x will be moved to 2.x. If a 1.x SDK is installed anyway,
|
|
143
|
+
`rapier mcp` says so and gives the command that fixes it.
|
|
144
|
+
|
|
145
|
+
## 0.5.3 — 2026-10-16
|
|
146
|
+
|
|
147
|
+
### Added: saved runs as MCP resources
|
|
148
|
+
|
|
149
|
+
MCP clients can now browse saved runs instead of calling tools:
|
|
150
|
+
|
|
151
|
+
- `rapier://runs`: every saved run, newest first, with its kind, topic and
|
|
152
|
+
verdict (JSON).
|
|
153
|
+
- `rapier://runs/{run_id}`: a run's report, as the CLI printed it (plain text).
|
|
154
|
+
- `rapier://runs/{run_id}/record`: a run's full record, redacted when it was
|
|
155
|
+
saved (JSON).
|
|
156
|
+
|
|
157
|
+
Each saved run also appears in the client's resource list, titled by kind and
|
|
158
|
+
topic, including runs saved after the server started. The `list_runs` and
|
|
159
|
+
`get_run` tools still work.
|
|
160
|
+
|
|
161
|
+
### Fixed: `rapier mcp` failed on a fresh install
|
|
162
|
+
|
|
163
|
+
The `[mcp]` extra allowed any `mcp>=1.2`, so a new install got the mcp 2.x SDK,
|
|
164
|
+
which renamed the server API this version uses. `rapier mcp` then exited with a
|
|
165
|
+
message telling you to install the extra you already had. The extra is now
|
|
166
|
+
capped at `mcp<2`, and if a 2.x SDK is present anyway, `rapier mcp` says so and
|
|
167
|
+
gives the command that fixes it.
|
|
168
|
+
|
|
169
|
+
## 0.5.2 — 2026-10-16
|
|
170
|
+
|
|
171
|
+
### Fixed: the report no longer calls a same-vendor review independent
|
|
172
|
+
|
|
173
|
+
Found on a live run with a single vendor's key, where the reviewer and the
|
|
174
|
+
author were the same model:
|
|
175
|
+
|
|
176
|
+
- **The report contradicted itself.** "Already fixed under challenge" said
|
|
177
|
+
"an independent, different-vendor reviewer raised each of these," and the
|
|
178
|
+
registry section pointed to "the cross-vendor challenge," while "How much to
|
|
179
|
+
trust this" correctly said the review was not independent. Every section
|
|
180
|
+
now says what actually happened; a cross-vendor run reads as before.
|
|
181
|
+
- **The progress warning blamed the wrong key.** It said "OPENAI_API_KEY
|
|
182
|
+
absent; falling back to a Claude reviewer" when the OpenAI key was set and
|
|
183
|
+
no Claude model was used. It now names the vendor that ran the review.
|
|
184
|
+
- **Arithmetic printed as raw LaTeX.** Math the model wrote as `\( H \times
|
|
185
|
+
0.60 \)` now reads `H × 0.60` in the report. Only text inside `\( \)` or
|
|
186
|
+
`\[ \]` is rewritten.
|
|
187
|
+
|
|
188
|
+
## 0.5.1 — 2026-10-16
|
|
189
|
+
|
|
190
|
+
### Changed: default models for five OpenAI-compatible vendors
|
|
191
|
+
|
|
192
|
+
Five built-in defaults named models that a vendor has retired or is retiring. If
|
|
193
|
+
you relied on a vendor's default (no `model:` in your manifest and no
|
|
194
|
+
`RAPIER_MODEL_<VENDOR>` set), **your runs now use a different model.** To keep
|
|
195
|
+
the old one while it still works, name it in your manifest or set
|
|
196
|
+
`RAPIER_MODEL_<VENDOR>`.
|
|
197
|
+
|
|
198
|
+
| Vendor | Was | Now | Why |
|
|
199
|
+
|---|---|---|---|
|
|
200
|
+
| `openrouter` | `openai/gpt-4o` | `openai/gpt-6-sol` | gpt-4o stops working 2027-01-14. gpt-6-sol is OpenAI's current flagship and costs slightly less. |
|
|
201
|
+
| `deepseek` | `deepseek-chat` | `deepseek-flash` | `deepseek-chat` was retired 2026-07-24, so the old default already fails. |
|
|
202
|
+
| `groq` | `llama-3.3-70b-versatile` | `openai/gpt-oss-120b` | Shut down 2026-08-16, so the old default already fails. Groq names gpt-oss-120b as the replacement. |
|
|
203
|
+
| `together` | `meta-llama/Llama-3.3-70B-Instruct-Turbo` | `openai/gpt-oss-120b` | Leaves Together's serverless tier 2026-10-22. |
|
|
204
|
+
| `gemini` | `gemini-2.5-flash` | `gemini-3.5-flash-lite` | 2.5 Flash is closed to new API users. Google recommends 3.5 Flash-Lite for new projects, at the same price. |
|
|
205
|
+
|
|
206
|
+
`xai` (`grok-4.3`), `mistral` (`mistral-large-latest`) and `ollama` (`llama3.1`)
|
|
207
|
+
are unchanged. Each was checked against its vendor's deprecation page on
|
|
208
|
+
2026-10-15.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rapier-runtime
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: A code-orchestrated engine that runs the SPARRING method: grounded, cross-vendor adversarial review for AI-in-the-loop decisions.
|
|
5
5
|
Project-URL: Homepage, https://rapierruntime.com
|
|
6
6
|
Project-URL: Repository, https://github.com/muddyone/rapier-runtime
|
|
@@ -49,9 +49,11 @@ Free and open source (Apache-2.0). Not monetized.
|
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
52
|
-
## Status:
|
|
52
|
+
## Status: alpha — the full ceremony runs end-to-end (M0–M4 complete)
|
|
53
53
|
|
|
54
|
-
This is early software, pinned pre-1.0 — but the whole method runs.
|
|
54
|
+
This is early software, pinned pre-1.0 — but the whole method runs. The interfaces can still
|
|
55
|
+
change in any minor release. How versions, maturity and evidence are kept apart:
|
|
56
|
+
[docs/versioning.md](docs/versioning.md). What works
|
|
55
57
|
today:
|
|
56
58
|
|
|
57
59
|
- **The full SPARRING ceremony, end-to-end.** The **Proposer** (divergent
|
|
@@ -19,9 +19,11 @@ Free and open source (Apache-2.0). Not monetized.
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## Status:
|
|
22
|
+
## Status: alpha — the full ceremony runs end-to-end (M0–M4 complete)
|
|
23
23
|
|
|
24
|
-
This is early software, pinned pre-1.0 — but the whole method runs.
|
|
24
|
+
This is early software, pinned pre-1.0 — but the whole method runs. The interfaces can still
|
|
25
|
+
change in any minor release. How versions, maturity and evidence are kept apart:
|
|
26
|
+
[docs/versioning.md](docs/versioning.md). What works
|
|
25
27
|
today:
|
|
26
28
|
|
|
27
29
|
- **The full SPARRING ceremony, end-to-end.** The **Proposer** (divergent
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
# Rapier — dev status
|
|
2
2
|
|
|
3
|
-
_Last updated: 2026-10-16 (tag v0.6.
|
|
3
|
+
_Last updated: 2026-10-16 (tag v0.6.1, 264 tests)._ A running "where we are /
|
|
4
4
|
what's next" so a new session can continue without reconstructing from git log.
|
|
5
5
|
|
|
6
6
|
## Done
|
|
7
|
+
- **RELEASED (2026-10-16) — `rapier-runtime` 0.6.1 on PyPI. The arithmetic
|
|
8
|
+
check ("WHETHER THE NUMBERS ADD UP") stops flagging correct formulas.** Git
|
|
9
|
+
tag `v0.6.1`; https://pypi.org/project/rapier-runtime/0.6.1/. Reported by
|
|
10
|
+
valkyrie-sparring-1: a stats-heavy spar
|
|
11
|
+
(sparring-framework `docs/spars/202610161853-gopnik-pilot-design-review/`)
|
|
12
|
+
got five false mismatches out of five, because every stated result was
|
|
13
|
+
checked as a sum of the numbers near it. Fixes: `difference` and
|
|
14
|
+
`expression` operations (the formula is evaluated as written, by a
|
|
15
|
+
literal-only evaluator); "not checked" where the operation can't be
|
|
16
|
+
recovered, or a "sum" quote shows a formula; the agreement margin is 0.5% of
|
|
17
|
+
the figures (no floor of 1) or half a unit of the last digit the quote
|
|
18
|
+
shows. Also: the ledger permission test skips where the filesystem ignores
|
|
19
|
+
chmod (WSL `/mnt/c`). Verified from PyPI: a clean install reports 0.6.1 and
|
|
20
|
+
the reported standard-error case agrees.
|
|
7
21
|
- **RELEASED (2026-10-16) — `rapier-runtime` 0.6.0 on PyPI. The MCP server runs
|
|
8
22
|
on the mcp 2.x SDK.** Git tag `v0.6.0`;
|
|
9
23
|
https://pypi.org/project/rapier-runtime/0.6.0/. `MCPServer` replaces
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Fix the arithmetic check's false alarms on formulas and release 0.6.1
|
|
2
|
+
|
|
3
|
+
**Timestamp**: 2026-10-16 21:28 (local)
|
|
4
|
+
**Project**: rapier-runtime
|
|
5
|
+
**Machine**: Valkyrie
|
|
6
|
+
**User**: Bart Niedner
|
|
7
|
+
**Session**: worktree-valkyrie-rapier-runtime-1
|
|
8
|
+
**Previous session**: [202610162038.five-releases-defaults-report-mcp2.md](202610162038.five-releases-defaults-report-mcp2.md)
|
|
9
|
+
|
|
10
|
+
## Session summary
|
|
11
|
+
valkyrie-sparring-1 reported that the reconcile stage ("WHETHER THE NUMBERS ADD UP")
|
|
12
|
+
flagged five correct formula results as mismatches in a stats-heavy spar. Fixed the
|
|
13
|
+
cause, two related weaknesses and a test that failed on this machine, then released
|
|
14
|
+
0.6.1 to PyPI.
|
|
15
|
+
|
|
16
|
+
## Decisions made
|
|
17
|
+
1. **Root cause was the extraction schema, not the arithmetic.** The extractor could
|
|
18
|
+
only label a relation sum/product/count/percent_of, and a missing operation
|
|
19
|
+
defaulted to sum, so the model filed formulas as sums. Added `difference`,
|
|
20
|
+
`expression` (formula transcribed as written, evaluated in code by a literal-only
|
|
21
|
+
AST evaluator) and `other` (not checked). The model still only extracts; Python
|
|
22
|
+
still decides.
|
|
23
|
+
2. **"Not checked" over a guess.** A missing operation, `other`, an expression that
|
|
24
|
+
won't evaluate, or a `sum` whose own quote carries a formula operator
|
|
25
|
+
(`· × ÷ √ ^ ± ² ³ ⁴`) is unverifiable, never a mismatch. `/` and Markdown `**`
|
|
26
|
+
are excluded from that guard so unit rates and bold totals are still checked.
|
|
27
|
+
3. **Margin measured against the figures.** The old `max(|s|, |c|, 1.0)` floor let
|
|
28
|
+
any figure under 1 agree with almost anything. Now: 0.5% of the figures, or half
|
|
29
|
+
a unit of the last digit shown.
|
|
30
|
+
4. **Precision read from the quote.** JSON drops trailing zeros (0.120 → 0.12), so
|
|
31
|
+
the allowance comes from the numeral in the aggregate quote that equals the
|
|
32
|
+
stated value (handles `1,200`, `6e-5`, `6×10⁻⁵`, `%`). Falls back to the number.
|
|
33
|
+
5. **Ledger permission test skips where chmod is ignored** (Bart chose option 1 over
|
|
34
|
+
changing TMPDIR). It probes its tmp dir and skips only the mode assertion.
|
|
35
|
+
6. **0.6.1** (patch): bug fixes to an existing check, no new interface.
|
|
36
|
+
|
|
37
|
+
## Files changed
|
|
38
|
+
- Engine: `src/rapier/stages/reconcile.py`
|
|
39
|
+
- Report: `src/rapier/stages/resolver/compose.py` (formula shown on a mismatch;
|
|
40
|
+
count of unchecked figures; section blurb)
|
|
41
|
+
- Tests: `tests/test_reconcile.py` (+17 tests), `tests/test_pipeline.py`
|
|
42
|
+
- Release/docs: `pyproject.toml`, `CHANGELOG.md`, `docs/STATUS.md`
|
|
43
|
+
|
|
44
|
+
## Current results
|
|
45
|
+
- Suite: 264 passed (263 + 1 skip when tmp is on /mnt/c).
|
|
46
|
+
- Replaying the stored extraction from the reported run
|
|
47
|
+
(sparring-framework `docs/spars/202610161853-gopnik-pilot-design-review/20261016185428-spar/`)
|
|
48
|
+
clears 4 of 5 false alarms. The 5th ("20-point effect") stays a mismatch because
|
|
49
|
+
that stored extraction labelled it `sum` with no operator in its quote; the new
|
|
50
|
+
prompt should extract it as `difference`. **Not confirmed with a live run.**
|
|
51
|
+
- PyPI: 0.6.1 published, tag `v0.6.1`. Clean install from PyPI reports 0.6.1 and
|
|
52
|
+
the reported SE case agrees.
|
|
53
|
+
|
|
54
|
+
## Bugs found and fixed
|
|
55
|
+
- Reconcile summed formula operands (1857d50).
|
|
56
|
+
- Reconcile margin floor of 1 made sub-1 figures unfalsifiable (dfda3de).
|
|
57
|
+
- Trailing-zero precision lost through JSON (62365e2).
|
|
58
|
+
- `test_ledger_persists_redacted_run` failed on drvfs tmp dirs (f475d2a).
|
|
59
|
+
|
|
60
|
+
## Environmental discoveries
|
|
61
|
+
- **TMPDIR=/mnt/c/Temp comes from `~/.bashrc:125`** (earlier in the session I
|
|
62
|
+
guessed it might be set by Claude Code; it is not). On that drive pytest's output
|
|
63
|
+
capture crashes ("no tests ran") and file modes read 0o777, so both deploy scripts
|
|
64
|
+
refuse with "suite is red" unless run with `TMPDIR` on the Linux filesystem.
|
|
65
|
+
- `!` commands from the Claude Code prompt get no stdin; the prod script's version
|
|
66
|
+
confirmation reads empty and refuses. Partner pipes it: `printf '0.6.1\n' | ...`.
|
|
67
|
+
- Recorded machine-specific in Claude memory `computer_Valkyrie.md`. No readiness
|
|
68
|
+
probe written: the project has no `.loom/readiness.d/`, and the repair (editing
|
|
69
|
+
`~/.bashrc`, or making the scripts set their own TMPDIR) is a partner decision.
|
|
70
|
+
|
|
71
|
+
## Surfaced items routed
|
|
72
|
+
None -- no in-flight captures this session.
|
|
73
|
+
|
|
74
|
+
## What's next
|
|
75
|
+
- Run a fresh spar with `--verify gate` on a stats-heavy topic under 0.6.1 and
|
|
76
|
+
confirm the "20-point effect" kind of figure is extracted as `difference`.
|
|
77
|
+
- Decide whether `loom-deploy-nonprod.sh` / `loom-deploy-prod.sh` should set a
|
|
78
|
+
Linux `TMPDIR` themselves when it points at `/mnt/*`, so deploys work from a
|
|
79
|
+
default shell on Valkyrie.
|
|
80
|
+
- Optional: give `loom-deploy-prod.sh` a `--preview` manifest and a
|
|
81
|
+
`loom-deploy-holds` check, which /deploy-prod expects and this script lacks.
|
|
82
|
+
|
|
83
|
+
_Run `/wn` for the ranked what's-next shortlist._
|
|
84
|
+
|
|
85
|
+
## Commits
|
|
86
|
+
- 1857d50 reconcile: stop summing formulas — add difference/expression ops, "not checked" when unrecoverable
|
|
87
|
+
- dfda3de reconcile: measure the margin against the figures, not a floor of 1
|
|
88
|
+
- 62365e2 reconcile: read a figure's precision from the quote, not the JSON number
|
|
89
|
+
- f475d2a test: skip the owner-only mode check where the filesystem ignores chmod
|
|
90
|
+
- 55b983f release: bump to 0.6.1 (reconcile check: no more false alarms on formulas)
|
|
91
|
+
- 9136648 docs(status): 0.6.1 released — arithmetic check stops flagging correct formulas
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# In-flight: six improvements from the Accountable Agents / Declarative AI concept papers
|
|
2
|
+
|
|
3
|
+
**Timestamp**: 2026-11-14 11:30 (local)
|
|
4
|
+
**Project**: rapier-runtime
|
|
5
|
+
**HEAD**: 9214c14b (chatlog: reconcile false alarms fixed, 0.6.1 released)
|
|
6
|
+
**Captured by**: Bart (from a vitae session, vit-1)
|
|
7
|
+
**Status**: open
|
|
8
|
+
|
|
9
|
+
## Source
|
|
10
|
+
|
|
11
|
+
Thomas Gessler's two public concept papers. Cite these, and only these, in this repo:
|
|
12
|
+
|
|
13
|
+
- *Declarative AI Architecture: Knowledge Artifacts as System Logic for Generative Systems*, DOI 10.5281/zenodo.20687710
|
|
14
|
+
- *Accountable Agents: Declarative Control Architecture for Operational AI Systems*, DOI 10.5281/zenodo.21850919
|
|
15
|
+
|
|
16
|
+
The ideas used here, in our words:
|
|
17
|
+
- A control counts as external only if the governed agent cannot change, disable or get around it.
|
|
18
|
+
Sitting outside the model is not enough.
|
|
19
|
+
- A negative test passes only if the intended control was active and caused the failure.
|
|
20
|
+
- A failure to run is a different outcome from "no decision". The papers name six final states:
|
|
21
|
+
act, refuse, block, defer, escalate, non-decision.
|
|
22
|
+
- Declared controls should be checked against what actually runs, before deployment.
|
|
23
|
+
- To measure drift, record the version of the method that ran.
|
|
24
|
+
|
|
25
|
+
Rapier already meets much of this. The method is declared in a manifest outside the models. The
|
|
26
|
+
models only answer API calls and have no tools. Review is cross-vendor and says so when it isn't. The
|
|
27
|
+
run record names each stage, model and vendor. And a verifier error on one artifact gives `flagged`,
|
|
28
|
+
never `clean` (`src/rapier/verify/_vendor/spar_verify_gate.py`, `decide()`). The items below are at
|
|
29
|
+
the edges.
|
|
30
|
+
|
|
31
|
+
## Items, most useful first
|
|
32
|
+
|
|
33
|
+
### 1. SCOPE-CANDIDATE: the calling agent can switch a check off (about half a day)
|
|
34
|
+
Over MCP the calling agent picks `verify` (`src/rapier/mcp/server.py`, `spar` / `sparring`).
|
|
35
|
+
`verify="off"` drops the citation gate and the Proposer's traceability gate (`src/rapier/presets.py:73`
|
|
36
|
+
and `:117`). The definitiveness gate always runs. So the agent whose output is being checked chooses
|
|
37
|
+
which checks run.
|
|
38
|
+
- `verify_mode` is recorded in `ceremony.json`. Not yet checked: whether the report tells the reader.
|
|
39
|
+
- Proposal: a minimum level the operator sets (env or config) that a tool argument can't lower, and a
|
|
40
|
+
report line naming any check that was turned off, and by whom (caller argument or operator config).
|
|
41
|
+
- The operator setting must live where the calling agent can't write it. An env var or config file the
|
|
42
|
+
agent can edit fails the papers' own test (externality is about authority, not location).
|
|
43
|
+
- Promised publicly on 2026-11-14 (a check the operator requires can't be turned off by the caller; the
|
|
44
|
+
report says when a check is off and who turned it off). Item 2 was promised the same day.
|
|
45
|
+
|
|
46
|
+
### 2. BUG-CANDIDATE: "didn't run" reads like "found nothing" (small)
|
|
47
|
+
When the definitiveness verdict is missing, `_verdict_sentence` in
|
|
48
|
+
`src/rapier/stages/resolver/compose.py` (around line 47) says "there were no hard specifics to check,
|
|
49
|
+
or the checker was unavailable". That merges a check that ran and found nothing with a check that
|
|
50
|
+
never ran. A stage that raises is also caught and logged, and the pipeline goes on
|
|
51
|
+
(`src/rapier/pipeline.py:150`, fail-soft), so a crashed gate lands in the same message.
|
|
52
|
+
- Proposal: separate outcomes (`not-run: <reason>` and `nothing-to-check`) in the verdict, the Trust
|
|
53
|
+
Rider and `ceremony.json`.
|
|
54
|
+
|
|
55
|
+
### 3. SCOPE-CANDIDATE: compare what the manifest declared with what ran (about half a day)
|
|
56
|
+
- At run time: the Trust Rider lists each declared stage and whether it produced a result, failed soft,
|
|
57
|
+
or was skipped. `ledger.jsonl` holds the trace tails today, but nothing compares them with the
|
|
58
|
+
manifest.
|
|
59
|
+
- Before a run (`rapier doctor` or manifest load): warn when a manifest declares no correctness gate,
|
|
60
|
+
or when a gate's result never reaches the verdict.
|
|
61
|
+
|
|
62
|
+
### 4. DESIGN-CALL: name the final outcomes
|
|
63
|
+
PASS / FAIL / REVIEW / unchecked map roughly onto block and defer. SPARRING has no formal
|
|
64
|
+
non-decision. A Proposer phase that exits at its cap still in disagreement (`stages/proposer/phase_stages.py`,
|
|
65
|
+
"disagreement-at-cap") is a non-decision: label it, and say what the reader should do next. Keep it
|
|
66
|
+
apart from "a check failed to run" (item 2).
|
|
67
|
+
|
|
68
|
+
### 5. SCOPE-CANDIDATE: record the method version (small)
|
|
69
|
+
`ceremony.json` has `sparring_version`, and the transcript has the models. There's no hash of the
|
|
70
|
+
manifest (resolved pipeline plus config) that actually ran. Add one, so we can tell whether the same
|
|
71
|
+
inputs under the same method version still give the same result.
|
|
72
|
+
|
|
73
|
+
### 6. DESIGN-CALL, optional: strict single-vendor mode
|
|
74
|
+
With one vendor available, the reviewer runs on the author's vendor and the report says it is "not an
|
|
75
|
+
independent check". A strict mode would stop and report that no independent check is possible,
|
|
76
|
+
instead of going ahead.
|
|
77
|
+
|
|
78
|
+
## Out of scope
|
|
79
|
+
Rapier only gives advice and never acts on anything, so the papers' commit boundary and "act is not
|
|
80
|
+
commit" don't apply. Their rule that conflicting validators must not produce a commit is met by
|
|
81
|
+
reporting: objections appear in a "contested" section rather than being merged away.
|
|
@@ -35,12 +35,24 @@ Return **both** a human-readable markdown report *and* a structured payload, so
|
|
|
35
35
|
client can render prose or branch on the result:
|
|
36
36
|
- `report_md` — the composed two-part report (what the CLI prints).
|
|
37
37
|
- `verdict` — `PASS | REVIEW | FAIL | unchecked` (the definitiveness gate).
|
|
38
|
+
- `correctness_check` / `citation_check` — what happened to each check: `ran`,
|
|
39
|
+
`nothing-to-check` (it ran and there was nothing to judge), or
|
|
40
|
+
`did-not-run: <reason>` (switched off, crashed, no key, or not in the pipeline).
|
|
41
|
+
A check that did not run is never reported as one that found nothing.
|
|
38
42
|
- `grounding` — `{gate, grounding_rate, verified, refuted, unverifiable}` from the
|
|
39
43
|
now-live citation gate (the external-canon check).
|
|
40
44
|
- `cross_vendor` — bool, plus `author_vendor` / `reviewer_vendor` (honest
|
|
41
45
|
degradation is visible, not hidden).
|
|
42
46
|
- `standing_objections` — forwarded Proposer dissent, when present.
|
|
43
47
|
|
|
48
|
+
An operator minimum (`/etc/rapier/policy.json` `{"min_verify": "gate"}`, or
|
|
49
|
+
`RAPIER_MIN_VERIFY`) refuses a `verify` argument below it with
|
|
50
|
+
`{"ok": false, "refused_by": "operator_minimum"}`. No tool argument can change
|
|
51
|
+
the minimum or the file's path; see `src/rapier/operator_policy.py`. It binds callers
|
|
52
|
+
that reach Rapier through its MCP tools or CLI. Code that imports Rapier and
|
|
53
|
+
builds a `Pipeline` directly in its own process is not held to it, and Rapier
|
|
54
|
+
cannot prevent that: keep the policy for agents that only get the tools.
|
|
55
|
+
|
|
44
56
|
All outputs pass through `secrets.redact_obj` (already the ledger's discipline)
|
|
45
57
|
before leaving the process.
|
|
46
58
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Versioning and maturity
|
|
2
|
+
|
|
3
|
+
Rapier keeps three things separate, because they answer different questions:
|
|
4
|
+
|
|
5
|
+
1. **The version number** says whether an upgrade can break you.
|
|
6
|
+
2. **The maturity stage** says how settled the software is.
|
|
7
|
+
3. **The evidence status** says how far the method itself has been shown to work.
|
|
8
|
+
|
|
9
|
+
The evidence never goes into the version number. A 1.0 release would mean the software
|
|
10
|
+
contract is stable, not that the method is proven.
|
|
11
|
+
|
|
12
|
+
## 1. Version number: Semantic Versioning, written as PEP 440
|
|
13
|
+
|
|
14
|
+
Versions follow [Semantic Versioning 2.0](https://semver.org/), written in
|
|
15
|
+
[PEP 440](https://peps.python.org/pep-0440/) form for PyPI.
|
|
16
|
+
|
|
17
|
+
**The public contract** is what a version number protects:
|
|
18
|
+
|
|
19
|
+
- the CLI: commands, flags, and exit codes;
|
|
20
|
+
- the manifest format: stage names, roles, and config keys;
|
|
21
|
+
- the MCP server: tool names and their parameters;
|
|
22
|
+
- the run record: the files under `~/.rapier/runs/<run>/` and the fields in `ceremony.json`.
|
|
23
|
+
|
|
24
|
+
Anything else, including prompt text, report wording, and internal modules, can change in any
|
|
25
|
+
release.
|
|
26
|
+
|
|
27
|
+
**Before 1.0:** a breaking change to the contract bumps the minor number (0.6 → 0.7). Everything
|
|
28
|
+
else bumps the patch (0.6.1 → 0.6.2). A deprecated name keeps working, with a warning, for at least
|
|
29
|
+
one minor release before it is removed. The CHANGELOG says so when it goes.
|
|
30
|
+
|
|
31
|
+
**From 1.0:** a breaking change bumps the major number.
|
|
32
|
+
|
|
33
|
+
## 2. Maturity stage
|
|
34
|
+
|
|
35
|
+
The stage is shown in two places that must agree: the PyPI `Development Status` classifier in
|
|
36
|
+
`pyproject.toml`, and the Status line in the README. A stage is earned by meeting its criteria, not
|
|
37
|
+
by declaring it.
|
|
38
|
+
|
|
39
|
+
| Stage | Classifier | Criteria |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| Pre-alpha | `2 - Pre-Alpha` | The method doesn't yet run end to end. |
|
|
42
|
+
| Alpha | `3 - Alpha` | The whole method runs end to end, is published, and is tested. The contract can still change in any minor release. |
|
|
43
|
+
| Beta | `4 - Beta` | The contract is frozen except for fixes. The deprecation policy holds. A security review is done. There are users beyond the maintainer. Every check reports whether it ran: a check that never ran is never reported as one that found nothing. The calling agent can't lower a check the operator requires. |
|
|
44
|
+
| Stable | `5 - Production/Stable` | Released as 1.0. The contract is under Semantic Versioning. |
|
|
45
|
+
|
|
46
|
+
## 3. Evidence status, per instrument
|
|
47
|
+
|
|
48
|
+
Each governance instrument is rated on its own:
|
|
49
|
+
|
|
50
|
+
- **Exploratory:** built and used, with no pre-registered test of whether it helps.
|
|
51
|
+
- **Tested:** a pre-registered study was run, and its result is published, whatever it found.
|
|
52
|
+
- **Validated:** a pre-registered study found the effect it predicted.
|
|
53
|
+
|
|
54
|
+
The instruments are the definitiveness (correctness) gate, the citation gate, anchored correction,
|
|
55
|
+
and the two-part report with its trust rider.
|
|
56
|
+
|
|
57
|
+
## Where Rapier is now (2026-11-14)
|
|
58
|
+
|
|
59
|
+
- **Version:** 0.6.1.
|
|
60
|
+
- **Stage:** Alpha. The full ceremony runs end to end, it is on PyPI, the tests pass, and
|
|
61
|
+
cross-vendor runs are live-proven. The contract is still changing.
|
|
62
|
+
- **Evidence:** every instrument is exploratory. Two pre-registered studies of the resolver are
|
|
63
|
+
published. In a blind rater test, raters didn't prefer the resolver's answers to a single AI pass.
|
|
64
|
+
Iterating review toward agreement gave no cleaner answers than one review. Neither study
|
|
65
|
+
validated the instruments above.
|
|
66
|
+
- **Open for Beta:** a stable contract, a security review, users beyond the maintainer, and the two
|
|
67
|
+
check-reporting criteria, which are open work today
|
|
68
|
+
(`docs/chatlogs/202611141130.inflight.accountable-agents-gaps.md`, items 1–3).
|
|
@@ -9,7 +9,7 @@ build-backend = "hatchling.build"
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "rapier-runtime"
|
|
12
|
-
version = "0.6.
|
|
12
|
+
version = "0.6.2"
|
|
13
13
|
description = "A code-orchestrated engine that runs the SPARRING method: grounded, cross-vendor adversarial review for AI-in-the-loop decisions."
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
requires-python = ">=3.10"
|
|
@@ -299,7 +299,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
299
299
|
run.add_argument("--manifest", required=True, help="path to a pipeline manifest (YAML)")
|
|
300
300
|
add_common(run)
|
|
301
301
|
|
|
302
|
-
sub.add_parser("doctor", help="check
|
|
302
|
+
dp = sub.add_parser("doctor", help="check vendor keys, the operator minimum, and what the "
|
|
303
|
+
"ceremonies declare")
|
|
304
|
+
dp.add_argument("--manifest", help="also check a custom manifest before running it")
|
|
303
305
|
ip = sub.add_parser("init", help="scaffold a .env.example for vendor keys")
|
|
304
306
|
ip.add_argument("--dir", default=".", help="directory to write .env.example into (default: cwd)")
|
|
305
307
|
sub.add_parser("mcp", help="run the MCP server (stdio) exposing frame/proposer/spar/sparring as tools")
|
|
@@ -333,10 +335,12 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
333
335
|
return {"failed": 1, "unchecked": 3}.get(report["status"], 0)
|
|
334
336
|
|
|
335
337
|
if args.cmd == "doctor":
|
|
336
|
-
from .onboarding import doctor_report
|
|
338
|
+
from .onboarding import doctor_report, method_report
|
|
337
339
|
|
|
338
340
|
print(doctor_report())
|
|
339
|
-
|
|
341
|
+
text, ok = method_report(getattr(args, "manifest", None))
|
|
342
|
+
print("\n" + text)
|
|
343
|
+
return 0 if ok else 1
|
|
340
344
|
if args.cmd == "init":
|
|
341
345
|
from .onboarding import init as _init
|
|
342
346
|
|
|
@@ -373,18 +377,36 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
373
377
|
if err: # no vendor keys — fail loudly, not silently
|
|
374
378
|
print(err, file=sys.stderr)
|
|
375
379
|
return 2
|
|
380
|
+
from .operator_policy import PolicyError, decide_independence, decide_verify
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
decision = decide_verify(
|
|
384
|
+
getattr(args, "verify", "gate"),
|
|
385
|
+
"command-line flag --verify"
|
|
386
|
+
if any(a == "--verify" or a.startswith("--verify=")
|
|
387
|
+
for a in (argv if argv is not None else sys.argv[1:]))
|
|
388
|
+
else "default",
|
|
389
|
+
)
|
|
390
|
+
except PolicyError as exc:
|
|
391
|
+
print(f"refused: {exc}", file=sys.stderr)
|
|
392
|
+
return 2
|
|
376
393
|
preset = load_preset(
|
|
377
|
-
args.cmd, settle=getattr(args, "settle", 0), verify=
|
|
394
|
+
args.cmd, settle=getattr(args, "settle", 0), verify=decision.mode,
|
|
378
395
|
seed=getattr(args, "seed", None), depth=getattr(args, "depth", "standard"),
|
|
379
396
|
reconcile=getattr(args, "reconcile", "gate"),
|
|
380
397
|
)
|
|
398
|
+
try:
|
|
399
|
+
decide_independence(getattr(preset, "policy", None))
|
|
400
|
+
except PolicyError as exc:
|
|
401
|
+
print(f"refused: {exc}", file=sys.stderr)
|
|
402
|
+
return 2
|
|
381
403
|
# Carry context the pipeline can't observe onto the envelope for the
|
|
382
404
|
# ceremony-ledger row: the resolver knobs, and the front-door Frame
|
|
383
405
|
# classification (from a separate call) via --frame.
|
|
384
406
|
seed_meta: dict = {
|
|
385
407
|
"settle": getattr(args, "settle", 0),
|
|
386
|
-
"verify": getattr(args, "verify", "gate"),
|
|
387
408
|
"reconcile": getattr(args, "reconcile", "gate"),
|
|
409
|
+
**decision.meta(),
|
|
388
410
|
}
|
|
389
411
|
frame_path = getattr(args, "frame", None)
|
|
390
412
|
if frame_path:
|
|
@@ -400,7 +422,18 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
400
422
|
report_all=getattr(args, "report_all", False), seed_meta=seed_meta,
|
|
401
423
|
no_save=getattr(args, "no_save", False))
|
|
402
424
|
if args.cmd == "run":
|
|
403
|
-
|
|
425
|
+
from .operator_policy import PolicyError, decide_independence, decide_manifest
|
|
426
|
+
|
|
427
|
+
manifest = Manifest.load(args.manifest)
|
|
428
|
+
try:
|
|
429
|
+
decision = decide_manifest(manifest.stages)
|
|
430
|
+
if any(s.stage in ("cross_review", "spark", "pattern_lock", "cut")
|
|
431
|
+
for s in manifest.stages):
|
|
432
|
+
decide_independence(manifest.policy)
|
|
433
|
+
except PolicyError as exc:
|
|
434
|
+
print(f"refused: {exc}", file=sys.stderr)
|
|
435
|
+
return 2
|
|
436
|
+
return _run(manifest, request, args.ledger_dir, seed_meta=decision.meta(),
|
|
404
437
|
no_save=getattr(args, "no_save", False))
|
|
405
438
|
return 1 # pragma: no cover
|
|
406
439
|
|