Files
felhom.eu/REPORT-record-correction-2026-07-29.md
T
admin 7383400a23 docs: file R-29 to the register; attach the gate-orphan instance to its class
d4c07873 filed "hostinstall_gates.py is invoked by nothing" as a novel
observation. It is not novel — R-29 already names the class (green gates are
enforced nowhere; one sat RED for 16 releases while every REPORT said green),
and R-29 was missing from OPEN-ITEMS.md entirely, having never been carried
across the 2026-07-27 register rebuild. An open item about work not getting
done was absent from the page that decides what gets done.

Ruling on whether R-29 is the right home for a non-design-v2 gate: YES. Its
title says design-v2, but its own audit list already spans mount-safety,
secrets and dedup gates across four repos, and its part (b) — "the systemic
half is the real item" — is about the enforcement mechanism, which is
gate-agnostic. hub_confirm_gate.py is already on its list and sits in the same
scripts/ directory. No new ID minted; R-29's own text forbids it, and this is
the third re-raise it has absorbed.

- OPEN-ITEMS.md: open R-29 (READY, S(a)/M(b)), with the orphan evidence and
  the two separable parts R-29 already defines.
- OPEN-ITEMS.md: R-94 leg (b) now points at R-29 as its class.
- ROADMAP.md:158: audit list extended with hostinstall_gates.py (RED today,
  1.19.0 != 1.22.0) + hub_confirm_gate.py verified orphan. Entry not rewritten.
- ROADMAP.md:147: cited a non-existent R-164 — it means controller v0.164.0.
- CONTEXT.md:564: asserted in the present tense that the version cross-check is
  "gated by scripts/hostinstall_gates.py". It exists, is red, and runs nowhere.
- OPEN-ITEMS.md: READY #1/#3/#4 markers dropped — they duplicated ranked-list
  positions and the gap was left by the row merged in d4c07873.
- OPEN-ITEMS.md: E-2d citation :322-341 widened to :322-343; the invocation it
  describes is at :343, two lines outside the old range.
- backlog/README.md: two-line lead naming OPEN-ITEMS.md and ROADMAP.md.
- REPORT-record-correction-2026-07-29.md: the report CLAUDE.md:82-87 requires
  for both commits. Root REPORT.md (E-2 increment 1) untouched.

No gate wired, fixed, run or deleted — that is R-29 part (b), its own task.
Documentation only. No version bump, no CHANGELOG entry, no box touched.
2026-07-29 11:13:23 +02:00

10 KiB

REPORT — installer-channel record correction + R-29 filing (2026-07-29)

Two commits, documentation only. No code, no version bump, no CHANGELOG entry, no build, no deploy, no box touched. Written as REPORT-<topic>.md per CLAUDE.md:82-87 so root REPORT.md (the E-2 increment-1 report) is preserved.

# Commit Baseline Scope
1 d4c07873ca0c3d3e547373a9fafc0e472a6535e8 36d635a4cdc1, unmoved Retract a false R-94/E-2d finding; open R-110
2 (this commit) d4c07873, unmoved File R-29 to the register; three record defects; this report

Commit 1 — d4c07873

What was false

36d635a4 recorded that felhom-bootstrap.sh fetches the installer from the hub, that the hub therefore serves 1.19.0, and that a fresh ISO install runs the pre-E-2 installer. All three wrong. The claim had propagated into two OPEN-ITEMS.md rows, the ranking rationale, and ROADMAP.md:149.

Confirmation table — all PASS

# Claim Read at Result
F1 bootstrap fetches from the website scripts/iso/felhom-bootstrap.sh:96 PASS — INSTALL_URL="${FELHOM_INSTALL_URL:-https://felhom.eu/scripts/felhom-host-install.sh}"
F2 hub-rendered command points at the same URL customer_unified.html:563, :1262 PASS — and three emission sites, not two: :563 static, :1262 JS error branch, :1267 JS success branch
F3 website serves /scripts/ from a git-sync tree tracking main manifests/webpage.yaml — nginx :74-77, sparse-checkout CM :211-218, git-sync :272-281, init :299-307 PASS — --branch=main --period=30s --link=current; sparse-checkout /website/ + /scripts/; location /scripts/ { root …/current; }. No image build, no ArgoCD step
F4 hostInstallVersion selects nothing configs.go:28, :487; render_test.go:219; customer_unified.html:494 PASS — repo-wide grep returns exactly those 4 code sites; all other hits prose. Rendered as a text label
F5 every generated flag is parsed by 1.22.0 generator customer_unified.html:1206-1239 vs parser felhom-host-install.sh:1175-1212 PASS — --mode --cores --memory --vmid --node --acl-storages --operator-pubkey-file --preserve-state-from --skip-provision --dry-run --preflight-only --allow-new-leaf (+ --customer-id); every one a parser case. No functional gap
F6 installer is 1.22.0 scripts/felhom-host-install.sh:187 PASS
F7 the drift test is hollow render_test.go:219-221 PASS — strings.Contains(html, hostInstallVersion) compares the constant to itself; passes at any value

