night 2026-10-22: the seven 15:47 rulings in effect or ready (D6, D8 live; D21 waits for controller 0.340.0; D3/D5 website patch; D4 two patches); data-loss candidates proven/fixed/filed; R-1214 cause + capped copy proven on 9202; R-1204 alarm built; repos-private read; STATUS morning list + D29/D30/D31; CONTEXT; 03/05/07/09; rows 178 -> 180 (opened R-1218..R-1222, closed R-206, R-992, R-1207)
gates / gates (push) Successful in 16m7s

This commit is contained in:
admin committed 2026-10-22 18:24:30 +02:00
1 parent 1100a344d5
commit acc78637d9
20 files changed
+413 -34

No files matched your search

@@ -129,6 +129,10 @@ the one trust root; the agent's API token is untouched; a box gets the new rule
`agent_config_update` (the order: signed `agent_update` first, then the bundle — after the bundle, an agent below
0.146.0 cannot update itself on that box).
**[DESIGN, ruled 2026-10-22 15:47 (D4, R-982) — built as a ready patch, NOT shipped] Root SSH from the LAN by key only; the console password stays.** The config bundle gains one fixed file, `/etc/ssh/sshd_config.d/10-felhom-root-key-only.conf` (`PermitRootLogin prohibit-password`), checked and reloaded by `felhom-os-apply`; the installer's uninstall removes it. Why a drop-in: Debian's `sshd_config` Includes `sshd_config.d/*` FIRST and sshd keeps the first value it reads, so the drop-in wins over the stock line; the out-of-band operator sshd (`FELHOM_SSHD`, port 8822) has its own config with no Include and is not touched. Proven on a fresh ISO 1.30.0 install: password SSH refused after, key SSH and the PVE web password login (200) and the console login still work (`audits/night-2026-10-22/P2-D4/`). It ships with the next agent release + installer tag.
**[FACT, agent main `a0c88e5`, unreleased] The heartbeat reports a WireGuard handshake from the future (R-1204).** WireGuard refuses an initiation whose TAI64N time is not newer than the last one accepted from that peer, so a box that once ran with its clock ahead is locked out of ep0 until real time passes that moment. The agent used to clamp the negative age to 0 (it looked healthy); `wgtunnel.handshakeFuture` now sets `handshake_future_s` when the handshake is more than 60 s ahead (`TestR1204_AFutureHandshakeIsReported`). The hub alarms on it (`05` §15.4b). The repair is STATUS decision D30.
## 4. Control model — reconcile + signed destructive ops
Two channels, split by **reversibility**, not by transport.
@@ -454,6 +454,11 @@ warning mails the operator (anything lost, still broken, failed or skipped); inf
The operator mail renders the counts as one `Repair:` line. The household's side is NOT a mail: the lost files (name,
date taken) are shown on its own app page, on its box, until it dismisses them — file names never leave the box.
### 15.4b A box whose tunnel to ep0 is dead — the clock-ahead alarm [hub 0.166.0, built, NOT deployed; R-1204]
**[FACT, hub `e267c5e2`]** The host report carries the agent's `wireguard` block (`hostWireguard`). `checkWGTunnel` (`api/host_tunnel.go`, called after `checkHostSwap`) calls the tunnel stale when the box reports `handshake_future_s` > 0 (the clock-ahead lock-out) or a last handshake older than 6 h (healthy boxes measured at most 113–124 s over 24 h). It is edge-triggered against the host's latest tunnel event (`store.LatestHostTunnelEvent`): `wg_tunnel_stale` once on the way down, `wg_tunnel_ok` once on the way back; both are allow-listed and operator-only (`notify.operatorOnlyEvents`, `wg_tunnel_operator_only_test.go`) — the household cannot repair a tunnel. A box with no `wireguard` block (an agent before the field, or no tunnel) raises nothing.
### 15.5 How "the Hungarian did not change" is known
56 goldens captured from v0.117.0 before any string moved, in
@@ -647,6 +647,8 @@ leg** — LIVE on demo-felhom, `backups/secondary/bookstack/` and `.../docmost/`
`recovery-unit` and nothing else, at 156 MB and 86 MB (INV Part B.2). Since v0.183.0 the button
refuses **before** stopping the app and names the action that works.
**[DESIGN] A template may leave a named volume out of every backup (2026-10-22, operator D21 = B, R-49; controller 0.340.0).** `.felhom.yml` `backup.volumes: [{name: <volume>, class: excluded}]` — the name as the compose file declares it; the controller dumps every named volume of the app EXCEPT `<project>_<name>` (`appbackup.ExcludedDockerVolumes` → `backup.Manager.dumpableVolumes`), so the volume leaves the local unit, the second-drive copy and the off-site copy at once, and the next run's stale clean-up removes its old tar. Only class `excluded` acts; a name the compose file does not declare is ignored and logged; **a list that would exclude every named volume of the app is refused whole** (nothing excluded) — a template typo must not empty a backup (`TestR49_*`). Use it only for data the app rebuilds by itself: the first user is Immich's `immich_ml_cache` (model weights, re-downloaded at start) — 9202: unit 1.16 GB → 337 MB; with the volume removed, Immich started and its ML answered after 9.2 s (`audits/night-2026-10-22/P2-D21/`). A controller older than 0.340.0 ignores the key (inert). The raw database folder and Immich's own `upload/backups/` stay in until a restore from the dump alone is proven (D21's option A).
### 6.3 Where capture and restore disagree
**[FACT]** Three asymmetries, each source-cited:
@@ -2549,7 +2549,13 @@ well, or the box goes on following the live catalog and reports success. Filed a
is fixed, the drill procedure is:
1. save `controller.yaml` as `controller.yaml.pre-update-night`;
2. set `git.repo_url` (and `username`/`token` — the drill repo is private);
2. set `git.repo_url` (and `username`/`token` — the drill repo is private). **The box's login is the Gitea user
`drill-reader`** — not an admin, a read collaborator on `admin/app-catalog-drill` only, token scope
`read:repository`; it cannot write or push and sees no other private repo (measured: 200 / 403 / 403 / 404,
`audits/night-2026-10-22/P2-D6/01-token-limits.txt`). The token is `DRILL_CATALOG_TOKEN` and the account's password
`DRILL_READER_PW` in CC's `sec` store — never printed. *Operator ruling 2026-10-22 15:47, D6: a read-only login, not
a public drill repo (R-992, closed).* Since that night 9202 keeps `git.username`/`git.token` while it follows the
live catalog (the public repo ignores them), so pointing it at the drill is the URL plus step 3;
3. **remove `<data>/catalog-cache`**;
4. restart the controller, sync, **rescan** (R-607: a sync can answer „nincs változás" while the
catalog has moved, and the badge answers from the stale value until the rescan);