Which gates each step runs
Which gates each step runs
Every gate in platforms.<platform>.quality declares its kind, and the kind decides which steps run it:
"quality": [
{ "name": "journey", "kind": "test", "argv": ["kompilator", "test", "--manifest-path", "Cargo.toml", "--test", "journey"] }
]
kind |
What the gate is | stado quality check without --pre-push, stado release submit --source and the release build |
the pre-push check, stado release changes submit and the delivery queue |
stado change run |
stado quality format |
|---|---|---|---|---|---|
format |
a formatter (Biome, or a web product's stado web quality); no Wisent gate formats Rust |
does not run | does not run | does not run | writes with a declared formatter; refuses to write web source |
lint |
a static check that compiles or analyses the source | does not run | does not run | does not run | does not run |
test |
a test the source carries; its compile is part of it | runs | does not run | runs on fleet hosts | does not run |
No step formats, lints or compiles to judge a tree: whether code compiles is learned from reading it and from the tests that compile it, and a test that does not compile fails as the test it is. The pre-push check, the change hand-off and the delivery queue check the committed source alone, its lock resolution, module declarations and reach, and ask no admission. Reach is two judgements of the lines the revision adds against its published origin/main: a service a capability family offers alternatives for dialled directly (Capability alternatives), and a catalog product the catalog does not show the product running without (Products, the same standing stado product dependencies reports). A format or lint gate a manifest still declares is read and validated, never run by a check. A kind other than these three, or a gate without one, is refused when the manifest is read, naming the field.
stado product install and stado product update run no gate of any kind: they export the committed revision, build it and place it. Whether the code compiles is learned from its tests and from reading it; a revision that does not build fails the install's build step, naming the build evidence, and no earlier verdict refuses it before it is exported.
Full qualification of the staged Stado CLI also reads the native installed
unit files for its platform and parses each Stado unit's argv with that
candidate (stado quality units --candidate <binary> --program stado --platform <platform>). A rejected unit refuses publication with its host,
path, argv, candidate, parser exit and stderr. An unreadable host is a refusal,
not an empty set of compatible units. stado quality parse -- <argv> exposes
the parser check without executing the requested command.
A gate that reads a release input names it under inputs, by the manifest's own key: { "name": "web-quality", "kind": "format", "argv": ["stado", "web", "quality", "--git-input", "wisent-errors-bundle=wisent-ai/wisent-errors.git"], "inputs": ["wisent-errors-bundle"] }. The pre-push check stages exactly the inputs the selected gates name and leaves every other pinned input in its store after confirming it is there, because a gate's script reads WISENT_INPUT_<NAME>_DIR where no reader of the manifest can see it and staging every pin fetched a desktop's whole SwiftPM resolution on every push for a formatter that reads the source alone. The release build stages every input whatever the gates declare. A gate naming an input the manifest does not pin, or naming one twice, is refused when the manifest is read: <platform>: quality gate "<gate>" reads release input "<name>", which the manifest does not pin under inputs. The real journey tests/quality/release_inputs.rs runs a gate without inputs over a stored pin and requires the input to stay in the store, a gate with inputs and requires it to read the staged bytes, and a gate naming an unpinned input and requires the refusal by name.
A gate's refusal names the gate and its kind: stado quality check: gate "<name>" (<kind>) of <product> refuses <revision> of <checkout>: <the gate's own report>. A non-web format gate ends with `stado quality format` writes what it reads. A web format gate ends with web gate: inspect the failed command and output; `stado quality format` does not write web source: inspect the command and diagnostics above it, whether an npm ci refusal or npm run typecheck naming a TypeScript file, and repair the cause with the product's own tools. A lint or test gate ends with a <kind> gate's refusal is repaired in the source it names; `stado quality format` changes nothing for it. A typecheck or clippy finding is never answered with a reformat. The real journeys tests/quality/web_typecheck.rs and tests/quality/gate_kind.rs exercise those refusals, a repaired committed source and a passing gate.
The web journey's isolated checkout locks a real TypeScript compiler and runs tsc --noEmit against an incompatible type before committing the corrected source. It checks the separate missing-script, failed-install and failed-typecheck refusals rather than treating a JavaScript syntax check as type qualification.
kompilator test --manifest-path stado-rs/Cargo.toml --test quality-web-typecheck
The gate-kind journey declares a format and a lint gate that refuse every tree beside a test gate that compiles the source's tests and runs them, and checks that the source passes, so neither refusing gate ran. It commits Rust sources whose compiler fails on a missing name and whose executed test assertion fails, and checks that each is refused as the test gate's failure, naming the compiler's or the assertion's own words. It retains actual commands, exit statuses and output; it never substitutes a canned nonzero command for compilation or a test failure.
It requires the real rustup toolchain with rustc available. A missing compiler fails the journey at that prerequisite; it is not a successful gate verdict.
Both journeys retain the source HEAD and any uncommitted source changes alongside recorded Stado, Git and dependency-command exit statuses and output. The report path is printed at fixture start, including on a failed prerequisite. A dirty checkout is recorded as such, not labelled an exact clean source revision.
kompilator test --manifest-path stado-rs/Cargo.toml --test quality-gate-kind
The check exports committed source into Stado's managed run area and removes its own export when finished. Every gate and the candidate build compile with kompilator, whose units are kept where KOMPILATOR_CACHE names, else in the build's own output directory (kompilator); the finished artifacts stay in the export, where the recipe's stage reads them. On a later check it reclaims an abandoned area only when its owning process is gone. An unreadable run directory, a name without a valid process ID and full hexadecimal commit revision, or a failed process inspection is reported with its path and cause on stderr and left intact; this diagnostic does not turn a quality-gate refusal into a formatting problem. The isolated tests/quality/link_input journey checks the preserved unrecognized area and repeated cleanup.
In Stado Desktop, Releases → Available operations… → Check committed gates and the built CLI command tree takes a repository path and exact revision on the selected Stado API host. Its Operation failed panel shows the CLI result message; Complete operation receipt retains stderr, including the failed script output and the web-specific refusal. The screen does not reinterpret the failure as a formatter request.
A gate that compiles with Cargo (every kind but format, and the build of the candidate CLI) runs with --message-format=json added before its --, and its diagnostics are read from the records Cargo prints, not from the words of its report. Each compiler diagnostic with a primary span is one finding: its location <file>:<line>:<column>, the lint or error code the record carries (clippy::needless_return, E0425) and its level and message. The rendered text of every diagnostic is printed where the check's lines go, as the compiler wrote it. The refusal then reads <argv> exited <status>; <n> finding(s): followed by one line per finding, <file>:<line>:<column> [<lint>] <message>. A gate that names no finding — a format gate, a gate that is not Cargo, a failure that is no compiler diagnostic — carries its whole report instead. A gate that sets --message-format itself is refused, naming the flag, since the records the check reads are the ones it asks for, and a line that begins as a Cargo record but does not read as one is refused quoting it. With --json the progress lines and the gate's report go to stderr and stdout carries one document: {"status": "passed", "revisions": [...]}, or the failure envelope whose details hold argv, exit, report and findings (location, lint, message), so a caller acts on the finding without parsing the sentence:
stado quality check --root /path/to/product --revision COMMIT --json
The main check of stado ci run records that same refusal on the red commit and in the Oko defect it files for the commit's authors. Read one gate's findings on a revision by running that check with --revision; stado product kompilator runs no gate (its one operation is stage), and Stado Desktop's Products "kompilator-stage" operation runs the same stage.
A manifest gains the field without breaking an older Stado: an installed Stado that predates kind ignores it. Push the manifests first, then install the Stado that reads kind; the other order makes the new Stado refuse every manifest that has not gained the field yet.
Source: this website