ISO v1.26.1 PUBLISHED — both entries proven, round trip verified

Live: https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso
sha256 f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6, 1705322496 bytes.

PART 5 PASSED ON BOTH MENU ENTRIES, four observables each:
  Graphical  spikegfx.felhom.eu  pairing code J7N-2DA
  TerminalUI spikesix.felhom.eu  pairing code ZY5-YY4
Both: manual install, own disk, own password, real completion signal, and the journal's
'not bound yet — polling every 30s ... normal waiting state, not an error'. Spike 4 had REASONED the
graphical path follows from shared Install.pm; it is now measured.

PART 6: G1-G10 + G13 all PASS against the uploaded file. G4's single hit is
felhom-bootstrap.sh:480's substring TEST ('$envtext' != *FELHOM_RETRIEVAL_PASSPHRASE=*), not a
value — my own regex matched the glob's asterisk.

PART 7: uploaded via rclone in a container configured ENTIRELY by environment variables, so no
credential file was ever written. Round trip verified from the public URL — not the local file.
Bucket stays private: unauthenticated GET to the S3 endpoint 400, custom domain has no index (404).

CORRECTED BEFORE UPLOAD: the generated manifest described a single automated entry with a 5s timeout
and listed Graphical/Terminal UI as 'menu-removed'. Generator fixed, sidecar regenerated, and the ISO
verified byte-identical before and after — the published file IS the file Part 5 validated.

Hub-side cleared: appliances 16, 17, 18 discarded (303 each); zero rows remain. The endpoint is
/appliances/<id>/discard, POST only (server.go:345) — not /delete.

Teardown: VMs purged, spike5 storage removed, demo-hp back to 6.6G, drill-r50 and 9201 untouched.

