docs(report): TASK-G - armed HP ISO, in-ISO and on-stick filter proof, byte-proof, R-58
This commit is contained in:
@@ -1,118 +1,132 @@
|
|||||||
# REPORT — TASK-F: app lifecycle + HP USB write + R-55 live leg (2026-07-21)
|
# REPORT — TASK-G: arm the HP install ISO + assisted-picker filing (2026-07-21)
|
||||||
|
|
||||||
Baselines at start (verified, all clean): controller `a96226a` v0.157.0, app-catalog `857ba53`,
|
Baseline `0073691`, clean tree; ISO tooling unchanged since v1.22.0, so this is a **rebuild at
|
||||||
felhom.eu `0b2c598`, agent `eba040d` v0.93.0 (source only — untouched this task).
|
v1.22.0** with a new profile name (`hp-demo`), not a version bump.
|
||||||
|
|
||||||
| Part | Status |
|
| Part | Status |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 1 — app lifecycle states | **DONE + LIVE-PROVEN** — controller v0.158.0, plus **v0.158.1 fixing a defect I shipped** |
|
| 1 — arm the ISO | **DONE**, filter verified from inside the built ISO |
|
||||||
| 2 — HP USB write | **DONE — byte-proven** |
|
| 2 — write it (gated) | **DONE**, byte-proven, and re-verified from the written stick |
|
||||||
| 3 — R-55 live leg | **DONE — PROVEN LIVE** |
|
| 3 — filing | **DONE** — **R-58** |
|
||||||
| 4 — resolvability table | **SKIPPED by operator ruling** (no Docker Hub login) |
|
|
||||||
|
|
||||||
## Part 2 — the HP boot stick
|
## Part 1 — the armed ISO
|
||||||
|
|
||||||
Written on felhom-pve under a format-operation evidence bar. **Two USB-shaped devices were present,
|
Built from an **uncommitted** working profile, `/mnt/5_hdd/felhom.eu/felhom-iso/hp-demo.profile`
|
||||||
and that turned out to matter:**
|
(mode 0600, the `n100-demo.profile` precedent — a real target serial never goes in git). It is the
|
||||||
|
committed `profiles/hp.profile` with exactly one change: the placeholder serial replaced.
|
||||||
- **`/dev/sdb` — ADATA HD710 PRO, 932G. EXCLUDED. It is the live customer data drive**, mounted at
|
|
||||||
`/mnt/hdd_1` and bind-mounted into guest 9201 (`mp8`) — immich and calibre-web data. Its by-id
|
|
||||||
path is `usb-ADATA_…`, but **`udevadm` reports `ID_BUS=ata` and sysfs `removable=0`**, so the two
|
|
||||||
required positive checks exclude it on their own. A bare-`/dev/sdX` workflow would have offered
|
|
||||||
`sdb` and `sdc` side by side with nothing but a letter between them.
|
|
||||||
- **`/dev/sdc` — Samsung Flash Drive, serial `0375123010001586`, 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
|
felhom-pve-9.2-1-v1.22.0-hp-demo-generic.iso
|
||||||
device sha256: 2b51d74c0eaf5155fd42a137dff803b9ab8692294cedcb727c9a80658c9f7823
|
sha256 de693f622c4c628d75eade691b2e8cb008175231f3ed97e29535e61de12bbd0b
|
||||||
iso sha256: 2b51d74c0eaf5155fd42a137dff803b9ab8692294cedcb727c9a80658c9f7823
|
bytes 1 705 338 880
|
||||||
|
loader shim (stock MS-signed chain; Secure Boot OK) secret-bearing: no
|
||||||
|
```
|
||||||
|
|
||||||
|
`validate-answer` gated on its **output text**, not `$?` — log shows
|
||||||
|
`The answer file was parsed successfully, no errors found!` through `gate_validate_answer`.
|
||||||
|
|
||||||
|
### The filter, extracted from INSIDE the built ISO
|
||||||
|
|
||||||
|
Not read from the profile — from the artifact, via `osirrox`, comments stripped:
|
||||||
|
|
||||||
|
```
|
||||||
|
[disk-setup]
|
||||||
|
filesystem = "ext4"
|
||||||
|
filter-match = "all"
|
||||||
|
filter.ID_SERIAL_SHORT = "182195804614"
|
||||||
|
```
|
||||||
|
|
||||||
|
| assertion | result |
|
||||||
|
|---|---|
|
||||||
|
| pins the SanDisk X600 128GB (`sda`) `182195804614` | 1 occurrence |
|
||||||
|
| NVMe `58BS11AFT8MQ` present anywhere in the answer file | **0** |
|
||||||
|
| `REPLACE-WITH-TARGET-SSD-SERIAL` placeholder remaining | **0** |
|
||||||
|
| `filter.*` directives | exactly **1** |
|
||||||
|
| `disk-list =` directive | **0** |
|
||||||
|
|
||||||
|
`filter-match = "all"` with a single `ID_SERIAL_SHORT` is an exact-one-disk selector. **The 1TB NVMe
|
||||||
|
is outside the filter** and is not touched by the installer; it joins later through the normal
|
||||||
|
Tárhely flow.
|
||||||
|
|
||||||
|
*Method note:* my first sanity check grepped the whole profile and reported the NVMe serial as
|
||||||
|
present — it appears in a **comment** documenting what is excluded. Re-verified by sourcing the
|
||||||
|
profile and inspecting the consumed `FELHOM_DISK_SETUP` variable, then again from inside the ISO,
|
||||||
|
which is what actually ships. Grepping a file is not the same as reading what a tool consumes.
|
||||||
|
|
||||||
|
## Part 2 — the write
|
||||||
|
|
||||||
|
Same procedure as TASK-F, no shortcuts. Full evidence block on the Samsung stick
|
||||||
|
(`/dev/disk/by-id/usb-Samsung_Flash_Drive_0375123010001586-0:0` → `/dev/sdc`, 119.5 GiB):
|
||||||
|
|
||||||
|
| check | result |
|
||||||
|
|---|---|
|
||||||
|
| `ID_BUS=usb` | usb |
|
||||||
|
| `removable=1` | 1 |
|
||||||
|
| `findmnt` (device **and** every partition) | empty |
|
||||||
|
| `/etc/fstab` | 0 lines |
|
||||||
|
| LVM PV | 0 (only `/dev/sda3` is a PV) |
|
||||||
|
| ZFS | 0 pools on the host |
|
||||||
|
| guest configs referencing it | 0 |
|
||||||
|
| open handles | 0 |
|
||||||
|
|
||||||
|
Destroyed: the `hp-generic` **safety** ISO written in TASK-F. Excluded: `/dev/sdb`, the ADATA
|
||||||
|
HD710 PRO — mounted at `/mnt/hdd_1` and bind-mounted into guest 9201, i.e. **live customer data**;
|
||||||
|
it reports `ID_BUS=ata` and `removable=0`, so it fails both required positive checks despite a
|
||||||
|
`usb-…` by-id name. Operator confirmed the printed device; identity was **re-asserted at write
|
||||||
|
time** in case of re-enumeration since the confirm.
|
||||||
|
|
||||||
|
```
|
||||||
|
device sha256: de693f622c4c628d75eade691b2e8cb008175231f3ed97e29535e61de12bbd0b
|
||||||
|
iso sha256: de693f622c4c628d75eade691b2e8cb008175231f3ed97e29535e61de12bbd0b
|
||||||
RESULT: MATCH - byte-proven
|
RESULT: MATCH - byte-proven
|
||||||
```
|
```
|
||||||
|
|
||||||
`dd … oflag=direct conv=fsync`, then the ISO's exact byte-length read back **from the device** and
|
`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
|
hashed. Customer data drive re-checked after the write: still mounted at both paths.
|
||||||
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)
|
**Belt-and-braces:** the stick was then mounted read-only and the filter read back off the physical
|
||||||
|
device — `filter.ID_SERIAL_SHORT = "182195804614"`, NVMe serial absent. The profile is what I
|
||||||
|
intended, the ISO is what I built, and the stick is what you will boot; all three now agree.
|
||||||
|
|
||||||
1. **Boot the stick with Secure Boot ON.** This is the shim variant. Expect the Felhom boot screen,
|
Staged ISO copies removed from `felhom-pve:/root/` (71G free).
|
||||||
then the installer **aborting having touched no disk** — that is success.
|
|
||||||
2. **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 at `180:/mnt/5_hdd/felhom.eu/felhom-iso/out/…-hp-generic-mkimage.iso` and is not on
|
|
||||||
this stick.
|
|
||||||
3. **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.
|
|
||||||
4. **The first boot is yours.** No remote install step was attempted.
|
|
||||||
|
|
||||||
## Part 1 — app lifecycle (summary; detail in `felhom-controller/REPORT.md`)
|
## Part 3 — R-58, assisted disk-picker install mode
|
||||||
|
|
||||||
`available` / `hidden` / `abandoned` as a `.felhom.yml` field, because the `retired/` directory move
|
Filed with your argument verbatim. Shape: a third ISO mode beside unattended-serial and
|
||||||
shipped hours earlier would have orphaned every customer running a withdrawn app. Deploy gate is
|
match-nothing-safety — enumerate candidates with size/model/serial, exclude the install media, take
|
||||||
server-side and fail-closed; unknown values fail open; orphan detection never sees the field.
|
a selection plus a confirm, proceed. Unattended+serial stays the appliance/factory mode.
|
||||||
|
|
||||||
Live on 9201 through the real endpoints: plant-it renders **0 times** on the catalog page (control
|
**Slice 1 is the abort screen**, deliberately, because it is the same enumeration code and it
|
||||||
app 10), a direct deploy POST returns **409 „Ez az alkalmazás jelenleg nem telepíthető."**, the app
|
collapses the two-boot dance on its own: on filter-no-match, print the candidate table plus the
|
||||||
page carries the permanent notice with no Telepítés button.
|
one-line hint naming which serial to put in the profile. Today the fail-safe is correct but mute —
|
||||||
|
which is exactly what made this task need a hand-read serial between two boots.
|
||||||
|
|
||||||
**v0.158.0 shipped a defect that I caught during live validation, not from the suite:** the lifecycle
|
It matters most for the **BYO / reinstall** flow: a customer's existing hardware, or a rebuild of a
|
||||||
predicates had pointer receivers, and html/template cannot call those on the non-addressable value
|
box whose disk layout nobody recorded, is precisely where the serial is unknown and a wrong guess is
|
||||||
the handler passes — so **every `/apps/<slug>` returned 500**, for every app, while compiling cleanly
|
destructive.
|
||||||
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
|
Also documented `scripts/iso/README.md` § **HP mini profile**: shim proven on this board by the
|
||||||
|
safety boot, the uncommitted-armed-profile pattern, verify-from-inside-the-ISO, and the prior-LVM
|
||||||
|
caveat below.
|
||||||
|
|
||||||
immich (drive-backed) stopped through the **real UI endpoint** → `compose down` → 0 containers;
|
## For the operator — boot instruction
|
||||||
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_1`
|
**Stick → HP, boot it, walk away.** It formats the SanDisk `sda`, installs, and reboots into day-0.
|
||||||
> `14:29:29 [gate] … 1 drive-backed app(s) left stopped — zero containers means the customer stopped them on purpose`
|
Secure Boot stays **ON** (this is the shim loader, proven on this board). Nothing else to press.
|
||||||
|
|
||||||
**immich came back STOPPED.** Hours earlier the identical fixture brought it back running — same
|
**One thing that could stop it, worth knowing before you walk away.** The Proxmox auto-installer does
|
||||||
experiment, opposite result. calibre-web recreated, bookstack back, `[bootrecon] no boot-orphaned
|
not force-clear a pre-existing **LVM PV** signature. If that SanDisk carries a previous
|
||||||
apps`, **zero alerts**, reboot → steady state in **~15 s**. The `left stopped` line fired in
|
Linux/Proxmox install, the install aborts at *"cannot init physical volume"* — safely, touching
|
||||||
production for the first time, so the honoured path is observable rather than silent.
|
nothing. A previous Windows/NTFS install is fine. If you see that message: wipe the target
|
||||||
|
(`blkdiscard -f /dev/sda` from any live environment) and boot **the same stick** again — the ISO does
|
||||||
|
not need rebuilding. This is documented behaviour (spike S2b), not a defect in this build.
|
||||||
|
|
||||||
## Part 4 — skipped
|
## Remaining (unchanged from TASK-F unless noted)
|
||||||
|
|
||||||
Operator ruled no Docker Hub login. The gate therefore still exits 2 (INCONCLUSIVE) on a full sweep
|
- **Agent v0.93.0 is source-only** — committed, unbuilt, unpublished; rides the next agent train.
|
||||||
rather than producing anonymous throttled accusations — which is the designed behaviour, not a
|
- **R-17** — deleting the `u629193-sub1` archive is an operator **console** action.
|
||||||
failure. One `docker login` on DooPlex plus
|
- **The full catalog resolvability table** is still owed (needs one `docker login` on DooPlex).
|
||||||
`python3 scripts/check-image-resolvable.py` closes it whenever convenient.
|
- **wanderer** was re-pinned to a 3-service upstream shape and has never been deployed.
|
||||||
|
- **`hidden` lifecycle state** has no catalog user yet; only `abandoned` is exercised end to end.
|
||||||
## Remaining
|
- **After the HP comes up:** bind it on the hub and run day-0; the 1TB NVMe is added afterwards
|
||||||
|
through the Tárhely flow, never through the installer.
|
||||||
- **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-sub1` archive 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.
|
|
||||||
- **`hidden`** lifecycle state has no catalog user yet; only `abandoned` is exercised end to end.
|
|
||||||
|
|
||||||
## Observations
|
|
||||||
|
|
||||||
1. **I pushed a commit that does not build.** A `git stash`/`stash pop` used to compare
|
|
||||||
`reuse_refs_check.py` output 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. **Never `git stash` mid-staging.**
|
|
||||||
2. **The stale-credential trap bit again, and the memory note already described it.** The controller
|
|
||||||
password in `~/.config/credentials` is 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.
|
|
||||||
3. **Two USB devices, one of them live customer data**, is the case the `ID_BUS=usb` + `removable=1`
|
|
||||||
rules are actually for — the dangerous device carried a `usb-…` by-id name and would have looked
|
|
||||||
plausible in any listing that showed model and size alone.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user