diff --git a/docs/RELEASE-BUILD-RUNBOOK.md b/docs/RELEASE-BUILD-RUNBOOK.md new file mode 100644 index 00000000..73dc3657 --- /dev/null +++ b/docs/RELEASE-BUILD-RUNBOOK.md @@ -0,0 +1,210 @@ +# Release Build Runbook + +**Current target:** `0.10.0` ("Operator Image") · **Channel:** `release` + +How to cut a reproducible, publishable operator image from merged sources. This +is the `BUILD_CHANNEL=release` path — distinct from the everyday +`BUILD_CHANNEL=dev` integration build. Run it on the **FreeBSD 15 build host**; +Linux can't produce the FreeBSD binaries. + +For a throwaway integration image (current `main`, no clean-tree requirement), +use `BUILD_CHANNEL=dev` and skip the pinning discipline below. + +--- + +## 0. What a release build guarantees + +- **Reproducible by record.** The release gate refuses to build unless every + staged source repo (`clawdie-iso`, `clawdie-ai`, `colibri`, `zot`) is a clean, + committed tree (`git status --porcelain` — untracked files count). The exact + commits are then written to `build-manifest.json`, so the image can be rebuilt + from that record. +- **Own product version.** `ISO_VERSION` is an explicit product number + (`0.10.0`), not a component's. Component versions are provenance, not identity. +- **Fits the stick.** The build aborts before shipping if the live filesystem + has less than `IMAGE_MIN_FREE_MB` (default 1024) free. + +Output: `tmp/output/clawdie-quindecim-0.10.0.img` (`quindecim` = FreeBSD 15). + +--- + +## 1. Host prerequisites + +- FreeBSD 15 build host (root for the build; it mounts/loops the image). +- Toolchains: **Rust** (`cargo`, `rustc`) for Colibri, **Go** for zot. See + `REQUIREMENTS.md`. +- Repos checked out **side by side** (the defaults assume `../colibri`, `../zot`, + `../clawdie-ai` relative to `clawdie-iso`, or `/home/clawdie/ai/`): + + ```text + /clawdie-iso + /colibri + /zot + /clawdie-ai + ``` + +Report host evidence in the release notes: + +```sh +freebsd-version ; uname -a ; rustc --version ; cargo --version ; go version +``` + +--- + +## 2. Sync clean, merged heads + +The gate requires every repo clean and on its intended commit. Do this for +**all four** repos: + +```sh +for r in clawdie-iso colibri zot clawdie-ai; do + git -C "../$r" fetch --prune origin + git -C "../$r" switch main && git -C "../$r" pull --ff-only # or checkout the release ref + git -C "../$r" status --porcelain # MUST be empty +done +``` + +Any output from `status --porcelain` (modified _or_ untracked) will fail the +release gate. Clean it before continuing — do not `.gitignore` your way past it. + +> `zot` ships at a pinned tag. Check out the tag you intend to release +> (`ZOT_VERSION`, default `v0.2.29`) so the recorded commit is the tag's commit. + +--- + +## 3. Build the artifacts (the ISO stages, never compiles) + +```sh +# Colibri release binaries +cd ../colibri +cargo build --workspace --release +cargo test --workspace # green before release +cargo clippy --workspace --all-targets -- -D warnings + +# zot agent binary (native FreeBSD build) +cd ../zot +git checkout v0.2.29 # the release tag +go build -trimpath -o bin/zot ./cmd/zot + +cd ../clawdie-iso +``` + +`build.sh` preflight will hard-fail if any of these are missing: + +```sh +ls -l ../colibri/target/release/colibri-daemon \ + ../colibri/target/release/colibri \ + ../colibri/target/release/colibri-test-agent \ + ../colibri/target/release/colibri-mcp \ + ../zot/bin/zot +# colibri-tui is optional (staged if present) +``` + +> Building binaries does **not** dirty the repos (`target/` and `bin/zot` are +> gitignored). If `git status --porcelain` is non-empty after building, something +> else changed — investigate, don't suppress. + +--- + +## 4. Run the release build + +```sh +cd ../clawdie-iso +sudo env BUILD_CHANNEL=release ISO_VERSION=0.10.0 \ + ./build.sh --clawdie-ref main +``` + +- `ISO_VERSION=0.10.0` — also the `build.cfg` default; an empty/`auto` value + fails fast. +- `--clawdie-ref main` bundles current `clawdie-ai` main (its commit is recorded + as provenance). Use `--clawdie-version X.Y.Z` instead to pin a clawdie-ai tag. + The gate does **not** require a tag — a recorded commit is enough. +- Defaults that matter: `FEATURE_COLIBRI=YES`, `COLIBRI_STAGE_AGENT=YES`, + `COLIBRI_COST_MODE=smart`. Override only with reason. + +What you should see, in order: + +1. **Banner** — `ISO : 0.10.0-release (zot v0.2.29)`. +2. **Release gate** — silent on success; on failure it lists each modified repo + and exits. (Fix the tree; don't switch to `dev` for a real release.) +3. **Preflight** — confirms the colibri binaries and `zot/bin/zot` exist. +4. **Image space report** — `df`/`du` of the live filesystem, then + `Free space OK (… MB, floor 1024 MB)` — or an abort if it won't fit. +5. **Output** — `Done : tmp/output/clawdie-quindecim-0.10.0.img`. + +--- + +## 5. Verify provenance + +```sh +cat tmp/output/build-manifest.json # or USB_SHARE copy +``` + +Confirm: + +- `"iso_version": "0.10.0"`, `"version_scheme": "product"`, + `"build_channel": "release"`. +- `zot_commit`, `colibri_commit`, `clawdie_ai_commit`, `iso_repo_commit` are all + real SHAs (not `unknown`). +- **Every** `*_modified` flag is `false` (`zot_modified`, `colibri_modified`, + `clawdie_ai_modified`, `iso_repo_modified`). A `true` here on a release means a + tree was modified — the gate should have caught it; investigate. + +--- + +## 6. Boot proof (the actual acceptance) + +Boot the image in bhyve or on hardware and run `docs/ISO-ACCEPTANCE-RUNBOOK.md`. +Minimum pass set for the milestone: + +```sh +id colibri +service colibri_daemon status # running, socket ready +colibri status # paths, cost.mode=smart, scheduler +colibri create-task --title "rc check" +colibri list-tasks --status queued # contains "rc check" +service colibri_daemon stop # socket + pidfiles cleaned up (SIGTERM path) +service colibri_daemon start # restart works; no stale-socket clobber +``` + +XFCE: confirm the desktop comes up and is usable (the milestone's headline). + +If anything fails out of the box, this is not the cut — fix, rebuild, and the +`rc1`→`rc2` style iteration is the version number doing its job. + +--- + +## 7. Publish + +Follow `skills/iso-publish/SKILL.md`: compress to `.xz`, write the `.sha256`, and +the publish manifest, then `scripts/publish.sh` to the CMS downloads jail. +`FLASHING.md` is the operator-facing flashing guide (already references the +`0.10.0` artifact name). + +--- + +## Acceptance checklist + +- [ ] All four repos clean (`git status --porcelain` empty) and on the release ref. +- [ ] `cargo test --workspace` + `cargo clippy -D warnings` green on colibri. +- [ ] `BUILD_CHANNEL=release ISO_VERSION=0.10.0 ./build.sh` completes; gate passed, + preflight passed, free-space check passed. +- [ ] `build-manifest.json`: channel `release`, all commits real, all + `*_modified` `false`. +- [ ] Booted image: `colibri_daemon` start/status/task/stop/restart clean; XFCE usable. +- [ ] Published `.xz` + `.sha256` + manifest; `FLASHING.md` accurate. + +--- + +## Notes / gotchas + +- **Future cuts:** bump `ISO_VERSION` in `build.cfg` (e.g. `0.10.1`, `1.0.0`). + Everything else here is unchanged. +- **`dev` vs `release`:** `dev` skips the clean-tree gate — fine for proving a + change, never for a published artifact. +- **Live field repair:** to rebuild Colibri on an already-booted USB without a + full image rebuild, use `colibri-live-rebuild` (see `docs/LIVE-COLIBRI-REBUILD.md`). + That is for validation, not release artifacts. +- **`BUILD_CHANNEL` is not the package channel.** It marks artifact provenance; + the future poudriere pkg repo's channel (latest/quarterly/signed) is a separate + axis — don't conflate them.