196 lines
19 KiB
Markdown
196 lines
19 KiB
Markdown
# Document edits — review round 2 (2026-10-24)
|
||
|
||
Every edit below corrects a FACT the main session read at the cited `file:line` before editing (the reviewer's item id
|
||
in brackets; the candidate files are in `reviewers/`). Each edited place carries „corrected 2026-10-24" in the text.
|
||
Rules, fences, „never" lines and promises were NOT edited — those are rows for the operator.
|
||
|
||
## 05-hub-architecture.md (DOC-C1)
|
||
- [S5] „the live hub is v0.11.0" → written against v0.11.0; the deployed version is read from `manifests/hub.yaml` (`:135` = 0.169.0).
|
||
- [S4] „hub 0.162.0 — not yet deployed" ×2, §15.4b „0.166.0 NOT deployed" → deployed (hub CHANGELOG headers v0.164–v0.169).
|
||
- [C3] §11 „ADD … the slim DR record onto hosts" → struck through, retired (R-105, §9).
|
||
- [S3] `autoMintSelfBindLink` four events → plus the fifth path (R-719 / R-1203) — `hub/internal/web/selfbind.go:384-400`.
|
||
- [S12] „39 event types" → 44 (`mail.event.*` keys counted in `hub/internal/i18n/locales/hu.json`).
|
||
- [S1/C1] §16.3 nightly 02:00, catch-up 24 h, push 02:30 → four slots, catch-up 6 h, push :30 after each, refuse > 7 h — `hub/internal/dbsnap/dbsnap.go:31,36`; `hub/cmd/hub/main.go:964-968`; `scripts/hub-db-backup/felhom-hub-db-backup.timer:7-10`.
|
||
- [S2] §16.5 `scheduleDaily` list → the four slots; prune at its configured time — `hub/cmd/hub/main.go:648,859,968,972`.
|
||
|
||
## 08-alarm-ladder.md (DOC-C1)
|
||
- [S11] info dropped before both legs → except the paired recoveries — `hub/internal/notify/dispatcher.go:137-167`.
|
||
- [S7] operator leg „only … a 1-hour cooldown" → per-type cooldown (5 min / 6 h / 1 h), R-723 first-hour suppression — `dispatcher.go:597-640`.
|
||
- [S9 — a dated note, the ruling line kept] backup_integrity_failed „default OFF" → superseded by operator Q1 2026-10-12: a default since controller v0.309.0 — `felhom-controller/controller/internal/settings/settings.go:713-721`.
|
||
- [S8] the per-APP grain table → five more per-app types — `dispatcher.go:470-480`.
|
||
- [S13] „a disabled box is still skipped" → also a box switched off on purpose (R-998) — `hub/internal/monitor/deadline.go:433-442`.
|
||
- [S10] §8.1 „NOT BUILT" → slice 1 built in v0.309.0 — `felhom-controller/controller/internal/settings/notif_groups.go:1-16`.
|
||
- [S6] §9 „NOT released" ×2 → released 2026-10-24 (controller CHANGELOG v0.342.0 header; `manifests/hub.yaml:135`).
|
||
- [U6/U7, listed as facts — each already has a ruling] the operator-only box alarms wg_tunnel_stale, host_swap_short, bind_old_host_linked, golden_not_vouched, recovery_older_package — `dispatcher.go:777,782,862,866,870`; `hub/internal/api/host_swap.go:25-37`.
|
||
- §6.5 header „hub main, unreleased" → released in hub v0.144.0 (hub CHANGELOG `:629` inside the v0.144.0 section).
|
||
|
||
## _hub-review.md (DOC-C1 S14)
|
||
- A HISTORICAL banner (stale threshold 45 m by config — `manifests/hub.yaml:88`; cooldown per type; push retired). The body is kept as the record.
|
||
|
||
## felhom-system-poster.facts.md + .html (DOC-C1 C2) — text only (the poster rule §6: facts file and matching html text)
|
||
- Timeline „02:30 hub database → ep0" → „… (and again at 08:30; every 6 h since D34)"; html „02:30 hub DB → ep0, 6-hourly".
|
||
|
||
## 03-host-agent.md (DOC-B)
|
||
- [S1] cloudflared three states → four (`absent`, v0.161.0) — `felhom-agent/internal/hub/cloudflared.go:12-23`.
|
||
- [S2] D4 „ready patch, NOT shipped" → shipped in v0.163.0 (`git tag --contains 1109092`) + installer-v1.36.0 (`manifests/webpage.yaml:347`).
|
||
- [S3/S4] `a0c88e5`, `ae69ad4` „unreleased" → in v0.163.0 (`git tag --contains`).
|
||
- [S5] old key `wg/private.key.prev` → first old key only; later `.prev.<unix>`, newest three; `wg/last-rekey` — `rekey.go:39,105-139`.
|
||
- [S6] host_busy „Unreleased 56aabc7" → v0.161.0; plus the line-test holder — `internal/linetest/linetest.go:62`.
|
||
- [S7] R-1010 „Unreleased 56aabc7" → v0.161.0.
|
||
- [S8] local API „default :8443" → `listen_addr` required, no default — `internal/config/config.go:317-319`.
|
||
- [S9] guest swap „once a minute after start" → once, one minute after start — `cmd/felhom-agent/main.go:940-955`.
|
||
- NOT edited (RULE → row): S10 break-glass „via the Cloudflare Tunnel behind Access".
|
||
|
||
## 06-offsite-connectivity.md (DOC-B) — dated notes; the design-of-record text kept
|
||
- [S11] „no slice is implemented yet" → note: S1–S4 shipped.
|
||
- [S12] sudoers `install … *.mount` → note: `felhom-priv-apply wg` — `felhom-agent/configs/felhom-agent.sudoers:223-229`.
|
||
- [S14] IdentityBundle `{TunnelToken, PBSToken}` → four fields — `felhom-agent/internal/escrow/identity.go:30-40`.
|
||
- [S15] the only automatic re-registration → plus D30 — `rekey.go`.
|
||
- [S16] „No new alarm channel" → `wg_tunnel_stale/ok` — `hub/internal/api/host_tunnel.go`.
|
||
- [S17] key rotation „design when fleet size warrants" → note: the D30 rotation exists.
|
||
- [S18] cloudflared „seam" → note: a guest container the agent only reads; withdrawing the plan is the operator's (row).
|
||
- NOT edited (RULE → row): S19 „no inbound listener … box→PBS only".
|
||
|
||
## 12-agent-tooling.md (DOC-B)
|
||
- [S20] „five byte-identical copies" → measured not identical; aligned (below).
|
||
- [S21] rules load „when a matching path is touched" → `unconditional: true` / no `paths:` load always — `felhom.eu/.claude/rules/live-probes.md:2`.
|
||
- [S22] skills „live at once … the list is the folder" → a NEW skill needs `install_skills.py` again (`felhom-web-design` has no link; not installed — no DooPlex change in this run).
|
||
|
||
## Instruction files (unprompted-work §5: a stale fact corrected / a proved fact added — named here)
|
||
- `felhom-agent/.claude/rules/unprompted-work.md`, `app-catalog-felhom.eu/.claude/rules/unprompted-work.md`, workspace root
|
||
`.claude/rules/unprompted-work.md` (unversioned): the missing item-6 paragraph „A version number is pushed once …"
|
||
added (before: 95 lines, md5 3b071ad2; after: byte-identical to the felhom.eu and controller copies, md5 b1891bd4).
|
||
Why: the file's own header says „change all five or none" and two copies had drifted; the paragraph states a fact
|
||
(`felhom-controller/controller/build.sh:115-125` refuses an existing tag and an unreachable registry).
|
||
- `felhom.eu/.claude/rules/live-probes.md:41`: before „no `/opt/felhom/stacks/<name>`"; after „no
|
||
`/opt/docker/stacks/<name>/app.yaml` (the folder itself stays — it holds the catalog's template files)". Why: the path
|
||
is `/opt/docker/stacks` (`felhom-controller/controller/internal/config/config.go:393`) and the folder stays after a
|
||
clean removal (the catalog's `box_walk.remove` checks `app.yaml` since 2026-10-24).
|
||
|
||
## 01-topology-and-trust.md (DOC-A)
|
||
- [S7] `docs/proxmox-platform.md` → `documentation/proxmox-platform.md` (the file exists; `docs/` does not).
|
||
- [S6] „every /api/ route needs a dashboard session" → but the read-only `/api/health` — `felhom-controller/controller/cmd/controller/main.go:4236`.
|
||
- [S1] claim mail link `templates.go:27` → `FormatClaimEmail` (`hub/internal/notify/templates.go:250-252`).
|
||
- [S2] the retrieval code „single-use … TTL" → a dated note: not burned, no TTL; D19/R-1159 rule — `hub/internal/api/passphrase_scope.go:19-30`.
|
||
- [S3] Cloudflare token reach check „hub main, unreleased" → released in hub v0.144.0.
|
||
- [S4] dead pointer `07:296-299` → a dated note.
|
||
- [S5] snapshot-before-deploy → [DESIGN — not built]: the agent serves `/snapshot`, `/rollback`; no controller caller (grep of `internal/agentapi`).
|
||
- NOT edited (RULE/promise → rows): C3 „the hub never connects into a box / no inbound control endpoint / no standing operator backdoor" vs poke + felhom-sshd; C4 „the operator cannot open the off-site backup" vs R-985.
|
||
|
||
## 04-control-plane-authorization.md (DOC-A)
|
||
- [S8] `docs/tests/…`, `docs/architecture/…` → `documentation/…`.
|
||
- [S10] time window → the 2-minute skew on `issued_at` — `felhom-agent/internal/authz/verifier.go:19-22,148-155`.
|
||
- [U2 → DESIGN — undocumented note + row] no cap on the window's length; opsign default 30 min — `felhom-agent/cmd/felhom-opsign/main.go:57`.
|
||
- [S9] §6.1 „controller + hub main, unreleased" → released in controller v0.304.0 + hub v0.144.0 (both CHANGELOGs).
|
||
|
||
## 13-threat-model.md (DOC-A) — facts corrected; every verdict cell LEFT AS IT WAS and marked „re-check" (a verdict is a judgement)
|
||
- [S11] „38 local-API routes" → 41 on main (`felhom-agent/internal/localapi/server.go`).
|
||
- [S12] hub routes → 54 API entries; `/bind/<token>` added to the no-credential list.
|
||
- [S13] homepage socket (R-981) → gone; the allow-list empty — catalog `templates/homepage/docker-compose.yml:21`; `privpolicy/allowlist.json:4`.
|
||
- [S14] R-983 / R-976 → fixed (controller v0.324.0, `internal/web/auth.go:352-366`).
|
||
- [S15] R-973 / R-978 → narrowed in agent v0.160.0 (`git tag --contains f17e197 / 8561dc8`).
|
||
- [S16] tokens unsealed (R-975) → sealed since hub 0.168.0 (deployed).
|
||
- [S17] root password SSH (R-982) → the drop-in shipped in agent v0.163.0.
|
||
- [S18] R-970 „does not hold" → the routes are removed, pinned by `r970_no_hub_key_door_test.go`.
|
||
- [S19] R-971 „design gap" → `privpolicy.Admit` before every write (controller v0.328.0).
|
||
- [S20] „hub 0.168.0 deploy pending", „R-1244 not released" → deployed / released 2026-10-24.
|
||
|
||
## 07-backup-architecture.md (DOC-D1)
|
||
- [S2/C3] Tier-1 „secret-stripped app.yaml" → carries the portable secrets (D5) — `felhom-controller/controller/internal/backup/recovery_unit.go:24-27`.
|
||
- [S7] `main.go:604-607` → `backupwindow.LegTimes` at `cmd/controller/main.go:1258-1264`.
|
||
- [S9] demo-hp „keep-last=1" → a dated note: keep-daily=N since R-1149 — `felhom-agent/internal/config/config.go:553-559`.
|
||
- [S1] D22 „controller main, unreleased" → released v0.338.0.
|
||
- [S11] §6.6 table → a row: the off-site restore also refuses a mismatched/mixed snapshot first — `internal/backup/offbox_reconstitute.go:826-833`.
|
||
- [S8] line citations moved (`GetAppDrivePath`, F5); `mp1` → a dated note (gone).
|
||
- [S3/C1] row 15 R-104 „open DEFECT" ×2 → FIXED 2026-10-05, v0.297.0 — `internal/backup/offbox.go:156-162`; CLOSED-ITEMS.md:895.
|
||
- [S6] row 10 R-893 / R-973 „unreleased" → released; „the next slice on R-893" → note: D20 (v0.336.0), D22 (v0.338.0).
|
||
- [S5] „Hub v0.158.0 … deploy waits" → deployed 2026-10-18 12:16 (hub CHANGELOG:288).
|
||
- [S10] „a restore is refused while any second-drive copy runs" → a dated note: the kept-data load checks only RestoreStatus/IsRunning (`internal/api/kept_install.go:89-92`) — a row.
|
||
- [U1/U2/U6 + hub U2/U3 + U7 → §8.2c, DESIGN — undocumented notes, one row for the operator]: the 60-min copy limit and stray handling; Eltávolítás refused during backups; start-after-put-back failure; the hub's off-site delivery checker (`offsite_delivery_stuck`, `maybeHeal`, the R-1230 skip — `hub/internal/monitor/offsite_delivery.go:103-110`); the release copy (D33) not in the matrix.
|
||
- NOT edited here: C4 (a stale code comment in `felhom-agent/internal/localapi/backup_cap.go:15`) — a row; C2 (G15 „nightly") — corrected in the capability map below.
|
||
|
||
## 09-update-architecture.md (DOC-C2) — dated notes; no §3 ruling text edited
|
||
- [S1/S2/S3] §1 (the 2026-09 measurement) → one dated note: `UpdateStack` gone, `StartGuardedUpdate`; moved line numbers.
|
||
- [S16] `stacks.update_window` „no Go code reads it" (inside ruling 11) → a dated note: removed.
|
||
- [S17] `unattended.go:433–435` → `:449-451`.
|
||
- [S4] §5.3 writers → note: `advancePinTo`; `pinBack`, the undo's `restoreDefinition`.
|
||
- [S7/C1] slice 6 „OPEN — R-450" ×2 → BUILT, R-450 closed 2026-10-05.
|
||
- [S12] R-646 residual → closed by `BackfillAppliedMeta` — `internal/stacks/undo.go:646-652`.
|
||
- [S18] `config.go L280-281` → L278-279.
|
||
- [S9] part 1 „DB up alone … empty-then-load" → note: the shipped folder copy — `undo.go:26-36`.
|
||
- [S10] „a step has no .felhom.yml of its own" → closed — `ladder.go:127-132`.
|
||
- [S11] „the box half … is not built" → built — `digest.go:15-24`.
|
||
- [S19] reason `current` → `already_current` — `update.go:432`.
|
||
- [S14] digest comparison „R-446 §3b Q6" → built for every ref with a ladder entry.
|
||
- [S13] §8.6 / „stepping is slice 6" → notes: any tier, the undo, the ladder.
|
||
- [S15] engine-major „until Slice 4" → note: MariaDB lifted, PostgreSQL by two-venue proof.
|
||
- [S5] recordInstalledImages callers → note: the real callers.
|
||
- [S8] §6.1 phase table → the bind-data tier order; a `converting` row (v0.273.0, `pgconvert.go`).
|
||
- [U1–U6, S6 → §6.4.x, DESIGN — undocumented notes]: build.sh's dirty/HEAD/non-git refusals (`controller/build.sh:144-166`); the once-retry; stopped_by_household; the manual leg's deadline; already_current/engine_no_test; the unreadable-template render row and R-971 admission.
|
||
- NOT edited (RULINGS — rows for the operator): C4 decision 13's „CompareImageRefs moves to the catalog gate" (not built); C5 decision 14's „never jumps" vs a person's press on an app older than the ladder; C7 decision 250 item 5's „by its AGE" vs the gate's proxy.
|
||
|
||
## 00-capability-map.md
|
||
- 20 PROVEN-LIVE rows marked „re-check (2026-10-24)" in their Scope cell, each with the commit that changed its mechanism after its evidence (status words unchanged): a7, a8, a10, a11, a17, b1, b2, b7, b11, c3, c4, c5, c6, d6, d10, d11, e17, g7, g15, g18. Each commit's files read with `git show --stat`.
|
||
- [DOC-D1 C2] G15 „a nightly consistent copy" → every 6 hours since D34.
|
||
|
||
## 16-storage-physical-identity.md (DOC-D2)
|
||
- [S2] the single-copy notice „a Go constant, not i18n" → the i18n keys — `felhom-controller/controller/internal/backup/backup.go:1485-1494`.
|
||
- [S3] `/disks/candidates` „whole disks only" → with nested partition candidates — `felhom-agent/internal/storage/candidates.go:84-90`.
|
||
- [S4] `felhom-host-install.sh:2261-2275` → `step_grows` at `:2475`.
|
||
- [S1] the R-1093 „not as written" → a note: fixed in agent v0.160.0 (`git tag --contains f7b7308`).
|
||
- [U4–U7 → DESIGN — undocumented notes]: detect-virt once; unreadable = same disk (R-668); the internal place's lifecycle refusals; its size rule.
|
||
|
||
## 15-media-library.md (DOC-D2)
|
||
- [S5/S6/C2] the §10 measurement table → one dated note before it: binds rewritten, restart on the household's press, the drive kept registered, and `b01bb4b`'s stopped-app rule.
|
||
- [S7] Transmission's watch/download folders → note: `excluded` since catalog `c50adfc` (`templates/transmission/.felhom.yml:46-51`).
|
||
- [U1/U3 → DESIGN — undocumented note]: the „Később" timer is in memory (`media_events.go` `handleMediaRestart`); the Sonarr/Radarr key read from `config.xml` (`mediawire.go:336-345`).
|
||
- [U2 — FIXED in code, not a note]: a media restart started a household-stopped app → controller `b01bb4b`.
|
||
|
||
## _recovery-inventory-2026-07-28.md (DOC-D2 S8–S13) — a WHAT HAS MOVED SINCE banner; the inventory body kept as its date's record
|
||
- one `mp0`, no `mp1` (`felhom-agent/configs/build-golden.sh:31-38,99`); portable secrets in the unit; `RestoreTier2Unit` (`tier2_restore.go:197`); volume tars replayed (R-354); ep0 keep-weekly 2 at 03:30 (`scripts/felhom-tenantsync.sh:187-197`); local keep-daily=3; restic pinned 0.19.1 (`Dockerfile:43-52`).
|
||
- runbooks/RUNBOOK-manual-guest-restore.md [DOC-D2 C3]: a dated note after the example config — one `mp0` at /var/lib/felhom, no `mp1` (golden v2.1.0+); the procedure unchanged.
|
||
|
||
## 14-host-power-off.md (DOC-E)
|
||
- [S2] „two exact sudoers vectors, FELHOM_POWEROFF" → `pct shutdown` in FELHOM_GUESTHOOK + `systemctl poweroff` in FELHOM_POWEROFF — `felhom-agent/configs/felhom-agent.sudoers:81-90`.
|
||
- [S1] heavy-gate holders → plus the line test (agent v0.164.0).
|
||
- [S3] the website FAQ line „a later task" → published — `website/gyik.html:128,603`.
|
||
- [S4] a paragraph that split the §3 table → moved below the table (rendering only).
|
||
- [U1–U3 → DESIGN — undocumented notes]: a re-enroll during the hold is „gone" (`hub/internal/api/reenroll.go:67-68`); the two info events; the three confirmation words.
|
||
|
||
## 11-os-updates.md (DOC-E)
|
||
- [S8] status „§8 step 2 BUILT" → steps 2–6 built by §8's own list (the ratification left to the operator).
|
||
- [S5] cloudflared `2026.6.0` → `2026.9.3` today — `felhom-controller/controller/internal/infra/infra.go:26`.
|
||
- [S6] apt sudoers/caller line numbers → `sudoers:68,228`, `lanresolver.go:133`, `wgtunnel/manager.go:659`.
|
||
- [S7] §5.4.1 „DRAFT … nothing installed" → note: built; sudoers holds only `--plan` (`sudoers:337`).
|
||
- [S9] BUNDLE_FILES 22 → 32 (counted in `felhom-agent/configs/felhom-os-apply`).
|
||
- [S10] HOST_SLOW_RE list → plus `linux-*`, `firmware-*`, `proxmox-secure-boot-support` (read from `felhom-os-apply`).
|
||
- [DOC-E U5 / DOC-C1 U5] §5.7 → the System page's „Upload line" cell (`hub/internal/web/system.go` `lineStaleAfter`).
|
||
|
||
## 10-localisation.md (DOC-E)
|
||
- [S12] „Part B is the remaining piece" → built (v0.256.0) — `felhom-controller/controller/internal/config/config.go:149-154`.
|
||
- [S13] formal-form ceiling 16 → 0 — `felhom-controller/controller/scripts/i18n_missing_gate.py:41`.
|
||
- [S11/C1] the setup wizard „still reachable … R-554" → deleted (`internal/setup` absent; `bootstrap.WaitForConfig`).
|
||
- [S15] `metadata.go L316` → L475.
|
||
- [S14] „53 real catalog files" (fixtures, still 53) / „fifth row" → sixth / „all 53 apps" → the freeze file's 65.
|
||
|
||
## 02-controller-module-map.md (DOC-E) — dated notes; the v0.33 plan tables kept
|
||
- [S16/C3] two in-flight markers → four (`update-journal.json`, `.felhom-install-pending`).
|
||
- [S17] three StartGate holders → four (1b `IsUpdating`, `cmd/controller/main.go:2459-2477`).
|
||
- [S18] `GetAlerts` → `GetBannerAlerts(page, lang)` (R-906) — `internal/web/alerts.go:353`.
|
||
- [S19] „no longer calls the Cloudflare API" → note: `cloudflare/` still wired with `cf_api_token` (`main.go:1992-2000`).
|
||
- [S20] `state.go`/`updater.go` DELETE → note: both live, `AgentSwapper` (`internal/selfupdate/updater.go:38-47`).
|
||
- [S21] `sync.go:319`, `config.go:351` → `:436`, `:399`.
|
||
- [S22] `locked_after_deploy` „read by no code" → note: read into `LockedFields`, enforced only by an uncalled function.
|
||
- [C2] §2 `UpdateStack` → note: deleted in v0.237.0.
|
||
- [U4] §1 → a note naming the 22 packages with no row (an `ls` of `controller/internal/`).
|
||
|
||
## felhom-controller/REUSE.md (DOC-D1 C5/U8, DOC-C2 C3)
|
||
- `CrashPutBack … (D22 / R-1195, unreleased)` → `v0.338.0`.
|
||
- `recordInstalledImages` callers `StartStack/RestartStack/UpdateStack/runComposeDeploy` → the real callers; `UpdateStack` deleted in v0.237.0.
|
||
- A new row: `Tier2CopyBlocksRestore` / `ClearLeftoverTier2Copies` / `MarkTier2CopyForTest` + the `tier2Docker` seam (`internal/backup/tier2_copy_lifecycle.go:85,255,319,341`).
|
||
|
||
## Late additions (the disposition check before the README)
|
||
- 03 §6 [DOC-B U1–U5, U8; DOC-A U4 → DESIGN — undocumented note]: 41 routes (24 unlisted), the controller-started line test, the island bridge, the line-test state and switch, the WG block's OOB fields, the D30 count in memory.
|
||
- 13 §5 [DOC-A U1 → DESIGN — undocumented note]: the file manager's one sign-in trust (`filebrowser_sso.go:15-22`).
|
||
- 08 §9 item 6 [SEC-1 X1]: the limits list names „any viewer explains any upload" (R-1262).
|