A release is often represented by one badge: released or not released. Real release pipelines usually have more than one output, and those outputs can reach different states.
WorldScript Studio’s v1.29.0 is a clear example. The signed tag exists and tag verification passed. The Docker publication succeeded and produced a GHCR image. The security audit failed. The Tauri release workflow was cancelled before a GitHub Release was created. That historical state changed with the successor: v1.29.1 is now the Latest GitHub Release. The v1.29.0 tag remains immutable and its desktop release was never published.
So was v1.29.0 released? The honest answer depends on which surface you mean. A container image was published. Desktop release assets were not.
Model transitions, not feelings
A useful release state machine names the transitions and the evidence needed for each:
- PREPARED: exact candidate, version, source, and intended outputs are recorded.
- TAGGED: an immutable tag identifies a commit.
- VERIFIED: required source and candidate checks have terminal results.
- ARTIFACT_BUILT: one output exists with a digest and platform identity.
- QUALIFIED: the exact output passed its required checks.
- PUBLISHED: that output is available at its intended destination.
- ANNOUNCED: user-facing notes accurately describe what is available.
- REVALIDATED: later review confirms that the published pointer still resolves to the qualified bytes.
These states are not synonyms. A tag can exist before every output is built. An artifact can be published while another platform remains cancelled. A release page can be absent even though a container tag is public.
Close the evidence state when a run ends
When a tag-time job reaches a terminal state, the record should stop saying “pending.” For v1.29.0, the audit failed, Docker succeeded, and Tauri was cancelled. Updater assets, installers, latest.json, and a GitHub Release were not produced because publication was cancelled.
That is more useful than a vague “release incomplete.” It tells the next maintainer exactly which outputs exist and which do not. It also prevents a stale PENDING label from being mistaken for an ongoing job that might still produce assets.
A release record should have a separate result for each artifact class. If an image alias points to a digest, record the digest. If no desktop release exists, say so. If a job was cancelled, record who or what cancelled it and at what stage.
Preserve provenance across corrections
A release recovery may create a successor version or rebuild outputs. That successor gets its own source SHA, tag, workflow runs, artifact digests, qualification, and publication records. It must not inherit PASS from the earlier attempt.
The successor chronology is terminal: candidate 99a664c5 failed the fresh OSV audit and was stopped without a tag; #912 raised the dependency floors; candidate f255d767 completed qualification, was signed as v1.29.1, and reached PUBLISHED then VERIFIED after #913 proved resulting main. No result from 99a664c5 was carried forward.
Make the user-facing statement match the state
Readers do not need a taxonomy for its own sake. They need to know which platform artifacts they can obtain, what was tested, and what remains unavailable. A precise release note might state that a container image exists while desktop artifacts are withheld. That is more trustworthy than either calling everything successful or hiding the work that did succeed.
Treat each output as a small state machine. Then the overall release is a set of independently evidenced state machines, joined by an announcement that describes their actual outcomes.
Continue reading
Next: A Release Protocol Must Fail Closed Too turns release-state distinctions into explicit stop conditions.
Related: A Release Is More Than a Tag extends the same idea across the artifacts and publication surfaces in a release.
Practical extension: require evidence at every transition
Use a release ledger instead of one overloaded “released” flag:
| State | Minimum evidence before advancing |
|---|---|
| Candidate built | source commit, workflow run, artifact identity |
| Candidate qualified | required checks and target-specific exercise results |
| Tag created | immutable tag target and signature verification where used |
| Artifact published | registry or release URL plus digest |
| Release verified | consumer-facing asset list and install or retrieval check |
Each artifact channel advances independently. A container image may be present while a desktop release is cancelled; one successful publication must not promote the other channel's state. A correction also creates a new candidate identity. Preserve the failed attempt and link the successor rather than rewriting the history into a single clean green run.
As a concrete later checkpoint for this project, v1.29.1 reached VERIFIED on 2026-09-30 at commit f255d767 after the first candidate was rejected and corrected. That later terminal state does not change what happened during v1.29.0 or make earlier artifacts equivalent. The release record is the user-facing anchor; the post-release truth-sync PR records the repository reconciliation.
Top comments (0)