Rust verification
September 21, 2026 · View on GitHub
Choose checks for the change
Documentation-only changes do not require the Rust verification gate, including before a commit or push. Do not run the full gate for prose edits, documentation moves, navigation changes, or documentation references in code comments.
For documentation reorganizations, check local links, referenced paths, and
preservation of retained artifacts. If moving a document requires updating an
embedded-document path such as include_str!, check only the affected consumer
and any relevant formatting. A documentation path update does not justify
workspace-wide Clippy, tests, compiler compatibility checks, or PostgreSQL
acceptance. Unrelated test failures do not block a documentation-only push.
Run the Rust gate
For Rust behavior changes, run the manual gate from a contributor machine or non-GitHub infrastructure:
./scripts/verify-rust.sh
A bare run is the full Rust gate. The documentation-only guidance above is an explicit exception; a full gate is not a prerequisite for every push. While iterating on Rust changes, scope the run instead of paying full-workspace cost for every check:
./scripts/verify-rust.sh --list # phase slugs
./scripts/verify-rust.sh --print # the resolved plan, unrun
./scripts/verify-rust.sh --phases fmt,clippy,tests # selected phases only
./scripts/verify-rust.sh --crates coder,gym # cargo phases on these packages
./scripts/verify-rust.sh --changed # packages changed since origin/main
./scripts/verify-rust.sh --changed=HEAD~5 # or against an explicit ref
./scripts/verify-rust.sh --keep-going # record every phase, not just to first failure
--changed maps crates/<name>/ paths to packages, maps the data
directories coder loads (programs/, questions/, capabilities/,
sources/) to it, and escalates to the whole workspace when
workspace-wide files (Cargo.toml, Cargo.lock, the toolchain pins) moved.
A change that touches no crates scopes the cargo phases out entirely and
records that honestly. Feature flags narrow the same way: scoped runs enable
only the features of selected packages. A scoped or skipped run reports
partial, never passed — the record is the evidence, and it says exactly
what it covered.
Every run writes .coder/verification/<run-id>/run.json (override with
--record-dir, disable with --no-record): run ID, start and end UTC,
elapsed, the tree it covered (HEAD, dirty flag, diff digest), the phases
requested, each phase's command, exit, elapsed, attempts, and log path, the
skipped phases and why, and the result. A pass binds to that tree; it is not
a standing fact about "the gate." Reuse it only for the coverage it names.
The preflight phase runs first and fails fast on the environmental
prerequisites the later phases assume: a file-descriptor limit of at least
2048 (worktree fan-out tests exhaust less; the script first tries raising
the soft limit itself), cargo, python3, git, and rustup on PATH, the
1.95.0 and 1.94.0 toolchains when their phases are selected, and free disk.
Fix what it names and rerun; it does not skip or weaken a check.
When a phase fails and its log shows resource exhaustion — file-descriptor
pressure, address reuse, or EAGAIN — the gate retries it once and records
both attempts. --no-retry disables that. A retry triggered by a signature
is not a pass over a defect; the log names why it ran.
rust-toolchain.toml pins Rust, Clippy, and rustfmt
to 1.97.1. rustfmt.toml pins Rust and formatter style
editions to 2024. Run the pinned formatter once for formatting-only
changes; do not mix a workspace reformat with behavioral fixes.
Package policy and minimum versions
Workspace packages inherit edition 2024, publish = false, and Rust 1.95
from the root manifest. Kev is the explicit exception: its standalone library
retains Rust 1.94 support, while its workspace test dependencies require
1.95. Every package inherits workspace Rust and Clippy lints, including Nostr
and the relay. Package-license metadata remains pending the owner decision
documented in the dependency policy.
Install 1.95.0 and 1.94.0 alongside the pinned gate toolchain to check those minimums. The script compiles workspace targets with runtime features on 1.95.0 and Kev's standalone library on 1.94.0. These are minimum-compiler checks, not a claim that all runtime tests ran on both compilers.
Feature and infrastructure coverage
The gate checks formatting, strict Clippy, and tests for both default features
and kev/serve,lev/serve,gym/tui,jev/blocking. It then checks minimum compiler
versions, dependency policy, and disposable PostgreSQL acceptance. It stops
on the first failed command; later commands have not run when that happens.
It also runs the small Python artifact-acquisition regression suite before
Rust checks; this suite needs Python 3 and no model weights or network.
Backup collection regressions also run before Rust checks. They force a blob
rename during collection and verify that missing or corrupt bytes prevent
publication. The PostgreSQL phase separately tests backup and restore under
concurrent uploads and deletions.
It also checks the delegation-result validator against completed, refused,
incomplete, and inconsistent execution records before the Rust checks.
The PostgreSQL script needs initdb, pg_ctl, createdb, curl, Python 3,
and ordinary shell tools on PATH. It creates disposable local databases;
never redirect its destructive-test environment to a production database.
Use a separate CARGO_TARGET_DIR per worktree. The acceptance script uses
that target directory for the relay binary it starts.
Optional coverage is explicit:
--skip-postgresprints a skip and makes the run partial. It does not satisfy PostgreSQL release acceptance.--with-metalruns strict Kev Clippy and tests withserve,metalon a supported Apple host with the required Apple toolchain. A successful compile does not establish inference results for external weights.--with-soakruns the existing long-running relay soak against a disposable PostgreSQL cluster. Routine runs print that it was skipped.
FoundationModels tests require the Swift helper, an eligible Apple host, and
model availability. Build the helper with ./scripts/build-lev-bridge.sh and
follow docs/lev/ for model-backed verification. Tests that conditionally
return without an available model are not evidence of live inference.
Coder delegation tests need an enforceable filesystem boundary, bwrap on
Linux with user namespaces enabled. On a host without one, the cases in
crates/coder/tests/program_run.rs and
crates/coder/tests/suite_questions.rs that run or offer a delegate step
print skipping: and return, which is not evidence that delegation works.
Install bubblewrap to run them.
Kev checkpoint conformance, model experiments, hosted Jev calls, and production
relay/worker proofs require their own documented inputs and records. The
routine gate does not download weights or authorize new paid measurements.
Shell orchestration and retained Python training/acceptance tooling are
infrastructure, not additional product implementation languages. Keep product
code in Rust, with the existing Swift FoundationModels bridge exception.
Preserve docs/transcripts/ and do not add GitHub-billed automation.
Dependency policy
deny.toml is the dependency policy: advisories, licenses,
sources, and bans over the resolved workspace graph with all features and
development dependencies. The manual command that enforces it is:
./scripts/check-dependencies.sh
It requires cargo-deny 0.20.2 on the pinned toolchain; install it with
cargo +1.97.1 install cargo-deny --version 0.20.2 --locked. The script
refuses when the RUSTSEC-2024-0436 exception is overdue for review or the
resolved paste version differs from the reviewed one, then runs
cargo deny --locked check advisories licenses sources bans. If cargo-deny
is absent, ./scripts/verify-rust.sh prints SKIPPED: dependency policy
and continues; that result is a partial gate, not a pass.
The dependency policy records the exception's owner,
reason, and review date, the paste dependency paths, and the license
review.
Current verification record
On 2026-09-20, the workspace passed strict all-target Clippy on Rust 1.97.1 with the runtime feature combination after enabling lint inheritance for Nostr and the relay. The workspace also compiled all targets with those features on Rust 1.95.0. Kev's standalone library compiled on Rust 1.94.0 and 1.94.1.
The disposable PostgreSQL acceptance script also passed with a separate
CARGO_TARGET_DIR, including store, gateway, multiprocess, import, release-load,
and binary deployment checks. The long-running soak and Metal checks were not
run for this package-policy change.
On 2026-09-20 at fc385a13a and the Jev fix after it, the whole gate passed
on a Linux host (Ubuntu, x86-64, Rust 1.97.1): formatting, both strict
Clippy runs, both test runs, the Rust 1.95.0 and 1.94.0 checks, the
dependency policy, and the PostgreSQL acceptance script including the
release-load proof. Debian and Ubuntu install the PostgreSQL server binaries
under /usr/lib/postgresql/<version>/bin, which is not on PATH by default;
prepend it before running the gate. Soak and Metal were not run.
Apple serving matrix, 2026-09-20
The Apple serving verification record
records the actual #9426 commands on an Apple M5 Max running macOS 26.4.
Lev default and serve tests and strict Lev/Kev Clippy passed. Weighted Kev
Metal F32 conformance passed for all four retained variants, but the full
serve,metal test command failed in its CPU HTTP round-trip test at the
unchanged 10-second client deadline. bf16 remains unmeasured. This is a partial
matrix, not a successful full gate; #9426 stays open.
Progress during the manual gate
Each manual-gate phase prints its name when it starts, an elapsed-time heartbeat
at least every 30 seconds while its command runs, and its elapsed time and exit
status when it finishes. Command output streams directly to the terminal and,
when a run record is being kept, is teed to that phase's log file. Cargo
tests use --nocapture, so test diagnostics appear while tests run rather than
only after a failure. The gate still stops at the first failing phase unless
--keep-going was passed; a heartbeat reports activity, not success or a
timeout extension.
The phase runner forwards interrupt, termination, and hangup signals to the command's process group and waits for the direct child. It does not add a test timeout, change feature or device settings, or skip an assertion. A test that prints no internal progress still produces the elapsed-time heartbeat.