Invariants
Invariants (crates/invariants, runner interface in scenario-runner) are
cross-operation checks judged over a whole run from the scenario
definition and the recorded observations — a second, independent lens that
per-step assertions cannot provide.
The seven built-in checks
Stable registry keys (referenced by scenarios via invariant_ids):
| Key | Checks that … |
|---|---|
conservation | total declared value is conserved across the run’s operations, computed from the declared amounts and the fixture starting ledger. |
ownership | state stays with the owner the operations imply, per protocol rules. |
commitment-consistency | commitment observations correspond to valid state relationships declared by the scenario. |
proof-binding | each proof generated in the run binds to the operation it claims to prove. |
input-binding | public-input mutations (adversarial runs) invalidate verification; binding is checked, not assumed. |
replay-protection | consumed or stale state is never reused. |
privacy | no public observation key carries a confidential field name (amount/witness/secret/…). |
Evaluation model
The runner’s InvariantRegistry::check_all(scenario, observations) returns
named InvariantChecks (id, held, safe detail). The executor counts
held/violated invariants onto the outcome, and runs that declare an
invariant expectation fail if it did not run or did not hold. The registry
receives the scenario + observations, never adapter internals — the checks
are pure functions of public evidence.
What is not asserted
Invariants only assert properties the protocol actually guarantees through the declared model. Nothing is invented: if the underlying implementation does not define a guarantee, no invariant claims it (spec §20, §34).
Use
- Happy-path and conformance scenarios attach all seven and must pass.
- The fuzz targets run every run through the full registry, so a fuzzed sequence that violates conservation or binding surfaces as a finding.
- Negative/adversarial packs attach invariants where the guarantee should hold despite the expected rejection.