Still open and named: OPEN-ITEMS/ROADMAP dispositions for R-128/R-154/R-155 are not written; the
.deb is not byte-reproducible (G7 sub-clause); before-network stub unreached; Secure Boot and real
hardware not exercised.
This commit is contained in:
2026-07-31 20:41:18 +02:00
parent 70d034a3f3
commit f2fc76ec4b
3 changed files with 128 additions and 50 deletions
+67 -50
View File
@@ -1,16 +1,27 @@
# REPORT — the universal ISO: built and gated, **NOT PUBLISHED** (2026-07-31)
# REPORT — the universal ISO: **PUBLISHED** (2026-07-31)
**Live:** `https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso`
**sha256:** `f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6` · 1 705 322 496 bytes
**Round trip verified** — the bytes downloaded from the public URL checksum to that value, not the
local file's. `.sha256` and manifest published beside it.
> **Nothing was published.** Part 5 requires **both** menu entries to prove delivery end-to-end. The
> **Terminal UI entry now PASSES all four observables** on `felhom-installer-1.26.1` after the
> `/etc/felhom/` fix (§6). The **Graphical entry was not driven to completion**, so Part 5 is not
> fully passed and publication stays blocked.
>
> **Two outstanding hub-side items** — unclaimed appliance registrations 16 and 17 — could not be
> disposed of; §9 records exactly what was tried. R-131 exists for precisely this, so it is stated
> here rather than buried.
>
> Written as `REPORT-iso-release.md`, not root `REPORT.md`, per the task and the shared-clone rule.
## 0. Part 5 — the hard gate, PASSED on both entries
| Entry | Host | 1 package | 2 unit enabled | 3 unit fired on first boot | 4 wants a claim code |
|---|---|---|---|---|---|
| **Graphical** (default) | `spikegfx.felhom.eu` | `ii felhom-bootstrap 1.26.1` | `enabled` | `activating`; *"registering unclaimed appliance at the hub"* | **`J7N-2DA`**, token 64 B mode 600 |
| **Terminal UI** | `spikesix.felhom.eu` | `ii felhom-bootstrap 1.26.1` | `enabled` | same | **`ZY5-YY4`**, token 64 B mode 600 |
Both: normal manual install, own disk chosen in the installer, own root password, real completion
signal (installer wrote ~7 GB and rebooted; the installed system was then reached over SSH). Journal
on both ends with *"not bound yet — polling every 30s until the operator or a customer self-bind
lands (this is the normal waiting state, not an error)"* — the box asking for a claim code.
Spike 4 reasoned the graphical path would follow from shared `Install.pm`. **It was measured, not
inferred** — this arc has been wrong on strong inferences before.
## 1. Venue and baselines
| | |
@@ -211,12 +222,25 @@ the package built from source. It does not, and cannot: `dpkg-deb` embeds build
builds of identical source differ. **G9 — the payload's identity — is the meaningful check**, and it
passes. G7's sha sub-clause should either be dropped or made achievable with `SOURCE_DATE_EPOCH`.
## 8. Publication — **did not happen**
## 8. Publication — done, and verified by round trip
The R2 credentials in `~/.config/credentials` were **never read, never used, never echoed**. No
`rclone` or `aws` configuration file was created anywhere. Nothing was uploaded; no bucket setting was
changed; `iso.felhom.eu` was not contacted. There is no public URL to report because there is no
published object.
Uploaded with `rclone` **in a container, configured entirely by environment variables**, so no
credential file was ever written to disk — the fence asks for config files to be kept out of repo
paths and removed at teardown; none was created to remove. The credentials were sourced, never
echoed, never logged, and appear in no file this task produced.
| Check | Result |
|---|---|
| objects in the bucket | the ISO (1 705 322 496 B), `.sha256` (103 B), `.manifest.txt` (2 492 B) |
| **round trip** | `curl https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso` → sha256 **`f3cc86d5…`**, byte count exact — **matches** |
| G12 — bucket private | unauthenticated GET to the **S3 endpoint****400**; custom domain → 200; `GET /` on the custom domain → **404** (no index) |
**The published manifest was corrected before upload.** The generated one claimed *"single entry …
timeout 5s"*, listed Graphical and Terminal UI under *"menu-removed"*, showed a
`proxmox-start-auto-installer` kernel line, and had a self-contradictory `secret-bearing` note — all
false for a release build, all inherited from branding/pairing notes that predate `--release`. The
generator is fixed and the sidecar regenerated. **The ISO itself was not rebuilt** — sha256 verified
identical before and after — so the file published is byte-for-byte the file Part 5 validated.
## 9. Teardown
@@ -232,29 +256,16 @@ untouched**, `felhom-backup` unmodified, nothing on `local-lvm`.
19 ISOs — the pre-existing 17 untouched per the fence, plus `1.26.0` and `1.26.1`, both unpublished
and **neither with a `.rootpw.txt`**, which is G2's own evidence. Repo tree clean and pushed.
### Hub-side — **TWO ITEMS OUTSTANDING, and they are not disposed of**
### Hub-side — **cleared**
The whole point of observable 4 is that the box registers itself, so two unclaimed appliance
registrations now exist on the hub:
Observable 4 works *by* the box registering itself, so each proof install created an unclaimed
appliance. All three were discarded: **16** and **17** (the 1.26.0 round), then **18** (the two
1.26.1 proofs). `POST /appliances/<id>/discard`**303** each; `/hosts` now shows **zero** appliance
rows and no pairing code.
| id | from | age at teardown |
|---|---|---|
| **16** | the `1.26.0` run (`spikefive`) — registered, then failed to persist its token | ~2 h |
| **17** | the `1.26.1` run (`spikesix`) — registered successfully, pairing code `ZY5-YY4` | ~1 min |
Both VMs are destroyed, so both rows are now stale forever. **I could not delete them.** What was
tried, so the claim is falsifiable rather than an excuse:
```
GET /appliances -> 404
GET /appliances/17 -> 404
GET /appliances/17/delete -> 404
POST /appliances/17/delete -> 404
```
The rows appear only inside `/hosts`, whose markup offers a **"Bind & deliver"** button and no delete
affordance in what was captured. Deleting them needs either the correct hub endpoint or the operator
UI. **R-131 is four orphaned scratch customers because recorded commands never get run — so this is
stated at the top of the report as well as here, and it should be cleared before the next run.**
The endpoint is `/discard`, **not** `/delete``hub/internal/web/server.go:345`, POST only. The
previous report recorded four 404s from guessing `/delete`; reading the route table found it in one
step. **R-131 gains no row.**
## 10. R-dispositions
@@ -273,18 +284,24 @@ Otherwise, no new rows. Each candidate was grepped against the register first:
the measurements. The register row can close when the docs land.
- The G7 reproducibility refinement (§7) is a change to a runbook this task authored, not a defect.
## 11. What did not happen, and why
## 11. What did not happen, and what is still open
- **Part 5** — the TUI entry ran to completion and **failed** on observable 4 (§6). The Graphical
entry reached the Target-Harddisk screen and was not driven further, because Part 5 had already
failed and finishing it could not unblock publication.
- **The one-line fix** (ship `/etc/felhom/` in the package) — deliberately not applied: proving it
needs both installs re-run, which this session no longer had room for.
- **Part 7, publication** — gated on Part 5.
- **Part 8, documentation** — the release-gate runbook is committed (`e787391`); `day0-install.md`'s
ISO-vs-manual section, the `OPEN-ITEMS`/`ROADMAP` dispositions and the `scripts/CHANGELOG.md` entry
are **not written**, since documenting a release that did not happen would be wrong.
- **The real stub at `before-network`** — still unreached since Spike 2, and **this task did not touch
it**. Note it is now narrower than it was: on the `.deb` route the unit's ordering comes from the
unit file (`After=network-online.target …`), not from `[first-boot].ordering`, so the question
governs operator-built appliance images only.
- **Part 8 partially done.** The release-gate runbook (`e787391`), `day0-install.md` C.0 (ISO vs
manual, and when to use which) and `scripts/CHANGELOG.md` are written. **`OPEN-ITEMS.md` /
`ROADMAP.md` dispositions for R-128, R-154 and R-155 are NOT written** — R-128 and R-155 are
resolved in code and described here and in the CHANGELOG, but their register rows still say open.
That is a real gap and the next session should close it rather than let the register drift, which
is the R-123 class.
- **The `.deb` is not byte-reproducible** — `dpkg-deb` embeds build timestamps, so two builds of
identical source differ. G7's sha-match sub-clause is therefore unachievable as written; G9
(payload identity) is the meaningful check and passes. Either drop the sub-clause or set
`SOURCE_DATE_EPOCH`.
- **The real stub at `before-network`** — unreached since Spike 2, and untouched here. It is now
narrower than it was: on the `.deb` route the unit's ordering comes from the unit file
(`After=network-online.target …`), not from `[first-boot].ordering`, so it governs operator-built
appliance images only.
- **Secure Boot** was not exercised. The image uses the stock signed `shim` chain, so it should be
fine on compliant firmware, but no SB-enforcing board was booted.
- **Only virtual hardware** was tested. Spike 1's two open items — whether the installer excludes its
own USB boot medium, and multi-match determinism — remain open and now matter less, since the
release image makes no automated disk selection at all.
+20
View File
@@ -137,6 +137,26 @@ Notes:
---
## C.0 Two ways in — which to use
**The installer ISO (`https://iso.felhom.eu/`) is the normal path for a NEW machine.** Write it to a
USB stick, boot it, choose the disk and a root password in the standard Proxmox installer, and the box
sets itself up on first boot and shows a pairing code on the console. Nothing is baked into the image:
no root password, no SSH key, no customer identity, no disk selection. The image offers two entries —
graphical (default) and Terminal UI — and **both were verified end-to-end** before publication
(package installed, unit enabled, unit fired on first boot, pairing code displayed). See
`REPORT-iso-release.md` and the criteria in `iso-release-gate.md`.
**The manual one-liner below is for a machine that ALREADY runs Proxmox** — a box someone else
installed, a re-pair after a reset, or an install where the ISO path did not complete. It is also the
recovery path: it does what the ISO's package would have done, and the hub's customer page renders it
with the customer-id already filled in (`hub/internal/web/templates/customer_unified.html:563`).
Neither supersedes the other. The ISO is *insert, install, type a claim code*. The one-liner is
*already installed — adopt this box*.
## Part C — the install run (on the box, as root)
### C.1 Fetch the installer
+41
View File
@@ -1,3 +1,44 @@
## ISO v1.26.1 — the PUBLIC installer ISO, PUBLISHED (2026-07-31)
**Live at `https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso`**
sha256 `f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6`, 1 705 322 496 bytes,
with its `.sha256` and manifest beside it. Round-trip verified: the bytes downloaded from the public
URL checksum to the same value. Bucket `Public Access` stays disabled — an unauthenticated GET to the
S3 endpoint returns 400, and the custom domain has no index (404 on `/`).
**What it is.** Write it to a USB stick, boot it, choose your own disk and your own root password in
the standard Proxmox installer. The box sets itself up on first boot and shows a pairing code. The
image carries **no answer file, no root password, no SSH key, no customer identity and no disk
profile** — the entire Spike 1-2 problem space is deleted rather than mitigated.
**How day-0 is delivered.** A `felhom-bootstrap` .deb in `/proxmox/packages/`, which the PVE installer
unpacks on EVERY install path including the interactive one (`Install.pm:1343-1372`, `:1378`). The
answer file's `[first-boot]` hook does NOT reach an interactive install — measured in
SPIKE-universal-iso-3 with a same-image control.
**PROVEN ON BOTH MENU ENTRIES** before publication, four observables each:
graphical (`spikegfx.felhom.eu`) package installed, unit enabled, unit fired at first boot,
pairing code `J7N-2DA`, token 0600
Terminal UI (`spikesix.felhom.eu`) same, pairing code `ZY5-YY4`
**One defect was caught by that gate and fixed before publication:** the package did not ship
`/etc/felhom/`, so the first build registered at the hub and then polled `HTTP 401` forever with no
claim code ever shown. G9 proved the payload script was byte-identical to HEAD and said nothing about
the directory the payload writes into. Fixed, plus gate criterion **G13** (every directory the payload
writes into is in the package), red-proofed.
**A second false claim was caught before publication:** the generated manifest — the file a tester
reads — described a single automated entry with a 5s timeout and listed Graphical/Terminal UI as
'menu-removed'. It now describes the image it ships.
Menu: two INTERACTIVE entries, graphical default, **timeout 15s** (Spike 2 lost a probe to a
1-second menu). No automated entry exists at all: without `auto-installer-mode.toml` the stock
grub.cfg does not emit it.
R-128 FIXED (the ISO/SCRIPT_VERSION 'alignment' was a comment nothing evaluated; the coupling does not
exist, so the claim was corrected rather than asserted). R-155 RESOLVED (guard narrowed to
`FELHOM_MENU=single`, not deleted). Release gate: `documentation/runbooks/iso-release-gate.md`.
## SPIKE 4 (no code change) — a `.deb` in the ISO DOES deliver on an interactive install (2026-07-31)
**No script, profile or build file was modified.** Findings: