# ADR-0054: Release versioning policy + version surfaces (`--version` / `version`) ## Status Accepted — **implemented 2026-06-16** (plan: `docs/plans/20260616-public-availability.md`, step 1). First step on the road to public availability. Adds a `--version` / `-V` CLI flag and an in-app `version` command, both reporting `CARGO_PKG_VERSION`, plus a release-CI guard that the `v*` tag equals that version. No prior issue or `requirements.md` item existed for this — it was an untracked gap. ## Context Before this, `Cargo.toml` carried `version = "0.1.0"`, the binary exposed **no** way to report its version, and `release.yaml` named assets from the **git tag** (`rdbms-playground--`) while building from `Cargo.toml`. Tag and crate version were **decoupled**: tagging `v0.2.0` would publish an asset named `…-v0.2.0-…` containing a binary that (had it been able to say) reported `0.1.0`. On the way to public availability — where users download a versioned artifact and file bug reports against "the version I'm running" — that drift is a correctness problem. ## Decision 1. **`Cargo.toml` `version` is the single source of truth.** This is the idiomatic Rust position and avoids making `Cargo.toml` lie. The version is read at compile time via `env!("CARGO_PKG_VERSION")`; no build-time injection of the tag into the crate. 2. **Two user-facing surfaces, one source:** - **`--version` / `-V`** — CLI flag (hand-rolled parser, mirrors `--help`): prints and exits before any other work (`main.rs`). - **`version`** — an in-app app command (REGISTRY node `app::VERSION`, `AppCommand::Version`), emitting the same line into the output panel. Both go through `cli::version_text()` → the catalog key `cli.version_line` (`"rdbms-playground {version}"`), so there is exactly one rendered string and one version source. 3. **Release-CI discipline.** `release.yaml`'s pre-build `test` job gains a **version guard**: it parses `CARGO_PKG_VERSION` from `cargo metadata` and **fails the release** unless the pushed tag equals `v`. So `--version`, the release name, and the downloaded asset are always in lockstep — enforced by the machine, not by memory. 4. **The release ritual:** bump `Cargo.toml` → commit → tag `v` → push the tag. The guard rejects any deviation. ### Rejected / deferred - **Inject the tag into the build** (tag as source of truth): fiddly with cargo and makes `Cargo.toml` a placeholder/lie. Rejected. - **Git-hash + build-date enrichment** (a `build.rs` so dev builds read `0.2.0 (a1b2c3d)`): useful for bug reports, but not needed for the tag↔release↔`--version` consistency this ADR is about. Deferred; can be added behind the same `version_text()` seam without changing the policy. - **UI placement beyond the `version` command** (status-bar string, etc.): the command + `help` listing is enough for now (user decision). ## Consequences - A release can no longer ship a binary whose self-reported version disagrees with its tag/filename. - Cutting a release now *requires* a `Cargo.toml` bump commit — a small, deliberate step (and a natural place to update a changelog later). - New keys: `cli.version_line` (+ `help.app.version`, `parse.usage.version`, `hint.cmd.version.what`/`.example`); a new REGISTRY command means the comprehensiveness coverage test now also requires `hint.cmd.version`, which is supplied. Tested: CLI flag parse (`--version`/`-V`/default-off), `version_text()` carries `CARGO_PKG_VERSION`, the in-app command parses to `AppCommand::Version` and emits the version. - This is step 1 of `docs/plans/20260616-public-availability.md`; the installer (`install.sh`) and package-manager work (D3) build on top.