AOS Hub / Docs

Running Crucible in CI

Use the packaged Crucible closure in CI. It contains the CLI, patched QEMU, plugin, kernel, and fixture image as one matched set.

#Build and qualify the runner

Build once at the start of the job and run the packaged gates before executing project scenarios:

nix build .#pkg-crucible
./result/bin/crucible --quiet selftest

Production builds run the QEMU-backed gates by default. A failure here means the runner is not qualified; do not continue with scenario results from that job.

#Run a scenario

Keep the scenario and its guest inputs under source control or produce them as fixed build outputs. Give every CI run an explicit seed, store, trace path, and budget:

mkdir -p .ci/crucible/store .ci/crucible/artifacts

set +e
./result/bin/crucible \
  --seed 0x8a54f31d \
  --store .ci/crucible/store \
  --artifact-dir .ci/crucible/artifacts \
  --trace .ci/crucible/events.jsonl \
  --format jsonl \
  --quiet \
  run scenarios/checkout.scn \
  --until virtual-time \
  --max-virtual-time 30s \
  --max-quanta 100000 \
  --save-on fail
status=$?
set -e

exit "$status"

The explicit --format makes the output independent of whether the CI runner allocates a terminal. --save-on fail retains a resumable execution only when the run fails. The quantum and virtual-time limits keep a stuck workload from occupying a runner indefinitely.

Archive these paths on failure:

  • .ci/crucible/events.jsonl;
  • .ci/crucible/artifacts/; and
  • .ci/crucible/store/, unless the job uses a durable content-addressed store.

The artifact alone describes the reproduction, but it may refer to objects in the store. Preserve them together.

#Interpret exit status

Crucible uses stable process classes so CI does not need to parse prose:

StatusMeaningCI treatment
0The command completed successfully.Pass.
1Property failure, divergence, replay mismatch, counterexample, or triage failure.Fail and retain the reproduction.
2A configured virtual-time or quantum bound expired.Fail or classify as a scenario timeout.
3Crash, daemon failure, replay-oracle failure, or build-identity mismatch.Fail and preserve diagnostics.
4The backend failed.Fail and inspect runner/QEMU diagnostics.
5Invalid scenario, artifact, store object, or local I/O input.Fail and repair or restore the input.
64Command-line usage error.Fail and fix the invocation.

See Running Crucible for command-specific detail.

#Add a determinism gate

After a scenario passes its ordinary run, compare independent reductions:

./result/bin/crucible \
  --seed 0x8a54f31d \
  --store .ci/crucible/store \
  --format jsonl \
  --quiet \
  verify scenarios/checkout.scn \
  --runs 2 \
  --bisect

Two runs are a useful pull-request gate. Increase --runs for scheduled jobs when the extra backend time is justified. --bisect prints the first causal divergence if fingerprints or canonical logs differ. The report keeps evidence coordinates distinct: first_virtual_time comes from a canonical-log event, while first_instruction comes from a fingerprint sample. A coordinate is unknown when that evidence stream does not localize the mismatch. Each coordinate has its own adjacent node field; do not pair an instruction count with first_virtual_time_node.

#Recheck a reported failure

Download the archived artifact and store, then replay against the original canonical log:

./result/bin/crucible \
  --store .ci/crucible/store \
  --format jsonl \
  replay .ci/crucible/artifacts/failure.toml \
  --check .ci/crucible/events.jsonl

Use the actual artifact filename emitted by the failed run. A replay exit of 0 confirms that a fresh packaged-QEMU run reached the recorded terminal configuration with identical event and fingerprint streams, and that the retained canonical log matched. Exit 1 means live replay or the explicit log check diverged; exit 5 means an artifact, store object, or local input was invalid or unavailable.

#Parallel jobs

Shard by scenario and seed, not by sharing a writable store directory. Give each concurrent process its own --store, --artifact-dir, and --trace paths. A useful matrix is:

scenario × fixed regression seeds × supported host architecture

Keep regression seeds stable in pull-request jobs. Run broader seed campaigns on a schedule and promote any finding to the fixed regression set only after its artifact replays.

#Keep secrets out of scenarios

Scenario files, traces, guest consoles, and reproduction artifacts are CI outputs, not secret stores. Use synthetic credentials inside test guests. Do not inject production tokens, private signing keys, or customer data into a Crucible run.