# REPORT — TASK-E: pre-invite sweep + HP mini ISO (2026-07-21) Baselines at start (all verified, all clean): controller `83f20c8` v0.156.0, agent `935904f` v0.92.1, felhom.eu `d4ac52d` hub v0.68.1, app-catalog `34d50a3`. ## Per-part status | Part | Status | Ships as | |---|---|---| | 1 — escrow wordlist | **DONE** | agent **v0.93.0** (not built/deployed; rides the next train) | | 2 — R-55 stop-honesty | **DONE — scope corrected by operator ruling** | controller **v0.157.0**, deployed to 9201 | | 3 — catalog honesty | **DONE, with one ruling** | catalog: wanderer re-pinned, plant-it retired, R-41 slice 1 | | 4 — operator one-pager | **DONE** | `documentation/PROMPT-TEMPLATE.md` | | 5 — §6 leftovers | **DONE** | controller **v0.157.1** + `scripts/build-hub.sh` **v1.23.0** | | 6 — HP mini ISO | **DONE, 2 artifacts not 3** (see below) | `v1.22.0` hp ISOs, both loaders | | 7 — rulings + R-17 | **DONE** (R-17 execution is operator-console) | ROADMAP + capability map | Two questions were put to the operator rather than guessed; both are recorded where they landed. ## Part 6 — the HP mini ISOs **Version: rebuild at `v1.22.0`, no bump.** Phase-0 probe confirmed **no functional change to the ISO tooling since the v1.22.0 artifacts** were built on 2026-07-19: the last content commit before that build was `8feed6d` (08:57:51, build at 09:00), and everything since is docs or `chmod +x` mode bits. `ISO_VERSION` tracks the Felhom release the ISO is tagged to; adding a build profile does not move it, and the profile name already makes the artifacts unmistakable, so no date-stamping was needed. New: `scripts/iso/profiles/hp.profile`, committed. It mirrors `n100.profile` with **one deliberate difference — the loader default stays at the stock signed `shim`.** `mkimage` exists to work around the N100's AMI firmware GRUB relocation defect; it is not a Felhom requirement, and it costs Secure Boot (it is unsigned). HP business firmware should take shim. | ISO | sha256 | bytes | |---|---|---| | `felhom-pve-9.2-1-v1.22.0-hp-generic.iso` (**shim**) | `2b51d74c0eaf5155fd42a137dff803b9ab8692294cedcb727c9a80658c9f7823` | 1 705 338 880 | | `felhom-pve-9.2-1-v1.22.0-hp-generic-mkimage.iso` (**mkimage**) | `09700442c297edcf81bdb9d6fddd14e79ba62091e7c2f183fa687c513f061142` | 1 704 482 816 | Both in `180:/mnt/5_hdd/felhom.eu/felhom-iso/out/` with `.sha256` + `.manifest.txt`. Build logs in `felhom-iso/logs/build-hp-{shim,mkimage}-2026-07-21.log`. Input PVE ISO `proxmox-ve_9.2-1.iso`, sha256 `4e88fe41…`. Both manifests: `secret-bearing : no`. **`validate-answer` was gated on OUTPUT text, not `$?`** — the documented trap (it exits 0 on failure). Both logs show `The answer file was parsed successfully, no errors found!` through the `gate_validate_answer` output-parse gate. ### Two artifacts, not three — and why that is the right answer TASK-E asked for a shim pairing ISO, a mkimage pairing ISO, and a separate `hp-safety` match-nothing ISO. **Both ISOs above ARE safety ISOs.** The `n100-safety` precedent is not a separate flag: it is the committed profile built as-is, because that profile ships a match-nothing disk filter. A third artifact would have been a byte-for-byte duplicate of one of these. Arming the real install requires the target SSD's `ID_SERIAL_SHORT`, which **cannot exist until the board is in hand** — inventing it is exactly the input the conventions say to ask about rather than guess. So all HP artifacts are deliberately inert, which satisfies "the first thing the new board ever runs must be provably harmless" more strongly than the three-artifact split would have. **Verified from INSIDE both ISOs, not merely from the profile** — the embedded `answer.toml` extracted with `osirrox` reads: ``` [disk-setup] filesystem = "ext4" filter-match = "all" filter.ID_SERIAL_SHORT = "REPLACE-WITH-TARGET-SSD-SERIAL" ``` ### Operator boot cheat-sheet — HP mini 1. **Flash `…-hp-generic.iso` (shim) FIRST.** Leave Secure Boot **ON**. Expect: GRUB loads, the Felhom boot screen appears, the installer starts and then **aborts having touched no disk**. That is success — it proves the loader and the firmware setting before anything destructive exists. 2. **If it fails at GRUB** — a `relocation` error, "no bootable device", or a hang before the boot screen — that is the N100's F1 defect on this board too. Switch to `…-hp-generic-mkimage.iso` **and set Secure Boot OFF** in firmware. mkimage is unsigned; with Secure Boot enforcing the firmware refuses it outright ("Access Denied" — proven, RUNBOOK-B leg 3). 3. **The safety ISO always precedes the real one.** Never boot an install-armed ISO on this board until one of the two above has been observed to abort cleanly. 4. **To arm the real install**, tell CC which loader worked and give it the internal SSD's `ID_SERIAL_SHORT` (`lsblk -o NAME,SERIAL` from any live boot). **Confirm it is the internal SSD and not an attached backup drive** — that check is what protected the N100's external HDD on the rehearsal run. CC copies `hp.profile` to an uncommitted working profile with the real serial (the `n100-demo.profile` precedent — a real serial is never committed) and rebuilds. 5. **No remote install step was attempted.** The boot is physically yours. ## Part 4 — the operator one-pager `documentation/PROMPT-TEMPLATE.md` gains a standard section between the header and §0. Mandatory for M+ tasks and anything carrying a STOP; guidance covers audience, the four things it must say in order, and the rule that it is a summary and never the only place a requirement appears. TASK-B/C/D cited as precedent. §10's seam-discipline row was **verified present** (line 229) and not duplicated. ## Part 5 — both §6 leftovers - **`.gitignore` anchor** → controller v0.157.1. Details and the both-directions verification are in `felhom-controller/REPORT.md`. - **The hub `build.sh` was not in any repo.** Adopted as `scripts/build-hub.sh` **v1.23.0**: build logic byte-identical (verified by diff), plus a `SCRIPT_VERSION` and a header naming the split. The operative path `/mnt/5_hdd/felhom.eu/build/felhom-hub/build.sh` is now a **symlink** to the repo copy — one source of truth, repo edits live immediately (the `install_skills.py` pattern). Previous copy retained as `build.sh.pre-adopt-2026-07-21`. ## Part 7 — rulings recorded R-25b (full-teardown cascade, three acks + typed name, **re-sized S → M**, spec to follow, no longer blocks R-3) · R-11 (direct Messenger; the doc is the architect's) · R-42 (option (a)) · R-4 (**COMPLETE** — freemail.hu operator-verified) · R-55 + R-41 slice 1 marked shipped · **new R-56** (app difficulty classification — the constructive half of the glance ruling; glance stays). Capability map updated on the boot-orphan row and the escrow-ceremony row. ### R-17 — spike-lite result: it CANNOT be done through tooling Ruled DELETE. CC did **not** improvise credentialed API calls, and found there is no tooling path: - `felhom-tenantsync.sh` does not touch Hetzner at all — PBS namespaces/tokens only. - The hub **can** delete sub-accounts (`hetznerapi.DeleteSubaccount`), but its only caller is `offsite.Deprovision`, which selects by the `felhom-customer=` label as part of a customer RESET. A legacy archive sub-account from the 2026-07-09/10 spikes carries no such label, so no verb targets it. - The only in-repo references are **test fixtures** (`hub/internal/hetznerapi/fake.go` generates the `u629193-sub%d` pattern; `dr_recipe_test.go` uses it as a literal). Nothing live points at it. **Operator console action:** Hetzner Storage Box console → box `u629193` → Sub-accounts → `u629193-sub1` → confirm the directory holds only the old-box archive → Delete. The 9/9 byte-identical restores are the sign-off; deleting the sub-account destroys its data. ## Observations (recorded, not acted on) 1. **A gate I shipped nearly shipped a lie, and it is the most transferable thing here.** The first full catalog resolvability sweep reported **24 of 65 pins dead**, including `postgres:16-alpine` and `redis:7-alpine`. They are fine — Docker Hub had started throttling. Worse, `docker manifest inspect` prints `toomanyrequests: …` and **still exits 0**, the identical exits-0-on-failure shape as `validate-answer` in the ISO tooling. Two independent instances of the same trap now sit in two different toolchains; it is worth treating "does this tool signal failure through its exit code?" as a standing question rather than a per-tool footnote. The gate now resolves ambiguity to INCONCLUSIVE, never to an accusation. 2. **The full 52-app resolvability table is still owed.** DooPlex is not logged in to Docker Hub, so the sweep exits 2 (incomplete) rather than producing the table. One `docker login` + re-run closes it. 3. **R-55's live reboot leg is not run** — see `felhom-controller/REPORT.md`. Shipped and wired, not yet proven live. 4. **wanderer is re-pinned but never deployed.** It went from 1 service to 3 with a second public hostname; it deserves a real deploy on the demo box before anyone is invited to it. 5. `reuse_refs_check.py` resolves REUSE.md citations against the repo root and so cannot follow a cross-repo pointer; the catalog's `healthprobe.go` citation still flags. Path corrected; the checker limitation is pre-existing. 6. **The `felhom-testing` skill's "known flake" line was actively harmful** — it instructed every future session to dismiss a true positive, for weeks. Removed, and generalised: "known flake, just re-run it" is a diagnosis and needs evidence like any other.