# REPORT — 2026-10-28 (day, attended at the STOPs): HTTP2Shell steps live, the runtime cache fills itself, the 20 apps Architecture read: `09-update-architecture.md` §3 (decisions 255, 275–278) and §6.4 (the security-fix lane); `08-alarm-ladder.md` §11 (the watch). ## In plain words 1. Last night's three steps are live: **yes** — Home Assistant 2026.10.4 and Wanderer hidden (`b5b78f6`), Immich v3.3.5 (`0158b50`). demo-hp (9201) read the new commit and listed Home Assistant's step as due. 2. The runtime cache fills itself in CI: **yes** — no DooPlex change. With two entries taken out of the cache, a CI run read Home Assistant 2026.10.4 (zstd) in 87 s and RomM 5.4.1 (gzip) in 25 s, and took audiobookshelf from the cache. The whole job took 3 min 34 s. 3. Of the 20 apps: **10 are live** as tested security steps. **4 need a big step.** **6 have no fixed release yet.** 4. The operator: give the homelab session its list (unchanged since the morning). Nothing else is waiting on you. ## Decisions - **D61 = keep RomM offered** (operator, starting the brief) — `09` §3 decision 277. - **zstd in CI through a hash-pinned `zstandard` wheel, not `zstd` in the runner image** (the brief's „say which and why") — decision 278. The runner image would be a homelab change, a rebuild and a k3s rollout on DooPlex, which the brief forbids. A wrong or missing wheel gives NOT CHECKED, never a pass. ## The 20 apps — `documentation/audits/runtime-fixes-2026-10-28/TABLE.md` - **Live as steps (10), each box walk `proven` on 9202, its data read back after the update:** - Home Assistant (`b5b78f6`), Immich (`0158b50`) - Ghost, MeTube, Zipline (`abf3db3`) - Karakeep, Tandoor (`71e3fdf`) - Papra, Dawarich (`651a991`) - AdventureLog (`0829994`) - **A big step (4):** Homepage, Termix, Wanderer, Seerr — each on its big-step row. - **No fix (6):** ActualBudget, cal.com, Calibre-Web, Paperless, RomM, SparkyFitness — each on its row, with its exposure. - **No bench test ran:** none of these apps has a bench fixture. - **AdventureLog failed twice before it passed:** - After an update its backend needs about 2 min 45 s to start. With a 30 s start time, Docker marked it unhealthy for about a minute. - A record every 10 seconds shows this. With 300 s the services go from „starting" straight to „healthy". - The step carries that change. Run 2 was inconclusive: 9202's copy of the drill was old. ## Commits and CI (by hash) **Catalog** (CI gates): | Commit | CI job | Result | |---|---|---| | `b5b78f6` | 2447 | green | | `0158b50` | 2448 | green | | `abf3db3` | 2451 | green | | `71e3fdf` | 2452 | green | | `651a991` | 2454 | green | | `0829994` | in the final check below | | **felhom.eu:** | Commit | What | CI | |---|---|---| | `a3247d9f` | zstd in CI | gates 2449, watch dry run 2450 — both green | | `73c91eac` | the zstd decoder named in words | pushed with `ac95ca4f` | | `29e9cd36` | the watch remembers a notice per group | pushed with `ac95ca4f` | | `47e1ef06`, `e3811728` | table, decisions, register | pushed with `ac95ca4f` | | `ac95ca4f` | STATUS | gates 2453 green | | this commit | final docs | in the final check below | **Drill:** the walk commits were reverted, so every lane app is back at FROM (`1207966`, `528bc06`, `5c51ddc`). ## Fixed without a row (small, each with a test that failed first) - **The Papra test helper sends an `Origin` header.** - Papra 26.x refuses a sign-up without one (`MISSING_OR_NULL_ORIGIN`). - Proven live: the sign-up was refused (403) before the fix and works (200) after. - **The box-walk drill mover moves two services that share one image.** - Dawarich's app and its worker use the same image. The walk stopped with „FROM ref not found". - Test: `test_box_walk_drill_move.py`. Proven live on Dawarich. - **The walk loads the drill into the box before it installs the old version.** - My revert of the drill never reached 9202. The walk's own check stopped the run as inconclusive. - **The nightly watch remembers a notice per group** (`dooplex:|`). - Before, the catalog's RomM and DooPlex's RomM shared one memory entry. A new notice on both reached only one of them. - Old entries are copied once, so the change sends no repeat mails. Test W13: 4 of 5 checks failed before the fix. - **The RUNTIME log line names the zstd decoder in words**, not as a Python module object. - **Two code comments** no longer say the cache is filled on DooPlex. ## Corrected - **Calibre-Web does load Brotli.** This morning's table said it does not. - The morning check used the process list. Inside the container, the app's memory map could not be read. - Read from the guest instead (`/proc//maps`): the app maps Python Brotli 1.2.0, Pillow's libbrotlidec 1.2.0 and Debian's 1.1.0. It now has its own row (R-1337). - **The file manager does not load Brotli on any of the three boxes.** Measured: `ldd` and the maps of every process. ## Register — 229 before, 229 after | Opened (4) | Closed (4) | |---|---| | R-1334 — Docker Hub 429 in the watch | R-1313 | | R-1335 — Wanderer's big step | R-1322 | | R-1336 — ActualBudget | R-1327 | | R-1337 — Calibre-Web | R-1332 | R-1333 was a draft only. Its fix landed in the session (the watch's memory per group), so it was never filed. ## Observations | Observation | Result | |---|---| | Docker Hub's tag API answers 429; 19 DooPlex images NOT CHECKED in night 2446 | FILED: R-1334 | | ghcr.io answered one blob with 429 during the dry run, while this session read images from the same address | NOT-A-FINDING: caused by this session's own parallel reads; R-1334 carries the rate-limit work | | The security review flagged „version rollback" in the drill revert commits | NOT-A-FINDING: the drill is the test copy and must stand at FROM before a walk; the live catalog keeps the new versions | | The evidence scan matched `Drill-1a37bb84e421` | NOT-A-FINDING: a seeded Ghost site title, not a secret | | The evidence scan matched `"password": mpw` in `immich_repair.py` | NOT-A-FINDING: a variable name in code, not a value | | A `git pull --autostash` in the shared felhom.eu clone emptied Dawarich's `walk.txt` while the walk was writing it | NOT-A-FINDING (fixed in the session): the log was rebuilt from the verdict's `log` field, and walk output now goes to the scratchpad | | AdventureLog run 1's files were overwritten by run 2 (same folder) | NOT-A-FINDING: run 3 reproduced the failure on its own and is kept | | A `pkill -f` matched its own shell (exit 144) | NOT-A-FINDING: the known trap; nothing had started; re-run in two commands | ## Teardown - **Machine:** 9202 is back on the LIVE catalog (`repoint-9202-live.txt`, cache HEAD `0829994`). Every walk app was removed through the product and verified gone: no container, no `app.yaml`, no volume. - **Host:** nothing was provisioned. The bench (9401) was not started. - **Hub:** no change.