ADR 0037: Release version scheme โ skip alpha/beta, RC discipline from v0.0.1¶
Status: Accepted
Date: 2026-06-03
Companions: ADR 0028 (one tag = both editions), ADR 0033 (RC tags + E2E gates)
Supersedes (partial): clause of ADR 0033 stating "Effective from v0.1.0-alpha.1"
Context¶
Leoflow has been shipping v0.0.1-prealpha.N since the project started. The next
question โ and one the existing release ADRs left open โ is how the version
scheme evolves after the pre-alpha series ends.
Two industry-standard answers exist:
- Alpha โ Beta โ RC โ Stable (the classic phase ladder). Each phase communicates a maturity bracket: alpha = experimental, beta = API freeze, RC = feature freeze, stable = supported. Promoted by Java/Eclipse-era projects; baked into ADR 0033 as the assumed shape.
- RC-only progression on every release. No alpha/beta phases. Every tag
that ships is either an RC waiting on E2E gates or a stable tag once gates
pass. The
0.x.ySemVer prefix already signals "pre-1.0, breaking changes allowed"; the maturity word is redundant. Used by Astral (uv, ruff), many modern Rust/Go projects, and (in spirit) Postgres core.
The phase ladder is heavier than Leoflow needs at this size. Defining "when
alpha becomes beta" is subjective; in practice every project that adopts it
spends meeting time on the question. SemVer's own 0.x.y namespace already
communicates "experimental โ breaking changes possible"; restating that with
the word -alpha.N adds rituals without information. The RC gate is the only
mechanism that produces an objective promotion signal โ and we already have it
(ADR 0033's E2E gates), so we can rely on it for every release rather than
reserving it for the final mile.
The decision below codifies the RC-only path and renumbers ADR 0033's effective-from threshold accordingly.
Decision¶
-
The pre-alpha series ends with a single
v0.0.1tag. Notv0.1.0-alpha.1, notv0.0.1-alpha.1โ the plainv0.0.1. That tag marks the moment the project stops calling itself "pre-alpha" and starts honouring the discipline below. Pre-alpha cuts before it continue under the existingv0.0.1-prealpha.Nconvention until the operator (the project owner) decides the next non-prealpha cut isv0.0.1. -
Every release after
v0.0.1follows the RC discipline. A new release goes throughvX.Y.Z-rc.NโvX.Y.Zmediated by the E2E gates from ADR 0033. There are noalpha/betasuffixes; the only pre-release suffix this project uses going forward is-rc.N. -
SemVer carries the maturity signal, not a word in the tag.
v0.x.ymeans "pre-1.0; breaking changes are allowed between any two releases, with clear release notes." This is the standard SemVer contract.-
v1.0.0means "API contract โ breaking changes only in a major bump." When that's cut requires an explicit decision; this ADR does not schedule it. -
Minor (
vX.Y+1.0) vs patch (vX.Y.Z+1) policy in the0.xrange. - Patch (
vX.Y.Z+1): bug fixes, security patches, polish, small features that do not change the public surface in a breaking way. Default for most releases in0.x. - Minor (
vX.Y+1.0): introduces a substantial new feature or a deliberately breaking change. Examples on the current roadmap: ADR 0036's runtime compatibility shim landing โv0.1.0; an AWS connector tier 80/20 cut โv0.2.0. -
Even in
0.x, every breaking change ships in release notes with a migration guide. -
No alpha or beta tags going forward. If someone wants to test a pre-release artifact, they pick an
-rc.Ntag from the GitHub releases page (or the install script'sLEOFLOW_VERSION=โฆflag).-rc.Nartifacts are marked as pre-releases on GitHub so package managers andlatestqueries skip them by default. -
ADR 0033 amendment. ADR 0033 declares its RC-tags + E2E-gates flow "effective from
v0.1.0-alpha.1". That clause is superseded: the flow is effective fromv0.0.2-rc.1(the first RC afterv0.0.1).v0.0.1itself uses the same simpler direct-tag flow as the pre-alpha series โ one final exception so the alpha cut does not block on the RC plumbing being in place. -
README and install docs carry a
๐งช Experimental โ pre-1.0notice for as long as the version starts with0.. Removed only whenv1.0.0ships. This is the user-facing maturity signal that replaces the missing-alpha/-betawords. -
Cadence is event-based, not time-based. A release happens when a set of fixes or features is ready and the RC's E2E gates pass. There is no fixed weekly/monthly cadence in the
0.xline. (Oncev1.0.0ships a cadence ADR can revisit this.)
Consequences¶
- Simpler narrative. Users only ever see
vX.Y.ZorvX.Y.Z-rc.N. Marketing copy and changelogs don't have to spend paragraphs explaining "what phase are we in." The version number alone says it. - Objective promotion signal. RC โ stable is gated by E2E (ADR 0033), not by subjective "is the API frozen?" debate.
- Recovery is fast. A critical bug in
v0.0.1ships asv0.0.2-rc.1the same day; the E2E gate runs; promotion tov0.0.2happens when green. No "we need to call this a beta first" detour. - The minor/patch line stays meaningful inside
0.x. Because every release goes through an RC, the version number alone doesn't tell the user "is this safe to upgrade?" โ but the release notes do, and the RC gate ensures no obvious regression slips through. v0.0.1becomes the project's actual public debut. The discipline it codifies (make ci-localclean, README/Helm docs aligned, install script tested across distros, the install-smoke gate green) is the promotion bar. Pre-alpha tags before it are dev iteration;v0.0.1is the first tag the project recommends to a stranger.- No backwards-incompatibility with ADR 0028. ADR 0028's "one tag = both editions" stays the underlying rule. ADR 0037 just governs what those tags look like.
Alternatives considered¶
- Stay with the alpha/beta/RC ladder (ADR 0033's original assumption). Rejected: adds vocabulary without information when SemVer already encodes maturity. The phase-transition decisions are subjective and consume meeting time. For a project of Leoflow's current size, the cost outweighs the benefit.
- CalVer (
YYYY.MM.PATCH). Rejected: harder to communicate breaking changes (the version number has no signal for that); cadence-implicit in the format (we want event-based for now). Worth revisiting atv1.0if we cement a monthly cadence. - Skip the RC suffix too โ straight
vX.Y.Zfrom CI. Rejected: the E2E gate from ADR 0033 needs a separate identifier for the candidate build vs the promoted build (we don't republish artifacts under a new tag once gates pass โ the same tag is the candidate, gated). Keeping-rc.Npreserves that. - Defer the question until after
v0.0.1. Rejected: the operator cuttingv0.0.1needs the answer to know what comes next. Locking it now removes a decision the operator would otherwise make under release-day pressure.