On this page
Module checks and behavioral qualification
What a committed-source check says about the Rust modules of the exported revision, and why a passing build is not a qualified change. The check runs no Cargo: whether a committed Cargo.lock resolves is answered by the declared gates, which build and test the revision with kompilator over that lock and refuse one that does not resolve.
Interpret module refusals
Compiling nothing, the check reads every Rust crate of the exported tree (a directory with a Cargo.toml beside a src/) from its roots (src/lib.rs, src/main.rs and each [[bin]] path) through its mod declarations, and refuses a mod name; that names no file the commit holds — neither <name>.rs nor <name>/mod.rs where the declaration resolves, nor the file a #[path = "…"] attribute on the line before gives it: <revision> of <checkout> declares module files it does not hold, so no build of it compiles: <file> declares mod , and the tree holds none of <name>.rs or <name>/mod.rs; …, every such declaration named. A commit that deleted a module file another still declares, or declared one it never added, is refused on the push that carries it and in the delivery queue's gates step — which runs this check for a product that declares no format gate — instead of by the first installation that builds on it. The real test is tests/quality/modules.rs.
A declaration inside an inline module resolves where rustc resolves it, one directory deeper under the inline module's name: mod outer { mod inner; } in a/mod.rs names a/outer/inner.rs or a/outer/inner/mod.rs, and is refused only when neither is committed. Braces inside comments, string and character literals do not end the inline module.
The same reading follows every crate::a::b path written in a module the crate reaches, segment by segment through the declared modules. A segment that names a module file the commit holds — <segment>.rs or <segment>/mod.rs where the walk stands — which no mod declaration reaches is refused: that file is not compiled, so the path resolves to nothing. <revision> of <checkout> uses modules no declaration reaches, so no build of it compiles: <file> uses crate::, and the tree holds <module file>, which no mod reaches; …, every such path named. A commit that added a module's file and the code calling it but not its mod line is refused here. Without name resolution the check leaves to the build a segment that names an item, or a module the commit holds no file for.
On case-insensitive filesystems, an item path can open a differently cased module file by filesystem alias. The check compares the committed directory-entry spelling before treating that file as a module; item names remain for Rust name resolution rather than an undeclared-module refusal.
Every Rust file must be compiled by something. The check reads each Cargo.toml of the tree as Cargo does (the paths [lib], [[bin]], [[test]], [[example]] and [[bench]] name, build.rs, and the files Cargo discovers unless the package turns discovery off) and follows their mod and #[path] declarations; a file under a crate's src/, or a file under tests/ holding a #[test], that none of them reaches is refused as stado.quality.check.files-uncompiled: <file> is a source file no mod declares or <file> is a test file no target runs, every such file named. Such a file compiles into nothing while every reader takes it for code, and a test file no target names never runs. A file kept uncompiled on purpose is listed in unreachable_modules.known beside its crate's Cargo.toml, one path relative to the crate per line with the reason after # (the list stado release gate modules unreachable --known reads); a listed path the crate no longer holds is named too (unreachable_modules.known lists <path>, which the crate no longer holds; remove the line). Real test: tests/quality/uncompiled_files.rs.
| What the check reports | What the result establishes |
|---|---|
declares module files it does not hold |
A mod names a file the commit lacks; commit the file or remove the declaration. |
uses modules no declaration reaches |
A crate:: path walks into a module file no mod reaches; declare it. |
stado.quality.check.files-uncompiled |
A source or test file nothing compiles; declare it, give it a target, or list it with its reason. |
A clearer refusal does not make an incomplete graph buildable. Commit and push the repaired source, rerun the quality check for that revision, and inspect the retained release handoff before treating the repair as delivered. Read builds and releases and the release contract for publication, inputs and final-state evidence.
Build success is not behavioral qualification
stado release changes list --id CHANGE_ID --json distinguishes a passing build from passing task qualification. Every required platform must declare post-build tests and retain exactly one passing receipt for each declared test, with its actual command and successful exit status. A platform with no declared tests leaves the handoff awaiting_tests, with no complete passing post-build test evidence; it does not turn an otherwise passing build into a failed build.
Receipts name qualification_policy: required-behavioral-tests-v1. The policy-specific observation is cached separately from historical build-only observations, so an old passed cache cannot supply the new verdict. An unreadable or malformed current observation is an error, not fabricated empty evidence. Oko refreshes receipts that predate this policy and keeps a task open while behavioral qualification is pending or its last read failed. CLI and native task reports consume that same task status; publication alone proves neither a particular defect's replay nor its graphical behavior.
The real read-only regression is tests/release/behavioral-qualification.mjs in the Stado repository:
node tests/release/behavioral-qualification.mjs
Supply STADO_BIN, STADO_TEST_SOURCE_REVISION, STADO_TEST_BUILD_ONLY_CHANGE and STADO_TEST_BEHAVIORAL_CHANGE. The two change IDs must name distinct real isolated fleet handoffs: one passing build without post-build tests and one with successful declared tests. The journey does not create a fake receipt, queue a build or alter its fixtures. It checks actual commands, statuses, receipt identities and the refusal reason, retaining command streams, source revision, binary and journey digests under .build/behavioral-qualification/. Missing fleet access or fixture evidence fails the journey; it is not a pass.
Source: this website