Live command 1 — what the URL actually serves

$ curl -fsS https://felhom.eu/scripts/felhom-host-install.sh | grep -m1 '^SCRIPT_VERSION='
SCRIPT_VERSION="1.22.0"   # the SINGLE version source (F-1): -h, the run banners, and the hub

Live command 2 — the drift gate's real state

$ python3 scripts/hostinstall_gates.py; echo "exit=$?"
  ok: SCRIPT_VERSION=1.22.0
  ok: header has no version literal
FAIL: hub Setup-tab hostInstallVersion=1.19.0 != SCRIPT_VERSION=1.22.0 (F-1: bump both together)
  ok: age is in the installed package set
  … (six further ok lines) …
hostinstall gates: 1 FAILURE(S)
exit=1

Phase 0 source read — PAIRING reaches the same installer invocation

Mode selection felhom-bootstrap.sh:537-541: a fresh VM with no baked customer-id calls run_pairing. On HTTP 200 from /api/v1/appliance/poll the loop writes the hub-delivered FELHOM_CUSTOMER_ID + FELHOM_RETRIEVAL_PASSPHRASE into the 0600 env, re-sources it, and calls run_direct in the same invocation (:495-499). run_direct is the single site that fetches $INSTALL_URL (:322-330), builds the args (:334) and invokes bash "$SCRIPT_TMP" "${args[@]}" (:343). The customer it yields is the one the operator bound — claimable. So the ISO leg is the spine for E-2d, not an obstacle to it.

Rows changed

ID Before After
R-94 (line 14) READY — deferred until E-2d, blocked on E-2d, false ISO/hub framing READY (XS), blocked on nothing, retracted + re-scoped to three legs
R-94 (line 16) duplicate row, READY #2, 1.19.0 vs 1.20.0 deleted — merged
R-110 did not exist opened, WAITING-ON-OPERATOR (S)
E-2d ISO implied as obstacle Next-action appended; ISO is the spine
ranked list 1 R-95 · 2 R-94 (high-consequence) · 3 R-86 · 4 R-87 1 R-95 · 2 R-94 de-ranked · 3 R-86 · 4 R-87 · 5 R-110

Files: documentation/backlog/OPEN-ITEMS.md, documentation/backlog/ROADMAP.md, documentation/runbooks/day0-install.md.


Commit 2 — R-29 filing + record hygiene

The §1.1 ruling — is R-29 the right home for a non-design-v2 gate? Yes. Proceeded.

R-29's title says "the design-v2 green gates", and scripts/hostinstall_gates.py is not one — it comes from drill F-1 (2026-07-12) and postdates the item. Four things decide it anyway:

  1. R-29's own audit list already spans well beyond design-v2 subject matter. It names docker_run_volume_path_gate (docker mount safety), offbox_rename_gate, app_row_dedup_gate and manifest_bearer_gate (secrets — runbooks/secrets.md:76). The title is a misnomer relative to the item's own body.
  2. Part (b) — "the systemic half is the real item" in R-29's words — is stated with no design-v2 restriction. It is about the enforcement mechanism: "the gates run only when a human remembers to run them… decide where they run (pre-push hook, build.sh step, or a CI job) and make a red gate block the train." That is gate-agnostic and repo-wide.
  3. hub_confirm_gate.py is already on R-29's list and lives in the same scripts/ directory as hostinstall_gates.py. Wiring one and not the other would be arbitrary.
  4. Identical failure shape, identical genre. Both self-describe as mechanical grep-assertions (hostinstall_gates.py:2, hub_confirm_gate.py:1-8); both exist, assert something true, and are invoked by nothing.

