Skip to content

A tag with a pre-release part is published as a prerelease, recorded on the prerelease channel, and never resolved as the stable release, so an unpinned installer and a node that follows stable keep the highest stable version

Publishing v1.0.0-alpha.1 does not change what curl -fsSL https://majordomus.dev/install.sh | sh installs. The alpha is a GitHub prerelease, its record says channel: prerelease, and releases/latest.json keeps naming the highest stable release. A person who wants the alpha names it with --version 1.0.0-alpha.1.

declared statusdeclared status: guaranteed Declared deterministic and blocking, implemented, and naming the behavioural test that is to prove it. Whether a recorded run supports it is the evidence verdict, shown beside it.

recorded evidencerecorded evidence: not run Declared guaranteed, and not supported by a recorded run: the test is named, and no passing run of the current inputs is recorded. how evidence is recorded

Held at three places that must agree. scripts/release-record derives the channel from the tag and refuses stable on a suffixed tag; release.yml passes --prerelease --latest=false for it; Release::is_stable_candidate refuses any version with a pre-release part whatever its record says, and Release::findings reports the mislabel. The resolution and the semver precedence (alpha.2 before alpha.10, build metadata ignored) are proved by the crate's distribution tests, which the case does not run. Found by the audit before v1.0.0-alpha.1, when the pipeline would have published the alpha as the stable release.

What it means

Publishing v1.0.0-alpha.1 does not change what curl -fsSL https://majordomus.dev/install.sh | sh installs. The alpha is a GitHub prerelease, its record says channel: prerelease, and releases/latest.json keeps naming the highest stable release. A person who wants the alpha names it with --version 1.0.0-alpha.1.

How it works

Three places decide the label and the claim holds only while they agree. scripts/release-record derives the channel from the tag (a - in the version means prerelease) unless --channel is given, and refuses --channel stable on such a tag with exit 2. The publish step of release.yml passes --prerelease --latest=false for the same tags. In the crate, Release::is_stable_candidate is false for any version with a pre-release part, whatever its record says, so a mislabelled record can never become the stable pointer; Release::findings reports the mislabel. Precedence follows semantic versioning: identifiers compare one by one, numeric ones as numbers (alpha.2 before alpha.10), a pre-release below its own final, build metadata ignored.

How to see it

bash test/run.sh 3179_a_prerelease_is_never_published_as_stable
scripts/release-record --tag v1.0.0-alpha.1 --dir dist --channel stable    # exit 2: cannot be recorded on the stable channel
cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib distribution::

What it does not cover

It does not publish anything and does not exercise GitHub: the workflow is checked for the flags it passes, not by a run. The version gates that parse the declared version (Version::parse, the compatibility gate, release bump) are a separate defect and still reject a pre-release part. majordomus self update is a design (ADR 0161) and is not implemented, so its stable-only rule is not claimed here.

Why it exists

The audit before the first alpha found that the pipeline recorded every tag as stable and created every release without --prerelease, and that latest_stable ranks by version. v1.0.0-alpha.1 would have outranked v0.27.0 in releases/latest.json and become what every unpinned installer installs. The ordering was also string-wise, so alpha.10 sorted below alpha.2.

Detail rendered from docs/claims/release-prerelease-channel.md.

From the statement to the proof

  1. 1 · the public statement

    A tag with a pre-release part is published as a prerelease, recorded on the prerelease channel, and never resolved as the stable release, so an unpinned installer and a node that follows stable keep the highest stable version

    No feature or README responsibility names it; this page is where it is stated.

  2. 2 · the canonical claim

    release-prerelease-channeldeclared status: guaranteed in docs/CLAIMS.yaml

    Defined in read it on this site · docs/DISTRIBUTION.md

  3. 3 · the implementation

    scripts/release-record

  4. 4 · the test and the scenarios

    Test: test/cases/3179_a_prerelease_is_never_published_as_stable.sh

  5. 5 · the recorded runs

    recorded evidence: not run how evidence is recorded

Verify it yourself

The test runs in a disposable temporary repository and asserts the behaviour, not a string in the source.

from a clone of the repository
bash test/run.sh 3179_a_prerelease_is_never_published_as_stable

Related claims same implementation

Searches the titles and descriptions of every page this site publishes.