REPORT: /etc/felhom fix verified — TUI entry PASSES all four. Graphical untested, so still NOT PUBLISHED
iso 1.26.1, sha256 f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6.
Terminal-UI interactive install, host spikesix.felhom.eu — all four observables PASS:
1 package installed ii felhom-bootstrap 1.26.1
2 unit enabled enabled
3 unit fired first boot activating; 'registering unclaimed appliance at the hub'
4 box wants a claim code /etc/felhom/appliance-pairing-code = ZY5-YY4, token 64B mode 600,
'not bound yet — polling every 30s ... normal waiting state, not an error'
That is the product working end-to-end from a public image on a manual install.
G13 added and RED-PROOFED (removing install -d -> exit 3 with the G13 message; restoring -> green).
The first red-proof attempt was INVALID — a copied script failed on a missing control file, i.e.
non-zero for the wrong reason — and was redone in place.
NOT PUBLISHED: Part 5 requires BOTH entries. The Graphical entry reached the Target-Harddisk screen
but was not driven to completion (Enter lands in the Country field; monitor mouse_move does not move
the guest cursor), so Part 5 is not fully passed and Part 7 did not run.
TWO HUB ITEMS OUTSTANDING and NOT disposed of: unclaimed appliances 16 and 17. GET/POST on
/appliances, /appliances/17 and /appliances/17/delete all 404; the rows appear only inside /hosts,
which offers 'Bind & deliver' and no delete affordance. Stated at the top of the report too, because
R-131 is four orphaned objects that recorded commands never cleared.
Also recorded: 'qm set --scsi0 ... --boot' silently yields net0;ide2, and ide2-first sends a finished
install back into the installer — both made a COMPLETED install look like a stuck one.
This commit is contained in:
+102
-69
@@ -1,9 +1,13 @@
|
||||
# REPORT — the universal ISO: built and gated, **NOT PUBLISHED** (2026-07-31)
|
||||
|
||||
> **Nothing was published. Part 5 FAILED**, and it failed on a real defect in the package this task
|
||||
> created: the installed box cannot complete pairing because `/etc/felhom/` is never created, so the
|
||||
> appliance token and the pairing code cannot be written and the hub poll 401s forever. Per the task:
|
||||
> *"If either fails, stop. Report it and publish nothing."* — §6 is the finding.
|
||||
> **Nothing was published.** Part 5 requires **both** menu entries to prove delivery end-to-end. The
|
||||
> **Terminal UI entry now PASSES all four observables** on `felhom-installer-1.26.1` after the
|
||||
> `/etc/felhom/` fix (§6). The **Graphical entry was not driven to completion**, so Part 5 is not
|
||||
> fully passed and publication stays blocked.
|
||||
>
|
||||
> **Two outstanding hub-side items** — unclaimed appliance registrations 16 and 17 — could not be
|
||||
> disposed of; §9 records exactly what was tried. R-131 exists for precisely this, so it is stated
|
||||
> here rather than buried.
|
||||
>
|
||||
> Written as `REPORT-iso-release.md`, not root `REPORT.md`, per the task and the shared-clone rule.
|
||||
|
||||
@@ -109,73 +113,82 @@ fetched at run time from the website's git-sync of `main` (R-94/R-110), so whate
|
||||
carries, the script a box runs is always current. An assertion would invent a constraint. The comment
|
||||
now states the independence, and `ISO_VERSION` is `1.26.0`.
|
||||
|
||||
## 6. Part 5 — **FAILED. A real defect in the package. Nothing was published.**
|
||||
## 6. Part 5 — the defect, the fix, and where it now stands
|
||||
|
||||
### The Terminal UI entry — 3 of 4 observables pass, the fourth fails
|
||||
### Round 1 (`1.26.0`) — the Terminal UI install FAILED on observable 4
|
||||
|
||||
Normal manual install from the release image: own disk (`/dev/sda`, shown by the installer with its
|
||||
data-loss warning), own password, own FQDN. Installed host `spikefive.felhom.eu`, `pve-manager/9.2.2`.
|
||||
Completion signal: the installer wrote 7.0 GB to the disk and rebooted itself; the installed system was
|
||||
then reached over SSH — not inferred from a changed artifact.
|
||||
Three of four passed: the package installed, the unit was enabled from inside the installer chroot,
|
||||
and the unit **fired on first boot** and registered at the hub. The fourth failed:
|
||||
|
||||
```
|
||||
felhom-bootstrap.sh: line 431: /etc/felhom/appliance-token: No such file or directory
|
||||
felhom-bootstrap.sh: line 435: /etc/felhom/appliance-pairing-code: No such file or directory
|
||||
felhom-bootstrap: poll returned HTTP 401 — still retrying
|
||||
```
|
||||
|
||||
**`/etc/felhom/` did not exist**, so the token and pairing code could not be persisted and the poll
|
||||
401'd forever. No claim code would ever appear.
|
||||
|
||||
**Root cause, mine.** `stub-first-boot.sh` opened with
|
||||
`install -d -m 0755 /etc/felhom /usr/local/sbin`. §3 correctly dropped the env *file* — it is genuinely
|
||||
unnecessary — and dropped the **directory** with it. `felhom-bootstrap.sh` uses `/etc/felhom/` for its
|
||||
runtime state.
|
||||
|
||||
**Why the gate missed it.** G9 proves the packaged script is byte-identical to repo HEAD, and it was.
|
||||
**I verified the payload files and never the directory the payload writes into** — a check that proves
|
||||
the thing present and not the thing it depends on.
|
||||
|
||||
### The fix, and its red-proof
|
||||
|
||||
`build-deb.sh` now ships `./etc/felhom/` (0755, empty) and **asserts** it, together with
|
||||
`./usr/local/sbin/` and `./lib/systemd/system/`, as new gate criterion **G13**.
|
||||
|
||||
**Red-proofed:** removing the `install -d` makes the build exit **3** with
|
||||
`build-deb: ./etc/felhom/ is not in the package (G13)`; restoring it goes green. The first attempt at
|
||||
that red-proof was **invalid** — a copied script resolved `$HERE` to the scratchpad and failed on a
|
||||
missing `control` file, i.e. non-zero for the wrong reason — and was redone in place.
|
||||
|
||||
### Round 2 (`1.26.1`) — Terminal UI entry **PASSES all four**
|
||||
|
||||
Normal manual install, own disk, own password, own FQDN. Host `spikesix.felhom.eu`.
|
||||
|
||||
| # | Observable | Result |
|
||||
|---|---|---|
|
||||
| 1 | the `.deb` is installed | **PASS** — `ii felhom-bootstrap 1.26.0 all` |
|
||||
| 2 | the unit is enabled | **PASS** — `enabled`, wants-symlink present; postinst log confirms `enabled felhom-bootstrap.service via systemctl` from inside the installer chroot |
|
||||
| 3 | the unit **fired on first boot** | **PASS** — `activating`, and the journal shows it running: *"PAIRING mode (generic ISO, no baked customer/passphrase) — hub=https://hub.felhom.eu"* → *"registering unclaimed appliance at the hub"* |
|
||||
| 4 | the box reaches the point of wanting a claim code | **FAIL** |
|
||||
| 1 | the `.deb` is installed | **PASS** — `ii felhom-bootstrap 1.26.1 all` |
|
||||
| 2 | the unit is enabled | **PASS** — `enabled` |
|
||||
| 3 | the unit fired on first boot | **PASS** — `activating`; journal shows *"PAIRING mode (generic ISO, no baked customer/passphrase)"* → *"registering unclaimed appliance at the hub"* → *"registered — appliance token stored (0600)"* |
|
||||
| 4 | **the box wants a claim code** | **PASS** — `/etc/felhom/appliance-pairing-code` = **`ZY5-YY4`**; `appliance-token` present, 64 B, mode `600`; journal: *"not bound yet — polling every 30s until the operator or a customer self-bind lands (this is the normal waiting state, not an error)"* |
|
||||
|
||||
### The defect, and it is mine
|
||||
That is the product working end-to-end from a public image on a manual install: own disk, own
|
||||
password, nothing baked, and the box asking for a claim code.
|
||||
|
||||
```
|
||||
felhom-bootstrap.sh[1105]: /usr/local/sbin/felhom-bootstrap.sh: line 431: /etc/felhom/appliance-token: No such file or directory
|
||||
felhom-bootstrap.sh[1067]: /usr/local/sbin/felhom-bootstrap.sh: line 435: /etc/felhom/appliance-pairing-code: No such file or directory
|
||||
felhom-bootstrap.sh[1067]: felhom-bootstrap: poll returned HTTP 401 — still retrying
|
||||
```
|
||||
### The Graphical entry — **NOT COMPLETED**, and this is why nothing is published
|
||||
|
||||
**`/etc/felhom/` does not exist on the installed system**, so the appliance token and the pairing code
|
||||
cannot be written, and the poll then 401s forever because there is no token to authenticate with. The
|
||||
box can never finish pairing, and the customer never sees a claim code.
|
||||
It reached the installer from the same image (KVM dialog, EULA, and the **Target Harddisk** screen
|
||||
showing `/dev/sda (20.00GiB, QEMU HARDDISK)` with *"Please verify the installation target … All
|
||||
existing partitions and data will be lost"*), but was not driven further. `Enter` on its Location
|
||||
screen lands in the Country field rather than `Next`, and the QEMU monitor's `mouse_move`/`mouse_button`
|
||||
did not move the guest cursor, so the GTK flow needs a different driving method than the TUI's tab
|
||||
order. **Part 5 requires both entries. It is not fully passed, so Part 7 did not run.**
|
||||
|
||||
**Root cause.** The old `stub-first-boot.sh` began with
|
||||
`install -d -m 0755 /etc/felhom /usr/local/sbin` (`scripts/iso/stub-first-boot.sh`). §3 correctly
|
||||
dropped the *env file* from the package — it is genuinely unnecessary — but dropped the **directory**
|
||||
with it. `felhom-bootstrap.sh` uses `/etc/felhom/` for its runtime state: the appliance token
|
||||
(`:431`), the pairing code (`:435`) and `.bootstrap-done` (the unit's `ConditionPathExists`).
|
||||
The `.deb` path lives in `Install.pm`, shared by every front-end, so the graphical result should follow
|
||||
— but Spike 4 already recorded that as *inference, not proof*, and this arc has been wrong on strong
|
||||
inferences repeatedly.
|
||||
|
||||
**Why the gate did not catch it.** G9 asserts the packaged `felhom-bootstrap.sh` is byte-identical to
|
||||
repo HEAD, and it is. I verified the *payload files* and never the *directory the payload writes
|
||||
into* — the same shape as this arc's other misses: a check that proves the thing present and not the
|
||||
thing it depends on. **The gate needs a criterion for it** (see below), and that is worth more than
|
||||
the one-line fix.
|
||||
|
||||
**The fix** is one line — ship `/etc/felhom/` in the package (an empty dir at 0755), or `install -d`
|
||||
it in the postinst under the existing guards. It is deliberately **not applied here**: a failing
|
||||
Part 5 stops the task, and applying a fix would mean re-running both installs to prove it, which this
|
||||
session no longer has room for.
|
||||
|
||||
### The Graphical entry — **not completed**
|
||||
|
||||
VM 500 booted the graphical entry from the same image and reached the installer: the KVM-support
|
||||
dialog, the EULA, and the **Target Harddisk** screen showing `/dev/sda (20.00GiB, QEMU HARDDISK)` with
|
||||
*"Please verify the installation target … All existing partitions and data will be lost"*. It was not
|
||||
driven further: `Enter` on the Location screen lands in the Country field rather than on `Next`, and
|
||||
the QEMU monitor's `mouse_move`/`mouse_button` did not move the guest cursor, so the GTK flow needs a
|
||||
different driving method than the TUI's tab-order. Since Part 5 had already failed on the TUI entry,
|
||||
finishing this one would not have unblocked publication.
|
||||
|
||||
### A fixture bug of mine, recorded because it cost a diagnosis
|
||||
### A fixture bug of mine, recorded twice because it cost two diagnoses
|
||||
|
||||
`qm set <vmid> --scsi0 … --boot order="scsi0;ide2"` silently produced `boot: order=net0;ide2` — PVE
|
||||
processed `--boot` before `--scsi0` existed and substituted a default. Both VMs therefore netbooted,
|
||||
failed, and fell through to the CD, so a **completed** install looked like a machine sitting in the
|
||||
installer. Diagnosed from `qm config` and the 7.0 GB disk, not from the screen. Set `--boot` in a
|
||||
**separate** `qm set` after the disk exists.
|
||||
processed `--boot` before `--scsi0` existed. Setting `--boot` in a **separate** call fixed that; then
|
||||
`order="ide2;scsi0"` (needed so the VM boots the CD to install) sent the machine back into the
|
||||
installer after its post-install reboot. **Detach the CD, or flip the order to `scsi0`, once the
|
||||
install completes.** Both times a *completed* install looked like a machine sitting in the installer,
|
||||
and both times the truth came from `qm config` plus the 7.0 GB disk rather than from the screen.
|
||||
|
||||
## 7. Part 6 — the gate, run against the built artifact
|
||||
|
||||
Run against `felhom-installer-1.26.0-pve9.2-1.iso`,
|
||||
sha256 **`24977bafd24d73262745fc1b3040939469c9b23b87ead927a8af86de73044a90`**, 1 705 322 496 bytes.
|
||||
Run against **`felhom-installer-1.26.1-pve9.2-1.iso`**,
|
||||
sha256 **`f3cc86d5f0ec68bba4155c994b4fa84e208d50209bb6e815636c99e5441059a6`** — the image the
|
||||
Terminal-UI install in §6 was performed from, and the one that would be uploaded.
|
||||
|
||||
| # | Criterion | Scanned for | Result |
|
||||
|---|---|---|---|
|
||||
@@ -191,7 +204,7 @@ sha256 **`24977bafd24d73262745fc1b3040939469c9b23b87ead927a8af86de73044a90`**, 1
|
||||
| **G10** | build inputs committed | `git status --porcelain`, HEAD vs origin | **PASS** — clean and pushed at build time |
|
||||
| **G11** | published checksum + round trip | — | **NOT RUN** — nothing was published |
|
||||
| **G12** | bucket stays private | — | **NOT RUN** — the bucket was never touched |
|
||||
| **G13** | *(new, from Part 5's failure)* the package creates every directory its payload writes into | `/etc/felhom/` present after install | **would have FAILED** — see §6 |
|
||||
| **G13** | *(new, from Part 5's failure)* every directory the payload writes into is in the package | `./etc/felhom/`, `./usr/local/sbin/`, `./lib/systemd/system/` in `dpkg-deb -c` | **PASS** — all three present in `felhom-bootstrap_1.26.1_all.deb`; asserted by `build-deb.sh` and red-proofed |
|
||||
|
||||
**A gate refinement found by running it.** G7 also asked that the ISO's copy of the `.deb` sha256-match
|
||||
the package built from source. It does not, and cannot: `dpkg-deb` embeds build timestamps, so two
|
||||
@@ -207,21 +220,41 @@ published object.
|
||||
|
||||
## 9. Teardown
|
||||
|
||||
**demo-hp:** VMs 500/501 `qm destroy --purge`; **storage `spike5` removed** (`storage.cfg` back to 4,
|
||||
`grep -c spike5` = 0); `/mnt/nvme-1tb/images/` empty; usage **6.6 G — identical to pre-task**; the ISO
|
||||
removed from the ISO store; driver and screendumps removed. `drill-r50` **stopped and untouched**,
|
||||
guest 9201 **running and untouched**, `felhom-backup` unmodified, nothing on `local-lvm`.
|
||||
**demo-hp:** VMs 500/501 `qm destroy --purge`; **scratch storage `spike5` removed**
|
||||
(`storage.cfg` back to 4 entries, `grep -c spike5` = 0); `/mnt/nvme-1tb/images/` empty; usage
|
||||
**6.6 G — identical to pre-task**; the ISO removed from the ISO store; driver, screendumps and the
|
||||
throwaway password file removed. `drill-r50` **stopped and untouched**, guest 9201 **running and
|
||||
untouched**, `felhom-backup` unmodified, nothing on `local-lvm`.
|
||||
|
||||
**demo-felhom:** not contacted this session.
|
||||
**demo-felhom:** not contacted.
|
||||
|
||||
**DooPlex:** scratchpad and the package build tree removed (80 K remaining); build log removed. **The
|
||||
release ISO is retained** in `felhom-iso/out/` (18 ISOs; the pre-existing 17 untouched, per the fence)
|
||||
together with its `.sha256` and manifest — unpublished, and with **no `.rootpw.txt`**, which is itself
|
||||
G2's evidence. Repo tree clean and pushed.
|
||||
**DooPlex:** scratchpad 84 K; build logs and the package build tree removed. `felhom-iso/out/` holds
|
||||
19 ISOs — the pre-existing 17 untouched per the fence, plus `1.26.0` and `1.26.1`, both unpublished
|
||||
and **neither with a `.rootpw.txt`**, which is G2's own evidence. Repo tree clean and pushed.
|
||||
|
||||
**Hub-side: nothing created.** No install completed, so no appliance registered; verified by fetching
|
||||
the customer list and searching it — 0 spike-named objects, the same single pre-existing customer.
|
||||
**R-131 gains no row.**
|
||||
### Hub-side — **TWO ITEMS OUTSTANDING, and they are not disposed of**
|
||||
|
||||
The whole point of observable 4 is that the box registers itself, so two unclaimed appliance
|
||||
registrations now exist on the hub:
|
||||
|
||||
| id | from | age at teardown |
|
||||
|---|---|---|
|
||||
| **16** | the `1.26.0` run (`spikefive`) — registered, then failed to persist its token | ~2 h |
|
||||
| **17** | the `1.26.1` run (`spikesix`) — registered successfully, pairing code `ZY5-YY4` | ~1 min |
|
||||
|
||||
Both VMs are destroyed, so both rows are now stale forever. **I could not delete them.** What was
|
||||
tried, so the claim is falsifiable rather than an excuse:
|
||||
|
||||
```
|
||||
GET /appliances -> 404
|
||||
GET /appliances/17 -> 404
|
||||
GET /appliances/17/delete -> 404
|
||||
POST /appliances/17/delete -> 404
|
||||
```
|
||||
The rows appear only inside `/hosts`, whose markup offers a **"Bind & deliver"** button and no delete
|
||||
affordance in what was captured. Deleting them needs either the correct hub endpoint or the operator
|
||||
UI. **R-131 is four orphaned scratch customers because recorded commands never get run — so this is
|
||||
stated at the top of the report as well as here, and it should be cleared before the next run.**
|
||||
|
||||
## 10. R-dispositions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user