R-29 has already absorbed one independent re-raise without minting an ID (2026-07-18 rehearsal note) and says so explicitly. This is the third. No new ID minted.

Orphan-search evidence — hostinstall_gates.py and hub_confirm_gate.py

Re-established at d4c07873. Pattern hostinstall_gates\|hub_confirm_gate.

# Scope Command Result
S1 felhom.eu, all file types grep -rn "$PAT" . --exclude-dir=.git 19 hits, zero invocations. All are docstrings (scripts/hostinstall_gates.py:5, scripts/hub_confirm_gate.py:7), code comments (hub/internal/web/configs.go:27, scripts/felhom-host-install.sh:189) or prose (REUSE.md:62, CONTEXT.md:540,564, hub/CHANGELOG.md:371,1292,1351,1385, scripts/CHANGELOG.md:483,524, 3 files under documentation/audits/, ROADMAP.md:149,158, OPEN-ITEMS.md:14)
S2 sibling repos grep -rln "$PAT" /mnt/5_hdd/felhom.eu/git --exclude-dir=.git minus this repo 3 files, all in .claude-memory/ (MEMORY.md, drtier-by-default-2026-07-12.md, polish-batch-2026-07-13.md). Notes, not invokers
S3 ~/.claude grep -rln "$PAT" /home/kisfenyo/.claude, and targeted on settings*.json, skills/, hooks/ Zero hits in settings, skills or hooks — where an invoker would live. Remaining hits are file-history/ (Claude Code's own backups of files edited in past sessions) and paste-cache/ (pasted task specs). Neither is an invocation site
S4 git hooks ls -1 .git/hooks/ | grep -v '\.sample$' Empty — every hook is a .sample stub
S5 build files find . -type f \( -iname Makefile -o -iname '*.mk' -o -iname justfile -o -iname 'Taskfile*' \) Only hub/Makefile; grep -n gate hub/Makefilezero occurrences
S6 CI find . -type d \( -name .github -o -name .gitea -o -name .woodpecker* -o -name .drone* -o -name .circleci \) Empty — felhom.eu has no CI configuration at all

Of the four gates in scripts/, only site_gates.py is mandated (CLAUDE.md:153); manifest_bearer_gate.py is named in runbooks/secrets.md:76.

Rows changed

ID Before After
R-29 absent from OPEN-ITEMS.md (grep -c → 0) while present at ROADMAP.md:158 since before the 2026-07-27 rebuild opened, READY (S for (a) / M for (b)), owner CC
R-94 leg (b) stood alone leg (b) carries → R-29 as its class. Row otherwise untouched
E-2d cited :322-341 for an invocation at :343 cited :322-343, with the fetch / args / call each pinned separately
R-95, R-86, R-87 READY #1, READY #3, READY #4 READY — markers dropped (see below)

Not added to the ranked list under "Why the READY rows rank this way": that list is a top-N rationale, not a complete ordering (R-99, R-102, R-103, R-104, R-108, R-109, R-89, R-92, R-93 and E-2d are all READY and absent from it). Ranking R-29 was not asked for and would be a priority claim this task has no basis to make.

§2.2 — markers dropped, not renumbered

The #1/#3/#4 markers duplicated ranked-list positions 1/3/4 for exactly those three rows; two orderings of one set is what produced the hole when the #2 row was merged in d4c07873. Removing the duplicate leaves the ranked list as the single maintained ordering.

The other two record defects

  • ROADMAP.md:147 — cited a non-existent R-164; it means controller v0.164.0's deliberate-stop filter. Corrected. (It had already cost one max-ID scan a false positive.)
  • CONTEXT.md:564 — asserted in the present tense that the single VERSION source is "gated by scripts/hostinstall_gates.py". The gate exists, asserts exactly that, is red, and runs nowhere. Corrected to say the cross-check exists but is not enforced, tracked as R-94 leg (b) / R-29. hub/internal/web/configs.go:27 carries the same false claim in a code comment and was left alone — R-94 leg (b) territory, needs a hub build.

Files: documentation/backlog/OPEN-ITEMS.md, documentation/backlog/ROADMAP.md, documentation/backlog/README.md, CONTEXT.md, this file.


Standing note

No gate was wired, fixed, run as a hook, or deleted by either commit. Filing R-29 is not doing R-29; the enforcement decision (pre-push hook / build.sh step / CI) and the audit of the remaining eight gates are R-29 part (b), M-sized, and its own task.