Machine: VM 330 destroyed with its disks. Host: ISO and scratch removed, ~8.5 GiB returned on nvme-scratch. Hub: customer drill0242 DELETED via the cascade (journal #17), pages 404; its ep0 WireGuard peer dropped at the next full-list push. Evidence pulled before the destroy. R-501: the documented CI-check recipe reads only the last jobs page, which is not in id order. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
33 KiB
Journal — DRILL fresh install 0.242.0, 2026-09-14
Every observable in the order taken. Times are UTC unless marked. Hub log lines print CEST
(UTC+2). Screens are in screens/, named by step.
Baselines (re-verified 12:5x UTC)
| repo | main | version |
|---|---|---|
| felhom-controller | 406755fa8fba |
v0.242.0 |
| felhom-agent | 4586f0f7f6d1 |
v0.130.0 |
| felhom.eu | 41590f8ee618 |
hub v0.112.0 |
Hub, before the bake: agent 0.130.0 vouched · golden 0.236.0 vouched · min_agent 0.129.0 ·
floor min_controller_version 0.242.0. Highest register id R-492.
Phase 0.1 — golden 0.242.0
Baked 13:01:04 → finished before 13:06:42 · round-trip verified · vouched 13:08:41.
Full record: documentation/tests/golden-0.242.0-2026-09-14/README.md.
Phase 0.2 — what a volunteer receives
Searched, with what was searched:
| source | what was looked for | result |
|---|---|---|
website/*.html (9 pages) |
iso.felhom, iso, letolt, telepit |
no mention of the installer, of iso.felhom.eu, or of any install step (only technologiak.html "comparison" and two FAQ answers on power loss / backups matched the loose pattern) |
https://iso.felhom.eu/ |
the root, index.html |
HTTP 404 both. Only a named object answers: felhom-installer-1.26.1-pve9.2-1.iso (200, 1 705 322 496 B, last-modified 2026-07-31) |
RUNBOOK-onboarding-draft-v4.md |
customer steps | operator document, operator present at the visit ("operator narrates"); C7 marked never executed |
email.md in the workspace |
find /mnt/5_hdd/felhom.eu -maxdepth 5 -iname '*email*.md' |
absent (only audits/FINDING-app-email-rollout-2026-06-29.md, unrelated) |
| the R-11 tester one-pager | find … -iname '*one-pager*', register |
never written — ROADMAP-HISTORY: "RULED 2026-07-21 (channel); doc is the architect's" |
| hub e-mails to a new customer | hub/internal/notify/templates.go |
two: „Kösd össze a Felhom dobozodat" (self-bind link, at customer creation) and „Elindult a Felhom szervered — beállító kód" (claim code, after day-0). Neither says how to get or install the software |
Harness limits, declared before the walk (not interventions — the volunteer is not limited this way)
- H1 — no mailbox. Both customer mails go only to the registered address. The hub stores
hashes; the Resend key on DooPlex is send-only (
401 restricted_api_key … only send emails, probed 13:00). A volunteer reads their inbox; this harness cannot. - H2 — keyboard.
qm sendkeyemits US scancodes; the installer defaults to Hungarian. The layout was switched to U.S. English (as walk 5). A volunteer keeps Hungarian. - H3 — the USB stick. Auto-reboot was unticked so the VM does not re-enter the installer from the
still-attached ISO; the ISO is detached by
qm setafter the install. A volunteer pulls the stick. - H4 — the Terminal UI entry was chosen over the graphical default for key-drivability. Both entries were release-gated.
Scope choice
- Customer created with the DR tier OFF (the form defaults it ON). The DR tier provisions an ep0 namespace and token; the brief fences ep0. Offsite is OFF by default and stayed OFF.
Step 1 — download
13:01:27 on demo-hp: curl https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso → rc 0,
32 s, 1 705 322 496 B, sha256 f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6
= the published .sha256 exactly. (No release report records a sha for 1.26.1; walk 5 recorded
"same sha256" without the value.) A volunteer must already know the exact file name — the site
lists nothing.
Hub side — the operator's steps
13:03:03 POST /configs/new customer drill0242, name "Drill 0.242 first hour", domain
drill0242.felhom.eu, e-mail drill0242@felhom.eu, DR tier off → 303 13:03:04. Hub log (CEST):
15:03:04 [INFO] Customer config created: drill0242
15:03:04 [INFO] self-bind link (hash 4270bdd2…, valid 7 days) emailed to the registered address of drill0242
15:03:04 [INFO] self-bind link auto-minted for drill0242 on customer creation (the console banner's promised email now exists)
The 5-word Tulajdonosi jelmondat was read from the customer page into a 0600 file on DooPlex
(shape: 5 words, 42 chars). The operator must hand it to the volunteer out of band — nothing sends
it. (The self-bind mail says „amelyet a beállításkor kaptál" — "which you received at setup".)
Step 2 — install
VM 330 drill0242-fresh-install on demo-hp: q35/OVMF (pre-enrolled-keys=0), 4 cores, 8 GB,
cpu=host, scsi0 200 G · scsi1 50 G · scsi2 50 G qcow2 on nvme-scratch (dir at
/mnt/hdd_1, the mount root), MAC bc:24:11:0c:23:cc.
| UTC | screen | what it said / what was done |
|---|---|---|
| 13:03:43 | power on | — |
| 13:03:49 | GRUB (s01, s02) |
Felhom logo, „Saját felhőd, saját szabályaid"; entries „Felhom telepítés" / „Felhom telepítés (szöveges mód)" — the only Hungarian the installer shows |
| 13:05:09 | s04 |
English Proxmox EULA, „I agree" |
| 13:05:27 | s05 |
„Target harddisk: /dev/sda (QEMU HARDDISK) (200.00 GiB)" — default is the right disk here; three disks present, no guidance which |
| 13:05:43 | s06 |
Country Hungary · Timezone Europe/Budapest · Keyboard Hungarian (H2: changed to U.S. English) |
| 13:09:18 | s13 |
Root password [at least 8 characters] · Confirm · Administrator email prefilled mail@example.invalid — the volunteer must decide what to type; set drill0242@felhom.eu |
| 13:12:01 | s16 |
nic0 bc:24:11:0c:23:cc · Hostname pve.example.invalid · IP 192.168.0.134/24 (the DHCP lease, frozen as static) · GW 192.168.0.1 · DNS 192.168.0.250 |
| 13:12:21 | s17 |
Next on the defaults → „Invalid values: hostname does not look valid". The default is refused; the volunteer must invent a hostname. Set drill0242.felhom.eu |
| 13:14:40 | s22 |
Summary: ext4 · /dev/sda · Europe/Budapest · U.S. English · drill0242@felhom.eu · nic0 · drill0242.felhom.eu · 192.168.0.134/24 · 192.168.0.1 · 192.168.0.250 · „[X] Automatically reboot" (H3: unticked, s25) |
| 13:15:54 | Install pressed | — |
| ≤13:19:18 | s28 |
„Success — Installation finished - reboot now?" (≤ 3 m 24 s of copying; disk 4.0 G) |
| 13:19:44 | first boot | H3: qm stop, --delete ide2, --boot order=scsi0 in its own qm set (verified boot: order=scsi0, ide2 lines 0), qm start |
Step 3 — the first screen and the claim
13:21:10 — the hub lists an Unclaimed appliance (86 s after first power-on): appliance 25,
pairing code ***-*** (redacted), MAC bc:24:11:0c:23:cc, "Standard PC (Q35 + ICH9, 2009)", 7.7 GB,
three SSH host keys.
The console (s29, code redacted), verbatim:
Welcome to the Proxmox Virtual Environment. Please use your web browser to
configure this server - connect to:
https://192.168.0.134:8006/
drill0242 login:
Felhom — a doboz készen áll, és a párosításra vár.
Párosító kód: ***-***
Nyisd meg az e-mailben kapott linket, és add meg
ezt a kódot és a jelszavadat.
Ez a képernyő magától frissül — nincs teendő a
doboznál, és nyugodtan itt hagyhatod bekapcsolva.
Two things a stranger meets here: an English line telling them to open the Proxmox admin page, above the Felhom text; and „a jelszavadat" ("your password") for the secret the self-bind mail calls „Tulajdonosi jelmondat" (R-323 renamed the mail, not the console).
The bind (H1 consequence). The volunteer's route is the self-bind link, which is in a mailbox this
harness cannot read. The operator's documented fallback was used: POST /appliances/25/bind
(customer_id=drill0242) at 13:21:43 → 303 flash=appliance_bound. The self-bind page itself
was therefore NOT exercised.
Hub log (CEST = UTC+2):
15:21:44 appliance 25 BOUND to customer drill0242 (mode=appliance) — delivery staged for its next poll
15:21:45 appliance credentials DELIVERED once to appliance 25 (… passphrase withheld)
15:21:52 [claim] claim code (gen 1) emailed to the registered address of drill0242
15:22:21 host enrolled: drill0242-3f4b42 (customer drill0242)
15:22:21 vaulted break-glass recovery credential for host drill0242-3f4b42 (user=root@pam, secret 32 chars)
15:22:22 Artifact manifest served for customer drill0242 (agent=0.130.0 golden=0.242.0)
15:22:38 wg registered: host=drill0242-3f4b42 … ip=10.77.0.5/32 changed=true gen=1 sync=ok
15:22:39 DR-recipe host-half stored for customer drill0242 (host drill0242-3f4b42, v1)
15:23:58 Event from drill0242: controller_started (info) — Controller elindult (0.242.0)
15:23:58 managed floor SERVED for drill0242: floor 0.242.0, agent requirement "0.129.0" from manifest (golden 0.242.0)
Note on ep0: wg registered … sync=ok is a WireGuard peer written on ep0 by enrolment itself,
with the DR tier OFF. The brief fenced ep0; the product touches it on every enrolment. Teardown owes
its removal.
Step 4 — "ready", and the version
| vouched | landed | |
|---|---|---|
| agent | 0.130.0 | 0.130.0 (felhom-agent --version) |
| controller | golden 0.242.0 | 0.242.0 (docker ps: felhom-controller:0.242.0 … (healthy)) |
No self-update happened because none was needed — golden == floor. Power-on → controller running
4 m 14 s; bind → controller 2 m 15 s. Infra: traefik:v3.6.7, gtstef/filebrowser:1.3.3-stable.
First local whole-guest backup ran unaided 15:28:53–15:29:23 CEST, OK (seen as a backup lock).
The console still shows the pairing banner and the stale code after bind (s30, 13:24:38) —
R-214, still open.
Intervention I1 — the dashboard has no address (R-494, filed 13:2x BEFORE acting)
The claim mail says https://felhom.drill0242.felhom.eu. Measured:
felhom.drill0242.felhom.eu @1.1.1.1 A: (none) AAAA: (none)
control felhom.enkisfelhom.hu @1.1.1.1 A: 104.21.3.175 172.67.130.252
https://felhom.drill0242.felhom.eu curl rc 6 (cannot resolve)
@192.168.0.1 (router) (none)
@192.168.0.250 (installer-offered DNS) (none)
@192.168.0.134 (the box) 13:27:39Z (none) — google.com resolves: the resolver is alive
agent 15:27:44 CEST lanresolver: applied split-horizon record vmid=9201 domain=drill0242.felhom.eu ip=192.168.0.158
@192.168.0.134 (the box) 13:29:18Z 192.168.0.158
The hub has no tunnel/DNS creation code; cf_tunnel_token is an optional pasted field. Act: the
dashboard is reached at the guest LAN address with the name forced (--resolve felhom.drill0242.felhom.eu:443:192.168.0.158), from demo-hp — which is where a browser on the
household LAN would be. GET / → 302 /claim; the page, verbatim:
A szerver beállítása — Drill 0.242 first hour — „Add meg az e-mailben kapott beállító kódot, majd válassz saját jelszót a vezérlőpult védelméhez." · Beállító kód (
szó-szó-szó) · Új jelszó (min. 12 karakter) · Új jelszó megerősítése · Beállítás és belépés · „Nem kaptad meg a kódot? Új kód kérése"
H1 — the setup code (harness substitution, not a volunteer act)
The code is in the mail. Observe access to the appliance: POST /hosts/drill0242-3f4b42/reveal-recovery-credential
→ 200 (the designed operator path; it emits an audit event), stored 0600, never printed. Then
pct exec 9201 -- docker exec felhom-controller … --print-reset-code.
Harness slip, recorded: the first mint at 13:29:28 (generation 2) was captured with a
pattern [a-z-]* that does not match accented letters, and the raw output was shredded before the
capture was checked — that code was lost unseen. Re-minted (generation 3) with a byte-agnostic
capture. Both mints supersede the mailed generation-1 code.
Step 3 (cont.) — the claim, through the front door
All dashboard requests from here are made from demo-hp (the household LAN) to the guest's traefik
on 192.168.0.158:443 with the dashboard name forced — intervention I1, once, for the whole walk.
Secrets travel on stdin to curl, never on a command line; the dashboard password is a generated
24-character value in a 0600 file on DooPlex.
| UTC | request | result |
|---|---|---|
| 13:31:19 | GET /claim |
200; felhom_claim_csrf cookie (82 B) + form token (64 hex) |
| 13:31:20 | POST /claim _csrf, code, new_password, confirm_password |
302 → /, Set-Cookie: felhom_session |
| 13:31:2x | GET /launcher |
200 — „Indítópult — drill0242.felhom.eu", one tile Filebrowser, „Indítópult megosztása … A megosztás jelenleg ki van kapcsolva." Menu: Vezérlőpult · Alkalmazások · Tárhely (Meghajtók, Hálózati tárhely) · Biztonsági mentés (Áttekintés, Távoli mentés, Alkalmazások, Visszaállítás) · Megosztás · Rendszermonitor · Debug · Beállítások · version 0.242.0 |
Power-on → claimed dashboard: 27 m 37 s (13:03:43 → 13:31:20), of which the harness's own keyboard driving is most of the install phase.
Step 5 — the app list
GET /stacks → 200, „Alkalmazások — drill0242.felhom.eu", filters Mind / Futó / Leállítva /
Telepíthető, 52 „Telepítés" links. GET /stacks/bookstack/deploy and /stacks/privatebin/deploy
→ 200. Both pages, verbatim in the parts a stranger reads:
BookStack — Telepítés · „Egyszerű, könyv-szerű wiki és dokumentáció platform" · ~150M · Pi kompatibilis · Memória 1058 MB / 3712 MB (28%) · „Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek (/mnt/sys_drive). A mentései így is elkészülnek." · „Automatikusan generált értékek … Jegyezze fel a szükséges jelszavakat!" (Alkalmazás kulcs, Adatbázis jelszó — Megjelenítés) · Aldomain
wiki· „Az aldomain telepítés után nem módosítható…"
PrivateBin — Telepítés · „Titkosított jegyzet és szöveg megosztás" · ~30M · Memória 1089 MB / 3712 MB (29%) · same data sentence · Aldomain
paste
Observation, not yet a row: the drive page's „Meglévő meghajtó csatolása" candidate list
(GET /api/disks/candidates) offers the guest's own system volume
/dev/mapper/pve-vm--9201--disk--1 (mount_source /mnt/sys_drive, already_mounted: true,
data_bearing: true) beside the two blank 50 G disks.
Step 5 (cont.) — deploy
Both through the deploy page's own call: every named input of #deploy-form →
POST /api/stacks/<app>/deploy {"values":{…}}, then GET /api/stacks/<app> every 5 s (the page
polls every 3 s). Generated secrets travelled on stdin and were shredded.
| app | fields sent | POST | state transitions | running after |
|---|---|---|---|---|
| bookstack | APP_KEY, DB_PASSWORD, SUBDOMAIN=wiki |
13:34:38 → 202 „Telepítés elindítva – az állapot a kártyán követhető" | +6 s deploying · +26 s degraded · +42 s starting · +68 s running |
68 s |
| privatebin | SUBDOMAIN=paste |
13:35:47 → 202 | +5 s starting · +21 s running |
21 s |
Observation: the deploy page's poll handles deploying / running / starting / unhealthy / exited / stopped and has no degraded branch (deploy.html ~1040–1095), so for those 16 s the page keeps
showing its previous step. Harmless here; recorded.
App pages (/apps/bookstack, /apps/privatebin): „Fut" · „Naprakész" · „Megnyitás ↗".
BookStack's „Első lépések": „Nyisd meg a wiki.DOMAIN címet a böngészőben · Jelentkezz be:
admin@admin.com / password · Változtasd meg azonnal az admin jelszót és email címet …" and a box
„Alapértelmezett belépés admin@admin.com / password — Az első bejelentkezés után azonnal változtasd
meg!". PrivateBin: „Nyisd meg a paste.DOMAIN címet …" → R-498 (52 of 53 templates).
Step 6 — using both, through their front doors
Front doors from demo-hp: wiki.drill0242.felhom.eu → 302 /login; paste.drill0242.felhom.eu →
200, 22 896 B, PrivateBin UI (English).
BookStack (over HTTPS, so its secure cookies work — R-460's 419 was a plain-HTTP effect):
| UTC | act | result |
|---|---|---|
| 13:37:18 | log in admin@admin.com / password (the page's own instruction) |
302 → /; logged-in markers 3 |
| 13:37:19 | change password via POST /users/1 |
405 — harness wrong route (BookStack ≥23 is /settings/users/1) |
| 13:37:52 | change admin e-mail + password via POST /settings/users/1 _method=PUT |
302 → /settings/users; old default login now → /login (refused); new → / (accepted) |
| 13:38:44 | create book „Családi receptek DRILL0242" | 302 → /books/csaladi-receptek-drill0242 |
| 13:38:4x | save a draft with _method=PUT |
405 — harness (the route is POST) |
| 13:39:35 | new draft 3 → POST name „Töltött káposzta", body DRILL0242-OLDAL Töltött káposzta: árvíztűrő tükörfúrógép 2026-09-14 |
302 → /books/csaladi-receptek-drill0242/page/toltott-kaposzta |
| 13:39:3x | upload attachment nagymama-recept.bin, 262 144 B random, sha256 2e252913844f8931… |
200, attachment id 1 |
| 13:39:3x | read back | page 200, sentence present 2 (negative control 0); attachment listed 1; GET /attachments/1 200 262 144 B, sha256 equal: YES |
PrivateBin — the browser's own v2 format (AES-256-GCM, PBKDF2-SHA256 100 000, zlib), key only in the fragment, as a browser does:
| UTC | act | result |
|---|---|---|
| 13:38:08 | POST / a paste „DRILL-0242 privatebin sentinel … — árvíztűrő tükörfúrógép", expire 1 week |
200 {"status":0,"id":"3963448c37a87005",…} |
| 13:38:08 | GET /?pasteid=3963448c37a87005, decrypt |
200, 471 B, decrypted == sent: True (sha256 5920d11290cca367…); wrong key → InvalidTag |
Step 7 — the backups pages, read as a first-timer (13:38:55)
/backups verbatim, in order: „Csak egy másolat készül (nincs második meghajtó) — a 3-2-1 mentéshez
csatlakoztasson egy második meghajtót vagy offsite tárolót." · „A rendszermentés jelenleg ugyanazon a
lemezen van, mint a rendszer — így hibás fájlok ellen véd, lemezhiba ellen nem. …" · Rendszer (/)
1.96 GB / 68.7 GB (3%) · DB mentések – · Utolsó teljes mentés 2026-09-14 15:28 (10 perce) 624.3 MB
Helyi tároló (local) Naprakész · „Következő mentés — 0 órája — a mentési ablakon belül" ·
Visszaállítás ellenőrizve „Még nem futott" · Mentés most · window 02:30 / 03:30 / 04:15 / 04:30–08:30
· Távoli rendszermentés „nincs beállítva".
- Honest: both warnings; the whole-box backup's date and target.
- Confusing: „Következő mentés" (next backup) with „0 órája" ("0 hours ago") under it — the value is
the age of the LAST backup (
backups.html:101-102,.AgeHours).
/backups/apps: „Utolsó adatbázis mentés: Még nem futott"; BookStack „Konfig + DB + Adatok" and
PrivateBin „Konfig + Adatok", each „1. mentés Auto helyi Utolsó: most" · „Nincs 2. (off-drive)
másolat" · „3. mentés Nincs beállítva".
„Utolsó: most" was checked, not assumed: timeAgoStr renders „most" only for a parseable time
under a minute old (an empty value renders nothing, funcmap.go:283-296), and
GET /api/backup/snapshots?stack=… returned for both apps
{"time":"2026-09-14T13:38:53Z","short_id":"helyi","tier":1,"drive_label":"Belső SSD (rendszer)"} —
3 s before the page was read. True. (That unit predates the BookStack content of 13:39:35.)
/stacks/bookstack/backup → R-499: „… már szerepelnek a teljes rendszermentésben (PBS) … ehhez
az alkalmazáshoz nincs külön teendő." — this box has no PBS.
/backups/restore: app select BookStack / PrivateBin, „Pillanatkép: — Válasszon alkalmazást —",
„Még nincs mentés felhasználói adattal."
Step 8 — „Mentés most" (the app-backups page's button, POST /api/backup/run)
| UTC | observable |
|---|---|
| 13:41:21 | pressed → {"ok":true,"message":"Mentés elindítva"} |
| +5 s | {"enabled":true,"running":true} |
| +21 s | {"db_dump":{"count":1,"duration":"15.752362463s","last_run":"2026-09-14T13:41:37.325510764Z","success":true},"enabled":true,"running":false} |
| 13:41:42 | both apps' restore points: {"time":"2026-09-14T13:41:37Z","short_id":"helyi","tier":1,"drive_label":"Belső SSD (rendszer)"} — one entry each; the 13:38:53 unit is gone (one local point kept) |
| 13:41:4x | /backups/apps: „Utolsó adatbázis mentés: 2026-09-14 15:41 (most)"; Adatbázisok: bookstack · MariaDB · 59.0 KB · 15:41 · 41 tábla · OK |
The date moved, to the true time, on both pages (R-476 class: holds). 21 s end to end.
Step 9 — version labels and Update
Both app pages: „Fut · Naprakész". GET /api/stacks/<app> at 13:42:28:
bookstack template_images {bookstack: lscr.io/linuxserver/bookstack:26.05.2, bookstack-db: mariadb:12.3}
catalog_images {bookstack: lscr.io/linuxserver/bookstack:26.05.2, bookstack-db: mariadb:12.3}
privatebin template_images {privatebin: privatebin/pdo:2.0.5} catalog_images {privatebin: privatebin/pdo:2.0.5}
The catalog offers no newer version of either app, so there was nothing to press. Skipped, per the brief. „Naprakész" is true on this evidence (installed == catalog).
Step 10 — removal: what the dialog shows for PrivateBin
The app page's delete opens removeStack() (layout.html:396), which loads
/api/stacks/privatebin/hdd-data → {"hdd_paths":null,"has_hdd_data":false} and
/backup-data → [{"path":"/mnt/sys_drive/felhom-data/backups/primary/privatebin","size_human":"40K","exists":true}].
Rendered text, in order:
Alkalmazás eltávolítása: privatebin · „Az alkalmazás visszaáll "Nincs telepítve" állapotba. A sablon megmarad, újratelepíthető." · „Ez a művelet nem visszavonható!" · Mindig törlődik: Docker kötetek (adatbázis, alkalmazás konfiguráció) · Telepítési konfiguráció (app.yaml) · Másodlagos mentés ütemezése · Mentési adatok: /mnt/sys_drive/felhom-data/backups/primary/privatebin (40K) · ☐ Mentési adatok törlése · „Az éjszakai restic pillanatképek nem törölhetők egyenként — a megőrzési szabályok szerint automatikusan elavulnak." · Mégsem · Eltávolítás
No „delete my data" box appears — PrivateBin has no drive data; its data is in a Docker volume,
which the dialog says is always deleted. „Delete my data too" was therefore performed as every
delete box ticked: remove_backups: true (the only box), remove_hdd_data: false (no box shown).
Observation: the sentence about „éjszakai restic pillanatképek" appears on a box with no restic
configured at all.
Step 11 prep — the household loses a recipe (13:43:07)
Through BookStack's own delete: GET …/page/toltott-kaposzta/delete → token; POST …/page/toltott-kaposzta
_method=DELETE → 302 to the book. Then: page 404, /attachments/1 404, the book page lists
the title 0 times. The last backup containing both is the 13:41:37 unit (step 8).
Step 11 — restore BookStack from its backup, through the restore page
The page's own submit: POST /backup/restore _csrf (from the page meta), stack_name=bookstack,
snapshot_id=helyi (the only point, 13:41:37 — step 8).
| UTC | observable |
|---|---|
| 13:44:13 | 302 → /backups/restore?flash=Visszaállítás elindult — az állapot itt frissül. |
| +6 s | app stopped |
| +11 s | starting |
| +26 s | running (probe pending) |
| +32 s (13:44:45) | running, health_probe.healthy: true |
| 13:45:09 | read back through the front door — login with the post-change password → /; page …/page/toltott-kaposzta 200; sentence present 2 (negative control 0); árvíztűrő tükörfúrógép present 2; /attachments/1 200, 262 144 B, sha256 equal to the pre-backup upload: YES |
DATA: PASS. The recipe the household deleted at 13:43:07 is back, with its attachment byte-identical and its Hungarian text intact, 32 s after pressing restore.
Reading the page at 13:45:11, after completion: the one-shot flash is gone and the page shows the
empty form again („Pillanatkép: — Válasszon alkalmazást — · Még nincs mentés felhasználói adattal.").
CORRECTED 13:46 — the first reading here was wrong. The page's script polls
/api/backup/restore-status, which at 13:46:03 returned "last":{"op":"restore","stack":"bookstack","ok":true, "message":"A(z) bookstack: 2 adatkötet és az adatbázis visszaállítva — az alkalmazás újraindult.", "finished_at":"2026-09-14T13:44:39Z"},"last_recent":true. So a Hungarian finish message exists and
names what came back; whether the page shows it is script-rendered and was not observed (no browser
here). The server-rendered HTML alone shows only the empty form.
Step 10 — removal, done the way the screens lead
Harness shortcut, withdrawn as a finding. At 13:43:36 the harness called
POST /api/stacks/privatebin/remove on a running app and got 409 stack "privatebin" is still running — stop it first before removing (English). The screens never offer that: for an operational
app stacks.html:99-102 shows Frissítés · Újraindítás · Leállítás and no „Eltávolítás"; the app
page shows none either. Nothing changed on the box (before/after identical, step10-remove-observe.txt).
| UTC | act | result |
|---|---|---|
| 13:45:26 | „Leállítás" → POST /api/stacks/privatebin/stop |
{"ok":true,"message":"Stack privatebin stop completed"} (English message; the UI shows its own text) · stopped at +6 s |
| 13:45:32 | observe before | volume privatebin_privatebin_data ×1 · containers 0 · /opt/docker/stacks/privatebin/.felhom.yml · backup dir 40K |
| 13:45:33 | „Eltávolítás" with every box ticked → POST …/remove {"remove_hdd_data":false,"remove_backups":true} |
200 {"removed":"privatebin","volumes_removed":["privatebin_privatebin_data"],"hdd_paths_removed":[],"hdd_paths_preserved":[],"backup_paths_removed":["/mnt/sys_drive/felhom-data/backups/primary/privatebin (40K)"]} |
| 13:45:39 | observe after | volumes 0 · containers 0 · backup dir No such file or directory · only the catalog template .felhom.yml remains (the dialog: „A sablon megmarad") |
| 13:45:4x | front door / API | paste. → 404 · restore points [] · state not_deployed, deployed=false |
PASS — the drive is clean of the app's data and its backups, and the response names each thing it
removed. (volumes_removed is populated here; R-489 recorded null over removed volumes on
demo-hp — this box did not reproduce it.)
Step 12 — status pages, read as a customer would a week later (13:46)
/launcher: tiles BookStack, Filebrowser (PrivateBin gone — correct)./dashboard: „3 Futó alkalmazás · 0 Leállítva · 55 Összes alkalmazás" · Memória 1.0 GB / 4.0 GB · Rendszer (/) 2.11 GB / 68.7 GB · Lemezek állapota: QEMU QEMU HARDDISK „Nincs adat" „0 °C" · „Utolsó mentés: 2026-09-14 13:41" while/backups/appssays 15:41 for the same run → R-500 (dashboard.html:154formats without the box zone)./monitoring: „Hub kapcsolat — Kapcsolódva … Utolsó sikeres jelentés: most"; graphs „Még nincsenek adatok…". The banner „A gazdagép metrikái jelenleg nem elérhetők" appeared in my text extraction, but it isdisplay:noneby default and shown only by script (monitoring.html:15) — not evidence; withdrawn. Whether the host card fills in was not observable without a browser.- Observation, not filed: „0 °C" beside „Nincs adat" on a virtual disk.
Evidence off the machine, end of Phase 1 (13:46)
box-logs-phase1/: controller.log (526 lines), agent-journal.log (2461), bootstrap-journal.log
(173, pairing code redacted), box-state.txt. Secret sweep over the copies for the claim code,
passphrase, dashboard password, BookStack password, break-glass credential and installer root password:
0 each; control (passphrase planted in a throwaway copy) 1.
Accident A1 — power cut (A1-power-cut.txt)
| UTC | observable |
|---|---|
| 13:47:31 | before: felhom-controller:0.242.0 · bookstack:26.05.2 · mariadb:12.3 · filebrowser:1.3.3-stable · traefik:v3.6.7, all healthy · agent 0.130.0 |
| 13:47:33 | qm stop 330 (hard) |
| 13:48:36 | qm start 330 (60 s dark) |
| +37 s | appliance answers SSH |
| +2 m 07 s (13:50:43) | hub: Event from drill0242: controller_started (info) — Controller elindult (0.242.0) |
| +2 m 9 s | dashboard /api/health 200 |
| 13:58:11 | the dashboard session did not survive: /api/stacks/bookstack → 401 authentication required (the customer logs in again; the harness loop misread this as unparseable for 8 min — harness fault, stopped) |
| 13:58:33 | after re-login: bookstack running, healthy, template images unchanged; every container Up 7 minutes (healthy), same five image tags; agent 0.130.0 |
| 13:58:36 | BookStack front door: page 200, sentence 2 (control 0), Hungarian 2, attachment 262 144 B, sha256 equal: YES |
Hub log across the cut (non-routine lines only): DR-recipe host-half stored 15:49:04 CEST,
controller_started 15:50:43, DR-recipe app-half stored 15:50:44. No alarm, no warning, no
customer mail event.
A1: PASS — every app back on the same version (Slice 3 holds), data intact, no false alarm, ≈2 min to a working dashboard. Cost to the household: one re-login.
Accident A2 — a typo in the code
Where it can be tried. The setup code is single-use and this box is already claimed, so the
first-claim screen cannot be re-entered. The login page's „Elfelejtett jelszó" opens the same
/claim form and the same code gate, titled „Jelszó visszaállítása — Felhom · Add meg az e-mailben
kapott beállító kódot, majd válassz új jelszót." A2 was run there, on the same box. The pairing-code
typo on the hub's self-bind page was NOT exercised (H1: no link).
Code: generation 4, minted by H1 at 13:59:30. The typo is the real code with its last letter changed
— exactly one character different, same length (checked, never printed). Limiter, from source
(claim.go:32-33, :170-200): 5 failures → 15-minute lock, counted per source AND globally.
| UTC | attempt | result |
|---|---|---|
| 14:00:09 | typo | 200, form re-rendered (not accepted) |
| 14:00:10 | the right code, new 24-char password | 302 → / — accepted after the typo |
| 14:00:10 | log in with the new password / the old one | 302 / 200 (old refused) |
| 14:00:10–12 | four more wrong codes (the spent code) | 200 each |
| 14:00:12 | the 5th failure | box: [WARN] [web] claim: code lockout tripped (source 192.168.0.104) — 15 min · Event pushed: claim_lockout (warning) — Túl sok hibás beállító kód — a beállító oldal 15 percre zárolva |
| 14:00:12 | a 6th attempt, during the lock | 200 |
| 14:00:16 | hub | Event from drill0242: claim_lockout (warning) … · Operator email sent for drill0242/claim_lockout |
Harness note: the text filter used on these replies missed the refusal wording, so the on-screen messages are taken from the reply bodies below, and the plain „Hibás vagy lejárt kód" reading is repeated after the lock expires. | 14:15:26 | a wrong code after the 15-minute window | 200, error box „Hibás vagy lejárt kód" — the form accepts attempts again |
On-screen wording, read from the reply bodies: during the lock „Túl sok próbálkozás — próbáld újra 15 perc múlva."; after it „Hibás vagy lejárt kód". Both Hungarian, both true.
A2: PASS — a one-letter typo is refused without harm, the right code is accepted right after it,
the lock is honest about its length and lifts on time. Two properties recorded, not filed: the lock is
global as well as per source (claim.go:188-200) — five wrong guesses from anywhere lock the real
household out for 15 minutes, by design against guessing; and the lockout e-mail went to the
operator only (Operator email sent for drill0242/claim_lockout), while the screen tells the
customer.
Teardown — three layers (teardown-before.txt, teardown-layer1.txt, teardown-layer2.txt, teardown-layer3-hub.txt)
Evidence was copied off the box before the destroy (box-logs-final/, 14:16, secret sweep 0).
| layer | UTC | result |
|---|---|---|
| 1. machine | 14:16:23 | qm destroy 330 --purge → qm list empty; /mnt/hdd_1/images/330 gone; images/9202 untouched |
| 2. host | 14:16:27 | ISO removed (0 left); /root/drill0242 shredded, removed; nvme-scratch used 19 059 372 → 10 130 532 KiB; local 24 768 200 → 23 013 832 KiB; local-lvm 44.17 % before and after; 9201 and 9202 running; vmbr9 pre-existed |
| 3. hub | 14:35:15 | host stale at 14:34:45 (true host_stale operator mail); customer DELETE cascade COMPLETE (journal #17); customer and host pages 404; lists 0 (control 1) |
| 3b. ep0 peer | 14:40:00 | 10.77.0.5/32 removed at the 14:39:30 periodic push (5 → 4 peers); 4 m 14 s after the delete; control peer present |
Disposition of drill0242: DELETED. The hub's event stream and the three operator mails
(claim_lockout, host_stale, and the bind/enrol log lines) are append-only and stay, by design.