doorstep: console is Felhom's (ISO 1.27.0 source), passphrase hand-over copy (hub 0.113.0 source), rulings
gates / gates (push) Successful in 19s

Phase 0: the public ISO never auto-installs by construction (no answer.toml,
G1); the operator re-affirmed the interactive installer 2026-09-14.
- felhom-bootstrap.sh: mask pvebanner.service, write a Hungarian /etc/issue
  (no :8006 admin URL); pairing banner names the Tulajdonosi jelmondat and
  paints through the CONSOLE_DEV seam (R-496). Harness: 8 checks, red first;
  fake hub now sends a pairing code (the banner was never tested, R-502).
- hub: created flash + Credentials block tell the operator to hand the phrase
  over; the self-bind mail names the operator (R-497). Tests red first.
- iso-release-gate G14-G16; domain ruling in 01-topology + CONTEXT; R-494
  narrowed to P3; R-502..R-504 filed; volunteer guide and day-0 A.2 aligned.
ISO_VERSION 1.27.0 (not built, not published).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-14 17:26:53 +02:00
parent 8c7f882d1c
commit 6fd8c87516
14 changed files with 269 additions and 34 deletions
@@ -148,6 +148,15 @@ credentials.
DNS/routing stay intact through an outage.
- **Outbound only** for control/report/backup (poll to hub, push to PBS). No inbound control
endpoint exists in the chosen model.
- **Every customer has their OWN domain — never a name under `felhom.eu`** (operator ruling
2026-09-14). The free Cloudflare tier's certificate covers one level below a zone, so nested names
such as `felhom.<customer>.felhom.eu` are not covered; the customer's own domain is a few thousand
forints a year and is **included in the customer's price**. The dashboard is `felhom.<customer
domain>`, each app `<sub>.<customer domain>`. **The tunnel is created by the operator** per
`runbooks/day0-install.md` A.1 today; the hub creating it at customer creation (for a domain already
on Cloudflare) is register row R-494, P3, not blocking. Measured reason this was ruled now: the
2026-09-14 first-hour drill used a `*.felhom.eu` customer domain with no tunnel, and the dashboard link
in the setup-code mail did not resolve.
- **Tunnel placement: host** (resolved, Part 3 §3/§5). `cloudflared` runs on the Proxmox host
as its own **agent-managed systemd service** — not inside the guest — so the data path
survives control-plane death by construction. Geo-restriction WAF is **hub-enforced** (the
+4 -1
View File
@@ -697,7 +697,7 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
| **R-489** | **[P3-LOW] `POST /api/stacks/{name}/remove` reports `volumes_removed: null` over named volumes it DID remove.** MEASURED 2026-09-13 on demo-hp five times (gokapi, actualbudget, adventurelog ×2, glance): `docker compose down --volumes` removed the app's named volumes (`docker volume ls` count 2 → 0) and the response carried `"volumes_removed":null`. The customer's confirmation dialog therefore cannot say what it deleted. Split out of R-474 (closed in v0.240.0 for the backups half). **Fix shape:** list the volumes before `down --volumes`, diff after, and report the difference (`[]` when none, never `null`). **PARTLY SHIPPED in v0.242.0 (`d698ce3`), measured live on 9202 the same night:** the difference is computed and a fresh compose-created volume IS reported (`["opengist_opengist_data"]`), but the listing filters on the compose project LABEL and a volume recreated by a unit restore (`docker volume create <name>`, `restore.go:154`) carries no labels — compose still removes it and the response says `[]` (`audits/v0242-2026-09-14/19-R489-cause.txt`). **Remaining fix:** list by the `<project>_` name prefix as well (union), or label the recreated volume as compose would. | **READY — rank P3-LOW; owner: CC (residual)** |
| **R-492** | **[P3-LOW] `cfg.Paths.HDDPath` is empty on every box and still has readers; delete it.** R-465 audited its six readers and found every one falling back; R-490 (v0.242.0) gave the last one, `systemInfo`, the same fallback. The global now carries no information on any box and its deletion was deferred twice. **Fix shape:** remove the field, its env binding and the readers' fallback branches; a build proves nothing reads it. Next controller release. | **READY — rank P3-LOW; owner: CC** |
| **R-493** | **[P1-HIGH] There are NO customer-facing install instructions, so a volunteer cannot begin — this blocks inviting anyone.** MEASURED 2026-09-14 (drill `audits/DRILL-fresh-install-0242-2026-09-14.md`, Phase 0.2), each source with what was searched: the website's 9 pages carry no mention of the installer, of `iso.felhom.eu`, or of any install step (`iso`, `letolt`, `telepit`); `https://iso.felhom.eu/` and `/index.html` both return **404** — only the exact object name `felhom-installer-1.26.1-pve9.2-1.iso` answers, so the file cannot be found without being told its name; `RUNBOOK-onboarding-draft-v4.md` is an operator-attended script; the R-11 tester one-pager was ruled 2026-07-21 and never written; no `email.md` exists in the workspace; the two hub mails a new customer receives (`Kösd össze a Felhom dobozodat`, `Elindult a Felhom szervered — beállító kód`) assume the box is already installed. **Stopgap written by the drill:** `documentation/runbooks/VOLUNTEER-first-hour.md` (Hungarian, the steps the product really needs, each addition over today listed at its top). **What it needs:** the operator to choose the channel and approve the text. | **WAITING-ON-OPERATOR — rank P1-HIGH; owner: operator (channel + text), CC (draft)** |
| **R-494** | **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **WAITING-ON-OPERATOR — rank P1-HIGH; owner: operator (ruling), CC (build)** |
| **R-494** | **NARROWED 2026-09-14 by operator ruling → [P3-LOW] the hub COULD create the tunnel at customer creation, for a domain already on Cloudflare. Not blocking: every customer has their own domain and the operator creates the tunnel per day-0 A.1 (`architecture/01-topology-and-trust.md`).** *Original finding, kept:* **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **READY — rank P3-LOW; owner: CC** |
| **R-495** | **[P2-MEDIUM] The public installer asks a stranger four questions nothing answers, and REFUSES its own default on one of them.** MEASURED 2026-09-14 on `felhom-installer-1.26.1` (drill screens `s04`–`s22`): every screen after the GRUB menu is **English** Proxmox (EULA, disk, locale, password, network, summary); **three disks are offered with no guidance which is the system disk** (the default happened to be right); the administrator e-mail is prefilled `mail@example.invalid`; the hostname is prefilled `pve.example.invalid` and pressing Next on it returns **„Invalid values: hostname does not look valid”** — a volunteer who accepts the defaults cannot continue; at the end, with the stick still in, the default-ticked auto-reboot boots back into the installer. None of this is wrong for Proxmox; all of it is unanswered for a Felhom household. **Fix shape (cheap first):** the volunteer instructions answer each question (done in `runbooks/VOLUNTEER-first-hour.md`); later, prefill hostname and e-mail from the ISO build. | **READY — rank P2-MEDIUM; owner: CC (ISO prefill), operator (instruction text via R-493)** |
| **R-496** | **[P2-MEDIUM] The box's console tells a stranger, in English and FIRST, to open the Proxmox admin page — and calls the owner passphrase „a jelszavadat”.** MEASURED 2026-09-14 (drill screen `s29`): above the Hungarian pairing banner the console prints Proxmox's own `Welcome to the Proxmox Virtual Environment. Please use your web browser to configure this server - connect to: https://192.168.0.134:8006/` — the operator admin UI, which a household must never be sent to; the Felhom banner below says „add meg ezt a kódot és **a jelszavadat**”, while the self-bind mail and page name the same secret **„Tulajdonosi jelmondat”** (R-323 renamed the mail; `scripts/iso/felhom-bootstrap.sh:71-72` was not renamed). **Fix shape:** replace the Proxmox `/etc/issue` block on appliance installs; rename the console word. Both live in `felhom-bootstrap.sh`, a frozen ISO payload (G9), so it ships with the next ISO. | **READY — rank P2-MEDIUM; owner: CC** |
| **R-497** | **[P2-MEDIUM] No product channel ever gives the customer the „Tulajdonosi jelmondat”, yet the self-bind mail says they received it at setup.** MEASURED 2026-09-14: the 5-word phrase is minted at customer creation (`hub/internal/web/configs.go`, `RandomPassphrase(5)`) and shown **only on the operator's customer page**; the self-bind mail (`FormatSelfBindEmail`) says „amelyet a beállításkor kaptál” and the console asks for it; nothing sends it. Day-0 runbook A.2 says the operator must dictate or hand it over — a step that exists only in an operator document. A volunteer whose operator forgets cannot bind the box and is told they already have the phrase. **Fix shape:** the operator's customer-create confirmation says, in one line, to hand this phrase to the customer now; the volunteer instructions say where it comes from (done in `VOLUNTEER-first-hour.md`). | **READY — rank P2-MEDIUM; owner: operator (process), CC (hub copy)** |
@@ -705,6 +705,9 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
| **R-499** | **[P2-MEDIUM] Every app without a data drive is told its data is „already in the full system backup (PBS)" and there is „nothing to do" — on a box with no PBS, whose only whole-box copy sits on the same disk.** MEASURED 2026-09-14 on a fresh 0.242.0 box with the DR tier off (drill step 7): `GET /stacks/bookstack/backup` renders „Ennek az alkalmazásnak az adatai a belső rendszerlemezen vannak, amelyek **már szerepelnek a teljes rendszermentésben (PBS)** … ehhez az alkalmazáshoz nincs külön teendő." The sentence sits under `{{if not .IsHDDApp}}` in `controller/internal/web/templates/tier2_config.html:20-26` and consults nothing about where the whole-guest backup goes. On the same box `/backups` says, correctly, „Helyi tároló (local)" and „A rendszermentés jelenleg ugyanazon a lemezen van, mint a rendszer — így hibás fájlok ellen véd, lemezhiba ellen nem." **Two pages of one product contradict each other, and the reassuring one is the false one.** **Fix shape:** branch the sentence on the box's actual whole-guest target (PBS vs local, same-disk flag the overview already computes); a render test per branch. | **READY — rank P2-MEDIUM; owner: CC** |
| **R-500** | **[P3-LOW] The dashboard shows the last backup in UTC while every backup page shows it in local time — two different clock times for one backup.** MEASURED 2026-09-14 on a fresh 0.242.0 box (drill step 12): the same backup (`last_run 2026-09-14T13:41:37Z`) reads „Utolsó mentés: **2026-09-14 13:41**" on `/dashboard` and „Utolsó adatbázis mentés: **2026-09-14 15:41** (most)" on `/backups/apps`. Cause, from source: `controller/internal/web/templates/dashboard.html:154` renders `{{.BackupStatus.LastRun.Format "2006-01-02 15:04"}}` with no conversion to the box's zone, while the backup pages go through the zone-aware helpers in `funcmap.go`. A household comparing the two screens sees a backup two hours apart from itself. **Fix shape:** format through the same zone-aware helper; a render test that pins a non-UTC zone and asserts the local hour. | **READY — rank P3-LOW; owner: CC** |
| **R-501** | **[P3-LOW] The documented "confirm your CI run" recipe reads only the LAST page of the jobs list, and that list is not in id order — so it can report a run as missing that exists and passed.** MEASURED 2026-09-14 for felhom.eu commit `38848ff`: `actions/jobs?limit=1` → `total_count 335`; the recipe's page `T/50+1` = page 7 held ids 473…570 and **no match for 8 minutes**; a scan of all seven pages found the job on **page 6** (ids 380…581): `job id=581 name=gates status=completed conclusion=success completed_at 2026-09-14T14:18:23Z`. Pages are not sorted (page 1 ids 1…273, page 2 84…208). `actions/tasks` listed the same run first (`id 582, run_number 335, success`). **Fix shape:** the recipe in `felhom.eu/CLAUDE.md` (end-of-session checklist) scans every page and matches `head_sha`; say so in the same sentence that warns about the id offset (R-417). | **READY — rank P3-LOW; owner: CC** |
| **R-502** | **[P3-LOW] The bootstrap regression harness is run by NO gate and NO CI — and it had never exercised the pairing banner.** MEASURED 2026-09-14: `grep -rn bootstrap-modes scripts/*.py .gitea/workflows` → nothing; the harness is run by hand in `felhom-iso-assistant:trixie`. While adding the R-496 checks, its fake hub's `register` reply turned out to carry no `pairing_code`, so `print_pairing_banner` returned early in every run: the banner that a household reads first had no test at all until ISO v1.27.0. **Fix shape:** register the harness in `repo_gates.py` behind a container-available check that reports INCONCLUSIVE (never skip-as-pass) when docker is absent, with a decoy. | **READY — rank P3-LOW; owner: CC** |
| **R-503** | **[P3-LOW] SPIKE (not built): an install-time disk rule for the public ISO — "exactly one internal disk → install; otherwise stop in Hungarian".** Offered to the operator 2026-09-14 and **not chosen**: the 2026-07-31 ruling (a person chooses the disk) stands. Recorded so a reversal starts from measurements, not from the offer. **What must be measured first:** (1) whether the Proxmox auto-installer's HTTP answer mode can serve a per-machine answer from posted system info without network being a precondition a volunteer can miss; (2) whether USB transport is reliably visible in sysfs (`/sys/block/*/device` path, `removable`) where udev properties were measured blind (SPIKE-universal-iso-1 §3.2); (3) whether any refusal can be shown in Hungarian without modifying the Proxmox installer squashfs. **Reverses two rulings if built — needs an operator word.** | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (ruling), CC (spike)** |
| **R-504** | **[P3-LOW] `iso.felhom.eu` cannot show an index page on its own — its root returns 404, and the download page lives on the website instead.** MEASURED 2026-09-14: `https://iso.felhom.eu/` and `/index.html` → 404; only named objects answer. The host is an R2 bucket behind a custom domain; whether R2 would serve an uploaded `index.html` at `/` was **not measured** (uploading anything to the public bucket is a publication). The ISO v1.27.0 task puts the Hungarian download page at `felhom.eu/letoltes` (published with the ISO, after the operator's yes). **Remaining:** a redirect from `iso.felhom.eu/` to that page needs a Cloudflare rule the session has no credential for. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (Cloudflare rule)** |
<!-- DUE-CHECKS-BEGIN — machine-readable. Parsed by scripts/due_checks_gate.py.
One row per dated check. The R-number must have a row above. Dates are UTC.
+15 -21
View File
@@ -8,18 +8,18 @@
> **Every step this document adds beyond what exists today** (none of these is written anywhere a
> volunteer can see):
>
> 1. **Where the installer is, by exact file name** — `iso.felhom.eu` has no index page (R-493).
> 1. **Where the installer is** — the Hungarian download page `felhom.eu/letoltes` (published with ISO
> v1.27.0 after the operator's yes; `iso.felhom.eu/` itself still has no index — R-504).
> 2. **That the installer screens are English Proxmox screens**, and what to type on each.
> 3. **A hostname to type** — the installer refuses its own default `pve.example.invalid`.
> 4. **An e-mail to type** — the installer prefills `mail@example.invalid`.
> 5. **To remove the USB stick** at „Installation finished — reboot now?".
> 6. **To ignore the English „Please use your web browser … https://…:8006/" block** on the console —
> that is the Proxmox admin page, not Felhom.
> 7. **That „a jelszavadat" on the console means the 5-word „Tulajdonosi jelmondat"**, and that it
> comes from the operator, not by mail.
> 8. **How to reach the dashboard** — **UNRESOLVED**: the setup-code mail's link does not resolve for
> a new customer unless the operator made a Cloudflare tunnel by hand (R-494). Step 5 below says
> what the operator must do before sending this document.
> 6. ~~To ignore the English Proxmox console block~~ — **removed in ISO v1.27.0** (R-496): the console
> shows Felhom's Hungarian text.
> 7. ~~That „a jelszavadat" means the Tulajdonosi jelmondat~~ — **removed in ISO v1.27.0 / hub v0.113.0**
> (R-496, R-497): console, mail and page use one name; the mail says the operator hands it over.
> 8. **How to reach the dashboard** — **ruled 2026-09-14**: every customer has their own domain and the
> operator creates the tunnel (day-0 A.1) before sending this document. R-494 is narrowed to P3.
>
> Operator prerequisites this document silently depends on (§ „Az üzemeltető előtte"):
> create the customer; **hand over the Tulajdonosi jelmondat out of band**; **create the Cloudflare
@@ -45,12 +45,8 @@
## 1. A telepítő letöltése (~1 perc)
Töltsd le ezt a fájlt (kb. 1,7 GB):
`https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso`
Ellenőrző összeg (SHA-256), ha szeretnéd ellenőrizni:
`f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6`
Nyisd meg a **https://felhom.eu/letoltes** oldalt, és töltsd le az ott megadott telepítőt
(kb. 1,7 GB). Az oldal a fájl ellenőrző összegét (SHA-256) is megadja.
Írd ki USB-kulcsra (Windows: Rufus, **„DD" módban**; Mac/Linux: balenaEtcher).
@@ -62,7 +58,7 @@ Indítsd a gépet az USB-kulcsról. **A telepítő képernyői angolul vannak**
|---|---|
| Felhom logó, két sor | Válaszd a **„Felhom telepítés"** sort (vagy várj, magától elindul) |
| END USER LICENSE AGREEMENT | **I agree** |
| Target harddisk | Válaszd azt a lemezt, **amelyre a rendszer kerüljön**. Ha több lemez van, a legnagyobb nem feltétlenül a jó — a külső adatlemezeket ne válaszd. |
| Target harddisk | **A telepítő soha nem választ helyetted.** Felsorolja a gép lemezeit méretükkel és típusukkal; válaszd azt, **amelyre a rendszer kerüljön — ez a lemez törlődik.** A külső mentőlemezt a telepítés idejére húzd ki. Ha több belső lemez van és nem tudod, melyik a jó, állj meg és szólj az üzemeltetőnek. |
| Country / Timezone / Keyboard | Hagyd így: Hungary, Europe/Budapest, Hungarian |
| Root password | Adj meg egy legalább 8 karakteres jelszót kétszer. **Nem kell megjegyezned** — a Felhom az első indulás után lecseréli. |
| Administrator email | Írd be a saját e-mail címedet (a `mail@example.invalid` helyett) |
@@ -73,10 +69,8 @@ Indítsd a gépet az USB-kulcsról. **A telepítő képernyői angolul vannak**
## 3. Az első indulás (~2 perc)
A képernyőn **először egy angol szöveg** jelenik meg („Welcome to the Proxmox Virtual Environment…
connect to: https://…:8006/"). **Ezzel nincs teendőd — ne nyisd meg.**
Alatta megjelenik a Felhom:
A képernyőn ez jelenik meg: „Felhom otthoni szerver — Ezen a képernyőn nincs teendőd, bejelentkezni
sem kell." Alatta, kb. 2 perc múlva:
> Felhom — a doboz készen áll, és a párosításra vár.
> Párosító kód: XXX-XXX
@@ -89,7 +83,7 @@ Alatta megjelenik a Felhom:
hivatkozásra (7 napig érvényes).
2. Add meg:
- a **Párosító kódot** a doboz képernyőjéről;
- a **Tulajdonosi jelmondatot** (5 szó). A doboz képernyője ezt „jelszónak" hívja — ugyanaz.
- a **Tulajdonosi jelmondatot** (5 szó), amelyet a Felhom üzemeltetőjétől kaptál.
3. Hagyd bekapcsolva a dobozt. **Kb. 3 perc** múlva megérkezik a következő e-mail.
*(Megjegyzés: a doboz képernyője az összekötés után is a párosító kódot mutatja — ez ismert hiba,
@@ -99,7 +93,7 @@ nem kell újra összekötni.)*
1. Nyisd meg a **„[Felhom] Elindult a Felhom szervered — beállító kód"** tárgyú e-mailt.
2. Kattints a benne lévő címre (`https://felhom.<a-te-domained>`).
**⚠ Ha a cím nem nyílik meg, szólj az üzemeltetőnek** — ez most ismert akadály (R-494).
Ha a cím nem nyílik meg, szólj az üzemeltetőnek.
3. „A szerver beállítása" oldalon add meg a **Beállító kódot** (3 szó, pl. `szó-szó-szó`), és válassz
**legalább 12 karakteres** jelszót. Ez lesz a vezérlőpult jelszava.
4. Ha nem jött meg a kód: **„Új kód kérése"** — mindig ugyanarra az e-mail címre érkezik.
+4 -1
View File
@@ -69,7 +69,10 @@ Hub UI (`https://hub.felhom.eu`, operator password) → **Customers → New**:
On save the hub generates two credentials:
- **Retrieval passphrase** (5 Hungarian words) — the ONE secret the installer carries to the box.
Dictate or hand it to whoever runs Part C. Treat it like a password.
The customer knows it as **„Tulajdonosi jelmondat”**. **Hand this phrase to the customer now** — in
person or by phone; it is never e-mailed, and the self-bind page asks for it. (The hub's
customer-created flash and Credentials block say the same sentence since hub v0.113.0, R-497; the
self-bind mail tells the customer they received it from the Felhom operator.) Treat it like a password.
- **Customer API key** — internal (baked into the generated controller.yaml); never handled manually.
### A.3 Verify the Day-0 artifact manifest
@@ -244,6 +244,53 @@ it. The installed box registered at the hub, failed to persist the token, and th
Any future criterion of the form "the correct file is present" should be paired with one of the form
"and everything it needs at run time is too". `build-deb.sh` asserts this itself and is red-proofed.
### G14 — a PERSON chooses the disk; the image never guesses (operator rulings 2026-07-31, re-affirmed 2026-09-14)
```bash
osirrox -indev "$ISO" -find / -maxdepth 1 2>/dev/null | grep -cE "'/answer\.toml'|'/auto-installer-mode\.toml'" # 0 (= G1)
grep -c 'filter\.' <every pipeline-added text file> # 0
```
**PASS =** both `0`, **and** the proof install shows the installer's own disk screen and `Bootdisk(s)`
summary before erasing, **and** `runbooks/VOLUNTEER-first-hour.md` tells a volunteer, in Hungarian, how
to recognise the system disk on that screen.
*The rule, in one paragraph a volunteer could read:* **the installer never picks a disk for you.** It
lists every disk it sees, with its size and model; you choose the one the system goes on, and that
disk is erased. If the machine has more than one disk, the guide tells you how to tell them apart
before you press Next — and the external backup drive should not be plugged in during the install.
*Why:* SPIKE-universal-iso-1 §3.2–3.3 measured that no udev property separates an internal disk from a
USB-caddy backup drive and that a filter matching two disks silently wipes one. On 2026-09-14 the
operator was offered an install-time "use the only disk" rule and chose to keep the person as the
safety mechanism. Changing this criterion reverses two rulings; the spike that would inform it is its
own register row.
### G15 — the console is Felhom's after first boot, with no admin URL
On the proof install, after the first boot and after **one reboot**:
```bash
grep -c 8006 /etc/issue # 0
grep -c 'Felhom otthoni szerver' /etc/issue # 1
systemctl is-enabled pvebanner.service # masked
```
**PASS =** all three, **and** a console screendump shows no `https://…:8006/` line. *Why:* Proxmox's
`pvebanner.service` rewrites `/etc/issue` on every boot; the 2026-09-14 drill (screen s29) found that
text — the operator admin UI, in English — was the first thing a household read. The reboot is part of
the criterion because an overwrite without the mask passes once and fails on the next boot.
### G16 — every Felhom-authored string on the volunteer's path is Hungarian, and names each secret once
```bash
grep -n "printf ' " <extracted felhom-bootstrap.sh> | grep -viE 'á|é|í|ó|ö|ő|ú|ü|ű|Felhom|%s' # review every hit
grep -c 'jelszavad' <extracted felhom-bootstrap.sh> # 0
grep -c 'Tulajdonosi jelmondat' <extracted felhom-bootstrap.sh> # >= 1
```
**PASS =** no English sentence in the review list, `jelszavad` absent, the R-323 name present. Search
with ASCII fragments where possible and keep one positive and one negative control in the record.
*Scope, stated so it is not read wider:* the **Proxmox installer's own screens are English** and stay so
under the 2026-07-31 ruling; G14 requires the guide to answer each of them. This criterion covers what
Felhom writes: the GRUB menu, the console banner and `/etc/issue`, the first-boot screens.
---
## Result recording