7.2 KiB
REPORT — TASK-F: app lifecycle + HP USB write + R-55 live leg (2026-07-21)
Baselines at start (verified, all clean): controller a96226a v0.157.0, app-catalog 857ba53,
felhom.eu 0b2c598, agent eba040d v0.93.0 (source only — untouched this task).
| Part | Status |
|---|---|
| 1 — app lifecycle states | DONE + LIVE-PROVEN — controller v0.158.0, plus v0.158.1 fixing a defect I shipped |
| 2 — HP USB write | DONE — byte-proven |
| 3 — R-55 live leg | DONE — PROVEN LIVE |
| 4 — resolvability table | SKIPPED by operator ruling (no Docker Hub login) |
Part 2 — the HP boot stick
Written on felhom-pve under a format-operation evidence bar. Two USB-shaped devices were present, and that turned out to matter:
/dev/sdb— ADATA HD710 PRO, 932G. EXCLUDED. It is the live customer data drive, mounted at/mnt/hdd_1and bind-mounted into guest 9201 (mp8) — immich and calibre-web data. Its by-id path isusb-ADATA_…, butudevadmreportsID_BUS=ataand sysfsremovable=0, so the two required positive checks exclude it on their own. A bare-/dev/sdXworkflow would have offeredsdbandsdcside by side with nothing but a letter between them./dev/sdc— Samsung Flash Drive, serial0375123010001586, 119.5 GiB. The target.
Checks, all passed: ID_BUS=usb; removable=1; absent from findmnt (device and every partition);
absent from /etc/fstab; not an LVM PV (only /dev/sda3); no ZFS pools exist on the host; not
referenced by any guest config; 0 open handles. Destroyed content: an old iso9660 "PVE" install
image. Operator confirmed the printed device before any byte was written.
The identity was re-asserted at write time, not only at survey time, in case of re-enumeration between the confirm and the write.
1705338880 bytes (1.7 GB, 1.6 GiB) copied, 55.9 s, 30.5 MB/s
device sha256: 2b51d74c0eaf5155fd42a137dff803b9ab8692294cedcb727c9a80658c9f7823
iso sha256: 2b51d74c0eaf5155fd42a137dff803b9ab8692294cedcb727c9a80658c9f7823
RESULT: MATCH - byte-proven
dd … oflag=direct conv=fsync, then the ISO's exact byte-length read back from the device and
hashed — byte-proof, not exit-code-proof. The source ISO's sha256 was verified after transfer to
felhom-pve and matches the published hash. The customer data drive was re-checked after the write and
is still mounted at both its paths.
Boot cheat-sheet (unchanged, restated)
- Boot the stick with Secure Boot ON. This is the shim variant. Expect the Felhom boot screen, then the installer aborting having touched no disk — that is success.
- On a GRUB failure (
relocation, "no bootable device", a hang before the boot screen): use the mkimage ISO and set Secure Boot OFF. It is unsigned; SB-enforcing firmware refuses it. That ISO is at180:/mnt/5_hdd/felhom.eu/felhom-iso/out/…-hp-generic-mkimage.isoand is not on this stick. - Both artifacts are inert (match-nothing disk filter). The real install ISO does not exist yet — it needs the HP's internal SSD serial, which needs the board in hand. Send me the serial and which loader worked, and I will build it.
- The first boot is yours. No remote install step was attempted.
Part 1 — app lifecycle (summary; detail in felhom-controller/REPORT.md)
available / hidden / abandoned as a .felhom.yml field, because the retired/ directory move
shipped hours earlier would have orphaned every customer running a withdrawn app. Deploy gate is
server-side and fail-closed; unknown values fail open; orphan detection never sees the field.
Live on 9201 through the real endpoints: plant-it renders 0 times on the catalog page (control app 10), a direct deploy POST returns 409 „Ez az alkalmazás jelenleg nem telepíthető.", the app page carries the permanent notice with no Telepítés button.
v0.158.0 shipped a defect that I caught during live validation, not from the suite: the lifecycle
predicates had pointer receivers, and html/template cannot call those on the non-addressable value
the handler passes — so every /apps/<slug> returned 500, for every app, while compiling cleanly
with a fully green test suite. Fixed in v0.158.1. The lesson is recorded in the controller report and
the R-57 row: a template method call is only checked when that template actually runs, so a
render test is the only coverage for template-facing methods.
Part 3 — R-55 live leg, PROVEN
immich (drive-backed) stopped through the real UI endpoint → compose down → 0 containers;
calibre-web (drive-backed) and bookstack (not drive-backed) left running; pct reboot 9201.
14:29:28 [gate] … live bind confirmed — recreating drive-backed app calibre-web … onto /mnt/felhom-drives/hdd_114:29:29 [gate] … 1 drive-backed app(s) left stopped — zero containers means the customer stopped them on purpose
immich came back STOPPED. Hours earlier the identical fixture brought it back running — same
experiment, opposite result. calibre-web recreated, bookstack back, [bootrecon] no boot-orphaned apps, zero alerts, reboot → steady state in ~15 s. The left stopped line fired in
production for the first time, so the honoured path is observable rather than silent.
Part 4 — skipped
Operator ruled no Docker Hub login. The gate therefore still exits 2 (INCONCLUSIVE) on a full sweep
rather than producing anonymous throttled accusations — which is the designed behaviour, not a
failure. One docker login on DooPlex plus
python3 scripts/check-image-resolvable.py closes it whenever convenient.
Remaining
- Agent v0.93.0 is source-only — the recovery-code wordlist fix is committed but unbuilt and unpublished; it rides the next agent train. Nothing on any host runs it yet.
- R-17 — deleting the
u629193-sub1archive is an operator console action; no tooling verb targets it. Exact steps are in the previous session's report. - HP first boot is physically yours (above).
- The full catalog resolvability table is still owed (Part 4).
- wanderer was re-pinned last session to a 3-service upstream shape and has never been deployed.
hiddenlifecycle state has no catalog user yet; onlyabandonedis exercised end to end.
Observations
- I pushed a commit that does not build. A
git stash/stash popused to comparereuse_refs_check.pyoutput silently discarded the staged index, so the first lifecycle commit carried only the new test files. Repaired with a follow-up commit rather than a force-push — rewriting already-pushed history is the worse trade. Nevergit stashmid-staging. - The stale-credential trap bit again, and the memory note already described it. The controller
password in
~/.config/credentialsis wrapped in single quotes; I stripped only double quotes, sent the quotes as part of the password, and concluded the credential was stale. It was not. Strip both quote styles. - Two USB devices, one of them live customer data, is the case the
ID_BUS=usb+removable=1rules are actually for — the dangerous device carried ausb-…by-id name and would have looked plausible in any listing that showed model and size alone.