# Tester gate — re-bake the golden, and prove a fresh box is safe to hand to a tester (2026-07-31) **The sentence that matters (§7.2): YES** — a fresh install from the existing v1.25.0 ISO is safe to hand to an external tester. Installed clean and unattended, registered, claimed, deployed two apps, and restored an app's data with the guest's `app.yaml` gone — with the data proven readable by the application over the path the application actually uses. Caveats in §8; none of them blocks a tester. Golden re-baked **0.186.0 → 0.188.0** (D5), published, and vouched. No ISO was rebuilt — Part 0 showed none was needed. Nothing already installed changed. --- ## 1. Baselines — established separately, at the start of this run | What | Value | How | |---|---|---| | controller `main` | **v0.188.0** (D5) | `HEAD`=`origin/main`=`4115e88`, tree clean | | controller on `demo-felhom` (9201) | 0.187.0 | `pct exec 9201 -- cat /etc/felhom-controller-image` | | controller on `demo-hp` | 0.187.0 | hub `/configs` row (the box's own report) | | **golden's baked controller, before this run** | **0.186.0** (sha `b760ac6a…`) | hub manifest; `drill/bake-0.186.0.log` | | agent published + vouched | 0.118.1 (sha `9a74c87d…`) | hub manifest; matches `felhom-agent --version` on felhom-pve | | hub | 0.83.0 | `deploy/hub` image tag | | ISO | v1.25.0, built 2026-07-23 | `build-felhom-iso.sh:44`; on-disk manifest | | `felhom.eu` HEAD | `0a9bd38`, clean | `git rev-parse` | | managed floor | v0.156.0 (DB override) | hub `/configuration` | The brief expected golden 0.186.0 and fleet 0.187.0 — both correct. It also assumed `main` was 0.187.0; it is **0.188.0**. See §3. ## 2. Part 0 — does the ISO need rebuilding? **NO** **1. What the ISO contains.** Three Felhom payloads, base64-injected into the first-boot stub (`scripts/iso/stub-first-boot.sh:22-38`, filled at `scripts/iso/build-felhom-iso.sh:324-329`): `felhom-bootstrap.sh`, `felhom-bootstrap.service`, and the bootstrap env. Plus `answer.toml` (fqdn, disk-setup, a per-build throwaway root hash) and the GRUB branding. **No controller image, no golden archive, no installer copy.** Verified against the ISO **on disk**, not inferred from source — full-base64 match, one hit each: | Probe | Hits | |---|---| | base64 of repo-HEAD `felhom-bootstrap.sh` (36 692 chars) | **1** | | base64 of repo-HEAD `felhom-bootstrap.service` | **1** | | base64 of the reconstructed secret-free pairing env | **1** | | `SCRIPT_VERSION="1.2` (host-install marker) | **0** | | `felhom-controller` | **0** | | `vzdump-lxc-9100` (golden marker) | **0** | **2. What the bootstrap fetches at run time.** `felhom-bootstrap.sh:96` — `INSTALL_URL="${FELHOM_INSTALL_URL:-https://felhom.eu/scripts/felhom-host-install.sh}"`, fetched on every attempt at `:322-326`. Served from the repo's `/scripts` by git-sync (`manifests/webpage.yaml:71-75`). Live check: 200, and **byte-identical to repo HEAD** (both sha256 `ab8b283e…`), SCRIPT_VERSION 1.22.0 — committed `f6aed82` on 2026-07-29, *six days after the ISO was built*. **Proven live in §5: the fresh box ran v1.22.0.** **3. How the golden reaches a fresh box.** The hub-vouched artifact manifest. `scripts/felhom-host-install.sh:423-433` `resolve_artifacts()` GETs `$HUB_URL/api/v1/artifacts/$CUSTOMER_ID` authed with the retrieval passphrase, reads `golden.version` + `golden.sha256`, then fetches from Gitea and verifies the sha. Nothing baked. **4. Version pins inside the ISO.** Four candidates; none pins the box's controller or golden: - `ISO_VERSION="1.25.0"` (`build-felhom-iso.sh:44`) — filename/manifest tag, read by nothing at run time. - The baked `felhom-bootstrap.sh` — **this one IS frozen**; a bootstrap change would require a new ISO. Currently identical to repo HEAD, so no drift today. This is the single thing that could ever force an ISO rebuild, and it is the answer to "what is baked". - `answer.toml`'s disk-setup + throwaway root hash — per-build, not versions. - The env's two URLs — endpoints, not versions. **Verdict: no ISO work.** Re-baking + vouching the golden is sufficient, and that is what was done. ## 3. Part 1 — bake, publish, vouch ### 3.1 The version baked, and why not 0.187.0 Part 1 said re-baking to **0.187.0** would level R-120's gate. It would — but it would ship a golden **without D5**, and Part 2 step 6 *is* the D5 claim, so the proof this task exists for could not have passed. The operator page also says "rebuilt on the current controller", and current is **0.188.0**. The brief's arithmetic predates D5 landing (2026-07-30). **Baked `felhom-controller:0.188.0`**, which also satisfies R-120 (`configs.go:1166` refuses only `compareVersions(golden, newest) < 0`; 0.188.0 vs the fleet's 0.187.0 is not `< 0`). Recorded here rather than absorbed silently, per standing rule 4. ### 3.2 The bake Venue: the DooPlex golden-bake nested VM, the **accepted exception for bakes** (`target-selection.md:59-61`). Reverted to `virgin` first, restored to `virgin` after. `build-golden.sh v2.1.0`, template `debian-13-standard_13.6-1_amd64.tar.zst`. Pass markers, as returned: `docker OK (overlay2; data-root /var/lib/docker)`; `including mount point` for **rootfs, mp0 and mp1** with **no** `excluding` and **no** `FATAL`; archive 619 MB; `upload OK (HTTP 201)`. Infra images baked = **4**, resolved from the controller itself (`--print-infra-images`), not the drift-prone fallback list: `traefik:v3.6.7`, `cloudflare/cloudflared:2026.6.0`, `gtstef/filebrowser:1.3.3-stable`, `gitea.dooplex.hu/admin/felhom-samba:1.1.0`. Literal-token leak grep on the saved log: **0**. GOLDEN_VERSION=0.188.0 GOLDEN_SHA256=7353d8beb63641f87a848e45f8aa12e465647e1190ad164a65b32ad01fc3d299 ### 3.3 The three observables, as returned **1 — published.** 404 pre-gate first, with a discriminating control so the check is not vacuous: golden 0.188.0 pre-gate: HTTP 404 golden 0.186.0 (control): HTTP 200 Then an **anonymous** full download — what a fresh box does, no auth header: http=200 bytes=649310288 7353d8beb63641f87a848e45f8aa12e465647e1190ad164a65b32ad01fc3d299 golden.tar.zst Byte count and sha both identical to what the bake printed. **2 — the manifest vouches it, read back:**