Review round 2 — the architecture documents against the code, and a fresh data-loss and security look (2026-10-24, unattended)
Baselines (read at start, 14:42 CEST): felhom.eu 44d19042, felhom-controller 321df1f (v0.342.0 released;
„next v0.343.0" unreleased on top), felhom-agent 5e05627 (v0.164.0; „next v0.165.0"), app-catalog 5e196e1, hub
deployed 0.169.0. Register: 190 rows.
Method. Thirteen read-only reviewers (each prompt carried the brief's fences word for word —
reviewers/FENCES-given-to-every-reviewer.md): seven on the documents (the brief's four groups, two of them split, plus a seventh for
02/10/11/14, which the groups did not name), four on data loss (restore and put-back; delete and retention;
keys; time and concurrency), two on security (hub + controller; agent + ep0 + installer + the DooPlex→ep0 jobs). Their
answers are CANDIDATES (reviewers/). The main session read every item it acted on at file:line; the edits and
their evidence are in EDITS.md.
Part 1 — the documents (claims checked by the reviewers: 493; stale reported: 121)
| Document | Verdict |
|---|---|
01 topology & trust |
7 stale facts corrected; 2 product statements contradict the code → R-1266 (D45) |
03 host agent |
9 corrected (shipped releases, key files, listen address, swap, cloudflared's 4th state); a note: 41 local-API routes, 24 unlisted; break-glass text → R-1266 |
04 control-plane authorization |
3 corrected; a note: a signed op's window has no length cap → R-1265 |
05 hub |
9 corrected (the 6-hourly DB copy, version literals, the fifth bind-link path, 44 event types, the retired DR record) |
06 off-site connectivity |
7 dated notes (the design-of-record kept); „no inbound listener" → R-1266 |
07 backup |
12 corrected (portable secrets, R-104 fixed, keep-daily, D22/D20 released, a refusal row); §8.2c notes → R-1265; the kept-data load beside a copy → R-1256 |
08 alarm ladder |
10 corrected (per-type cooldowns, R-723, per-app grain, R-998 skip, §8.1 built, §9 released, the operator-only box alarms); one ruling line kept with a dated note (operator Q1 made backup_integrity_failed a default) |
09 updates |
19 dated notes and corrections (the §1 measurement, slice 6 built, the undo as shipped, digests, phase table); §6.4.x notes → R-1265; three rulings the code does not do as written → R-1266 |
10 localisation |
7 corrected (Part B built, ceiling 0, the wizard deleted, counts) |
11 OS updates |
7 corrected (cloudflared 2026.9.3, sudoers lines, the wrapper built, 32 bundle files, HOST_SLOW_RE); the System page's „Upload line" cell added |
12 agent tooling |
3 corrected; the five rule copies aligned (the instruction-file edits below) |
13 threat model |
11 facts corrected, every verdict cell left as it was and marked „re-check"; a note on the file manager's sign-in trust |
14 power-off |
4 corrected (sudoers vectors, line-test holder, FAQ published, the table split); notes → R-1265 |
15 media library |
a dated note on the §10 measurement table; R-1019's fix; notes → R-1265 |
16 storage identity |
4 corrected; notes → R-1265 |
02 controller module map |
8 dated notes (markers, holders, banner alerts, cloudflare still wired, updater live, LockedFields, 22 packages with no row) |
_hub-review.md / _recovery-inventory-2026-07-28.md |
a HISTORICAL banner / a „what has moved since" banner — both dated records kept as they were |
00 capability map |
20 PROVEN-LIVE rows marked „re-check" with the commit that changed their mechanism (no status lowered); G15's „nightly" corrected |
felhom-system-poster facts + html |
the timeline's hub-DB push (text only; no drawing needed) |
Rules, fences and promises were not edited. Seven items that need the operator are in R-1266 (D45); about 30
behaviours with no document are written as [DESIGN — undocumented, found 2026-10-24] notes for the operator to confirm
(R-1265, D44).
Instruction files edited (unprompted-work §5 — facts only): the workspace root, felhom-agent and app-catalog copies
of .claude/rules/unprompted-work.md got the missing „A version number is pushed once" paragraph (now byte-identical to
the other two); felhom.eu/.claude/rules/live-probes.md:41 — the stack path /opt/felhom/stacks/<name> → /opt/docker/ stacks/<name>/app.yaml. Details: EDITS.md.
Parts 2 and 3 — findings, ranked
| # | Sev | Finding | What was proven | Row |
|---|---|---|---|---|
| 1 | P1 | A power cut during a restore of a drive-backed app: the app runs on the cut restore's data, and a later controller restart pours the pre-restore copy back over newer writes | the real Recover code in a lean clone: boot 1 „copy gone → refused → marker kept", boot 2 put-back after the app ran (proofs/H1-drive-cut-restore/); the boot recreate's missing check read at intermediary.go:470-476 |
R-1251 |
| 2 | P2 | One rejected backup block makes the night's second-drive copy delete the app's household-file copies | reproduced on 9202: control kept the copy twice; one bogus path → „removed stale dest dir userdata/media" (proofs/H2-bad-backup-block/) |
R-1252 |
| 3 | P2 | An export with „stop first" overwrites another app's restore marker | static, read at file:line |
R-1253 |
| 4 | P2 | The hub saves the escrow package in two writes; a lost answer tells the household „the previous code still works" | static | R-1254 |
| 5 | P2 | D4's sshd drop-in reaches BYO hosts (against 11 §1); the in-force check and the all-or-nothing sshd -t |
static | R-1257 (D43) |
| 6 | P3 | Escrow carry / set-aside name edges | static | R-1255 |
| 7 | P3 | Four restore edges (definition write, merge, a mirror race, the unused copy) | static | R-1256 |
| 8 | P3 | ep0's iperf3 takes any tunnel peer's test | static (no ep0 change) | R-1258 |
| 9 | P3 | The DooPlex→ep0 copies: the vouched agent can drop out; deletions mid-transfer; no future bound; 2026-10-25: the 02:30 push re-sends the 20:00 snapshot | DST timing verified on DooPlex (systemd-analyze, Go) |
R-1259 |
| 10 | P3 | Spring 2027: the leg's deadline vs the gate's clock; two legs at one instant | Go's mapping verified | R-1260 |
| 11 | P3 | The unreleased R-1250 line hold: two seeders, a removed app, alt-speed | static | R-1261 |
| 12 | P3 | Any viewer explains any upload (the upload watch) | static; 08's limits list now names it |
R-1262 |
| 13 | P4 | Small items (a mislabelled operator mail, undeclared volumes on Remove, mount views, stale comments, a DNS-name password, rrsync) | static | R-1263 |
| 14 | P4 | Skills tooling (no size cap on the grandfathered skill; a new skill not installed) | read | R-1264 |
| 15 | P4 | Immich leaves an empty anonymous volume per recreate (296 on 9202); photos unaffected | read in the running image | R-1267 |
Fixed in this session (small, not recovery code, red-proved, commit only — controller b01bb4b, CI 2294 / #480 success):
a media restart („Újraindítás most", „Később", the safe removal) no longer starts an app the household stopped (R-721;
two tests, each seen failing with the rule off); the file manager's header name file appears whole (a race the
existing test caught 44 times in 300 runs on clean main; 0 in 300 after, 0 in 50 under -race).
NOT-A-FINDING: SEC-1 X2 (a passphrase enroll after the operator's host delete gets ciphertext — the window D19
accepts); SEC-1 X3 (the refused-passphrase mail is operator-only with a one-hour cooldown); DOC-D1 U4 (the fit check
that passes on a statfs error — the copy then fails and the app restarts untouched, restore_unit.go:502-512);
HUNT-3 D31's comment wording (no data effect); Immich's /data volume for data placement (R-1267 holds the leak);
the stack folder left after a clean removal (it is every catalog app's template folder).
Machines
- 9202 (Tier 0): as found at 12:46 UTC (
9202/as-found-2026-10-24.txt); at the end (9202/at-end-…) the same containers and images, healthy (restarted by the test night chains), the catalog on the live repo, the controller 0.342.0. The only difference: Immich's running container uses a new empty anonymous volume (R-1267); the two others my test runs made were removed by name. audiobookshelf installed and removed through the product; my marker file removed; its second-drive copy removed by the product's remove. - DooPlex: reads, lean clones in the scratchpad, the gates; no service changed. ep0, household boxes, the hub: not touched (hub reads only, none needed in the end).
Teardown (three layers)
Machine: 9202 as above. Host (demo-hp): nothing provisioned. Hub: nothing changed.