On this page

Release

What exactly is a release in Stado, and what makes it safe to put on a fleet host? A release is an immutable, signed set of objects whose identity is verified at every step from publication to the running process.

What it is

A release is published under an immutable coordinate, stado://releases/<product>/<version>/<platform>/, in one canonical order:

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 (operations). A release run marks a platform published only once release.json and release.tar.gz read back through the release reader; when either cannot be read yet, the platform is refused with the objects and that reader's origin named, no delivery is queued, and stado release resume marks it published once they can. The manifest binds product, SemVer, platform, source revision, archive digest and size, binary and launcher paths, config and state schemas, minimum Stado version, rollback compatibility, qualification evidence, builder and key id (architecture). Promotion changes references, never bytes: stado release promote re-fetches every platform, verifies the exact bytes, signature and passed qualification, then compare-and-swaps one desired registry generation. It never rebuilds (cli).

One run per product and channel is worth building. A submission supersedes every live run of the same product and channel it replaces (a lower version, or the same version submitted earlier): that run is marked superseded and its builds are cancelled, queued or running, the way stado cancel JOB_ID cancels a job, so the builder and the product's Cargo directory there go to the run that replaced it. Each platform records superseded by release run <id> (<product> <version>).

Reads under stado://releases/ are public and bearer-free through the one durable origin, https://stado.wisent.com/api/release/object. Publication is authenticated and create-only. The signing key stays in Skarbiec: only the item name (stado-release-signing) and the trusted key id are configuration (operations); the consumer that reads it is a dedicated grant.

Who declares it

stado release submit starts from a clean committed tree, verifies the explicit --version against the product's checked-in version source, and never contacts a Git remote. Run identity is derived from product, version, channel, source digest, and manifest digest, so repeating the same submit resumes the run; a published platform is verified, never rebuilt (release).

The per-host declaration is targets[].managed_versions in the registry: the exact semantic version each stado-managed binary is required to be at on that host. A target that omits it declares nothing and is reported undeclared, never as agreeing (architecture). Operators write it with stado release version declare --host TARGET --binary NAME --version X.Y.Z.

Who observes it

The host re-verifies every manifest binding before extraction and rejects links, traversal, excessive entry counts or expanded size (architecture).

stado release version show and stado release version converge are the reconciliation of managed_versions: per declared binary it compares the declared version against what the host actually runs (cli):

Verdict Meaning
in-sync The host runs exactly the declared version, and its delivery receipt names the revision the declared release was built from. A receipt that names no revision, or a declared release whose signed manifest cannot be read, is still in-sync, and the detail says the build was not compared and why.
revision-mismatched The host runs the declared version string built from another revision than the declared release: the receipt beside its staged copy names a different source_commit than the release's signed manifest names. Report mode exits non-zero; version converge reinstalls the declared release over the staged copy and re-reads afterwards.
host-behind The host runs strictly older; version converge delivers the declared version and re-reads afterwards.
host-ahead The declaration is stale; delivery would downgrade a live host, so version converge refuses and names the version declare command that fixes the document.
host-missing The reporter answered and there is no artefact at all: the host declares a binary it does not carry. version converge delivers the first copy — nothing is replaced, and no process is running the declared binary.
unknown The measurement failed: nothing usable came back. Never silently treated as in-sync, and never delivered to.

With --json each row also carries installed_revision, the revision the host's delivery receipt names (null when none does), and declared_revision, the revision the declared release's signed manifest names, or {"unreadable": "<cause>"} when it could not be read.

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. It also reports which artefact the live process is actually running (running_binary, binary_matches_process), because an installed version says nothing about a process that started before it (cli). When the host could not be asked about that process, both fields are null, process_error carries the cause, and the table run prints it on stderr beside the unknown process cell.

stado release 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 (cli).

Each run in stado release status --json carries phase: published once the channel pointer has moved (promoted, reconciled, completed), failed for a run that died or was superseded, and in_flight while it is still building, publishing or delivering. Stado decides the phase once, from the run state's own definition, so Stado Desktop's release console colours a row from that field instead of re-reading the state word.

Delivery input refusals

The delivery worker refuses unreadable request JSON with the request path and actual filesystem or decoder cause. An unsupported request schema names the observed version. Archive and source-archive read failures name the specific path and filesystem cause; a digest disagreement names the input, its measured SHA-256 and the digest declared by the retained request. These checks precede extraction and delivery command execution.

After decoding the request, the worker requires its queue-supplied WC_JOB_ID. An unset, unreadable or whitespace-only value is refused with the request path and exact cause before consulting release state, extracting files or executing the delivery. A successful worker retains that same job identity in its receipt; it never substitutes an empty identity after running the command.

Inspect the failed delivery through stado release status --product PRODUCT --json and the same run in Stado Desktop's Releases screen. Plain CLI output also lists each delivery's state, platform, required flag, job identity and complete retained diagnostic. The graphical run pane includes every recorded platform and delivery diagnostic, not only the first run-level failure. This exposes optional delivery errors and failed legs while other deliveries remain pending. Desktop requires the canonical deliveries map; a missing or malformed map is a decoding error, not an empty successful delivery list. Its error names the response coding path, missing key or expected type, decoder description and underlying cause when present. A failed refresh preserves the previous displayed diagnosis instead of replacing it with an empty run list. A queue outcome is not proof that the inputs or terminal receipt were valid. The original run, product and published-platform fences still apply.

Run node tests/release_delivery/job-identity.mjs from the Stado checkout. Declare STADO_BIN, its exact STADO_TEST_SOURCE_REVISION, and STADO_TEST_DELIVERY_REQUEST pointing to a genuine retained delivery request. The journey requires a committed matching checkout and verifies the executable's embedded revision. It invokes the real worker with an unset, empty and whitespace-only job identity in isolated homes, checks the specific refusal and preserved request, and checks that no output or local queue store appeared. It also exercises a missing request and malformed JSON before queue identity admission, retaining the measured filesystem error number and decoder cause. Both refusals must identify the input path and leave the inputs, delivery output and local queue store unchanged. Archive/schema qualification still requires a genuine current queue job and release fixture. Reports under .build/delivery-job-identity/ retain command exits, diagnostics, source and executable identities, and request digests.

Where it lives

Coordinate Contents
stado://sources/<product>/<sha256>/source.tar.gz Create-only deterministic source archive with commit and manifest identity.
stado://releases/<product>/<version>/<platform>/ Archive, qualification receipt, signature, signed manifest — immutable, in that order.
stado://<queue-namespace>/runs/release-pipeline/<id>/run.json Durable run record: job IDs, output coordinates, delivery state, failure.
registry.release_control Desired generation, moved only by compare-and-swap.
deployment.json Written only after every declared target reports the promoted version, artifact digest, and manifest digest exactly.

Commands

stado release submit --source /path/to/product --version 1.4.2 --channel candidate
stado release catalog sync --root /path/to/registered-checkouts
stado release catalog audit
stado release version declare --host example-host --binary stado --version 0.6.0
stado release version show --host example-host
stado release version converge --host example-host --binary stado

Flag-by-flag detail lives in cli.

Not to be confused with

  • A build. Builds publish artifacts and record versions; they never write release_control.products[...] desired state. Promoting a signed release is a separate, deliberate step (cli).
  • A git commit or channel. managed_versions values are exact semantic versions — a channel, alias or range cannot be compared for equality, and equality is the whole of the question (cli).
  • A mirror. Optional deliveries (a Git forge among them) may mirror completed releases, but their availability cannot change source, qualification, signing, desired state, or observed rollout truth (operations).

Source: this website