[#554] Add stateful invariant coverage for commitment flows - #556
1nonlypiece merged 2 commits into
Conversation
…-Org#554) Add a seeded stateful reference-model suite for commitment_core covering create/update/settle/early_exit/allocate/fee flows with per-step model-vs- contract verification, principal/fee/ownership/terminal/atomicity invariants, 40 fixed seeds x 20 commands plus hand-written regression scripts, greedy sequence minimization, and single-seed replay via CGQA_LIFECYCLE_SEED.
|
Independent Max-mode verification and model hardening are complete on exact head The hardened lifecycle suite passes 20/20 in both parallel and sequential execution. The full The generator now covers bounded per-slot value recovery without classifying unbounded markup as valid: 71 accepted downward updates, 41 accepted upward recoveries, and zero unsafe generated upward updates. The GitHub CI failure is not introduced by this PR: the same The audit also identified a separate potentially security-relevant ownership-isolation/custody behavior outside #554. I have kept the detailed reproduction out of this PR. Please advise the preferred private or maintainer-reviewed disclosure channel. |
Closes #554
Model
contracts/commitment_core/src/lifecycle_model_tests.rsadds a bounded, deterministic stateful reference model for the core commitment lifecycle over the realcommitment_coreentrypoints.This PR changes test wiring and test/model code only. The
lib.rschange only registers the test module. No production contract behavior, public API, workflow, dependency, lockfile, deployment, or release configuration is changed.Modeled state mirrors the economically relevant fields of
commitment_core: per-commitment{owner, net principal (amount), current_value, released, expires_at, max_loss, penalty, status}, plus TVL, collected fees, creation-fee bps, ledger time, token custody balances, exact owner-index contents and order, the all-ID index, and the reentrancy guard.Commands are bound 1:1 to the real entrypoints:
create_commitment(owner, amount, asset, rules)update_value(caller, id, new_value)violatedon a max-loss breachsettle(id)now >= expires_atearly_exit(id, caller)allocate(caller, id, pool, amount)set_creation_fee_bps/set_fee_recipient/withdraw_feesThe lifecycle graph follows
docs/commitment_core/SEMANTICS.md:active → {active, violated, settled, early_exit};violated,settled, andearly_exitare terminal.Invalid variants are generated explicitly, including wrong state, nonexistent slots, wrong actors, duplicate terminal operations, signed and zero amounts, overdraft allocation, excess fee withdrawal, insufficient funding, and settle-before-expiry.
After every executed command—valid or invalid—the harness re-reads observable contract and token state and compares it with the model. Rejected operations must preserve the complete observable state.
Independent Max-mode hardening pass
A second independent audit was completed against the original PR head:
0b8e009877607eaad5f0f9202389526307256a24The audit did not trust the original model or its reported invariants. It independently reviewed command-to-entrypoint mapping, model arithmetic, observable-state comparison, invalid-operation rollback, deterministic seeds, failure minimization, replay behavior, terminal absorption, fee accounting, ownership/index consistency, and cross-commitment custody interactions.
The resulting test/model-only hardening commit is:
c782c4d84910fcc6d5696ecd53c1061330519dabSafe recovery coverage
The hardened generator no longer treats unbounded value markup as a valid recovery scenario.
For each slot:
A generated upward recovery is accepted only when:
Final deterministic coverage:
The recovery path is deterministic and replayable:
The minimizer preserves this causal prefix when it is required to reproduce an upward-recovery failure.
Hardened validation result
commitment_coreunit suite: 182 passed, with the same 3 pre-existing master failures;RecoverWithoutOwnPrincipalCapmutant: detected;The hardening remains test/model-only. No production contract behavior, dependency, lockfile, workflow, deployment configuration, or public API was changed.
CI truth
The GitHub CI run for exact head
c782c4d84910fcc6d5696ecd53c1061330519dabis RED, but its first relevant failures reproduce on exact upstream base:fb8349e63d7cfd78d68151b4b15d249b6b358b47The failure occurs before the new lifecycle model executes and is associated with the existing
ethnum 1.5.2/ current Rust stable incompatibility. The workflow also contains a separate pre-existing Ubuntu/brewinstallation problem.Therefore:
This PR does not modify the toolchain, dependencies, lockfile, or workflows to conceal that blocker. CI is not represented as GREEN.
Separate production finding
The independent audit identified a separate potentially security-relevant ownership-isolation/custody behavior outside the implementation scope of #554.
No production fix and no detailed public reproduction are included in this PR. The evidence is retained pending maintainer guidance on the preferred private or maintainer-reviewed disclosure channel.
Invariants
Reproducibility
Every failure report contains the seed, failing step and reason, original command sequence, and minimized sequence.
Single-seed replay:
The minimizer runs only on the failure path and preserves the causal command prefix and failure dimension needed for reproduction.
ContractGraph-QA
ContractGraph-QA is used as an independent external lifecycle oracle and is not a production dependency of this repository. No ContractGraph-QA code, configuration, dependency, or lockfile change is committed here.
Exact-subject and durable verification passes 36/36. All 8/8 negative controls are detected, including the
RecoverWithoutOwnPrincipalCapmutant. Deterministic positive replay is byte-identical across two runs.No PR-introduced regression was identified within the test/model scope. The separate out-of-scope production finding is handled only through the disclosure note above.
CI budget
Execution is deterministic and bounded: 40 seeds × 20 commands, with full observable-state verification after each step, plus focused regression, replay, minimization, and negative-control coverage. The focused lifecycle-model suite contains 20 tests and has no wall-clock, network, or unseeded-randomness dependency.
Validation
commitment_coreunit suiteThe exact baseline unit failures are:
emergency_tests::test_emergency_mode_toggle_emits_events;tests::test_create_commitment_event;tests::test_create_commitment_updates_storage_layout.Acceptance criteria
Design choices and tradeoffs
current_valueas newly created backing.Limitations
require_authcall.