The first Rust audit
Field note. Every number below is from one signed ledger entry,
94d9296c5801
(the signed file
on the corral/ledger branch), and the audit log of the run that wrote it.
What we ran
Warp is a terminal written in Rust, a
Cargo workspace of 80 crates. We picked one small crate,
crates/fuzzy_match: 672 lines of matching logic in src/lib.rs, tested by 33
tests in src/fuzzy_tests.rs. It builds and tests in about a second, so every
planted fault costs almost nothing to run, and its tests live where most of
Warp’s do, in a separate file the source points at:
#[cfg(test)]#[path = "fuzzy_tests.rs"]mod tests;The command, with corral built from main at 59facd91, on a clone of
Warp’s upstream main at 714c51f1e:
corral certify --repo crates/fuzzy_match --substrate workspace --top 1 \ --derive-model gemini-3.8-flash --mutant-model gemini-3.8-flash \ --writer-model gemini-3.8-flash --critic-model codex \ --max-tokens 3000000 -- cargo nextest run -p fuzzy_matchOne model plants faults that break the goal it derived for the file. Warp’s own
cargo nextest runs against each one. For every fault the suite does not
catch, a model writes a test, and corral runs that test against both the fault
and the unchanged code. A fault counts as a proven gap only if the new test
passes on the real code and fails on the fault. The critic seat was the Codex
CLI on a subscription, not an API key; corral can seat a coding agent in any
role now.
What it measured
| faults planted and graded | 34 (40 budgeted from 71 decision points) |
| caught by the crate’s own 33 tests | 11: a kill rate of 0.32, 95% interval 0.19–0.49 |
| got through | 23 |
| caught by a test corral wrote and ran | 22 |
| tried and missed | 1 |
| tokens | 0.3M in, 13.2k out, 35 calls, against a cap of 3M |
| wall clock | 10m08s |
Two of the faults that got through, each one line:
if text.ends_with(suffix) {if text.starts_with(suffix) {for start_idx in 0..text_chars.len() {for start_idx in 1..text_chars.len() {The first is in the fast path for patterns like *.rs: it checks the wrong end
of the text. The second stops a glob from ever matching at the first character.
The existing suite passes with either one in place. corral wrote a test for
each that passes on Warp’s code and fails on the fault.
Where the tests went
A test corral writes has to compile where the project keeps its tests, and in
Rust that is a module, not a file name. Here the source declares its test module
in fuzzy_tests.rs, so corral appends one block to that file and leaves the
source byte-identical:
#[cfg(test)]mod corral_tests { use super::super::*; // 35 tests}super::super because the block sits inside the declared tests module, one
level below the code it tests. The run printed append it to src/fuzzy_tests.rs, and the same path is in the ledger entry, so whoever reads
the record knows where the block compiles.
How we checked it
The run’s own grading is execution: each new test ran against the unchanged code and against its fault. We also checked it outside corral. On a separate clone of the same commit we appended the 35-test block and ran Warp’s command:
cargo nextest run -p fuzzy_matchSummary [0.031s] 68 tests run: 68 passed, 0 skipped33 of Warp’s, 35 of corral’s, all green on the real code. After the run, git status
in the checkout corral had worked in showed no change.
What this does not show
- It is one file. A kill rate of 0.32 on 34 faults has a 95% interval of 0.19 to 0.49. It says something about this file’s tests and nothing about Warp’s.
- A second run plants different faults. The day before, the same command on an unreleased build graded 37 faults, caught 9 (0.24) and proved 27. Both results fall inside each other’s interval. The faults are generated, so the counts move between runs; the finding, that this file’s suite misses most of what was planted, did not.
- A fault that gets through is a missing test, not a bug. The code is correct as far as we know. What the run shows is that 22 ways of breaking it would pass the current suite.
- “Proven” means caught by execution, not reviewed. Each of the 22 proving tests fails on its fault and passes on the real code. Whether each is a test Warp’s maintainers would want is their call, and nobody on their side has seen them yet.
- The tests were written by a model. They compile and run; they are not hand-written, and some overlap.
- Rust has no per-test selection in corral yet, so every fault ran the crate’s whole suite. At about a second a run that cost nothing here; on a slow crate it would.
What broke
Two things, both ours.
corral runs several faults at once, each in a private copy of the directory it
was pointed at. Here that directory was the crate, and the crate inherits
settings from Warp’s top-level Cargo.toml, which the copy did not include. So
cargo refused to build the copies. corral noticed, said why on the scan line,
and fell back to one fault at a time in the real checkout. The result is the
same; it took longer. For a crate inside a Cargo workspace the copy needs the
workspace root, and that is the next fix.
The other we found while writing this up: corral’s Rust preflight asked for a
system-wide Rust install even when no sandbox runs, so a developer with rustup
in their home directory, which is nearly everyone, was refused before
anything ran. That is fixed on main
(#404): the system-wide
toolchain is required only when the jail runs, and a --substrate workspace run
uses whatever cargo is on the PATH. It ships in the next release.
Next
Rust files whose tests sit inline in the same file are still refused; that needs the test block and the planted fault to coexist in one file, which is the next piece of work after the two above. And before any of it, we are going to run corral on a Rust crate the way someone who has never seen it would: a clean account, the public docs, nothing else.