Source handoff and later batch qualification
How a commit reaches a release after its author pushes it.
Writing code does not start a release. The author commits, pushes to origin/main,
then records the Oko work item (a task, task- and 16 hex digits, or a registered defect, defect- and 8 hex digits) and the exact full commit:
stado release changes submit --source /path/to/product --commit FULL_SHA --task <task-id> --session AUTHOR_SESSION --json
stado release changes list --task <task-id> --json
stado release changes list --id CHANGE_ID --id CHANGE_ID --json
--id (repeatable) reads only the named tickets: a caller that follows a few handoffs, such as Oko refreshing its unsettled qualification receipts, does not wait on every ticket the fleet ever queued.
Admission checks the committed product manifest and the remote branch's actual
ancestry. A checkout that is not on main (the refusal names the checkout and
its branch), a missing work id or session, a commit that is not on origin's
main (the refusal names the repository and origin's head), an unreadable remote
and releases:false are stated refusals. Repeating the same handoff returns its
identity; it neither creates another ticket nor resets a failed qualification.
Admission also runs the product's own lock and formatting gates over the
handed-off commit, the check stado quality check runs: each committed
Cargo.lock must resolve its manifest, and every fmt gate the platform
manifest declares must pass on that commit, exported beside the checkout and
not written to it. A commit that fails one is refused before any ticket exists:
<commit> is not handed off: stado quality check: gate "fmt" of <product> refuses <commit> of <checkout>: …; stado quality format writes what it reads.
The gate's own output (the formatter's diff) goes to stderr, so --json keeps
one ticket on stdout. Commit and push the formatting, then hand off that commit;
an unformatted commit otherwise reaches the batch build and fails every other
session's work in that batch.
The check runs cargo, and each gate's program, from the paths the fleet
declares for that program — the table stado host exec probes, for Cargo
~/.cargo/bin/cargo, /Users/Shared/.cargo/bin/cargo,
/opt/homebrew/bin/cargo and /usr/local/bin/cargo in that order — and never
from the calling shell's PATH, so a shell started outside a login hands off
exactly as a login shell does. A program installed at none of them is refused
with every path tried: cannot run cargo: cargo is installed at none of its declared paths: /Users/<you>/.cargo/bin/cargo, …. A program the table does
not declare runs as the manifest names it.
Before the gates run, the same check confirms every release input the manifest
pins (inputs.<name>.uri) is in its store, and stages the inputs a selected
gate declares it reads as the release worker does: a gate names them under its
own inputs ({"name": "web-quality", "kind": "format", "argv": [...], "inputs": ["deep-analytics-bundle", "onboarding-web"]}), and for each the
check fetches the object, checks its bytes against the pinned sha256,
extracts or mounts it beside the exported tree as extract declares, and hands
the gates the same WISENT_INPUT_<NAME>_DIR variables (the name upper-cased,
every other character an underscore). A gate that reads an input, such as
stado web quality --git-input, therefore gives the verdict here that it gives
on the builder. An input no selected gate declares is confirmed stored and left
there (release input <name> is stored at <uri>; no selected gate declares reading it, so it stays in the store): a formatter reads the source alone, so
a push never fetches inputs, such as a desktop's whole SwiftPM resolution, that
no selected gate reads. A release build stages every input whatever the gates declare. A gate
that names an input the manifest does not pin is refused when the manifest is
read: <platform>: quality gate "<gate>" reads release input "<name>", which the manifest does not pin under inputs. An input whose object is not there is
refused: release input <name> of <product> pins <uri>, which <store> (<backend>) answers is absent: store the object the pin names, or pin one that is stored; one whose bytes differ: release input <name> of <product> at <uri> hashes to <digest>, but the manifest pins <sha256>. This is the shape of a pin
written before its archive was stored, or of a Cargo.lock that moved past
the archive exported for it; store the exported archive with stado storage put <uri> <file>, or repin the manifest. A store that refused, could not
answer now or could not be reached is reported as that state, the same
five-state answer stado storage stat gives, and never as absent. A passing
check ends with <product> resolves its locks, passes its quality gates and finds its release inputs stored at <commit> of <checkout>.
stado web quality --git-input INPUT=OWNER/REPOSITORY.git answers a private
Git dependency from an input that is a Git bundle mounted as a file
("extract": false): both spellings GitHub is reached by are rewritten to the
bundle's path, which Git clones and lists as a repository.
stado quality format [--root DIR] writes with the declared gate's own
formatter (its argv without --check) and then runs the gate's check. One
rustfmt pass is not always enough: a match arm whose body is a literal longer
than the line becomes a block only on the next pass. So format writes again
while the check refuses, printing stado quality format: gate "fmt" still refuses after that pass; writing again, and ends when the check passes. A pass
that leaves the check's report exactly as before is refused with gate "fmt" of <product> still refuses <dir> after left its report unchanged, so another pass would not satisfy it either; the gate reports: followed by that
report, because no further pass would change it.
The coordinator later runs stado build submit --source DIR --commit FULL_SHA --version V --json for the accumulated source. Before jobs start, Stado freezes
the waiting changes whose commits are ancestors of that build. The binding is
stored at runs/build/<build id>/changes.json, beside the build record, and is
never rewritten. Unrelated branches and already-qualified changes are not
attributed to that build. A change submitted after the freeze whose commit the
same build contains — a build is identified by its commit, so building that
commit again reaches the same build — is bound in an additional batch
runs/build/<build id>/changes-<digest>.json the next time the build is
submitted, and from then on reads that build's verdict instead of staying
queued. No release or signing grant is
needed to read its qualification; release submit --source uses the same build
admission. There is no per-commit build poller, and handoff spends no build budget.
Each platform manifest can declare tests, an array of named argv steps.
They execute after a successful build and before packaging and publication.
Receipts retain the exact source, job, platform, commands and exit statuses;
test entries in quality use the test: prefix. A test step belongs in a
manifest only once the operator has approved its path with tama tests approve. Under required-behavioral-tests-v1, a passing build without
declared tests on any required platform remains awaiting_tests, not
qualified. Each required platform must retain exactly one passing receipt
entry per declared test, with matching argv and successful exit status,
alongside a passing build. Missing, duplicated or mismatched test entries
cannot qualify the change. Older workers that did not execute the declared
steps cannot provide passing qualification evidence. The policy is returned
as qualification_policy; observations cached under a former build-only
policy are not reused as behavioral proof.
An awaiting_tests observation names its platform and the first unmet proof
obligation: no tests declared, no receipt for a named test, duplicate entries
for that test, recorded argv differing from the manifest, or an unsuccessful
build/test status or exit code. Command mismatches retain both declared and
observed argv; execution failures retain the actual status and optional exit
code rather than inventing an exit. The worker's own failed-receipt cause
remains authoritative. Read evidence for the complete retained receipts.
Such a platform is named before anything is built, not only after: stado release catalog enroll <checkout>, stado build submit --source DIR --version V, and stado release submit --source DIR --version V refuse a
manifest whose required platform declares no tests. The refusal names the
product, platform and awaiting_tests consequence, and asks for real product
journeys in that platform's tests array in .wisent-release.json. It is
returned before Stado publishes the source object, creates a build or claims
a version. stado release catalog audit lists every catalogued deficient
manifest and exits nonzero. These commands use the same declaration rule;
a build or qualification observation recorded before this admission rule
remains awaiting_tests, not passed.
Step names must be unique across both quality and tests in one platform.
Reusing a name refuses admission
before a handoff or build is created; the diagnostic names the platform and
the duplicate step. Correct the manifest, commit and push it, then submit the
new full commit. Renaming a step does not remove or skip its command.
changes list reports queued, building, awaiting_tests, passed or
failed, with the build id in run_id, observed failure and worker evidence.
stado build status BUILD_ID --json reads that build. Qualification reads
terminal jobs itself; it does not require publication or a prior status query.
A failed required platform, including a placement refusal before a job exists,
fails its covered changes. Optional platform failures stay in the evidence and
do not override required-platform success. A failed read is an error, not an
empty queue. Oko's task control refreshes these records. An accepted handoff
records source ownership; it does not finish a task while qualification is
pending or failed. Passing fleet evidence cannot override an unmet acceptance
check, a recorded blocker, a later operator correction or an applicable
independent not-done/blocked judgment. A batch failure identifies the covered
set; it does not claim to have isolated which commit caused the failure.
Stado Desktop exposes the same operations in Releases:
Hand pushed work to a later build and Read waiting changes and batch test verdicts.
The read form accepts the optional task identity and exact handoff identities,
one per line. Supplying both restricts the result to those handoffs belonging
to that task, just as combining CLI --task with repeated --id does.
The result retains the same platform-specific qualification failure cause.
Oko Desktop exposes source handoff and verdict refresh in each Tasks row.
Source: this website