Cross-repository pinning
Crucible is three repositories that compile each other, and each dependency edge is pinned to an immutable revision rather than a version range. That is deliberate — a moving upstream would silently change what this repository’s conformance results mean — but it creates one obligation: the pinned set has to be recorded somewhere a reviewer can read, and it has to be impossible to move a pin without moving the record with it.
This document is that record, and a test in this repository fails when it goes stale.
What each repository owns
| Repository | Role | Consumes |
|---|---|---|
crucible-simulator | SIMULATE — deterministic state and execution model | nothing |
crucible-prover | PROVE — circuits, witnesses, proving, verification | crucible-simulator (proof seam) |
crucible-scenarios | STRESS-TEST — orchestration, conformance, adversarial, privacy, regression, reporting | crucible-simulator, crucible-prover |
The graph is acyclic and one-way: nothing upstream depends on anything downstream, so a pin can only ever be bumped deliberately, never to resolve a cycle.
The pinned set in force
Every revision below is a 40-character commit SHA. The table is ordered by consumer.
| Consumer | Dependency | Pinned revision |
|---|---|---|
crucible-scenarios | crucible-prover | 983ed400ddd3ba9c0ddad1ab6a41e471c6ab3c8c |
crucible-scenarios | crucible-simulator | 7fe82b7c8fc7e2f7bece6a6af36016d8229b3fc3 |
crucible-prover | crucible-simulator | 7fe82b7c8fc7e2f7bece6a6af36016d8229b3fc3 |
Both consumers name the same crucible-simulator revision. Nothing upstream
forces that — it is a property this repository chooses to hold, and the test
below fails if a bump here is not mirrored in the prover row.
What the test enforces
crates/adapters/prover/tests/pinned_revisions.rs reads the manifests of this
workspace and this document and asserts that:
- every
rev = "<sha>"pin in this workspace appears in the table above, and - every revision the table attributes to a
crucible-simulatordependency is the same revision this workspace pins, so a simulator bump here cannot land while thecrucible-proverrow still names the old commit.
It is a drift detector, not a resolver: it reads files only and never touches
the network, so it runs in the ordinary cargo test job.
Why a revision pin and not a version
A semantic-version range would let a dependency change under this repository between two CI runs on the same commit. Every claim this project makes is a determinism or conformance claim, and a claim that can be invalidated by someone else’s release is not a claim. Revision pins make the compiled graph a pure function of these repositories’ own history — which is exactly the property the audit trail depends on.
How a pin moves
- Change the revision in the manifest that owns it. Here that is
crates/adapters/simulator/Cargo.tomlandcrates/adapters/prover/Cargo.toml; incrucible-proverthe simulator crates resolve through[workspace.dependencies]in the root manifest, so a bump there is a single edit. - Run the consuming repository’s own test suite. Its CI compiles the pinned revision, so the consuming repository is what validates the combination.
- Update this table in the same commit. Step 3 is enforced: the test fails otherwise.
Honest limitation
There is no umbrella repository and no cross-repository CI job. Each consuming repository validates its own pins by compiling them, which is a real check, but nothing here verifies that the prover’s manifest still names the simulator revision in the third row — only that the table agrees with itself. A prover bump to a new simulator revision would be caught when the prover’s own CI builds, not by this test.
Closing that properly means a fourth repository whose only job is to check out all three at the revisions named here and build them together. That is an org-level decision, not something either repository can do alone, and it is recorded here rather than implied.