Cargo-Rail records why it selected, skipped, widened, or refused work. Start at the boundary that made the decision; do not infer it from the final Cargo command.
cargo rail plan --merge-base --explain
cargo rail plan --merge-base -f json
cargo rail run --merge-base --dry-run --print-cmd --explainRead these fields in order:
inputs.refs— did the plan compare the intended range?files— did it capture and classify the expected paths?trace— which ownership, semantic, graph, confidence, or fallback reason fired?surfaces.NAME— was the relevant surface enabled, and with which reason IDs?surfaces.NAME.scope— which packages belong to that surface?- the run preview — which profile actions, feature/target view, and argv were expanded?
Use scope for combined execution and surfaces.NAME.scope for one surface. impact is explanation, not an execution
handoff. Historical --from/--to plans widen package work because Cargo cannot resolve an unchecked-out tree.
If plan is right but run is wrong, check the selected action/profile, configured when policies, trailing Cargo
arguments, and --ignore-bin-crates. Planner surfaces such as infra and custom:* are conditions, not executable
action IDs. See Planning and execution.
cargo rail config locate
cargo rail config explain -f json
cargo rail config validate --strictlocate shows the discovered file. explain shows effective values and their sources. A CLI --config override
bypasses the normal search order.
Use the doctor for the cache boundary you are testing:
# Expanded action-key eligibility
cargo rail doctor hermeticity --action build --format json
# Exact native compiler-cache identity
cargo rail doctor native-cache --format json
# Compiler evidence used by unify
cargo rail unify --check -f jsonFor native reuse, inspect the run summary's hits, misses, bypasses, hashed/restored bytes, and stable reasons. Failure to capture the exact compiler identity, incremental compilation, an existing wrapper, a non-JSON compiler diagnostic format, an unsupported compiler class, or incomplete observed input executes normally; it is not a false cache hit. A different physical source root has different action authority: Cargo-Rail compiles cold, emits exact output for that root, and can reuse the result only in later sessions bound to the same root.
For the hermetic whole-action profile, read the report under target/cargo-rail/hermetic/reports/. fetch.reused
describes only the dependency inventory; it does not mean the action result was restored. platform_limited means the
isolated check ran without an authorizing cache key.
For unify, evidence_cache reports diagnostic-observation reuse. That cache never restores Cargo build artifacts.
The full eligibility matrix, result meanings, storage paths, and current measurements are in Caching. Inspect the affected scope, then preview validated cleanup before removing cache state:
cargo rail cache status --scope workspace
cargo rail cache clean --scope workspace --check
cargo rail cache clean --scope workspace
cargo rail cache status --scope local
cargo rail cache clean --scope local --check
cargo rail cache clean --scope localrelease run and release finalize persist a journal before their first side effect. Inspect it, then use the safe
command Cargo-Rail reports:
cargo rail release status
cargo rail release status --format json
cargo rail release resume target/cargo-rail/releases/release-<id>.jsonstatus does not load Cargo metadata. It reports the phase, exact SHA, observed and next effects, ambiguity,
recoverability, and a safe command. resume reconciles local Git, remote refs, readiness checks, registry versions,
tags, and forge state before advancing. It does not replan from already-mutated manifests.
Readiness and registry propagation are explicit wait boundaries: Cargo-Rail exits instead of polling. Resume after the provider settles. GitHub readiness requires at least one successful context, complete reported counts, and no pending or failed context.
Release commit trailers retain the transaction and effect authorization. From the exact release commit in a fresh
checkout, release status can report reconstructable state and
cargo rail release resume release-<transaction-id> can rebuild a missing local journal.
Abort only while no external side effect may exist:
cargo rail release abort target/cargo-rail/releases/release-<id>.json --yesAfter that boundary, resume and reconcile. Plain cargo rail clean removes completed or aborted journals but refuses
active, malformed, or ambiguous release state.
[release] source = "commits" or "both" needs release tags for each crate's history range. Fetch complete history
for release jobs:
git fetch --unshallow --tagsGitHub Actions release checkouts should use fetch-depth: 0. The default reviewed-change source does not use commit
history to choose bumps.
release finalize expects the version and changelog mutations from release run --pr in the current checkout. Merge
the PR, update its target branch, then finalize that merged commit.
A manual conflict exits 1, leaves the merge on cargo-rail-sync-<crate>, and writes a conflict receipt. Resolve every
listed file and remove all conflict markers, then let Cargo-Rail validate and commit the resolution:
cargo rail sync --resume target/cargo-rail/receipts/sync-conflict-<crate>-<id>.jsonDo not commit the conflict manually. Resume verifies the branch, parent, owned paths, and marker-free files.
Use the same base ref and confidence policy in both environments. --merge-base and --since are not interchangeable
unless they resolve to the same commit. Compare inputs.refs.resolved_base, inputs.confidence_profile, and
inputs.config_fingerprint in JSON output before inspecting package impact.
0: success or a clean check1: a check found required changes, or a resumable sync conflict2: an argument or operational failure
Executed subprocesses may deliberately propagate another status.