# 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<that number>`
  → 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-<tag>-<target>`; 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 <gitea-url>; 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.)
