On this page
Walkthrough: release end-to-end
How does a committed source tree become the exact bytes every fleet host runs, and how do you take it back? This page walks one release from source to fleet and back as commands and their readings. The strict manifest and catalog contract lives in release; what a release is lives in primitives/release; the operational entry points live in operations.
Catalog first
Stado owns product release policy independently of repository hosting:
stado release catalog sync --catalog /path/to/release-catalog.json
stado release catalog audit
Sync imports the fleet's reviewed central catalog — including explicit
releases:false manifests — refuses missing or duplicate product names, and
CAS-updates stado://system/release-catalog/<product>.json; --root ROOT
bootstraps a catalog from local registered checkouts. Audit reads only Stado
catalog objects and refuses malformed, duplicate, or silent catalogs; it does
not enumerate a Git forge or require forge tokens.
Submit
stado release submit --source /path/to/product --version <exact-version> \
--channel candidate
Submit requires a clean committed tree and never contacts a Git remote. It
verifies --version against the product's checked-in version source,
archives the exact committed tree, publishes the create-only source object at
stado://sources/<product>/<sha256>/source.tar.gz, records source and
manifest identity in the catalog, and creates one provider-neutral queue job
pinned to a registry builder whose release_platform matches the recipe.
Run identity is derived from product, version, channel, source digest, and
manifest digest, so repeating the same submit resumes the run instead of
starting another. The durable run record at
stado://<queue-namespace>/runs/release-pipeline/<id>/run.json shows job
IDs, output coordinates, delivery state, and failure. A terminal successful
platform output is read from JobStorage and published, never rebuilt.
Qualification, signing, publication
Builders receive no repository coordinate or repository token: they
materialize only the exact source URI and declared immutable inputs, run the
manifest's quality argv in order and one build argv, and write
status/<job>/output/{receipt.json,release.tar.gz} through the queue's
canonical job-output collection.
Publication under the immutable coordinate
stado://releases/<product>/<version>/<platform>/ is ordered:
release.tar.gz -> qualification.json -> release.sig -> release.json
The signed manifest (release.json) is written last and is the commit
marker: required delivery jobs run only after it exists and consume its exact
URI and digest. The signing key stays in Skarbiec — only the item name
(stado-release-signing) and the trusted key ID are configuration, never a
secret value in a manifest or command line. Optional mirrors (a Git forge
among them) do not gate canonical success.
Promote
stado release promote <product> <version>
Promotion changes references, never bytes: it re-fetches every platform,
verifies the exact bytes, signature, and passed qualification, then
compare-and-swaps one desired registry.release_control generation. It never
rebuilds.
Hosts converge
The per-host declaration is targets[].managed_versions — the exact
semantic version each stado-managed binary must run on that host, written by
the operator:
stado host declare-version <target> --binary <name> --version <X.Y.Z>
stado service converge <target>
converge compares each declared version against what the host actually
runs. Verdicts are in-sync, drifted, and unknown for a binary whose
installed version could not be read; unknown is never folded into either of
the other two, so an uninstalled reporting helper cannot masquerade as drift.
Reporting exits non-zero on drifted alone; --apply delivers the declared
version of every drifted binary through stado host release, re-reads the
installed versions afterwards, and exits non-zero unless every binary in
scope is confirmed in-sync. converge never writes the registry: the
declared version is the operator's statement of intent, and a converge that
edited the document to match the host would turn a drift report into a
rubber stamp.
Runtime products on registry hosts also converge without an operator:
stado release agent reconciles desired releases on its exact registry
target from the release_control desired generation.
Verify the rollout
stado release status <product>
status joins desired state with each host's observed rollout state and the
host's own software report, and exits non-zero for a host that has never
reported, reports stale, or runs unmanaged bytes — silence is a failure,
never a pass. The rollout is done when deployment.json exists: it is
written only after every declared target reports the promoted version,
artifact digest, and manifest digest exactly.
Back out
stado release rollback <product>
Rollback atomically restores the previous desired release — the exact previously recorded coordinate, never a rebuild in place.
If one host keeps refusing a version it was already given, check quarantine. The release agent quarantines a digest that failed to become ready and never retries it on its own — correct, since a candidate that dies in ninety seconds must not respawn in a loop:
stado release quarantine list <product> --target <target>
stado release quarantine clear <product> --target <target> \
--digest <digest> --reason "<why this digest gets another chance>"
clear starts nothing, restarts nothing, and kills nothing: it removes one
map entry, and the agent's next tick finds the desired digest no longer
quarantined and rolls it out on its own — the same path it would have taken
had the digest never failed. --target and --reason are never inferred or
defaulted; the reason is recorded in the audit trail beside the host's
rollout state.
Symptom-first triage for a release that did not land lives in the runbook; flag-by-flag detail lives in cli.
Source: this website