Contributing to Crucible Simulator
Thanks for contributing! Crucible is a deterministic testing foundation, so its quality bar is exactness: every behavior change must come with tests that pin it down.
Getting started
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets # must be warning-free
cargo fmt --check
The workspace must stay clippy- and fmt-clean; CI enforces it.
Where things live
| Area | Crate | Notes |
|---|---|---|
| Domain model | crates/core | No engine dependencies |
| State engine | crates/state | Store, commitments, nullifiers, transitions, rollback, snapshots |
| Flows | crates/flows | Five lifecycle flows + validation + ProofProvider |
| High-level API | crates/simulator | Configuration / Environment / Simulator |
| Fixtures & suites | crates/fixtures | Versioned fixtures + the integration/determinism/invariant/regression suites |
Dependency direction is strictly core → state → flows → simulator → fixtures.
Ground rules
- Determinism is sacred. Never introduce system entropy, wall-clock
reads,
Hash*state collections, or float math into simulation logic. Randomness flows only throughDeterministicRng. - Never silently mutate state. Every applied change goes through the
flow pipeline and ends in a recorded, audited
StateTransition. - Failed operations must leave no trace. Apply inside
TransactionScope; on error, state (including sequence counters) must be bit-identical. - Privacy boundary. Observable output (events, published records) never contains amounts or commitment values. Private values are only reachable through explicitly labeled inspection APIs.
- One behavior change, one focused commit, with a message explaining the why. Do not bundle unrelated improvements.
- Every bug becomes a fixture. Found a bug? Write the failing test
first (
crates/fixtures/tests/regression.rs), fix, and — when the bug is reproducible from outside the code — add a failure fixture underfixtures/scenarios/failures/so it can never return silently.
Scoping your change
This repository is the root of a three-repository system: crucible-prover
and crucible-scenarios both compile it, each at a revision pinned in their
own manifests. Two consequences follow, and they point in opposite
directions.
- A change here cannot break a consumer. They build the pinned revision, not your branch, so their CI stays green while your change lands. You do not need to coordinate a release to land work in this repository.
- A change to a published contract blocks the next pin bump. If you alter a signature, a serialized shape, or a state/event semantic that a consumer depends on, that consumer cannot move to your revision until it adapts. Scope such work as two issues — the change here, and a separate follow-up to bump the pin and adapt — never as one PR spanning repositories. A pull request that requires edits in two repositories cannot be reviewed, tested, or reverted as a unit.
See docs/cross-repo-pinning.md for the pinned set and the bump procedure.
Testing
cargo test --workspace # everything
cargo test -p crucible-fixtures --test full_lifecycle # the MVP flow
cargo test -p crucible-fixtures --test determinism # the defining property
cargo test -p crucible-fixtures --test invariants # conservation & friends
cargo test -p crucible-fixtures --test regression # pinned bugs
Fixture corpus changes must keep
loader::tests::repository_fixtures_load_and_all_scenarios_replay green —
every checked-in scenario must replay.
Review checklist
- Determinism preserved (see
docs/deterministic-execution.md) - Atomicity preserved (rollback on failure)
- Observable output stays value-free
- Tests added or updated; full workspace green
-
cargo clippy --workspace --all-targetswarning-free -
cargo fmtclean - No unrelated changes bundled