# Plan — road to public availability (versioning + install + packaging) Status: **planning** (2026-06-16). Captures the decisions taken in discussion plus the open questions, so the work can proceed in steps. The versioning piece is being implemented first and is recorded as a decision in **ADR-0054**; the install-script and package-manager pieces are roadmap items here until each is built. Scope note: this repo lives on the self-hosted Gitea at `git.lazyeval.net` (`oli/rdbms-playground`); releases publish there (ADR-ci-001/003). Publication branding uses the company name **Lazy Evaluation Ltd → `lazyeval`**, not the personal `oli` username, for anything user-facing (taps, buckets). --- ## 1. Versioning + version surfaces — DECIDED (→ ADR-0054, building now) - **`Cargo.toml` `version` is the single source of truth.** `--version` reads `env!("CARGO_PKG_VERSION")` (compile-time, no deps). - **Two surfaces:** a `--version` / `-V` CLI flag (prints + exits, like `--help`), and an in-app **`version`** app command. - **CI discipline:** `release.yaml` gains a guard that asserts the pushed tag `vX.Y.Z` equals `CARGO_PKG_VERSION`, and **fails the release on mismatch** — so the binary's self-reported version, the release name, and the downloaded asset always agree. - **Release ritual:** bump `Cargo.toml` → commit → tag `v` → push tag. (The guard enforces it.) - Optional enrichment (not decided): a `build.rs` baking a git short-hash + build date so non-tagged dev builds read `0.2.0 (a1b2c3d)`. Good for bug reports; can be added later. --- ## 2. `install.sh` (curl | sh) — DONE 2026-06-17 (ADR-0055) **Shipped** `scripts/install.sh` (POSIX sh, shellcheck-clean). Verified end-to-end against the live public `v0.1.0` release: platform mappings (Linux/macOS × x86_64/aarch64; Windows + unknown arch error cleanly), pinned (`RDBMS_VERSION`) and latest (`releases/latest`) paths, SHA-256 verification (incl. a tamper-rejection check), install to `~/.local/bin`, PATH hint. **`install.ps1` (Windows) added 2026-06-17** (user chose both a one-liner *and* Scoop/winget; ADR-0055 Amendment 1): `irm | iex`, maps host CPU → our `*-windows-gnu`/`-gnullvm` `.exe`, SHA-256-verifies, installs to `%LOCALAPPDATA%\Programs\…` + user PATH — **written but untested from this env** (no PowerShell; validate on Windows). The website copy that references these commands is the **website branch's** job (separate agent), later. A **shellcheck CI gate** for `scripts/` is a recommended follow-up (not added — shellcheck isn't in the flake yet; touches ADR-ci-002). Original decided shape (for reference): - **Hosted from the Gitea repo URL** on `git.lazyeval.net` (simplest): `curl -fsSL https://git.lazyeval.net/oli/rdbms-playground/raw/branch/main/scripts/install.sh | sh` (exact raw-URL form to confirm against the Gitea version). - **Behaviour:** POSIX `sh`; detect `uname` OS+arch → target triple (Linux → the **musl static** build, our universal Linux artifact); query the latest release via the Gitea API (`/repos/oli/rdbms-playground/releases/latest`) → tag → deterministic asset name `rdbms-playground--`; download + **verify the `.sha256`**; install to `~/.local/bin` (fallback `/usr/local/bin` with a sudo prompt); `chmod +x`; print a PATH hint if needed. - **macOS:** binaries are signed (see §4 signing note); a `curl` download does **not** apply the Gatekeeper quarantine xattr, so the installed binary runs without `xattr` faff. - **Windows:** not `curl | sh` — provide a PowerShell `install.ps1` (`irm … | iex`) and/or steer to Scoop/winget (§3). - **Security posture:** HTTPS only; in-script checksum verification; document the download-inspect-run alternative (`curl|sh` is a trust tradeoff). - **Deliverables we own now:** `scripts/install.sh` (+ later `install.ps1`); confirm releases are **publicly downloadable**; decide whether to also upload `install.sh` as a release asset for a stable link. Website copy referencing the command is the **website branch's** job (separate agent), later. --- ## 3. D3 — package managers (roadmap; each layers on the release assets) Common thread: a manifest pointing at our checksummed assets + a per-release step to bump it. Ordered cheapest → most gatekept. ### 3a. `cargo binstall` + crates.io — PREPARED 2026-06-17 (ADR-0056) **Done (prep):** crate made publish-ready (dropped `publish = false`; added `homepage`/`keywords`/`categories`/`exclude`; authored `README.md` + `LICENSE-MIT`); `[package.metadata.binstall]` added with per-target overrides (linux-gnu→musl, windows-msvc→gnu/gnullvm; macOS direct); `cargo publish --dry-run` clean (913 KiB compressed). Dual license kept; `LICENSE-MIT` + `LICENSE-APACHE` (© Lazy Evaluation Ltd) + `CONTRIBUTING.md` (inbound=outbound) all in place. **Gated / remaining:** the actual `cargo publish` (token, irreversible) at a **new tagged release** (not 0.1.0); a real `cargo binstall` validation. - **Bootstrapping matters (user-flagged):** `binstall` is **not** a built-in cargo subcommand — users must install **`cargo-binstall`** first (its own `curl|sh`/PowerShell installer, or `cargo install cargo-binstall`). **Our instructions must say this.** - Add `[package.metadata.binstall]` to `Cargo.toml` (pkg-url template → our Gitea release assets; our naming already fits). - **DECIDED (2026-06-17): publish to crates.io** — so the frictionless `cargo binstall rdbms-playground` resolves the crate, and the project is discoverable there. (A crates.io publish is its own small task: metadata completeness — description/license/repository/keywords/readme — and `cargo publish`; the `[package.metadata.binstall]` URL template points binstall at our Gitea release assets.) *(Verify current cargo-binstall behaviour when wiring.)* ### 3b. Scoop (Windows) - A **bucket** repo under `lazyeval` on Gitea with a JSON manifest (`.exe` URL + hash + `autoupdate`). Release job commits the bump. - Users: `scoop bucket add lazyeval ; scoop install rdbms-playground`. ### 3c. Homebrew (macOS/Linux) - A **company-branded tap** — `lazyeval/homebrew-tap` (on Gitea) — with a Ruby formula (per-arch `url` + `sha256`). Release job commits the bump. - Users: `brew tap lazyeval/tap https://git.lazyeval.net/lazyeval/homebrew-tap` then `brew install lazyeval/tap/rdbms-playground` (the explicit-URL tap form, since the `user/repo` shorthand assumes GitHub). - *"Notability bars"* = the acceptance criteria for the default **homebrew-core** tap (must be sufficiently popular/maintained). Our own `lazyeval` tap sidesteps that entirely — no review gate. ### 3d. winget (Windows) - Manifests are YAML PR'd to `microsoft/winget-pkgs` (reviewed by MS). - **`wingetcreate` is Windows-only** (.NET) — no good without a Windows runner. **Automatic path to evaluate first: `komac`** — a cross-platform (Rust) winget manifest creator/submitter that runs on our **Linux** CI. *(Verify komac's current capabilities/auth model.)* - **Fallback:** a manual YAML PR per release — acceptable given releases are infrequent (user-confirmed). ### Cross-cutting (3a–3d) - Two extra repos (tap + bucket) under `lazyeval`, with CI push credentials — setup TBD (user: "we'll figure that out"). - **`cargo-dist`/"dist"** automates installers + Homebrew + CI, but is **GitHub-Actions/Releases-centric**; on self-hosted Gitea it won't drop in cleanly (installer-script generation might be reusable). Likely hand-roll the manifests + a small "update on release" job instead. *(Verify cargo-dist's current Gitea support before fully ruling out.)* --- ## Open decisions 1. **crates.io:** **RESOLVED 2026-06-17 — yes, publish.** (See §3a.) 2. **Tracking:** **RESOLVED 2026-06-17 — doc + ADR only, no Gitea issues.** 3. **Release downloads public:** **CONFIRMED 2026-06-17** — the Gitea releases are publicly downloadable (no auth); `install.sh` relies on it and was verified against the live `v0.1.0`. ### Still open / postponed - **macOS signing — CONFIRMED BUG (2026-06-16), POSTPONED by the user (2026-06-17)** pending the correct signing ID. Details: - `release-macos.yaml` does `codesign --force --sign -` (ad-hoc) and has **no signing scaffolding at all** (no keychain import, no secrets) — so a downloaded binary is *not* properly signed (user-verified). - **The credential the user has is the wrong type:** `Apple Development: Oliver Sturm (W687M898E4)` is a *development* cert (Gatekeeper won't trust it for distribution). Distribution needs a **`Developer ID Application`** cert (same format, different type). Signing under the company name *"Lazy Evaluation Ltd"* would need an **Organization** Apple Developer account; a personal account signs as "Oliver Sturm". - **Notarization** (required with Developer ID for non-quarantined trust on browser downloads): after signing, `xcrun notarytool submit`. Creds = an **App Store Connect API key** (Issuer ID + Key ID + `.p8`, recommended for CI) *or* Apple ID + app-specific password + Team ID. A bare CLI binary can't be *stapled* (only bundles/dmg/pkg) — Gatekeeper does an online check instead. - **Urgency caveat:** the `curl|sh` path doesn't need any of this (curl downloads aren't quarantined); signing matters for browser downloads from the releases page. Fix when the right cert + creds exist; corrects the ad-hoc docs once landed. ## Sequencing 1. ✅ **Version discipline** (ADR-0054) — `--version`/`-V` + `version` command + CI tag-match guard + tests. 2. ✅ **`scripts/install.sh`** (ADR-0055) — built + verified against the live public release. 3. Package managers, cheapest first: - ✅ **`cargo binstall` + crates.io** — *prepared* (ADR-0056); publish gated on a new tagged release + the token. - **← next:** Scoop (`lazyeval` bucket) → Homebrew (`lazyeval` tap) → winget (komac / manual). Two `lazyeval` repos (tap + bucket) + CI push creds to set up. 4. **Cut a release at a new version** — bump `Cargo.toml` (0.1.0 → 0.1.1/0.2.0; the ADR-0054 guard checks the tag), tag, push; the four Linux/Windows targets build immediately. (macOS leg awaits signing.)