docs(v1.24.0): R-59/R-60/R-61 SHIPPED — CHANGELOG, README, ROADMAP (+R-62), runbook, capability map, drill evidence, REPORT
Virgin-ISO nested drill closed the train: dead-NIC install baked the fallback (incl. the dead default gateway), the R-59 screen painted (capture committed beside the spike doc), the cable move healed + registered at the hub in 23s unaided, and the build's rootpw file matched the installed box's shadow hash. R-59 SHIPPED with the recorded deviation (first-boot gate; installer-initrd abort out of scope by operator ack). R-60 SHIPPED (spike + drill cited; F-P9 route-flush fix included). R-61 slice 1 SHIPPED. New R-62 row (hub delete-dialog cosmetics, XS). Capability map: new PROVEN-LIVE row (nested != metal, said so). Cleanup verified: felhom-pve interfaces byte-identical, bridge/VMs/ISO removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UuFPHmHNrCJj1VhY6QdDMU
This commit is contained in:
@@ -1,5 +1,57 @@
|
||||
# Felhom scripts — Changelog
|
||||
|
||||
## ISO train v1.24.0 — the box that can never call home learns to say so, heal itself, and let you in (R-59 + R-60 + R-61) (2026-07-22)
|
||||
|
||||
All three findings are from the HP t740 install (2026-07-21). Proven end-to-end on a nested
|
||||
wrong-NIC install (spike + virgin-ISO drill: `documentation/audits/SPIKE-firstboot-nic-sweep-2026-07-22.md`).
|
||||
|
||||
- **R-59 — the silent unreachable box gets a legible screen.** A no-DHCP install bakes the
|
||||
installer's **192.168.100.2 fallback as a static `vmbr0` config** (with a dead
|
||||
`gateway 192.168.100.1`) and completes; the box then waited silently forever. The first-boot
|
||||
bootstrap now runs a **network gate before mode dispatch**
|
||||
(`scripts/iso/felhom-bootstrap.sh:251` `network_gate`, called at `:510`): hub unreachable →
|
||||
physical-NIC diagnosis (name/MAC/carrier/speed; NICs are raised first — unused ports sit
|
||||
admin-DOWN with unreadable carrier), the fallback signature named when present, and a calm
|
||||
Hungarian console screen (`paint_network_screen`, `:230` — the `print_pairing_banner` pattern)
|
||||
with the NIC table and the one-line remedy; then retry every 60 s with the unit held in
|
||||
`activating` (waiting is not failing — the v1.21.0 lesson, unit `TimeoutStartSec=infinity`).
|
||||
The trigger is always **hub-unreachable, never the fallback signature**: the drill proved a
|
||||
second wrong-NIC variant (the installer picks the NIC that LEASES and bakes the lease as
|
||||
static — a later cable move leaves a plausible-looking dead config with no signature).
|
||||
*Recorded deviation:* R-59 ships as this first-boot refuse-loudly gate, not an install-time
|
||||
abort — the fallback is baked inside the Proxmox auto-installer itself, unreachable without an
|
||||
installer-initrd hook (out of scope by operator ack, noted on the ROADMAP row).
|
||||
- **R-60 — first-boot NIC sweep self-heal.** While the hub is unreachable AND no install attempt
|
||||
has begun (`state.json` gate; the unit's `ConditionPathExists=!done-flag` confines the whole
|
||||
script to pre-install anyway), the gate sweeps (`sweep_nics`,
|
||||
`scripts/iso/felhom-bootstrap.sh:178`): per candidate NIC, re-point `vmbr0`'s `bridge-ports`
|
||||
(atomic tmp+mv, always rendered from the pristine copy) → `ifreload` → **flush vmbr0's
|
||||
addresses/routes** → bounded `dhclient` (20 s) → hub probe (any HTTP status counts — the hub
|
||||
answers `/` with 302). The flush is load-bearing: the baked fallback default route survives a
|
||||
successful lease otherwise (dhclient-script never replaces an existing default route) and the
|
||||
probe rides the dead gateway — found live in the drill. First success persists
|
||||
`bridge-ports <winner>` + `iface vmbr0 inet dhcp` (original kept as
|
||||
`interfaces.felhom-bak`) and proceeds; total failure restores the config **byte-identically**.
|
||||
Drill: cable moved → healed + registered at the hub in well under a minute, unaided.
|
||||
- **R-61 slice 1 — the baked root password becomes knowable.** `build-felhom-iso.sh` writes the
|
||||
minted throwaway plaintext to a **0600 sibling `<iso>.rootpw.txt`** (password + ISO name +
|
||||
build date; `scripts/iso/build-felhom-iso.sh:254`) — the single record of truth. Never
|
||||
stdout/logs; the manifest carries only a pointer (`:383`). A fixed well-known password stays
|
||||
REJECTED (operator ruling 2026-07-21). Drill: the emitted password's hash matches the
|
||||
installed box's `/etc/shadow` — the console lockout is closed.
|
||||
- **Harness** (`scripts/iso/test/bootstrap-modes.sh`): caught up with the v1.21.0 in-script wait
|
||||
(the old pairing scenarios would hang), plus four gate scenarios — hub-reachable = ZERO new
|
||||
behavior (no ip/ifreload/dhclient/sleep call, fixture untouched), sweep-success (persist +
|
||||
bak + proceed), sweep-fail (screen + byte-identical config), state-file-present (sweep NEVER
|
||||
invoked). New `test/rootpw-emission.sh` for R-61 (emission, 0600, plaintext↔answer-hash
|
||||
cross-check, manifest guard). **Four red-proofs run and restored:** manifest-plaintext leak,
|
||||
restore-on-failure dropped, state gate removed, hub-reachable early-return removed — each
|
||||
failed exactly its guarding assertion.
|
||||
- Assistant image gains `python3` (the bootstrap's JSON parsing needs it; PVE ships it on real
|
||||
boxes — the harness runs the bootstrap in the image). `build-felhom-iso.sh` gains the
|
||||
`FELHOM_ISO_KEEP_WORK=1` debug/test escape and resolves `OUT_ISO` before the mint (the rootpw
|
||||
sibling is named after the ISO).
|
||||
|
||||
## build-hub.sh v1.23.0 — the hub build script enters the repo (2026-07-21)
|
||||
|
||||
It never was in one. `/mnt/5_hdd/felhom.eu/build/felhom-hub/build.sh` lived only in a DooPlex build
|
||||
|
||||
+21
-5
@@ -49,7 +49,13 @@ scripts/iso/build-felhom-iso.sh \
|
||||
> `/mnt/5_hdd/felhom.eu/felhom-iso/out`** (override with `$FELHOM_ISO_OUT` on other hosts), so on 180 you
|
||||
> can omit `--out` entirely and output still lands on the HDD, never the SSD.
|
||||
|
||||
Output: `felhom-pve-<pvever>-v<isover>-<profile>.iso` + `.sha256` + `.manifest.txt`.
|
||||
Output: `felhom-pve-<pvever>-v<isover>-<profile>.iso` + `.sha256` + `.manifest.txt` +
|
||||
**`.rootpw.txt` (0600, R-61 slice 1)** — the minted throwaway root password in plaintext (one line:
|
||||
password + ISO name + build date), the operator's console credential for every box installed from
|
||||
that build. It is the SINGLE record of truth: never logged, never in the manifest (which carries
|
||||
only a pointer — manifests get pasted into committed REPORTs), **never committed or pasted
|
||||
anywhere**. A fixed well-known password stays rejected (operator ruling 2026-07-21): a pre-pairing
|
||||
box sits on a stranger's LAN.
|
||||
|
||||
The build **gates the answer on validate-answer's OUTPUT TEXT, never `$?`** — `validate-answer`
|
||||
returns exit 0 even on a broken file (spike S1 trap; also `prepare-iso` was observed to exit 0 on a
|
||||
@@ -170,10 +176,20 @@ wired NICs and the install picks wrong:
|
||||
| `wlo1` | `iwlwifi` | wifi | unused |
|
||||
|
||||
Plug the cable into the **onboard** port. If the install already happened on the wrong port, the
|
||||
symptom is nasty: the installer does not abort, it bakes its **192.168.100.2 fallback as a STATIC
|
||||
`vmbr0` address** and completes, so the box looks installed and can never reach the hub (R-59).
|
||||
Repair on the console: point `bridge-ports` at `enp2s0f0` in `/etc/network/interfaces`, set the
|
||||
correct address (or `dhcp`), `ifreload -a`. R-60 is the self-heal that would make this unnecessary.
|
||||
symptom used to be nasty: the installer does not abort, it bakes its **192.168.100.2 fallback as a
|
||||
STATIC `vmbr0` config** (address AND a dead `gateway 192.168.100.1`) and completes, so the box
|
||||
looks installed and can never reach the hub (R-59). **Since v1.24.0 the trap has a gate and a
|
||||
self-heal (R-59+R-60):** on first boot, hub-unreachable → the bootstrap sweeps every physical NIC
|
||||
(re-point `bridge-ports` → bounded DHCP → hub probe) and keeps the first that reaches the hub
|
||||
(persisted as `iface vmbr0 inet dhcp`, original in `interfaces.felhom-bak`); if nothing works it
|
||||
paints a legible Hungarian console screen (NIC table: név/MAC/kábel/sebesség + remedy) and retries
|
||||
every minute — so *moving the cable to any port is enough, no console repair needed*. The sweep
|
||||
runs only before the install attempt begins (`state.json` gate); a box already past that point
|
||||
gets the screen but its interfaces are never touched. Manual repair (pre-v1.24.0 boxes): point
|
||||
`bridge-ports` at `enp2s0f0` in `/etc/network/interfaces`, set the correct address (or `dhcp`),
|
||||
`ifreload -a` — and mind the baked stale `gateway` line. Proven end-to-end on the nested drill
|
||||
(`documentation/audits/SPIKE-firstboot-nic-sweep-2026-07-22.md`); metal proof rides the next real
|
||||
install.
|
||||
|
||||
**Confirm the serial is the system disk and not a data drive.** On this board the SanDisk X600 128GB
|
||||
(`sda`) is the system disk; the 1TB NVMe is the future data drive and must stay OUTSIDE the filter —
|
||||
|
||||
Reference in New Issue
Block a user