From df78b6caae2fe573d19f6635477b972b08c274ab Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 22 Oct 2026 18:11:45 +0200 Subject: [PATCH] =?UTF-8?q?night=202026-10-22:=20README=20(backup.volumes?= =?UTF-8?q?=20excluded,=20the=20capped=20second-drive=20copy),=20CONTEXT,?= =?UTF-8?q?=20REPORT=20=E2=80=94=20four=20fixes=20on=20main,=20not=20relea?= =?UTF-8?q?sed=20(0.340.0=20next)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- CONTEXT.md | 2 ++ REPORT.md | 48 ++++++++++++++++++++++++++------------------ controller/README.md | 13 ++++++++++++ 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 7b7c0b8..484845b 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -1,5 +1,7 @@ # CONTEXT.md — Project Memory +> **2026-10-22 night — four fixes on `main`, NOT released (night brief: no release). The next release is 0.340.0, MinAgent 0.158.1.** R-49 (D21 = B): `.felhom.yml` `backup.volumes` class `excluded` (`6a17c95`); R-1187(c): an import over an installed app that is not running is refused (`d5f88a2`, reproduced and proven fixed on 9202); R-1189(d): `nightchain.CatchUp.After` runs the off-site proof + integrity once after a catch-up (`d5f88a2`); R-1214: the second-drive copy runs in a 512 MB memory-capped container for clean `/mnt/` paths with no symlink (`03c0a69`, `ae39467`). 9202 ran rc.1–rc.4 and is back on 0.339.0. rc tags pushed: 0.340.0-rc.1..rc.4 (never offered: not X.Y.Z). + > **2026-10-20 — v0.336.0 is the floor (MinAgent 0.158.1, 08:54 UTC).** R-893 option A (operator D20): a failed off-site restore > copies the app's live volumes first and puts them back exactly, then starts the app (proven on 9202: schema, data and row-count > md5 equal before and after a forced failure); R-1169 the held sentence. Follow-up row: the put-back's ERROR log level and an diff --git a/REPORT.md b/REPORT.md index 6d5d978..a56f970 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,22 +1,30 @@ -# REPORT — controller v0.339.0 released (2026-10-22 day brief) +# REPORT — night 2026-10-22: four fixes on `main`, not released -**What:** R-1199 reopened — a rebuilt box never overwrites the household's saved mail list; R-1216 (D28 = A) — the -install page's swap sentence only when host swap is really short. Design: `08-alarm-ladder.md` (the 2026-10-22 -`[DESIGN]` paragraph), `03-host-agent.md` (guest swap), `05` (`customer_notifications`). **MinAgent 0.158.1**; needs hub -≥ 0.165.0 (deployed first, operator yes). +**What:** the night brief's controller parts. Nothing released (the brief forbids a controller release tonight). +Design read: `07-backup-architecture.md` §6.1.1 (catch-up), §6.2 (capture set), §10.2; `09` §6.5 (drill catalog). +Next release **0.340.0**, **MinAgent 0.158.1** (unchanged). -- **Found:** v0.338.0's start-up default push replaced demo-felhom's own 13-event list on the hub with the 17 defaults - (07:54:55 UTC) and would repeat at every start. Now a box with no list of its own reads the hub's: adopts a - household's (nothing pushed), pushes its default once only when no household saved one, sends nothing when the hub - cannot be read. Every push names its `source`. Red-proved against v0.338.0's rule. -- **Fixed without a row:** an empty saved list read back as the 17 defaults (`omitempty`; Tester 1 and demo-hp hold - that file shape) — now `[]` persists and a saved list with no events reads as empty; the add-only seeds are marked - done on a fresh settings file (they re-added a just-switched-off mail at a new box's second start). Red-proved. -- **R-1216:** `hostSwapRuleShort` = no host swap, or < 90 % of min(guest swap, 8192 MB); the hub's case table copied - byte-identical (`testdata/host_swap_rule_cases.json`, felhom.eu `host_swap_rule_gate.py`). Red-proved. -- **Release:** rc.1 on 9202 (`sha256:7d4c8852…`; no hub link there — start-up and pages only: healthy, 0 errors, - `/login` 200). `0.339.0` from `fc5a20f` (CI 2209 green): `sha256:fee71aafceb4a7d5f24ae4a6a273a8d51eb26e0550fe9d12d4d86955f6a343a8`. - Per-customer floors → Tester 1, demo-hp, demo-felhom on 0.339.0 within 40 s; 10/24/9 containers, 0 unhealthy, 0 - restarting, 0 errors; https-only every name 301. demo-felhom logged „adopted the household's saved list from the hub - (13 events …) — nothing pushed"; its box file and the hub row now agree. Global floor 0.339.0 / 0.158.1 (read back - with the WAL, 11:14:21 UTC); per-customer floors cleared. Evidence felhom.eu `documentation/audits/day-2026-10-22/`. +- **R-49 (operator D21 = B), `6a17c95`.** `.felhom.yml` `backup.volumes: [{name, class: excluded}]` leaves a named + volume out of every backup (`appbackup.ExcludedDockerVolumes` → `backup.Manager.dumpableVolumes`); declared names + only, a list that would exclude every named volume is refused whole. Red-proved (`TestR49_*`, both packages) and + the R-591 deep-copy alias test caught a shared slice (fixed in `deepCopyStack`). 9202: Immich unit + 1 160 553 832 → 336 788 031 B; with the cache volume removed Immich's ML answered after 9.2 s. +- **R-1187 (c), `d5f88a2`.** A `.fab` import over an installed app that is not running merged the old volume data with + the bundle's. Reproduced on 9202 rc.1 (a marker written after the export survived the import; the running control + replaced it); now refused with a Hungarian sentence, the app untouched (rc.2: markers unchanged; the running path + still replaces). Red-proved (`r1187c_test.go`). Evidence felhom.eu `audits/night-2026-10-22/P3-candidates/r1187c-9202.txt`. +- **R-1189 (d), `d5f88a2`.** The off-site proof (05:30) and integrity check (06:00) never ran on a box that is off + then. `nightchain.CatchUp.After` now runs both once after the catch-up's legs; the false comment in `main.go` + corrected. Red-proved (`nightchain/r1189d_test.go`, `cmd/controller/r1189d_wiring_test.go`). +- **R-1214, `03c0a69` + `ae39467`.** The 03:30 second-drive copy's page cache pushed the apps out of memory. + `rsyncMirror` runs rsync in a 512 MB memory-capped container of the controller's own image, only for clean `/mnt/` + paths with no symlink (a security review found the symlink case; fixed and tested). 9202 (4 GB, 1.8 GB held, 6 GB): + full stall 5.7 / 2.5 s → 0.37 / 0.32 s; peak „full" 16.8 / 6.9 % → 0.9 / 1.0 %. A real `POST /api/backup/tier2` on + rc.4: 6 capped containers, each exit 0; Immich's copy equals its source (0 differences, 44 = 44 files). + `docker_run_volume_path_gate.py` allow-list entry with its WHY. +- **Gates:** `controller_gates.py --fast` green before each push; CI by commit — see felhom.eu + `REPORT-night-2026-10-22.md`. +- **Teardown (9202):** throwaway uptime-kuma removed through the product (`.fab` deleted); hog container and 19 GB of + test files removed; memory 25898 MB / swap 512 MB again; Immich's `.felhom.yml` back to its pre-night file; controller + back on **0.339.0** (healthy); the drill catalog equals live main again. Host: `/tmp/r1214*` removed on demo-hp. Hub: + 9202 has no hub link — nothing. diff --git a/controller/README.md b/controller/README.md index dadbba3..ccd2251 100644 --- a/controller/README.md +++ b/controller/README.md @@ -1392,6 +1392,19 @@ retired in v0.126.0 when the moved blocks were legitimately rewritten onto the s fallback is a state-only tier (unit + mandatory; optional skipped, honest reason). **NETWORK (NAS) storage is never a tier-2 target** — pinned or auto (F-6C-1: rsync `-og` under root_squash → wrong-owner restore). Restore reads v2 behind the marker gate; a pre-v2 copy is refused. +- **The copy runs in a memory-capped container (unreleased, rides 0.340.0; R-1214).** A plain `rsync` charges its page + cache to the guest and pushes the apps' working set out (on the 8 GB box: memory „full" pressure > 20 % for minutes at + 03:30). `rsyncMirror` now runs `rsync -a --delete` in `docker run --rm --memory 512m --memory-swap 512m --network none` + of the controller's own image, the source mounted read-only — only when both paths are clean, under `/mnt/`, and + contain no symlink (`tier2CappedPath`, `filepath.EvalSymlinks(p) == p`: a link could point the mount elsewhere). A + docker start error (exit 125) falls back to plain rsync; any other failure is returned. Measured on 9202 (4 GB, 1.8 GB + held, 6 GB copy): full stall 5.7 s → 0.37 s. Tests `r1214_capped_copy_test.go`. +- **A template may leave a named volume out of every backup (unreleased, rides 0.340.0; R-49, operator D21 = B).** + `.felhom.yml` `backup.volumes: [{name: , class: excluded}]` — every named volume is dumped except + `_` (`appbackup.ExcludedDockerVolumes` → `backup.Manager.dumpableVolumes`), so it leaves Tier 1, Tier 2 + and off-site at once and the stale clean-up removes the old tar. Only `excluded` acts; an undeclared name is ignored + and logged; a list that would exclude ALL of an app's named volumes is refused whole. First user: Immich's + `immich_ml_cache` (model weights; Immich re-downloads them). Design: `07` §6.2. **Per-app Tier 2 contents by app type:**