On this page
Delivery destinations
Release source declares what to install. The canonical registry declares where it belongs. A product can select its declaration with "target": { "product": "example-product" } on each delivery in .wisent-release.json. The product must match the manifest's own product. Registry hosts never need to appear in that source.
Declare and inspect
stado release destinations list --json
stado release destinations show PRODUCT --json
stado release destinations set PRODUCT --target HOST_A --target HOST_B --json
stado release destinations adopt PRODUCT --json
stado release destinations remove PRODUCT --json
set replaces the complete target set in registry.release_delivery_targets.PRODUCT. Targets must be distinct registered identities with declared release platforms. The normal validated compare-and-swap writer preserves other products and verifies the stored registry. show reports the declaration, platforms and registry generation; it does not claim that software is installed. remove removes the declaration, not installed files or an existing release's retained placement. A subsequent release needs a declaration again.
adopt reads the product's existing release catalog and adopts its explicit delivery hosts. Repeating the same adoption is safe. It refuses to replace a different existing destination declaration; an intentional replacement uses set.
Catalog publication also adopts destinations when a product first replaces explicit delivery hosts with product selectors. It reads the preceding catalog entry before overwriting it. It preserves every former delivery operation, including argv, platform, required status and secret references, and checks that each selector resolves to that operation's former host set. Missing authority, changed host coverage, removed operations or dependencies that cannot be mapped refuse migration. An existing validated destination declaration is authoritative and is never overwritten by adoption. There is no guessed builder or all-fleet fallback.
Freeze each release
Stado resolves the declared hosts against each delivery's runner_platform before it queues deliveries and retains deliveries/placement.json under the run. The record binds the run ID, source digest, manifest digest, registry generation and exact target/platform pairs. Every matching target gets its own delivery with the source's required status; dependencies wait for every expanded predecessor.
A delivery named native-cli becomes native-cli--HOST for a declared host. Names that collide are refused before queueing. A delivery platform with no matching destination, or a declared destination with no matching delivery platform, is refused rather than silently omitted. The binary and its helper remain separate required deliveries from the same platform archive.
Resume and redelivery read the retained placement, not the current destination declaration. A missing or mismatched placement refuses those operations instead of selecting replacement hosts. A failed destination keeps its own refusal and does not prevent independent destinations from being queued. stado release status PRODUCT --json reports the expanded delivery names, jobs and recorded failures. stado machine status JOB_ID and stado machine logs JOB_ID read the exact job's observations.
Plain status also prints each delivery's exact output_prefix and, when
present, its accepted receipt_sha256. The digest remains visible after a
later proof failure: it identifies the previously accepted bytes, not a
claim that the current receipt is still valid. The recorded state and cause
must be read alongside it.
The placement is an ordinary retained object at stado://NAMESPACE/runs/release-pipeline/PRODUCT/RUN_ID/deliveries/placement.json; NAMESPACE is the configured Stado storage namespace. Read it with stado storage cat to compare the run's frozen destinations with today's declaration.
An explicit string target still selects that exact registry host. An empty string retains builder placement for operations such as publication that do not install onto a declared consumer. An object-valued product selector never takes that path. Older Stado readers that only accept string targets reject the manifest; update both submitters and workers before releasing it.
Refusals
A missing declaration names the product and the destinations set command. Invalid products, empty lists, duplicate or missing targets, and targets without a release platform fail without a registry write. Registry reads and conditional-write failures retain their actual causes. Adoption cannot silently overwrite another declared host set. A run with recorded attempts but no placement fails with refusing to choose replacement hosts. Redelivery with a missing placement fails with redelivery cannot choose destinations from the current registry. No published artifact for a delivery's platform is a recorded delivery failure, not a panic or a successful omission.
Desktop
The Releases screen exposes Read declared delivery destinations, Read one product's delivery destinations, Replace a product's declared delivery destinations, Adopt the catalog's existing delivery destinations, and Remove a product's delivery destination declaration. It sends the same operations to the selected Stado API host. Reads do not request mutation confirmation. Set, adopt and remove use the existing mutation review. The complete operation receipt preserves the registry generation, stdout, stderr and process result. Release status continues to show each expanded delivery and its own failure.
Select a pipeline run to read every delivery, including successful deliveries without a failure message. Its details show the job, required status, platform, output prefix and any accepted receipt digest, followed by the complete failure cause when present. An empty output prefix is displayed as recorded, not replaced by a guessed job path. Missing or wrongly typed required delivery fields produce the release response's decoding error.
Real qualification
The reusable journey is tests/release_destinations/ in the Stado repository. Run it from that checkout with a committed candidate source and the dedicated fixture configuration:
STADO_DESTINATION_JOURNEY=<configuration.json> cargo test --locked --manifest-path stado-rs/Cargo.toml --test release-destinations-journey -- --ignored --nocapture
The fixture supplies real authenticated storage, signing credentials, native workers and the Stado API used by Desktop. The test invokes Cargo's actual candidate stado executable, requires its reported source identity to match the clean checkout, and retains its checksum. It does not replace providers, fake transcripts or substitute a dry run for release delivery.
Configuration fields are shown below. Replace every angle-bracket value with the actual isolated fixture's value. Both worker accounts must be dedicated test accounts, not the operator's accounts or aliases. The product checkout is the existing canonical checkout; the journey reads its declared commit without cloning it or changing its branch.
{
"home": "<isolated existing home>",
"config": "<isolated STADO_CONFIG file>",
"source": "<canonical Jeden checkout>",
"commit": "<full product source commit>",
"version": "<version declared by that commit>",
"product": "jeden",
"targets": ["<darwin-target>", "<linux-target>"],
"consumer_instances": {
"<darwin-target>": "<actual worker instance_ref>",
"<linux-target>": "<actual worker instance_ref>"
},
"api_origin": "<dedicated Stado API origin>/",
"api_token_file": "<dedicated API bearer file>",
"checks": [
{"binary": "jeden", "arguments": ["--version"], "expect_version": true},
{"binary": "jeden-sandbox-helper", "arguments": ["--version"], "expect_version": true},
{"binary": "jeden-sandbox-helper", "arguments": ["--probe"], "expect_version": false}
]
}
Before a write, the journey compares successful live reads from the fixture and operator stores. The fixture must have a different canonical registry and empty product catalog and release prefixes, while the operator's corresponding records remain stable and present. A second local configuration file or a different printed registry URI is not isolation proof. The native API must read the same isolated registry as the test CLI.
The journey creates, reads, replaces and removes a declaration through CLI and API. It verifies duplicate, missing and unknown targets, unconfirmed graphical mutation, conflicting adoption and dropped-installation refusals against persisted state. It publishes an actual legacy catalog derived from the committed recipe, then exercises automatic adoption into the host-independent catalog. It builds and delivers the exact candidate on every matching worker, changes the declaration, resumes against frozen placement, removes the declaration and redelivers to a formerly selected host. It reads each real job's terminal state, stored worker identity and complete command log. Finally it runs the configured installed binaries as normal machine jobs, including both version reads and the real sandbox probe.
Completion is not assumed after a single resume. When a pass returns submitted
jobs, the journey observes those real jobs with machine status --until terminal
and resumes only after their terminal observations. A failed job retains its
actual observation; a nonterminal run with no new job to observe fails explicitly
instead of sleeping or endlessly rereading the same state.
The receipt-integrity part uses that completed worker's actual output, not a
constructed successful receipt. Through storage get, put and rm in the
isolated namespace, it removes or corrupts the receipt, checks replay and new
redelivery admission refusals, and compares the retained transaction bytes.
Cases cover malformed JSON, missing or unknown fields, wrong field types, each
release/job/artifact identity field, schema, required status, secret references,
arguments, an empty or changed executable, failed status, an unsuccessful or
absent exit code, invalid completion time and a byte-only change to an otherwise
valid receipt.
Each refusal must retain the job identity and the relevant concrete cause.
The selected real delivery must be required. Before restoring its receipt, the
journey runs ordinary release resume twice: once from retained passed state
and once from the resulting failure. Both must refuse with the actual cause,
persist failed run/delivery state and preserve the same job and accepted digest.
The journey restores and downloads the original bytes even after a failed
assertion. Resume must then recover that same delivery and its response must
match persisted state; replay must still return the original accepted job.
Reports include each corruption and restoration result. These cases qualify
normal retained-proof refresh plus redelivery admission and replay. Live
sibling/dependency transitions and graphical qualification remain distinct.
Every corrupted-proof replay and new-admission case also runs through the
selected Desktop API's POST /api/operator/run command transport. Its response
must retain an executed nonzero exit and complete stderr with the same job and
cause; an HTTP admission rejection is not a substitute for the command failure.
After both failed passes and restored success, the journey compares CLI and
native API release status --run delivery records against the persisted run,
then checks that text status retains the actual job, output prefix, accepted
digest and every line of the recorded failure.
Reports under .wisent-output/release-destinations/ retain the source revision, executable checksum, commands, exit statuses, HTTP responses, registry observations, placement and worker receipts. Test releases and evidence remain in the dedicated fixture; use a fresh isolated fixture for another journey. Missing workers, credentials, source or release bytes fail qualification.
Source: this website