Media drive events, night 2026-10-14: 15 §10 (event x app, measured), K4-K8 evidence, rows R-1044..R-1049, narrowed R-1022/1023/1024/1026/1028/1037/1038, night report
gates / gates (push) Successful in 6m34s

- 15-media-library.md §10: what the box does on each drive event, per app, with the measured call; the guards
  that ARE needed and the ones that are NOT (K1: nothing lost while a drive is gone).
- Evidence K4 (dead-drive check: mountinfo `shutdown`, stat unreliable), K5 (restart), K6 (unclaimed Plex),
  K7 (old Sonarr/Radarr repair on the bench), K8 (hub received the drive-return events and mailed none), K9 (files identical).
- nightly-rotation.md runs scripts/https_only_check.py first every night; scripts/CHANGELOG.md entry.
- STATUS, CONTEXT (decisions 244-246), REPORT-night-2026-10-14.md.

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-14 23:40:26 +02:00
parent 5aaa3312ba
commit 0e88b7eb99
19 changed files with 616 additions and 18 deletions
+9
View File
@@ -16,6 +16,15 @@
> and holds nothing of its own; this file does hold its own content, namely the standing rulings below.
> **Night 2026-10-14 — https only and the media drive events.** Operator rulings recorded as `09` §3 **244** (R-1033 is
> P1) and **245** (drive events = option A: the box handles each event per app). **Decided by CC unattended — operator
> may reverse:** `09` §3 **246** — https-only is enforced on the box (traefik `felhom-forwarded` chain: a
> `redirectScheme` on a trusted `X-Forwarded-Proto: http`, a priority-1 catch-all router for unknown names, HSTS
> `max-age=86400` without includeSubDomains/preload), because no box's Cloudflare key may change zone settings
> (measured 403, R-1042). Controller v0.312.0 on all three Tier-0 boxes, NOT vouched; the floor stays. Proof:
> `scripts/https_only_check.py` (29 names). Drive events: `architecture/15-media-library.md` §10; rows R-1044..R-1048;
> report `REPORT-night-2026-10-14.md`.
> **Rulings 2026-10-12 (evening) — the first real tester, and what his domain needs.** Asked before the work,
> answered by the operator; recorded here rather than numbered in `09` §3 because another session held that file
> open the same day.
+146
View File
@@ -0,0 +1,146 @@
# Night 2026-10-14 — https only (P1), then the media drive events (unattended)
## What waits on you this morning
1. **Vouch controller 0.312.0, then raise the global floor to 0.312.0** (hub → Configs). This makes every box https only, Tester 2 too. If you do not: only the three test boxes are https only.
2. **Decide the Plex access (D9, R-1046):** the household's Plex token, or Plex trusts the box's own address. I recommend: trust the box's address.
3. **Plex claim test, 5 minutes (R-1028):** open plex.tv/claim. Put the code in `~/.felhom-tester1/plex-claim` on DooPlex, `chmod 600`. Do not paste it in chat. Then say „done”. I claim the throwaway `plex-k6` with it and read the result.
4. **HSTS length (D10, R-1041):** keep one day now, or one year now. I recommend: one day now, one year after a month with no trouble.
5. **Optional (R-1042):** give each box's Cloudflare key „Zone → Zone Settings → Edit” in the Cloudflare dashboard. Then Cloudflare's „Always Use HTTPS” can be a second layer. Without it, the box layer is enough.
6. **Tester 2 (`sajatfelhom.hu`):** nothing to do there. It gets https only with the floor of item 1, when it is on again.
7. **Teardown word for Tester 1 (R-1022):** say „tear it down” when you want it back. Now it has three test drives and a throwaway Plex.
8. **System poster:** it needs a refresh for „https only” (the facts file is updated; the drawing is not).
No leg stopped. No STOP condition was hit.
## Decision I took (decided by CC unattended — you may reverse)
- **`09` §3 decision 246:** https only is enforced on the box (traefik), not at Cloudflare. Reason: no box's Cloudflare key may change zone settings (measured 403 on all three zones). The box layer covers every name, also unknown names. It is re-applied when it drifts.
- Your two rulings are recorded as decisions 244 (R-1033 is P1) and 245 (drive events = option A).
## 1. https only
- **Which boxes:** Tester 1 (`enkicsifelhom.hu`), demo-hp (`enkisfelhom.hu`), demo-felhom (`demo-felhom.eu`).
- **What it does:** a plain `http://` request gets `301` to the same `https://` address. The path and the query stay. A name that does not exist also gets the 301. `https://` answers are the same as before. Browsers get `Strict-Transport-Security: max-age=86400` (one day). No includeSubDomains. No preload.
- **Proof:** `scripts/https_only_check.py` asked 29 public names on the three boxes: all OK. Its negative control (a stub answering 200 over http) was convicted. Its positive control (Tester 1's dashboard) passed. Before and after headers per box are in `documentation/audits/https-only-2026-10-14/`.
- **Sonarr sign-in:** Sonarr still sends its own `http://…/login` redirect. The browser then gets the 301 to https. The password goes to https only.
- **Where:** in the controller's traefik file. The controller writes it at start and on every health tick. An old or changed file is rewritten. So a new box gets it with the controller, with no step.
- **Code:** controller v0.312.0 (`8bc7ec5`). Two new tests. I saw both fail when I removed the redirect, and when I made HSTS one year. A third test failed when the drift rewrite was removed.
- **Other zones:** only Tester 2 `sajatfelhom.hu` (box off, controller 0.292.0). Not changed.
- **Nightly check:** `nightly-rotation.md` now runs `https_only_check.py` first every night.
## 2. While a drive is gone, what each app loses
**Nothing.** Media B was pulled for 4 minutes.
- Plex scans (empty trash on and off): no item removed. Watch count kept.
- Jellyfin scan: no item removed. Watched mark kept.
- Sonarr and Radarr refresh and rescan (unmonitor on and off): nothing changed.
- After the return: every torrent seeds again. No re-check. No missing files.
- Every file on Media A and B was the same at the end as at 22:52.
Why it is safe: the guest keeps a **dead mount**. Every read is an I/O error. Each app reads that as „unavailable”, not as „deleted”.
**Guards that are needed:**
1. Bind only the drives that are there. A bind to an absent path stops the app from starting.
2. Before a safe removal, recreate the media apps without that drive.
3. Restart through the controller's environment, never with a bare `docker compose`.
4. When a drive comes back, restart every container that uses it, FileBrowser too.
5. Write Transmission's settings at start, not by its API.
**Guards NOT needed — do not build them:** scan protection for Plex and Jellyfin; unmonitor protection for Sonarr and Radarr; torrent pausing on a pull.
**One warning:** the fix for R-1038 must not change the dead mount into an empty folder. An empty folder can look like „all files deleted” to a scan.
## 3. A new drive: what the box can make ready alone
Media C was added. One script run made it ready in every app. A second run changed nothing.
| app | alone? |
|---|---|
| qBittorrent, Transmission, Sonarr, Radarr, FileBrowser | yes |
| Plex | yes, but only with a token (D9 decides which) |
| Jellyfin | yes, if the box made the first admin. If not: one household step (an API key) |
| Prowlarr | nothing to do per drive |
## 4. The other tests
- **Safe removal (K3):** pausing only that drive's torrents works. But the eject does **not** free the drive from the running apps: they still read its files. After the eject the drive is also forgotten, so the household must attach it again. A restart after the eject fails, because the bind path is gone. → R-1044.
- **Dead-drive check (K4):** read `/proc/self/mountinfo`. A dead drive shows `shutdown`. No disk access is needed. Each container's own mountinfo shows if it still holds the dead drive. A timed `stat` is **not** reliable: it said „ok” on a dead drive.
- **Real restart (K5):** stop + start, or recreate, works in 2–10 s per app. FileBrowser: 5 s. Today's dashboard restart does nothing when the compose did not change (R-1026). A restart cuts a playing stream; Jellyfin answered again after 22 s.
- **Plex without the race (K6):** Plex starts with no code. The code can be given later to the running server. So the box can ask for the code last. But an unclaimed Plex opens everything without a password to a private address. Through the tunnel every request comes from a private address. So an unclaimed Plex must never get a public name (R-1045, P2). `ADVERTISE_IP`: still open; it needs the claim test.
- **Old installs (K7):** Sonarr and Radarr from before `bc54c01` lose their library folder after the update. Nothing is deleted. Repair by the apps' own API, with no file moved: proven on the bench. → R-1047.
- **Hub mails (K8):** a pulled drive sends an error mail. When it comes back, no mail is sent. → R-1049.
## 5. Proposed build plan (for the reviewer, not a spec)
| step | what | where | household |
|---|---|---|---|
| 1 | Restart = stop+start or recreate, with the stack's environment; the log says what changed (R-1026) | controller | — |
| 2 | Media apps get one bind per **present** drive (R-1023, R-1031); FileBrowser's pattern | controller + catalog | — |
| 3 | Drive returns → restart every container that uses it; find them by `shutdown` in their mountinfo (R-1038) | controller | — |
| 4 | Restart notice: „restart now” / „later”; check playing streams first | controller UI | one click |
| 5 | Safe removal = pause that drive's torrents → recreate apps without it → unmount; keep it known (R-1044) | controller + agent | — |
| 6 | New drive → wire every app (R-1024 calls, `15` §10); Plex „scan on change” on (R-1037) | controller | Plex: D9 |
| 7 | Plex: install unclaimed, no public name, ask the code last, claim on the running server (R-1028, R-1045) | controller + catalog | the code |
| 8 | One-time Sonarr/Radarr path repair for old installs (R-1047) | controller | — |
| 9 | „Drive came back” mail (R-1049) | hub | — |
| 10 | Prowlarr into the live catalog (R-1048) | catalog | indexers |
Order: 1 first (2–5 need it). Then 2, 3, 5 together. Then 6, 7. 8, 9, 10 are independent.
## 6. Disk detach times (CEST)
| time | what | hub mail |
|---|---|---|
| 22:54:48 | Media B detached | 22:55 „disconnected” |
| 22:59:00 | Media B re-attached | none (R-1049) |
| 23:03:10 | Media C added | — |
| 23:10:23 | Media C safe removal (eject) | none |
| 23:12:41 | Media C detached | none (it was forgotten) |
| 23:13:11 | Media C re-attached | none |
| 23:20:47 | Media C detached (a pull) | 23:21 „disconnected” |
| 23:21:22 | Media C re-attached | none (R-1049) |
Also 23:11: two „app does not run” mails (Plex, Jellyfin) — from the restart test after the eject.
## 7. Claims in the prompt that were wrong
1. „Your test shows in Plex and Jellyfin may disappear during the scan test.” They did not. Nothing was removed.
2. Option (a), Cloudflare „Always Use HTTPS” per zone: not possible. No stored key may change zone settings.
3. K4's example check (a timed `stat` in a separate process): not reliable. It said „ok” on a dead drive.
4. K3 assumed the safe removal frees the drive. It does not, while the apps run.
5. K6 asked for a throwaway Plex on a test subdomain. **I did not give it a public name.** Reason: an unclaimed Plex is open without a password to every request through the tunnel.
My own predictions that were wrong: I expected Plex and Jellyfin to remove items, and the torrents to re-check. Neither happened.
## Commits
- felhom.eu: `0144be8c`, `b7807c11`, `5aaa3312`, and the final commit of this report.
- felhom-controller: `8bc7ec5` (v0.312.0, image `gitea.dooplex.hu/admin/felhom-controller:0.312.0`, delivered to all three boxes; MinAgent unchanged).
- app-catalog-drill: `925f3fd` (Media C binds; drill catalog only).
## Register
- Rows before: **154**. Rows after: **163**. Opened: **9** (R-1041 … R-1049). Closed: **0**.
- Narrowed: R-1022, R-1023, R-1024, R-1026, R-1028, R-1033, R-1037, R-1038.
- `STATUS.md`: **58 lines**.
- `unproven.py --summary`: not walked 35 of 55 — no number moved.
## Teardown, three layers
- **Machine (Tester 1):** not torn down, on purpose (your word is needed). Left: Media C, the throwaway `plex-k6` and its volume `plex-k6-config` (for the claim test). Both are in R-1022.
- **Host (demo-hp):** VM 341 has a new disk `scsi4` (`nvme-scratch:341/vm-341-disk-5.raw`, 50 GB). The bench (LXC 9401) is off, as found.
- **Hub:** nothing changed. Read only.
- The echo container of the https spike was removed (0 left).
## Fixed without a row
- `https_only_check.py`: a browser-like User-Agent (Cloudflare refused Python's own); the script goes to the box on stdin.
## Instruction files
None changed.
## System poster
The facts file has the https sentence. The drawing has no such text, so `STATUS.md` has the line „System poster needs a refresh”.
+10 -4
View File
@@ -2,10 +2,11 @@
**Ready for the first real tester (Tester-2): yes. Tester 2 (a laptop) is off; nothing was sent to it.**
**Updated 2026-10-14 (evening).** Agent 0.156.1 + its bundle and controller 0.311.0 on all three boxes; hub 0.150.0; golden 0.311.0 (vouched, global floor). Open items: see `documentation/backlog/OPEN-ITEMS.md`. Older notes, day by day:
`documentation/backlog/STATUS-HISTORY.md`. Reports: `REPORT-immich-rollout-2026-10-14.md`, `REPORT-seo-felho-tarhely-2026-10-14.md`, `REPORT-immich-repair-2026-10-14.md`, `REPORT-power-cut-fixes-2026-10-14.md`, `REPORT-night-power-2026-10-13.md`, `REPORT-poweroff.md`.
**Updated 2026-10-14 (night).** Agent 0.156.1 + its bundle on all three boxes; controller 0.312.0 on all three boxes (NOT vouched; the floor stays 0.311.0); hub 0.150.0; golden 0.311.0. Open items: see `documentation/backlog/OPEN-ITEMS.md`. Older notes, day by day:
`documentation/backlog/STATUS-HISTORY.md`. Reports: `REPORT-night-2026-10-14.md`, `REPORT-immich-rollout-2026-10-14.md`, `REPORT-seo-felho-tarhely-2026-10-14.md`, `REPORT-immich-repair-2026-10-14.md`, `REPORT-power-cut-fixes-2026-10-14.md`, `REPORT-night-power-2026-10-13.md`, `REPORT-poweroff.md`.
## What works
- Every public name of the three test boxes answers only over https: plain http gets a 301 to the same https address, and browsers are told to remember it for one day (29 names checked, 2026-10-14 night).
- Media apps work together on one drive: a download reaches Sonarr/Radarr as one file, no copy; the download apps see only their own folder (live catalog, proven on demo-hp).
- A power cut in the middle of a backup no longer blocks later backups: the box removes the half-written backup at start-up (proven with a real cut on demo-hp, on all three boxes now).
- After a power cut, Immich repairs the photos the cut left broken, by itself, and the app page lists any lost photo (proven with a real cut on demo-hp: 41 of 41 repaired; on all three boxes now). An Immich update cannot switch it off quietly: the catalog refuses an untested Immich version.
@@ -24,7 +25,7 @@
## What we work on
- The power-cut findings still open (R-1004, R-1005, R-1010, R-1012, R-1013).
- Media apps on every drive (R-1023): proven on Tester 1 with your test — one file per download, no copy; a pulled drive needs a real restart when it comes back (R-1038).
- Media apps on every drive (R-1023): every drive event is measured. Nothing is lost while a drive is gone. A third drive was made ready in every app by script. The „safe removal” is not safe yet while the apps run (R-1044). The build plan is in the night report.
## Waiting on you — decide
@@ -37,12 +38,17 @@
| D5 | R-993 (R-991) | Approve the minimum machine (`audits/sizing-2026-10-13/SIZING.md` §5: x86-64, 4 cores, 8 GB, 256 GB SSD)? | **Approve** | Change it: one edit | no hardware page; a buyer with a Raspberry Pi can still download the installer | the hardware page |
| D6 | R-992 | The scratch box cannot read the private drill catalog: give it a read-only login, or make that copy readable? | **A read-only login** | Readable copy: the drill catalog becomes public | every new-app test needs hand-staging | new-app tests |
| D7 | R-990, R-989 | Rule yes / no / later on the forum ideas (`audits/forum-research-2026-10-12/FELHOM.md` §5) and the selfh.st ideas (`audits/selfhst-survey-2026-10-12/FELHOM.md` §6) | — | — | nothing changes; the research ages | — |
| D9 | R-1046 | How may the box talk to Plex: with the household's Plex account token, or by trusting the box's own address in Plex? | **Trust the box's address** — no account token is copied | The token opens the household's whole Plex account | Plex stays manual: no new drive appears in Plex by itself | the media build |
| D10 | R-1041 | How long must browsers remember „https only”? | **Keep one day now; one year after a month with no trouble** | One year now: a mistake locks a name out for a year | it stays one day; safe, a little weaker | — |
| D8 | R-206 | Install DooPlex's Docker settings from git (restarts Docker), and prune the build cache weekly: yes or no? | **Yes, in a quiet window** | — | a rebuild of DooPlex still has the settings in git | — |
## Waiting on you — do
- **Vouch controller 0.312.0 and raise the floor** (hub). It makes every box https only, Tester 2 included. If not: the other boxes keep answering plain http (R-1033, P1).
- **Plex claim test (5 min):** open plex.tv/claim, put the code in `~/.felhom-tester1/plex-claim` on DooPlex (`chmod 600`, not in chat), then tell me „done”. If not: the Plex claim fix stays unproven (R-1028).
- System poster needs a refresh: every public name answers only over https (http → 301).
- **Clear demo-hp's own floor** (hub → Demo HP → floor: empty → Save floor). It still reads 0.311.0. If not: the next global raise passes demo-hp by.
- **Leftovers moved out of the shared checkout** to `/mnt/5_hdd/felhom.eu/leftovers/2026-10-14/` (nothing deleted): the Facebook `first-post/` folder is not in git — keep, commit or delete it. The rest is already in git. If not: it just stays there.
- **The media test on Tester 1 is finished** — results in `REPORT-media-all-drives-2026-10-14.md`. Say „tear it down" when you want Tester 1 back to normal (R-1022).
- **The media tests on Tester 1 are finished** — results in `REPORT-night-2026-10-14.md`. Say „tear it down" when you want Tester 1 back to normal (R-1022; now three test drives and a throwaway Plex).
- **Ask Google to index the new page:** Search Console → URL-ellenőrzés → `https://felhom.eu/sajat-felho-tarhely` → „Indexelés kérése". If not: the page may sit unseen, and the 11 November / 9 December checks (R-1035) read zero for a reason that is not the page.
- **N100 BIOS:** read „After Power Loss" (the HP's „Previous State" made it start after 8 of 8 cuts). **HP BIOS:** „Bypass F1 Prompt on Configuration Changes" → Enable.
- **Pull the failed disk** Z6A07P2G (R-934; the twin Z6A070XZ is `/mnt/3_hdd`). If not: its alarms return on 11 November.
+51 -3
View File
@@ -5,7 +5,7 @@
> learn. **No document covered this before 2026-10-14** — itself a finding: the four templates were written one by one
> and never tested together (R-1014). Rulings: `09` §3 decisions 237–241. Measured on Tester 1:
> `audits/media-all-drives-2026-10-14/`. Marks as in `01`: **[DESIGN]** a decision or proposal; **[FACT]** read in a
> named file or measured. **Status: DRAFT** — measured end to end on Tester 1; the layout of §2 is RULED (decision 242) and live for one drive.
> named file or measured. **Status: DRAFT** — measured end to end on Tester 1; the layout of §2 is RULED (decision 242) and live for one drive; the drive events of §10 measured (decision 245, option A).
## 1. The problem
@@ -82,8 +82,8 @@ container does not see a drive added later (guest propagation is `shared,slave`,
not change; it logged success in 0.1 s while the containers kept their start time. Stop + start works. The notice of
decisions 238–239 needs a real restart (`up -d --force-recreate` once the per-drive binds are in the compose).
**[DESIGN]** The restart notice (decision 238) fires on: a drive added, a drive removed, and — pending S6 — a drive
that came back. Each drive card carries „apps restarted since this drive was added: yes/no" with the button
**[DESIGN]** The restart notice (decision 238) fires on: a drive added, a drive removed, and a drive that came back
(S6 and K1-c/K5 measured it: after a return nothing sees the drive until restarted; §10 has the per-app actions). Each drive card carries „apps restarted since this drive was added: yes/no" with the button
(decision 239).
## 5. A drive is pulled / comes back [FACT, measured on Tester 1 2026-10-14, `audits/media-all-drives-2026-10-14/S5-S6/`]
@@ -179,3 +179,51 @@ Call sites that assume ONE `HDD_PATH`/`USERDATA_PATH` per app (controller main a
An installed media app keeps its `HDD_PATH` (its config's unit lives there) and gains binds for the other drives at its
next recreate. Because the paths are the same everywhere (§2 reason 2), nothing Sonarr or Radarr stored changes. A
household's existing files under `media/torrents` stay where they are.
## 10. What the box does on each drive event [FACT, measured 2026-10-14 night on Tester 1 + the bench; `09` §3 decision 245 — option A]
Evidence: `audits/media-drive-events-2026-10-14/` (K1–K7). „Idempotent" = a second run changes nothing (K2: run 2 left every entry, folder and library as it
was). „Household" = a step only the household can take.
| event → app | action | measured call | idempotent | household | evidence |
|---|---|---|---|---|---|
| **added** — every media app | the compose gains the drive's bind → `up -d` recreates it (the compose CHANGED, so today's restart works) | controller compose `up -d` | yes | no | K5-1: 1–10 s per app |
| added — FileBrowser | already: `SyncFileBrowserMounts` recreates on a new path | — | yes | no | K2-2 |
| added — the drive's folders | `torrents/{tv,movies}`, `transmission/{tv,movies}` made (the skeleton lacks them for a drill template; Sonarr raises a „remote path mapping" health error without them) | mkdir, owner 1000, 2775 | yes | no | K2-6 |
| added — qBittorrent | categories `tv-<d>`, `movies-<d>`: save path AND incomplete path on that drive; automatic torrent management ON | `createCategory`/`editCategory`, `setPreferences auto_tmm_enabled` | yes (re-writes equal values) | no | K2-6/7 |
| added — Transmission | no per-drive setting; one incomplete folder → OFF, written into `settings.json` at start (an RPC `session-set` was LOST after the 17:25 power cut) | entrypoint `jq` | yes | no | K1 note, wire run 3 |
| added — Sonarr, Radarr | root folder, tag `<d>`, „qBittorrent <d>" (category) + „Transmission <d>" (directory, category CLEARED), min free space | `/api/v3/rootfolder`, `/tag`, `/downloadclient` (Host: <app>) | yes (check before create) | no | K2-6/7 |
| added — Prowlarr | nothing per drive (it feeds Sonarr/Radarr) | — | — | indexers | H |
| added — Plex | the drive's folders added to the EXISTING libraries, a scan, „scan when a change is detected" ON | `PUT /library/sections/<id>?…&location=…` (all locations repeated), `/refresh`, `PUT /:/prefs FSEventLibraryUpdatesEnabled=1` | yes | no — but the token is the server's own `PlexOnlineToken` (a household-account token; 401 without one, K2-5) → R-1046 | K2-6 |
| added — Jellyfin | the drive's folders added, a scan; an API key for the box | `POST /Library/VirtualFolders/Paths`, `/Library/Refresh`, `POST /Auth/Keys?app=felhom` | yes | no IF the box made the first admin itself; else ONE step (an API key) | K2-6 |
| **safe removal** — qBittorrent, Transmission | pause ONLY the torrents saved on that drive | qBit `torrents/stop` by `save_path`; Transmission `torrent-stop` by `downloadDir` | yes | no | K3-2 |
| safe removal — every media app | **recreate WITHOUT the drive's bind BEFORE the unmount**: today's eject detaches the guest's bind and keeps the raw mount, while the running apps still HOLD the filesystem (they saw its files after the „safe" removal) | render binds for present drives; `up -d` | yes | no | K3-3 |
| safe removal — the drive | eject today also DEREGISTERS it; after a re-attach the agent mounts it again, but the household must „Meglévő meghajtó csatolása" (`register-mounted`) | — | — | **yes, today** | K3-5 |
| safe removal — Plex, Jellyfin | nothing (they keep every item, §5) | — | — | no | K1 |
| **pulled** — every app | NOTHING is lost: Plex (autoEmptyTrash on or off), Jellyfin, Sonarr/Radarr refresh + rescan (unmonitor on or off), torrents — the guest keeps a DEAD mount and every read is an I/O error, which every app treats as „unavailable" | — | — | no | K1 |
| pulled — the box | knows which apps hold a dead view WITHOUT disk I/O: the guest's `/proc/self/mountinfo` shows `shutdown` on the drive; each container's `/proc/<pid>/mountinfo` shows the old device + `shutdown` | read `/proc` only | yes | no | K4 |
| pulled — restart an app | still starts while the DEAD mount is there (K1: Jellyfin); FAILS (500, „error while creating mount source path … permission denied") once the path is gone (after an eject) — the app is down until the drive returns | — | — | no | K3-4 |
| **came back** — every media app + FileBrowser | stop+start, or `up -d --force-recreate` WITH the controller's environment (a bare `compose up` lost every `${…}` value: routes `Host(\`.\`)`, an empty password — K5-2); today's restart (`up -d`, compose unchanged) does nothing (R-1026) | `StopStack`+`StartStack`, or `composeExecCustomEnv(…, "up","-d","--force-recreate")` | yes | no | K5-2/3: 2–10 s per app, FileBrowser 5 s |
| came back — qBittorrent, Transmission | nothing: every torrent seeds again, no „missing files", no re-check | — | — | no | K1-c, K3-6 |
| came back — a registered drive | the gate re-binds it by itself; an EJECTED one needs the household's attach | — | — | after an eject | K1-c, K3-5 |
| came back — a playing stream | is CUT by the restart (curl exit 56), Jellyfin answers again 22 s later → offer „later", or check active sessions first | Jellyfin `/Sessions`, Plex `/status/sessions` | — | no | K5-4 |
**Guards the measurements show ARE needed:** (1) never start a media app with a bind to an absent path — render one bind per
PRESENT drive (the FileBrowser pattern); (2) a safe removal recreates the media apps without the drive, then unmounts the
raw device (R-1044); (3) every restart through the controller's environment; (4) a returned drive restarts every container that binds
it, FileBrowser included; (5) Transmission's settings written at start, not by RPC. **Guards NOT needed — do not build
them:** a scan or „empty trash" suppression for Plex/Jellyfin, an unmonitor guard for Sonarr/Radarr, pausing torrents on
a pull — K1 measured no loss in any of them while the dead mount stands. **The one condition behind that:** the guest keeps
a DEAD mount (I/O errors). R-1038's fix must NOT turn a pulled drive into an EMPTY folder that a scan could read as „all
files deleted" — keep the dead mount, or stop the media apps first.
**Old installs (K7):** Sonarr/Radarr from before app-catalog `bc54c01` keep their library at `/media/tv` / `/media/movies`;
after the update the root folder is missing (health „Missing root folder"), records stay. Repair through the apps' own API,
no file moved: add the same-path root folder; `PUT /series/editor` (`/movie/editor`) `rootFolderPath`, `moveFiles:false`;
rescan; delete the old root folder; Radarr's collections keep the old root (a separate setting) and the health page shows the
old warning until its next check. File and inode unchanged.
**Plex without the race (K6):** an unclaimed Plex starts with no code and answers every request from a private address
WITHOUT a token — it must never be routed publicly while unclaimed; `POST /myplex/claim?token=<code>` on the RUNNING server
claims it (the route answered and called plex.tv; a real code needs the household's account — the morning step). So the box
asks for the code only once the server is up: no 4-minute race with the pull.
@@ -0,0 +1,26 @@
=== all live (B has a returned-drive history, C was re-registered) 21:20:37
adatlemez A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 4 ms | => live
media_a A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
media_b A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
media_c A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 2 ms | => live
=== Media C DEAD (pulled 30 s ago) 21:21:22
adatlemez A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 2 ms | => live
media_a A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 2 ms | => live
media_b A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 2 ms | => live
media_c A: mounts stacked=2 top-super=rw,shutdown shutdown=True | B: stat ok in 2 ms | => DEAD
=== Media C RETURNED (re-attached 60 s ago, no app restart) 21:22:25
adatlemez A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
media_a A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
media_b A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
media_c A: mounts stacked=2 top-super=rw shutdown=False | B: stat ok in 3 ms | => live
958 405 8:64 /felhom-data /mnt/felhom-drives/media_c rw,relatime shared:506 master:591 - ext4 /dev/sde rw
959 804 8:64 /felhom-data /mnt/felhom-drives/media_c rw,relatime shared:506 master:591 - ext4 /dev/sde rw
sonarr sees C: ls: cannot access '/mnt/felhom-drives/media_c/userdata/media/tv': I/O error
filebrowser sees C: ls: /mnt/felhom-drives/media_c/userdata/media/tv: No such file or directory
sonarr (pid 463719): ext4 /dev/sdd rw,shutdown
radarr (pid 460265): ext4 /dev/sdd rw,shutdown
qbittorrent (pid 464094): ext4 /dev/sdd rw,shutdown
transmission (pid 461036): ext4 /dev/sdd rw,shutdown
plex (pid 461609): ext4 /dev/sdd rw,shutdown
jellyfin (pid 462353): ext4 /dev/sdd rw,shutdown
filebrowser (pid 458188): ext4 /dev/sdd rw,shutdown
@@ -0,0 +1,18 @@
qbittorrent dashboard stop+start (200,200) 2.9s
transmission dashboard stop+start (200,200) 6.1s
sonarr dashboard stop+start (200,200) 4.1s
radarr dashboard stop+start (200,200) 4.3s
plex dashboard stop+start (200,200) 9.8s
jellyfin dashboard stop+start (200,200) 1.9s
filebrowser compose up -d --force-recreate (no variables in its compose — the controller's own composeUp would run the same): 5.2s Container filebrowser Started
sonarr: /dev/sde rw
radarr: /dev/sde rw
qbittorrent: /dev/sde rw
transmission: /dev/sde rw
plex: /dev/sde rw
jellyfin: /dev/sde rw
filebrowser: /dev/sde rw
Felhom Probe Show (2026)
sonarr rule: Host(`sonarr.enkicsifelhom.hu`)
qbittorrent rule: Host(`torrent.enkicsifelhom.hu`)
@@ -0,0 +1,3 @@
jellyfin restarted (docker stop+start) at +10 s, took 10.4s
the stream: curl exit=56 200 bytes=22970488 exit_after (exit 18/56 = the transfer was cut)
jellyfin answers again 22s after the restart began
@@ -0,0 +1,15 @@
started
identity: version="1.0" claimed="0" version="1.41.4.9463-630c9f557"
no token, from another container: GET /library/sections -> 200
no token, from another container: GET /:/prefs -> 200
no token, from another container: GET /myplex/account -> 200
POST /myplex/claim with an INVALID code -> 500<html><head><title>Internal Server Error</title></head><body><h1>500 Internal Server Error</h1></body></html>
public route: none (no traefik labels):
Oct 14, 2026 23:25:52.548 [129866045209400] DEBUG - [Req#f5/HCl#5b] HTTP requesting GET https://plex.tv/api/v2/release_channels?X-Plex-Token=
Oct 14, 2026 23:25:52.690 [129866068745016] DEBUG - [HttpClient/HCl#5b] HTTP/1.1 (0.1s) 200 response from GET https://plex.tv/api/v2/release_channels?X-Plex-Token=xxxxxxxxx
Oct 14, 2026 23:25:52.690 [129866045209400] DEBUG - [Req#f5/HCl#5c] HTTP requesting GET https://plex.tv/api/v2/features?X-Plex-Token=
Oct 14, 2026 23:25:52.852 [129866068745016] DEBUG - [HttpClient/HCl#5c] HTTP/1.1 (0.2s) 200 response from GET https://plex.tv/api/v2/features?X-Plex-Token=xxxxxxxxx
Oct 14, 2026 23:25:52.853 [129866045209400] DEBUG - [Req#f5/HCl#5d] HTTP requesting GET https://plex.tv/api/v2/server/users/features
Oct 14, 2026 23:25:52.988 [129866068745016] DEBUG - [HttpClient/HCl#5d] HTTP/1.1 (0.1s) 401 response from GET https://plex.tv/api/v2/server/users/features (reused)
Oct 14, 2026 23:25:52.988 [129866043099960] ERROR - [Req#f5] MyPlex: Error 401 requesting JSON from: https://plex.tv/api/v2/server/users/features
Oct 14, 2026 23:25:52.988 [129866080086840] DEBUG - Completed: [172.18.0.2:43806] 500 POST /myplex/claim?token=<code> (6 live) #f5 991ms 325 bytes (pipelined: 1)
@@ -0,0 +1,7 @@
# K6 predictions (before the run, ~23:28 CEST)
- An unclaimed Plex starts fine with no PLEX_CLAIM; /identity says claimed=0.
- While unclaimed, Plex lets a request from a private address in WITHOUT a token (it treats the LAN as the owner) —
which is exactly why it must not be reachable through the tunnel unclaimed (traefik's address is private).
- Plex's own API takes a claim code AFTER the start: POST /myplex/claim?token=<code> on the server — so the box can
ask for the code only when the server is up (no 4-minute race with the image pull). Proof needs the household's
plex.tv account → the morning step; without it, the route's answer to an invalid code shows it exists.
@@ -0,0 +1,49 @@
0
======== sonarr
Container sonarr Started
1. installed from the OLD template (bind /media/tv)
rescan -> completed
[OLD template] root folders: [('/media/tv', True)]
[OLD template] Problem Child: path=/media/tv/Problem Child files=1 sizeOnDisk=145093
[OLD template] health: [('IndexerRssCheck', 'No indexers available with RSS sync enabled, Sonarr will not grab new releases automatical'), ('DownloadClientCheck', 'No download client is available'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Sonarr will not provide any automatic')]
2. updated to TODAY's template (bc54c01): one bind, the same path inside
Container sonarr Started
rescan -> completed
[NEW template, before the repair] root folders: [('/media/tv', False)]
[NEW template, before the repair] Problem Child: path=/media/tv/Problem Child files=1 sizeOnDisk=145093
[NEW template, before the repair] health: [('DownloadClientCheck', 'No download client is available'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Sonarr will not provide any automatic'), ('IndexerRssCheck', 'No indexers available with RSS sync enabled, Sonarr will not grab new releases automatical'), ('RootFolderCheck', 'Missing root folder: /media/tv')]
3. the repair, through the app's own API, NO file moved
add root folder /srv/k7/userdata/media/tv -> 201
editor: rootFolderPath -> /srv/k7/userdata/media/tv, moveFiles=false -> 202
rescan -> completed
remove the old root folder /media/tv -> 200
[NEW template, after the repair] root folders: [('/srv/k7/userdata/media/tv', True)]
[NEW template, after the repair] Problem Child: path=/srv/k7/userdata/media/tv/Problem Child files=1 sizeOnDisk=145093
[NEW template, after the repair] health: [('DownloadClientCheck', 'No download client is available'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Sonarr will not provide any automatic'), ('IndexerRssCheck', 'No indexers available with RSS sync enabled, Sonarr will not grab new releases automatical'), ('RootFolderCheck', 'Missing root folder: /media/tv')]
the file: same inode before and after = True (moved by nobody), size=145093
======== radarr
Container radarr Started
1. installed from the OLD template (bind /media/movies)
rescan -> completed
[OLD template] root folders: [('/media/movies', True)]
[OLD template] Night of the Living Dead: path=/media/movies/Night of the Living Dead (1968) files=True sizeOnDisk=290186
[OLD template] health: [('IndexerRssCheck', 'No indexers available with RSS sync enabled, Radarr will not grab new releases automatical'), ('DownloadClientCheck', 'No download client is available'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Radarr will not provide any automatic')]
2. updated to TODAY's template (bc54c01): one bind, the same path inside
Container radarr Started
rescan -> completed
[NEW template, before the repair] root folders: [('/media/movies', False)]
[NEW template, before the repair] Night of the Living Dead: path=/media/movies/Night of the Living Dead (1968) files=True sizeOnDisk=290186
[NEW template, before the repair] health: [('IndexerRssCheck', 'No indexers available with RSS sync enabled, Radarr will not grab new releases automatical'), ('DownloadClientCheck', 'No download client is available'), ('RootFolderCheck', 'Missing root folder: /media/movies'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Radarr will not provide any automatic'), ('MovieCollectionRootFolderCheck', 'Missing root folder for movie collection: /media/movies (Living Dead Collection)')]
3. the repair, through the app's own API, NO file moved
add root folder /srv/k7/userdata/media/movies -> 201
editor: rootFolderPath -> /srv/k7/userdata/media/movies, moveFiles=false -> 202
rescan -> completed
remove the old root folder /media/movies -> 200
[NEW template, after the repair] root folders: [('/srv/k7/userdata/media/movies', True)]
[NEW template, after the repair] Night of the Living Dead: path=/srv/k7/userdata/media/movies/Night of the Living Dead (1968) files=True sizeOnDisk=290186
[NEW template, after the repair] health: [('IndexerRssCheck', 'No indexers available with RSS sync enabled, Radarr will not grab new releases automatical'), ('DownloadClientCheck', 'No download client is available'), ('RootFolderCheck', 'Missing root folder: /media/movies'), ('IndexerSearchCheck', 'No indexers available with Automatic Search enabled, Radarr will not provide any automatic'), ('MovieCollectionRootFolderCheck', 'Missing root folder for movie collection: /media/movies (Living Dead Collection)')]
the file: same inode before and after = True (moved by nobody), size=145093
======== teardown
Volume k7sonarr_sonarr_config Removed
Volume k7radarr_radarr_config Removed
left: 0 containers; 0 volumes
@@ -0,0 +1,29 @@
# K8 — what the hub received and what it mailed for the night's drive events (tester-1), read 2026-10-15 ~00:00 CEST
# Two channels: (1) the hub's own DB, copied from the RUNNING pod with hub.db-wal + -shm (R-286), times UTC;
# (2) the operator's mailbox (Gmail connector, the @felhom.eu catch-all), times CEST — the control from another channel.
== hub events (UTC)
20:55:01 storage_disconnected error Meghajtó váratlanul leválasztva: Media B (detach 22:54:48 CEST)
20:56:29 health_degraded warning Rendszer állapot romlott (volt: ok)
20:59:32 storage_reconnected info Meghajtó újra csatlakoztatva: Media B (re-attach 22:59:00 CEST)
21:01:28 health_recovered info Rendszer állapot helyreállt: ok (volt: warn)
21:11:28 app_start_failed warning Telepített alkalmazás nem fut: Jellyfin (K3-4, restart after the eject)
21:11:28 app_start_failed warning Telepített alkalmazás nem fut: Plex (K3-4)
21:21:01 storage_disconnected error Meghajtó váratlanul leválasztva: Media C (detach 23:20:47 CEST)
21:21:28 health_degraded warning Rendszer állapot romlott (volt: ok)
21:21:32 storage_reconnected info Meghajtó újra csatlakoztatva: Media C (re-attach 23:21:22 CEST)
21:26:28 health_recovered info Rendszer állapot helyreállt: ok (volt: warn)
(no event for the safe removal 23:10:23 nor for the disk detach 23:12:41 after it — the drive was deregistered)
== hub notification_log (UTC)
20:55:01 storage_disconnected sent operator
20:56:29 health_degraded sent operator
21:11:29 app_start_failed sent operator (x2)
21:21:01 storage_disconnected sent operator
21:21:28 health_degraded suppressed operator
-> NO row for either storage_reconnected or either health_recovered: received, never mailed.
== mailbox (CEST), monitoring@felhom.eu, after 2026-10-14 22:50
22:55 storage_disconnected Media B · 22:56 health_degraded · 23:11 app_start_failed Jellyfin · 23:11 app_start_failed Plex
23:21 storage_disconnected Media C
-> the mailbox agrees with notification_log: five mails, no „came back" and no „recovered".
@@ -0,0 +1,70 @@
/mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE.mkv 909464483 4194364 2 1791997622
/mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE.mkv 720261766 4194368 2 1791997651
/mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE.mkv 829645981 4194375 2 1791997623
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE.mkv 909464483 4194364 2 1791997622
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e01.1080p.web.h264-grace.nfo 497 4194376 1 1791997577
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e01.1080p.web.h264-grace.sample.mkv 35166429 4194366 1 1791997623
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.mkv 3789544605 4194398 1 1791997839
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.nfo 62 4194400 1 1791997834
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/slow.horses.s06e03.1080p.web.h264-cakes.mkv 3931160378 4194385 1 1791997887
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/slow.horses.s06e03.1080p.web.h264-cakes.nfo 2728 4194367 1 1791997882
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e03.1080p.web.h264-cakes-sample.mkv 85809338 4194392 1 1791997778
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/slow.horses.s06e02.proper.1080p.web.h264-ethel.nfo 1023 4194397 1 1791997846
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL.mkv 3758255491 4194369 1 1791997854
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/Sample/slow.horses.s06e02.proper.1080p.web.h264-ethel.sample.mkv 77743753 4194383 1 1791997852
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE.mkv 720261766 4194368 2 1791997651
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e03.1080p.web.h264-grace.nfo 492 4194377 1 1791997591
/mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e03.1080p.web.h264-grace.sample.mkv 21739818 4194370 1 1791997622
/mnt/felhom-drives/media_a/userdata/media/torrents/movies/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.nfo 602 4194405 1 1791997982
/mnt/felhom-drives/media_a/userdata/media/torrents/movies/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.mkv 4697542077 4194391 2 1791997988
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/slow.horses.s06e04.1080p.web.h264-cakes.mkv 4039934637 4194396 1 1791997987
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/slow.horses.s06e04.1080p.web.h264-cakes.nfo 2730 4194399 1 1791997757
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e04.1080p.web.h264-cakes-sample.mkv 94200139 4194395 1 1791997773
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/slow.horses.s06e01.1080p.web.h264-cakes.mkv 3859110437 4194387 1 1791997961
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/slow.horses.s06e01.1080p.web.h264-cakes.nfo 2693 4194388 1 1791997744
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e01.1080p.web.h264-cakes-sample.mkv 104128605 4194390 1 1791997759
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e02.1080p.web.h264-grace.nfo 497 4194374 1 1791997576
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE.mkv 829645981 4194375 2 1791997623
/mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e02.1080p.web.h264-grace.sample.mkv 31210978 4194373 1 1791997609
/mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.mkv 2819947717 4194408 1 1791998428
/mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.nfo 8091 4194409 1 1791998340
/mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Sample/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY-Sample.mkv 22742740 4194411 1 1791998422
/mnt/felhom-drives/media_a/userdata/media/movies/Hope (2026)/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.mkv 4697542077 4194391 2 1791997988
/mnt/felhom-drives/media_b/userdata/media/torrents/movies/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.mkv 3393846457 1048578 2 1791998022
/mnt/felhom-drives/media_b/userdata/media/torrents/movies/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.nfo 619 1048579 1 1791998019
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131101 1 1791997602
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E01.13.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1314062473 131100 2 1791997680
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E03.Rauhnacht.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 813589489 131110 2 1791997659
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131113 1 1791997627
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E07.The.Baddest.Witch.of.Them.All.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 956532263 393221 2 1791997699
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 67 393223 1 1791997690
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E05.Date.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 969653267 393218 2 1791997719
/mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E05.Date.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 77 393220 1 1791997712
/mnt/felhom-drives/media_b/userdata/media/movies/Matchbox the Movie (2026)/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.mkv 3393846457 1048578 2 1791998022
/mnt/felhom-drives/media_b/userdata/media/movies/WHO (2026)/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.mkv 2819947717 2097156 1 1791998428
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1164079593 131107 2 1791997676
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1314062473 131100 2 1791997680
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 913481011 131112 2 1791997757
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 956532263 393221 2 1791997699
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 813589489 131110 2 1791997659
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1274167804 131103 2 1791997733
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 969653267 393218 2 1791997719
/mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1149433990 262146 2 1791997741
/mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.mkv 3789544605 524295 1 1791997839
/mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E01.1080p.WEB.H264-CAKES.mkv 3859110437 524298 1 1791997961
/mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E04.1080p.WEB.H264-CAKES.mkv 4039934637 524299 1 1791997987
/mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL.mkv 3758255491 524296 1 1791997854
/mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E03.1080p.WEB.H264-CAKES.mkv 3931160378 524297 1 1791997887
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E02.1.13.AM.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1274167804 131103 2 1791997733
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131104 1 1791997605
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E04.Is.That.All.There.Is.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1164079593 131107 2 1791997676
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E04.Is.That.All.There.Is.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 67 131108 1 1791997615
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E08.Hell.No.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1149433990 262146 2 1791997741
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 67 262147 1 1791997643
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E06.The.Return.of.Devils.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 913481011 131112 2 1791997757
/mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E06.The.Return.of.Devils.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 93 131114 1 1791997633
/mnt/felhom-drives/media_c/userdata/media/tv/Felhom Probe Show (2026)/Season 01/Felhom Probe Show (2026) - S01E01.mkv 145093 655382 1 1792011968
/mnt/felhom-drives/media_c/userdata/media/transmission/tv/k3-own-bytes-trans/data.bin 3000000 655393 1 1792012185
/mnt/felhom-drives/media_c/userdata/media/movies/Felhom Probe Film (2026)/Felhom Probe Film (2026).mkv 145093 655383 1 1792011968
/mnt/felhom-drives/media_c/userdata/media/torrents/tv/k3-own-bytes-qbit/data.bin 3000000 655391 1 1792012185
1 /mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE.mkv 909464483 4194364 2 1791997622
2 /mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE.mkv 720261766 4194368 2 1791997651
3 /mnt/felhom-drives/media_a/userdata/media/tv/Avatar - Seven Havens/Season 1/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE.mkv 829645981 4194375 2 1791997623
4 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE.mkv 909464483 4194364 2 1791997622
5 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e01.1080p.web.h264-grace.nfo 497 4194376 1 1791997577
6 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E01.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e01.1080p.web.h264-grace.sample.mkv 35166429 4194366 1 1791997623
7 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.mkv 3789544605 4194398 1 1791997839
8 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.nfo 62 4194400 1 1791997834
9 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/slow.horses.s06e03.1080p.web.h264-cakes.mkv 3931160378 4194385 1 1791997887
10 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/slow.horses.s06e03.1080p.web.h264-cakes.nfo 2728 4194367 1 1791997882
11 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E03.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e03.1080p.web.h264-cakes-sample.mkv 85809338 4194392 1 1791997778
12 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/slow.horses.s06e02.proper.1080p.web.h264-ethel.nfo 1023 4194397 1 1791997846
13 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL.mkv 3758255491 4194369 1 1791997854
14 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL/Sample/slow.horses.s06e02.proper.1080p.web.h264-ethel.sample.mkv 77743753 4194383 1 1791997852
15 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE.mkv 720261766 4194368 2 1791997651
16 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e03.1080p.web.h264-grace.nfo 492 4194377 1 1791997591
17 /mnt/felhom-drives/media_a/userdata/media/torrents/tv/Avatar.Seven.Havens.S01E03.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e03.1080p.web.h264-grace.sample.mkv 21739818 4194370 1 1791997622
18 /mnt/felhom-drives/media_a/userdata/media/torrents/movies/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.nfo 602 4194405 1 1791997982
19 /mnt/felhom-drives/media_a/userdata/media/torrents/movies/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.mkv 4697542077 4194391 2 1791997988
20 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/slow.horses.s06e04.1080p.web.h264-cakes.mkv 4039934637 4194396 1 1791997987
21 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/slow.horses.s06e04.1080p.web.h264-cakes.nfo 2730 4194399 1 1791997757
22 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E04.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e04.1080p.web.h264-cakes-sample.mkv 94200139 4194395 1 1791997773
23 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/slow.horses.s06e01.1080p.web.h264-cakes.mkv 3859110437 4194387 1 1791997961
24 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/slow.horses.s06e01.1080p.web.h264-cakes.nfo 2693 4194388 1 1791997744
25 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Slow.Horses.S06E01.1080p.WEB.H264-CAKES/Sample/slow.horses.s06e01.1080p.web.h264-cakes-sample.mkv 104128605 4194390 1 1791997759
26 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/avatar.seven.havens.s01e02.1080p.web.h264-grace.nfo 497 4194374 1 1791997576
27 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE.mkv 829645981 4194375 2 1791997623
28 /mnt/felhom-drives/media_a/userdata/media/transmission/tv/Avatar.Seven.Havens.S01E02.1080p.WEB.h264-GRACE/Sample/avatar.seven.havens.s01e02.1080p.web.h264-grace.sample.mkv 31210978 4194373 1 1791997609
29 /mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.mkv 2819947717 4194408 1 1791998428
30 /mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.nfo 8091 4194409 1 1791998340
31 /mnt/felhom-drives/media_a/userdata/media/transmission/movies/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY/Sample/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY-Sample.mkv 22742740 4194411 1 1791998422
32 /mnt/felhom-drives/media_a/userdata/media/movies/Hope (2026)/Hope.2026.720p.AMZN.WEB-DL.DDP5.1.Atmos.H.264-N1H4L.mkv 4697542077 4194391 2 1791997988
33 /mnt/felhom-drives/media_b/userdata/media/torrents/movies/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.mkv 3393846457 1048578 2 1791998022
34 /mnt/felhom-drives/media_b/userdata/media/torrents/movies/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.nfo 619 1048579 1 1791998019
35 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131101 1 1791997602
36 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E01.13.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1314062473 131100 2 1791997680
37 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E03.Rauhnacht.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 813589489 131110 2 1791997659
38 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131113 1 1791997627
39 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E07.The.Baddest.Witch.of.Them.All.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 956532263 393221 2 1791997699
40 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 67 393223 1 1791997690
41 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E05.Date.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 969653267 393218 2 1791997719
42 /mnt/felhom-drives/media_b/userdata/media/torrents/tv/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E05.Date.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 77 393220 1 1791997712
43 /mnt/felhom-drives/media_b/userdata/media/movies/Matchbox the Movie (2026)/Matchbox.The.Movie.2026.720p.ATVP.WEB-DL.DDP5.1.Atmos.H.264-FLUX.mkv 3393846457 1048578 2 1791998022
44 /mnt/felhom-drives/media_b/userdata/media/movies/WHO (2026)/Who.2026.720p.DSNP.WEB-DL.DDP5.1.H.264.HuNSUB-TRiNiTY.mkv 2819947717 2097156 1 1791998428
45 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1164079593 131107 2 1791997676
46 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E01.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1314062473 131100 2 1791997680
47 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 913481011 131112 2 1791997757
48 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E07.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 956532263 393221 2 1791997699
49 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E03.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 813589489 131110 2 1791997659
50 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1274167804 131103 2 1791997733
51 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E05.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 969653267 393218 2 1791997719
52 /mnt/felhom-drives/media_b/userdata/media/tv/American Horror Story/Season 13/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.mkv 1149433990 262146 2 1791997741
53 /mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E05.Sayonara.1080p.ATVP.WEB-DL.DDP5.1.H.264-NTb.mkv 3789544605 524295 1 1791997839
54 /mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E01.1080p.WEB.H264-CAKES.mkv 3859110437 524298 1 1791997961
55 /mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E04.1080p.WEB.H264-CAKES.mkv 4039934637 524299 1 1791997987
56 /mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E02.PROPER.1080p.WEB.h264-ETHEL.mkv 3758255491 524296 1 1791997854
57 /mnt/felhom-drives/media_b/userdata/media/tv/Slow Horses/Season 6/Slow.Horses.S06E03.1080p.WEB.H264-CAKES.mkv 3931160378 524297 1 1791997887
58 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E02.1.13.AM.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1274167804 131103 2 1791997733
59 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E02.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 68 131104 1 1791997605
60 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E04.Is.That.All.There.Is.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1164079593 131107 2 1791997676
61 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E04.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E04.Is.That.All.There.Is.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 67 131108 1 1791997615
62 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E08.Hell.No.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 1149433990 262146 2 1791997741
63 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E08.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB.nfo 67 262147 1 1791997643
64 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E06.The.Return.of.Devils.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.mkv 913481011 131112 2 1791997757
65 /mnt/felhom-drives/media_b/userdata/media/transmission/tv/American.Horror.Story.S13E06.1080p.DSNP.WEB-DL.DDP5.1.H.264-PlayWEB/American.Horror.Story.S13E06.The.Return.of.Devils.Night.1080p.DSNP.WEB-DL.DD5.1.H.264-playWEB.nfo 93 131114 1 1791997633
66 /mnt/felhom-drives/media_c/userdata/media/tv/Felhom Probe Show (2026)/Season 01/Felhom Probe Show (2026) - S01E01.mkv 145093 655382 1 1792011968
67 /mnt/felhom-drives/media_c/userdata/media/transmission/tv/k3-own-bytes-trans/data.bin 3000000 655393 1 1792012185
68 /mnt/felhom-drives/media_c/userdata/media/movies/Felhom Probe Film (2026)/Felhom Probe Film (2026).mkv 145093 655383 1 1792011968
69 /mnt/felhom-drives/media_c/userdata/media/torrents/tv/k3-own-bytes-qbit/data.bin 3000000 655391 1 1792012185
@@ -7,3 +7,7 @@
23:10:23 K3 safe removal of Media C (POST /api/storage/eject) — expect a hub mail?
23:12:41 K3 DETACH Media C disk (scsi4) after the safe removal
23:13:11 K3 RE-ATTACH Media C disk (scsi4)
23:20:47 K4 DETACH Media C (scsi4) — a pull without safe removal
23:21:22 K4 RE-ATTACH Media C (scsi4)
23:30 K7 done on the bench; bench shut down as found
23:30 END check: Media A+B files identical to the baseline
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""k4.py [label] — K4: tell a LIVE drive from a DEAD one (mountpoint yes, reads I/O error), run INSIDE the guest.
Two checks per /mnt/felhom-drives/<name>:
A. NO disk I/O (the controller's rule: health checks issue no block I/O — gates.md): /proc/self/mountinfo only.
How many mounts are stacked on the path, and the TOP one's super options (a dead ext4 says `shutdown`;
the stacked dead one under a returned drive is listed too).
B. A timed read in a SEPARATE process: `stat` of <path>/userdata with a 3 s timeout — the caller never blocks; the
result and the time it took.
"""
import os, subprocess, sys, time
label = sys.argv[1] if len(sys.argv) > 1 else ""
mi = open("/proc/self/mountinfo").read().splitlines()
print(f"=== {label} {time.strftime('%H:%M:%S')}")
for d in sorted(os.listdir("/mnt/felhom-drives")):
p = f"/mnt/felhom-drives/{d}"
rows = [l for l in mi if l.split()[4] == p]
top = rows[-1] if rows else ""
sup = top.split(" - ", 1)[1].split()[2] if " - " in top else "-"
t0 = time.time()
try:
r = subprocess.run(["timeout", "3", "stat", "-c", "%i", f"{p}/userdata"], capture_output=True, text=True)
res = "ok" if r.returncode == 0 else ("TIMEOUT" if r.returncode == 124 else "ERR " + r.stderr.strip().split(":")[-1].strip())
except Exception as e:
res = f"EXC {e}"
dt = (time.time() - t0) * 1000
shut = "shutdown" in sup.split(",")
verdict = "DEAD" if (shut or res.startswith("ERR")) else ("absent" if not rows else "live")
print(f" {d:10} A: mounts stacked={len(rows)} top-super={sup[:40]:40} shutdown={shut} | B: stat {res} in {dt:.0f} ms | => {verdict}")
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""k7.py — K7 on the BENCH (LXC 9401): Sonarr and Radarr installed from the templates BEFORE app-catalog bc54c01
(library at /media/tv, /media/movies inside the container), then updated to bc54c01 (one same-path `media` bind), then
repaired through the apps' OWN API without moving a file. Needs /tmp/k7/{old,new}-{sonarr,radarr}.yml and
/tmp/k7/probe.mkv (a 10 s self-made clip). Everything it makes is removed at the end (containers, volumes, folders).
"""
import json, os, re, shutil, subprocess, time, urllib.error, urllib.request
W = "/srv/k7"; U = f"{W}/userdata"
def sh(c, t=600):
r = subprocess.run(c, shell=True, capture_output=True, text=True, timeout=t)
return (r.stdout + r.stderr).strip()
def ip(c):
return sh(f"docker inspect {c} -f '{{{{range .NetworkSettings.Networks}}}}{{{{.IPAddress}}}}{{{{end}}}}'")
def call(m, url, H, body=None):
h = dict(H); data = None
if body is not None:
data = json.dumps(body).encode(); h["Content-Type"] = "application/json"
try:
with urllib.request.urlopen(urllib.request.Request(url, data=data, headers=h, method=m), timeout=120) as r:
t = r.read(); return r.status, (json.loads(t) if t else None)
except urllib.error.HTTPError as e:
return e.code, e.read().decode()[:300]
def up(app, yml):
os.makedirs(f"{W}/{app}", exist_ok=True); shutil.copy(yml, f"{W}/{app}/docker-compose.yml")
open(f"{W}/{app}/.env", "w").write(f"DOMAIN=bench.invalid\nSUBDOMAIN={app}\nUSERDATA_PATH={U}\n")
print(sh(f"cd {W}/{app} && docker compose -p k7{app} up -d 2>&1 | tail -1"))
port = 8989 if app == "sonarr" else 7878
for _ in range(60):
time.sleep(3)
if sh(f"docker inspect {app} -f '{{{{.State.Health.Status}}}}'") == "healthy":
break
key = re.search(r"<ApiKey>([^<]+)", sh(f"docker exec {app} cat /config/config.xml")).group(1)
return f"http://{ip(app)}:{port}/api/v3", {"X-Api-Key": key}
def cmd(base, H, name, **kw):
c, d = call("POST", base + "/command", H, dict(name=name, **kw))
for _ in range(60):
time.sleep(2)
c2, s = call("GET", base + f"/command/{d['id']}", H)
if s.get("status") in ("completed", "failed"):
return s["status"]
def report(app, base, H, label):
kind = "series" if app == "sonarr" else "movie"
c, items = call("GET", base + f"/{kind}", H)
c, roots = call("GET", base + "/rootfolder", H)
c, health = call("GET", base + "/health", H)
print(f" [{label}] root folders: {[(r['path'], r['accessible']) for r in roots]}")
for x in items:
st = x.get("statistics") or {}
print(f" [{label}] {x['title']}: path={x['path']} files={st.get('episodeFileCount', x.get('hasFile'))} sizeOnDisk={st.get('sizeOnDisk')}")
print(f" [{label}] health: {[(h['source'], h['message'][:90]) for h in health]}")
for app, kind, lib, lookup, fname in (
("sonarr", "series", "tv", "/series/lookup?term=tvdb:73705", "{t} - S01E01 - Episode.mkv"),
("radarr", "movie", "movies", "/movie/lookup/tmdb?tmdbId=10331", "{t}.mkv")):
print(f"======== {app}")
os.makedirs(f"{U}/media/{lib}", exist_ok=True); os.makedirs(f"{U}/downloads", exist_ok=True)
sh(f"chown -R 1000:1000 {W}; chmod -R 2775 {U}")
base, H = up(app, f"/tmp/k7/old-{app}.yml")
print(" 1. installed from the OLD template (bind /media/" + lib + ")")
call("POST", base + "/rootfolder", H, {"path": f"/media/{lib}"})
c, lk = call("GET", base + lookup, H)
lk = lk[0] if isinstance(lk, list) else lk
qp = call("GET", base + "/qualityprofile", H)[1][0]["id"]
body = dict(lk, qualityProfileId=qp, rootFolderPath=f"/media/{lib}", monitored=True,
addOptions={"searchForMissingEpisodes": False} if app == "sonarr" else {"searchForMovie": False})
if app == "sonarr":
body["languageProfileId"] = 1; body["seasonFolder"] = True
c, item = call("POST", base + f"/{kind}", H, body)
title_path = item["path"] # /media/tv/<Title> (container path)
host_dir = f"{U}/media/{lib}/" + title_path.split(f"/media/{lib}/", 1)[1] + ("/Season 01" if app == "sonarr" else "")
os.makedirs(host_dir, exist_ok=True)
f = os.path.join(host_dir, fname.format(t=item["title"] + (f" ({item['year']})" if app == "radarr" else "")))
shutil.copy("/tmp/k7/probe.mkv", f); sh(f"chown -R 1000:1000 '{U}/media/{lib}'")
ino0 = os.stat(f).st_ino
print(" rescan ->", cmd(base, H, "RescanSeries" if app == "sonarr" else "RescanMovie"))
report(app, base, H, "OLD template")
print(" 2. updated to TODAY's template (bc54c01): one bind, the same path inside")
base, H = up(app, f"/tmp/k7/new-{app}.yml")
print(" rescan ->", cmd(base, H, "RescanSeries" if app == "sonarr" else "RescanMovie"))
report(app, base, H, "NEW template, before the repair")
print(" 3. the repair, through the app's own API, NO file moved")
new_root = f"{U}/media/{lib}"
c, r = call("POST", base + "/rootfolder", H, {"path": new_root}); print(f" add root folder {new_root} -> {c}")
c, items = call("GET", base + f"/{kind}", H)
ids = [x["id"] for x in items]
if app == "sonarr":
c, r = call("PUT", base + "/series/editor", H, {"seriesIds": ids, "rootFolderPath": new_root, "moveFiles": False})
else:
c, r = call("PUT", base + "/movie/editor", H, {"movieIds": ids, "rootFolderPath": new_root, "moveFiles": False})
print(f" editor: rootFolderPath -> {new_root}, moveFiles=false -> {c}")
print(" rescan ->", cmd(base, H, "RescanSeries" if app == "sonarr" else "RescanMovie"))
for r0 in call("GET", base + "/rootfolder", H)[1]:
if r0["path"].rstrip("/") == f"/media/{lib}":
print(f" remove the old root folder /media/{lib} -> {call('DELETE', base + f'/rootfolder/{r0['id']}', H)[0]}")
report(app, base, H, "NEW template, after the repair")
print(f" the file: same inode before and after = {os.stat(f).st_ino == ino0} (moved by nobody), size={os.path.getsize(f)}")
print("======== teardown")
for app in ("sonarr", "radarr"):
print(sh(f"cd {W}/{app} && docker compose -p k7{app} down -v 2>&1 | tail -1"))
shutil.rmtree(W, ignore_errors=True)
print("left:", sh("docker ps -aq -f name=sonarr -f name=radarr | wc -l"), "containers;", sh("docker volume ls -q | grep -c k7"), "volumes")
+17 -11
View File
@@ -124,7 +124,7 @@ stopping line that lies.
| **R-494** | Install & onboarding | P4 | **NARROWED 2026-09-14 by operator ruling → [P3-LOW] the hub COULD create the tunnel at customer creation, for a domain already on Cloudflare. Not blocking: every customer has their own domain and the operator creates the tunnel per day-0 A.1 (`architecture/01-topology-and-trust.md`).** *Original finding, kept:* **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **READY — rank P3-LOW; owner: CC** **Re-ranked 2026-10-03: P3→P4: operator-side automation; the operator creates the tunnel by hand per the day-0 runbook.** | — | — | CC |
| **R-504** | Install & onboarding | P4 | **[P3-LOW] `iso.felhom.eu` cannot show an index page on its own — its root returns 404, and the download page lives on the website instead.** MEASURED 2026-09-14: `https://iso.felhom.eu/` and `/index.html` → 404; only named objects answer. The host is an R2 bucket behind a custom domain; whether R2 would serve an uploaded `index.html` at `/` was **not measured** (uploading anything to the public bucket is a publication). The ISO v1.27.0 task puts the Hungarian download page at `felhom.eu/letoltes` (published with the ISO, after the operator's yes). **Remaining:** a redirect from `iso.felhom.eu/` to that page needs a Cloudflare rule the session has no credential for. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (Cloudflare rule)** **Re-ranked 2026-10-03: P3→P4: households are sent to the website's download page; the bare address is cosmetic.** | — | — | operator |
## Apps & catalog — 16 rows (P2 1, P3 10, P4 5)
## Apps & catalog — 19 rows (P2 1, P3 13, P4 5)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -133,17 +133,20 @@ stopping line that lies.
| **R-676** | Apps & catalog | P3 | **[P3-LOW] Watch: immich's first start restarted 12 times — decision 28's crash-loop stop (6 in 10 min) would stop it.** From the 2026-09-17 chaos night (DB connection dropped during the first-start geocoding import on a 6 GB guest; it did not recover that night). No healthy app in any drill evidence restarts on a first start (1831 samples, 40 live containers), so the threshold stands; this row exists so the first immich install under v0.269.x is watched. `audits/night-2026-09-24/A3/40-first-start-restarts.txt` **2026-09-25 night (read from source, v0.271.0): a DEPLOY's first start is NOT covered by decision 28's suppression** — `Deploying` clears when `compose up -d` returns (`deploy.go` "Clear deploying flag"), and `ObserveUnhealthy` then samples the app; an automatic update's step, verify and undo ARE covered (`Updating`, pinned by `TestD28_NoCrashLoopStopDuringAnAutomaticStep`). So a first start that restarts ≥ 6 times in 10 min is stopped — which R-676 already accepts for a broken first start; a healthy slow first start would be stopped too. **-- 2026-09-30: the first-start restarts are explained.** immich's first-start geodata import OOM-kills its database at 512M on a guest with no swap (R-732, measured: 61–104 kills); the 2026-09-17 chaos-night case (DB connection dropped during the import on a 6 GB guest) fits it. Fixed in the catalog (`56c4888`, 768M). The watch itself (decision 28 on a DEPLOY's first start) is unchanged. | **OPEN — P3; owner: CC (watch)** | — | — | CC |
| **R-994** | Apps & catalog | P3 | **Seven apps peak above 80 % of a memory limit, and 23 apps' typical use is above their catalog `mem_request`.** MEASURED 2026-10-13 (`documentation/audits/sizing-2026-10-13/SIZING.md` §3, `evidence/catalog-check.json`). Near a limit — risk: the container is stopped for using too much memory: docmost (container 475 of 512 MB), romm (703 of 768), termix (117 of 128), uptime-kuma (227 of 256, tester-1 telemetry), grafana (435 of 512), immich (`immich-server` 1,665 of 2,048 during a 200-photo import), tandoor (827 of 1,024). No container was killed during the bench. Under-stated request (typical ÷ request): calcom ×4.0, adventurelog ×3.6, termix ×3.4, claper ×2.5, grafana ×2.2, komga ×2.2, docmost ×2.1, recipe-importer ×2.1, uptime-kuma ×2.1, zipline ×2.0, and 13 more ≤ ×1.8. Templates NOT changed (read-only run). | **READY** — filed 2026-10-13 | — | Raise the seven limits and the 23 requests in their templates, each through the catalog's harness; re-measure Immich with a larger library first | CC |
| **R-1018** | Apps & catalog | P3 | **The OnlyOffice links (FileBrowser, Nextcloud) have no recorded live proof since the move to Proxmox.** `controller/internal/integrations/` holds two handlers; no audit after the Proxmox move shows a document opened from FileBrowser or Nextcloud in OnlyOffice (searched 2026-10-14). The media-app links of `15` §6 will copy this code, including its revoke-on-stop rule (`lifecycle.go:10-13`). | **OPEN** — filed 2026-10-14 | — | One live walk on a Tier-0 box: install OnlyOffice + FileBrowser, open a document, save, read it back; then stop one app and record what the link does | CC |
| **R-1026** | Apps & catalog | P3 | **The dashboard's app „restart” restarts nothing.** `RestartStack` runs `docker compose up -d`, which changes nothing when the compose did not change; it logged „Stack qbittorrent restarted successfully (took 0.1s)” while the container's StartedAt stayed the same (Tester 1, 2026-10-14, `audits/media-all-drives-2026-10-14/``D-plex-remove-deleted.txt`). So the button cannot make an app see a new drive or recover from a deleted bind source, and its success line is presence, not result. Stop + start did work. | **READY** — filed 2026-10-14 | — | Make restart a real restart (`up -d --force-recreate`, or stop+start), and make its log line state what changed; a test that asserts a new container start time. The restart notice of R-1023 depends on it | CC |
| **R-1024** | Apps & catalog | P3 | **Links for the media apps: Sonarr and Radarr connected to the download apps and to a drive by the box.** Measured calls and answer shapes: `audits/media-all-drives-2026-10-14/``tools/wire.py` + `C-wire-run2.txt`. Facts the code needs: the API key can be SET at install (`SONARR__AUTH__APIKEY`/`RADARR__AUTH__APIKEY`, measured 200/401); qBittorrent needs automatic torrent management on, or a category's folder is ignored; a Transmission entry must clear the default category („Cannot use Category and Directory”); Transmission's one incomplete folder must be off; a show with no tag gets no download app when every entry is tagged — SEEN LIVE 2026-10-14 18:50: the operator added two shows with a root folder each and no tag, and Sonarr queued 11 episodes as „Pending - Download client is unavailable” while all four entries passed Sonarr's own test (`audits/media-all-drives-2026-10-14/I-client-unavailable.txt`), so the drive choice must SET the tag; the category folders (`torrents/{tv,movies}`, `transmission/{tv,movies}`) must exist before the first grab or Sonarr raises a „remote path mapping” health error; the OnlyOffice revoke-on-stop rule (`lifecycle.go:10-13`) must NOT apply (it would delete the download entries at every restart). | **OPEN** — filed 2026-10-14 | R-1023 | Build with R-1023 | CC |
| **R-1028** | Apps & catalog | P3 | **Plex's claim code can run out during the install, and the box cannot recover it.** plex.tv's code lives 4 minutes from the moment the household copies it; the clock covers the wizard, the image pull (`plexinc/pms-docker` is 351 MB, measured) and the first start. Plex reads `PLEX_CLAIM` only on its first run, and the field is `locked_after_deploy` — so a late code leaves an unclaimed server and the only way back is remove + install again. Reported by the operator during the 2026-10-14 test; on Tester 1's line the pull+start took 8.5 s and the claim worked (`audits/media-all-drives-2026-10-14/``G-auth/G3-plex-claim.txt`), so it bites on a slow line or a slow hand. | **READY** — filed 2026-10-14 | — | Pull the image BEFORE asking for the code (or ask for it on a step after the pull), and give the household a „claim again” action that sets the code on the running server (Plex's `/myplex/claim?token=` call) | CC |
| **R-1026** | Apps & catalog | P3 | **The dashboard's app „restart” restarts nothing.** `RestartStack` runs `docker compose up -d`, which changes nothing when the compose did not change; it logged „Stack qbittorrent restarted successfully (took 0.1s)” while the container's StartedAt stayed the same (Tester 1, 2026-10-14, `audits/media-all-drives-2026-10-14/``D-plex-remove-deleted.txt`). So the button cannot make an app see a new drive or recover from a deleted bind source, and its success line is presence, not result. Stop + start did work. **Night 2026-10-14 (K5):** stop+start, or `up -d --force-recreate`, works in 2–10 s per app — but ONLY with the controller's environment: a bare `docker compose up -d --force-recreate` by hand lost every `${…}` value (Sonarr's and qBittorrent's routes became `Host(`.`)` → public 404, qBittorrent's password empty); the dashboard restart repaired it. FileBrowser has no `${…}` and recreated in 5.2 s. | **READY** — filed 2026-10-14 | — | Make restart a real restart through `composeExecCustomEnv` (`up -d --force-recreate` with the stack env), and make its log line state what changed; a test that asserts a new container start time. The restart notice of R-1023 depends on it | CC |
| **R-1024** | Apps & catalog | P3 | **Links for the media apps: Sonarr and Radarr connected to the download apps and to a drive by the box.** Measured calls and answer shapes: `audits/media-all-drives-2026-10-14/``tools/wire.py` + `C-wire-run2.txt`. Facts the code needs: the API key can be SET at install (`SONARR__AUTH__APIKEY`/`RADARR__AUTH__APIKEY`, measured 200/401); qBittorrent needs automatic torrent management on, or a category's folder is ignored; a Transmission entry must clear the default category („Cannot use Category and Directory”); Transmission's one incomplete folder must be off; a show with no tag gets no download app when every entry is tagged — SEEN LIVE 2026-10-14 18:50: the operator added two shows with a root folder each and no tag, and Sonarr queued 11 episodes as „Pending - Download client is unavailable” while all four entries passed Sonarr's own test (`audits/media-all-drives-2026-10-14/I-client-unavailable.txt`), so the drive choice must SET the tag; the category folders (`torrents/{tv,movies}`, `transmission/{tv,movies}`) must exist before the first grab or Sonarr raises a „remote path mapping” health error; the OnlyOffice revoke-on-stop rule (`lifecycle.go:10-13`) must NOT apply (it would delete the download entries at every restart). **Night 2026-10-14 (K2, `audits/media-drive-events-2026-10-14/``K2-6/K2-7`):** a NEW drive (Media C) made ready in every app by script in one run — qBittorrent categories, Sonarr/Radarr root folder + tag + two download entries, Plex and Jellyfin library folders + a scan, Plex „scan on change” on; the second run changed nothing (it re-sent equal qBittorrent category edits — the build checks before it writes). Two gaps stay: Plex needs a token (R-1046) and Jellyfin an API key (needs an admin session: the box has one only if it made the first admin). Narrowed 2026-10-14 night. | **NARROWED** — filed 2026-10-14; per-drive wiring proven idempotent on a third drive | R-1023 | Build with R-1023 from `15` §10 (the „added” rows) | CC |
| **R-1028** | Apps & catalog | P3 | **Plex's claim code can run out during the install, and the box cannot recover it.** plex.tv's code lives 4 minutes from the moment the household copies it; the clock covers the wizard, the image pull (`plexinc/pms-docker` is 351 MB, measured) and the first start. Plex reads `PLEX_CLAIM` only on its first run, and the field is `locked_after_deploy` — so a late code leaves an unclaimed server and the only way back is remove + install again. Reported by the operator during the 2026-10-14 test; on Tester 1's line the pull+start took 8.5 s and the claim worked (`audits/media-all-drives-2026-10-14/``G-auth/G3-plex-claim.txt`), so it bites on a slow line or a slow hand. **K6, 2026-10-14 night (`audits/media-drive-events-2026-10-14/``K6-1-unclaimed-plex.txt`):** an unclaimed Plex starts with no code at all, and `POST /myplex/claim?token=` on the RUNNING server reaches plex.tv (a wrong code → 500 after plex.tv's 401). So the box can pull + start first and ask for the code after: no race. A real claim needs the household's code — the morning step on the throwaway `plex-k6` on Tester 1. Narrowed 2026-10-14 night. | **NARROWED** — the claim-on-a-running-server call exists; a real claim not yet seen | the operator's claim code (morning step) | Claim `plex-k6` with a real code through that call, read `PlexOnlineToken` back; then the build: install unclaimed, never routed publicly until claimed (R-1045), ask for the code last | CC |
| **R-1029** | Apps & catalog | P3 | **Plex's folder picker shows the drives as identical „media” folders.** With one bind per drive at the same path (`/mnt/felhom-drives/<drive>/userdata/media`), the leaf of every library folder is `media`; the drive's name sits two levels up, so in Plex's picker the household sees several folders all called „media” (reported by the operator during the 2026-10-14 test on Tester 1). It conflicts with `15` §2 reason 2 (the same path everywhere). | **READY** — filed 2026-10-14 | the layout decision (STATUS D9) | Decide in `15` §2: the players (`:ro`, never linked) may get a readable path per drive (e.g. `/media/<drive label>`) without breaking the hardlink rule, which binds only the download/library apps | CC |
| **R-1036** | Apps & catalog | P3 | **The apps page lags the catalog by two apps.** `app-catalog-felhom.eu/templates/` holds **64** apps; `/alkalmazasok` and `/en/apps` render **63** cards, one of which (`filebrowser`) is built in and not a catalog template — so **62 catalog apps are listed**. Missing: **`plant-it`** and **`wger`**, both in the catalog since 2026-10-06/08. Their website assets are ALREADY present (`plant-it-logo.svg` + 3 screenshots, `wger-logo.png` + 3 screenshots, renamed to the catalog slug by `a3507761`, 2026-10-08) — only the cards were never written, so this is not a new-asset job. Found 2026-10-14 while reconciling the app count for the „felhő tárhely” page, where four places said **60** and the rest said **62**. **Done in that session:** every stated count on the site set to **62** (`index.html`, `szolgaltatasok.html`, `en/services.html` were 60), which is what the apps page actually shows — so no visitor can count the cards and find the number wrong. **62 is still not the catalog's number.** **To close:** write the two cards on both apps pages (gate 15 keeps the two pages' app sets equal, so they move together), then raise every stated count 62 → 64 in the same commit. **The operator chose this split at the 2026-10-14 STOP** over doing it inside the SEO change. | **OPEN** | — | write the `plant-it` + `wger` cards on both apps pages, then 62 → 64 everywhere, one commit | CC |
| **R-1037** | Apps & catalog | P3 | **Plex never notices new files: its automatic scan is off by default.** MEASURED 2026-10-14 on Tester 1 (`audits/media-all-drives-2026-10-14/K-plex-empty.txt`): the operator made the TV and Movies libraries with both drives' folders at ~18:35; 16 episodes and 2 films were imported from 19:07 on; at 19:15 Plex still showed 0 items, no scan running, and `Preferences.xml` carries neither `FSEventLibraryUpdatesEnabled` nor `ScheduledLibraryUpdatesEnabled` (Plex's defaults: both off). One manual `/library/sections/<n>/refresh` → 3 shows and 2 films. A household sees an empty Plex and concludes the box is broken. | **READY** — filed 2026-10-14 | — | Seed „Scan my library automatically” (and a periodic scan) at install, or let Sonarr/Radarr tell Plex after each import (their „Connect → Plex Media Server”, part of R-1024); decide with `15` §6 | CC |
| **R-1037** | Apps & catalog | P3 | **Plex never notices new files: its automatic scan is off by default.** MEASURED 2026-10-14 on Tester 1 (`audits/media-all-drives-2026-10-14/K-plex-empty.txt`): the operator made the TV and Movies libraries with both drives' folders at ~18:35; 16 episodes and 2 films were imported from 19:07 on; at 19:15 Plex still showed 0 items, no scan running, and `Preferences.xml` carries neither `FSEventLibraryUpdatesEnabled` nor `ScheduledLibraryUpdatesEnabled` (Plex's defaults: both off). One manual `/library/sections/<n>/refresh` → 3 shows and 2 films. A household sees an empty Plex and concludes the box is broken. **Night 2026-10-14 (K2):** the box can switch it on by script — `PUT /:/prefs FSEventLibraryUpdatesEnabled=1` (+ `FSEventLibraryPartialScanEnabled=1`), read back from `Preferences.xml`. Narrowed 2026-10-14 night. | **NARROWED** — the call is measured; needs the Plex token of R-1046 | R-1046 | Seed it at install with R-1024's wiring | CC |
| **R-76** | Apps & catalog | P4 | **FileBrowser-created folders break the setgid chain, and a drop-zone's mode is not stable** **MIGRATED FROM `ROADMAP.md` 2026-08-22 (R-369) — originally filed 2026-07-26, size S, roadmap state `idea (surfaced by the R-75 spike, 2026-07-26)`.** Moved verbatim; nothing added or reinterpreted. The roadmap keeps its copy as history, marked moved. | **OPEN — migrated from ROADMAP 2026-08-22, rank unchanged** **2026-10-06 night: not a catalog fix** — the setgid chain is set by the controller's FileBrowser setup; a controller row. | — | Two related findings from `audits/SPIKE-catalog-data-paths-2026-07-26.md` P3/P5, both **pre-existing** and deliberately left alone by that spike. **(a)** FileBrowser Quantum 1.3.3 creates files `0644` and folders `0755` and does **not** propagate the setgid bit — even though the entrypoint wrapper's `umask 002` really is in effect (`/proc/1/status` `Umask: 0002`). Group inheritance itself works (a file uploaded into a 2775 group-100 dir landed group 100, not the process gid 1000), so the convention's *group* half holds and only its *mode* half is lost. The consequence is proven with a control: inside a UI-created `0755` folder a gid-1000 process's file landed group **1000**, while the identical write into the 2775 parent landed group **100**. So **any folder a customer creates through FileBrowser breaks the shared-group chain one level down.** Latent today — every userdata-touching catalog app that declares an identity declares uid/gid **1000**, the same uid FileBrowser runs as, so owner permissions mask it; it bites the day a content app runs as a different non-root uid with gid 1000. The comment at `infra/infra.go:156` is right that the image ignores `-e UMASK` but does not say t | CC |
| **R-707** | Apps & catalog | P4 | **[P2] 37 apps still start with a login a stranger can take (`09` §3 decision 45).** Audit of all 53 apps: `app-catalog-felhom.eu/FIRST-ADMIN.md` (class, fix route, status, measured or read). Open: **3 hard-coded defaults** — calibre-web (`admin / admin123`, measured working on demo-hp and 9202; its own `cps.py -s` route needs a generated password WITH a special character — our generator is letters+digits, a controller change), mealie (`changeme@example.com / MyPassword`), wger (`admin / adminadmin`); **34 open first-run screens** (the first visitor creates the admin: actualbudget, adventurelog, audiobookshelf, calcom, docmost, emby, ghost, gitea, gramps-web, home-assistant, homebox, immich, jellyfin, komga, n8n, navidrome, opengist, outline, papra, plant-it, radarr, rallly, recipe-importer, romm, seerr, sonarr, sparkyfitness, tandoor, termix, uptime-kuma, vikunja, wanderer, wishlist, zipline). **Stale notes:** romm's `default_creds` `admin / admin` answers 401 on demo-hp (like a wrong password) — the page now warns with a login that does not exist; zipline's looks stale too. **Measured on demo-hp 2026-09-28 (read-only):** bookstack's default still logs in on the INSTALLED app (the fix is for new installs; the page now warns). Each fix: route (a) env or (b) the app's own CLI/API via `after_install:`, proven on 9202 with the default failing and the generated password working; route (c) a page sentence. Several sessions (operator, 2026-09-28). **2026-09-29 (controller v0.280.0, catalog `d0e7e2e`):** every class-3 app fixed — mealie, wger, calibre-web by `after_install` (calibre-web with the new `password:24:special`), proven on 9202 fresh installs (`audits/login-gate-2026-09-29/D/`); the setup gate (decision 46, spike PASSED) built and live on immich, n8n, audiobookshelf (probes measured) and uptime-kuma (button) (`…/C/`); romm's and zipline's stale notes removed. **Left: 30 class-4 apps** — gate each (probe measured on 9202 where one exists — 11 upstream candidates listed in `…/B/B-VERDICT.md` §3; the button otherwise). **2026-09-29 afternoon (controller v0.281.0, catalog `6faf432`):** 28 more class-4 apps gated — 32 of 34 — each proven on 9202 (`audits/gate-rollout-2026-09-29/`B): stranger → gate page / 401, household reached the first-setup screen, the gate opened (9 by a measured probe, the rest by the press), the app answered after. seerr, outline, rallly: gated, their opening needs a media server / e-mail (not proven). **Left:** wanderer (R-714); plant-it is not installable. | **NARROWED** (2026-10-03 triage: the row's verdict was finished, but it names open work no other row carries — seerr, outline and rallly are gated, but the gate OPENING is not proven (needs a media server / e-mail)) — **CLOSED — 2026-09-29 (the rest → R-714)** | — | — | CC |
| **R-905** | Apps & catalog | P4 | **wger's collected style files (283 MB) go into every wger backup, though the app rebuilds them at every start.** Since R-762's fix (`DJANGO_DEBUG=False` + `collectstatic`, catalog `cf1ed43`) the static files sit in a named volume that the backup legs copy like data (measured 283 MB, `audits/design-build-2026-10-06/`); `collectstatic` regenerates them, so they are rebuildable bytes in every Tier-1 unit, Tier-2 copy and off-site snapshot. wger is `lifecycle: hidden` and no box runs it (hub read 2026-10-08). Options to weigh: a non-backed-up volume class for regenerable data, or an anonymous volume. Found by the R-762 helpers 2026-10-08. | **OPEN — needs a design before wger is shown** | — | Design the „regenerable volume" exclusion (catalog + controller backup legs) | CC |
| **R-995** | Apps & catalog | P4 | **Removing an app through the product can leave unnamed Docker volumes and an empty import folder behind.** MEASURED 2026-10-13 on demo-felhom after 61 removals (`documentation/audits/sizing-2026-10-13/METHOD.md` „Teardown”, `evidence/leftover-volumes-after-bench.txt`): 8 unnamed volumes (4–72 KB; immich 1, romm 2, privatebin 3, onlyoffice 2 — volumes the images declare themselves) and `userdata/import/{paperless,calibre,grimmory}` (empty, created by the deploy). The removal answered 200 and its own leftover check was clean, because it looks only at labelled volumes. No data risk; disk and tidiness only. Removed by name on the bench. | **READY** — filed 2026-10-13 | — | Make the removal account for the containers' unnamed volumes (and an empty import folder it created), with a test that deploys an image that declares a VOLUME | CC |
| **R-1043** | Apps & catalog | P4 | **Sonarr, Radarr and Prowlarr build their login redirect as an absolute `http://` URL.** They trust forwarded headers only from their „Trusted networks” (the household set `192.168.0.0/24`; traefik is `172.18.x`), so they ignore `X-Forwarded-Proto: https` and answer `Location: http://<name>/login` to an https visitor. Since controller v0.312.0 that hop is sent back to https by traefik (a GET, no password), so it is cosmetic; a template could seed traefik's network as trusted. (`audits/https-only-2026-10-14/``1A-3-4.txt`) | **OPEN** — filed 2026-10-14 | — | Seed the docker network as a trusted proxy in the *arr templates (with the R-1030 seed), measure the redirect | CC |
| **R-1046** | Apps & catalog | P3 | **The box can drive Plex only with the household's Plex account token.** MEASURED 2026-10-14 night (`audits/media-drive-events-2026-10-14/``K2-5-plex-access.txt`): a claimed Plex answers 401 to every call without a token, even from localhost. The only token the box holds is `PlexOnlineToken` in the server's own `Preferences.xml` — the household's plex.tv account token, which also opens their account. The other way is Plex's „List of IP addresses allowed without auth” (`allowedNetworks`) set to the controller's address — no account token, but every container on that network is then trusted too. Needed for R-1024 and R-1037. | **WAITING-ON-OPERATOR** — filed 2026-10-14 night | the operator's pick of the two ways | Decide; then wire Plex with it | operator |
| **R-1047** | Apps & catalog | P3 | **Installed Sonarr and Radarr from before app-catalog `bc54c01` lose their library path on their next start.** MEASURED 2026-10-14 night on the bench (`audits/media-drive-events-2026-10-14/``K7-old-install.txt`): the old template mounted the library at `/media/tv` / `/media/movies`; after the new template's one same-path bind the root folder is missing (health „Missing root folder”), the records stay, nothing is deleted. Repair through the apps' own API, no file moved (same inode): add the same-path root folder, `PUT /series/editor` (`/movie/editor`) `rootFolderPath` + `moveFiles:false`, rescan, delete the old root folder. Left over: Radarr's collections keep the old root folder (a separate setting), and the health page shows the old warning until its next check. | **READY** — filed 2026-10-14 night | — | A one-time migration step in the controller for Sonarr/Radarr installed before `bc54c01` (the K7 calls + Radarr's collection root); find which boxes have one | CC |
| **R-1048** | Apps & catalog | P3 | **Prowlarr into the live catalog (full new-app checklist), linked by the box.** Today it is in the drill catalog only (test, 2026-10-14): config in a named volume, no media folders; the box linked it to Sonarr and Radarr by script (Prowlarr → Settings → Apps, full sync — `audits/media-all-drives-2026-10-14/tools/wire.py`). The live catalog needs the full new-app checklist (`app-catalog-felhom.eu/REUSE.md`), Hungarian copy, the apps page, and the link made by the box at install. | **READY** — filed 2026-10-14 night | — | Add it with the checklist; the link with R-1024 | CC |
## App updates — 4 rows (P3 4)
@@ -190,20 +193,21 @@ stopping line that lies.
| **R-878** | Backup & restore | P4 | **A catch-up (R-871) runs the database-dump leg in the DAY, and that leg stops an app with a volume for its copy — the household may notice the stop, and a large volume makes it longer.** MEASURED 2026-10-05 on demo-felhom: the catch-up at 08:25:02 stopped opengist, copied 182.5 KB, started it again — about 1 s, then a few seconds of `health: starting`; the night does exactly the same, unseen. Nothing measured for a large volume. Fix direction (if it matters): skip the volume copy of a running app in a DAYTIME catch-up and leave it to the next night, or warn. `audits/catchup-2026-10-05/partA/live-demo-felhom.txt` | **READY — owner: CC** **2026-10-05 (burn-down night): NEEDS A LIVE MEASUREMENT** — a timed catch-up on 9202 for an app with a multi-GB volume, then the skip-or-warn choice. | — | measure a large volume first | CC |
| **R-32** | Backup & restore | P4 | **[P2-HIGH] RESET must purge the customer base dir; the orphan card must stay honest; unattributed bytes must be visible.** The rehearsal's S7 said in advance that an orphan card would BE a finding — and one appeared (16:58:14). Cause: RESET's `"hetzner":"ok"` leg destroys the sub-account, but **a Hetzner sub-account is an access-control object, not a data object** — its directory survives, so re-enabling offsite recreated an account over the previous lifecycle's ciphertext, encrypted under a key that same RESET had destroyed. **MIGRATED FROM `ROADMAP.md` 2026-08-22 (R-369) — originally filed 2026-07-21, size M, roadmap state `idea`.** Moved verbatim; nothing added or reinterpreted. The roadmap keeps its copy as history, marked moved. | **OPEN — migrated from ROADMAP 2026-08-22, rank unchanged** **2026-10-06 night: design written** (`audits/night-burndown-2026-10-06/design-R-32.md`) — pick A: purge the repo + set-aside copies through the sub-account's own password login BEFORE deleting it (no main-account credential); the „repo data destroyed" comment at `hub/internal/offsite/offsite.go:276-280` is false for the shared tier; part (3) waits on a read-only measurement (`du` on port 23). Operator: agree to route A. **2026-10-07 07:58: `09` §3 decision 167 — option A yes, and delete the old RESET leftovers once.** **2026-10-07 (Part D step 2, read only):** the hub shows bx11 holding 3.3 GB of data while the four live customers account for ~0.6 GB → **~2.7 GB belongs to no live customer**; no live customer shows a set-aside folder, so the leftovers are in homes whose sub-account is gone, reachable only by the pool box's MAIN account. **The one-time clean-up is STOPPED:** no main-account login for bx11 is held on DooPlex (the API token in the credentials file sees no box). Needs: the main-account login, or the operator lists and deletes in the Hetzner console (`audits/day-2026-10-07/D/D2-listing-readonly.txt`). **2026-10-07: option A DELIVERED (hub 0.142.0):** RESET purges the repo and every `.orphaned-*` through the sub-account's own login before deleting it, and keeps the sub-account if the purge fails (red-proved, `audits/day-2026-10-07/D/`). Not yet seen live (no scratch RESET today). **The one-time clean-up of the ~2.7 GB of leftovers is STOPPED:** it needs the pool box's main-account login (see above). **2026-10-07 14:43 — `09` §3 decision 173: leave the ~2.7 GB of old leftovers for now; re-ranked P2 → P4.** Option A itself is delivered (hub 0.142.0). What stays open is ONLY the leftovers: they were computed (box total minus live customers), never listed, and deleting them needs the pool box's MAIN login, which reaches every customer's data. **Blocker: a safe main-account path.** | — | **Ruling from the run (three parts, deliberately separate):** (1) because RESET destroys custody, the ciphertext it leaves behind is unrecoverable **BY DESIGN** → RESET gains a **main-account purge of the customer base dir** (the existing operator ack already covers it); (2) the **move-aside guard STAYS** for reinstall-*without*-RESET — there custody survives and the card's "history recoverable" promise is true (R-26 depends on exactly that); (3) the operator **Restic tab shows per-customer directory bytes vs attributed snapshot bytes**, so dead data cannot hide. Measured on the pool box that night: **49 M attributed** (2 snapshots, 48.717 MiB) against **1.4 G + 3.0 M unattributed** across TWO `.orphaned-*` dirs. Evidence `restic-and-pool.txt` | CC |
## Storage & devices — 8 rows (P2 5, P3 2, P4 1)
## Storage & devices — 9 rows (P2 6, P3 2, P4 1)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
| **R-1027** | Storage & devices | P2 | **„Delete my data too” deletes every bind under the app's drive — read-only and shared ones included.** MEASURED 2026-10-14 on Tester 1: removing a throwaway Plex (drill template: `/mnt/felhom-drives/media_a/userdata/media` bound `:ro`, `HDD_PATH=/mnt/felhom-drives/media_a`) with `remove_hdd_data:true` logged „Removed HDD data: /mnt/felhom-drives/media_a/userdata/media (80K)” — the WHOLE media folder of the drive, which four other apps were using. `ParseComposeHDDMounts` counts a literal path under `HDD_PATH` as the app's own data, and `ProtectedHDDPaths` does not protect `userdata/media` (R-1032). Only an empty test skeleton was lost; it was rebuilt by the controller's next file-browser sync and the apps restarted (`audits/media-all-drives-2026-10-14/``D-plex-remove-deleted.txt`). Today's LIVE templates bind `${USERDATA_PATH}` and are not hit (R-800); **the media-library build (R-1023) would be, unless removal learns that a shared library is never one app's data.** The note „literal binds are never removed” in this session's first draft was WRONG and is retracted. | **READY** — filed 2026-10-14 | — | Removal: never delete a `:ro` bind nor anything under `userdata/`; a test that removes a reader app and asserts the shared folder survives (red-proof first); `15` §8 | CC |
| **R-1023** | Storage & devices | P2 | **Build: media apps see every drive, and the box says when they must restart (operator rulings 2026-10-14, `09` §3).** Scope from `architecture/15-media-library.md`: one bind per drive of `userdata/media/<library folders>` at the same path; the drive-absent gate per bind (today it keys on the app's one `HDD_PATH`, and the boot gate waits only for THAT drive — measured after the 17:25 power cut); the restart notice after a drive is added, removed or comes back, with „restart now” / „later” and a per-drive „apps restarted since” mark; removal, export and backup classes taught that a shared library is no app's own (R-1027, R-1019). **S5/S6 measured 2026-10-14:** a pulled drive stops none of the media apps (they key on another drive), they keep a dead view; on return nothing restarts them — so the restart notice MUST also cover „a drive came back”, the restart must be stop+start, and Sonarr/Radarr's own health page says nothing about an unreachable root folder, so the box must say it. | **OPEN** — filed 2026-10-14; design in `15` (S5/S6 results pending the operator's test) | the operator's test on Tester 1 („done”), then S5/S6 | Finish `15` with S5/S6; then a build task | CC |
| **R-1023** | Storage & devices | P2 | **Build: media apps see every drive, and the box says when they must restart (operator rulings 2026-10-14, `09` §3).** Scope from `architecture/15-media-library.md`: one bind per drive of `userdata/media/<library folders>` at the same path; the drive-absent gate per bind (today it keys on the app's one `HDD_PATH`, and the boot gate waits only for THAT drive — measured after the 17:25 power cut); the restart notice after a drive is added, removed or comes back, with „restart now” / „later” and a per-drive „apps restarted since” mark; removal, export and backup classes taught that a shared library is no app's own (R-1027, R-1019). **S5/S6 measured 2026-10-14:** a pulled drive stops none of the media apps (they key on another drive), they keep a dead view; on return nothing restarts them — so the restart notice MUST also cover „a drive came back”, the restart must be stop+start, and Sonarr/Radarr's own health page says nothing about an unreachable root folder, so the box must say it. **Night 2026-10-14 measured every event × app (`15` §10, `audits/media-drive-events-2026-10-14/`):** nothing is lost while a drive is gone (K1), so the build needs NO scan/unmonitor/torrent guard; it DOES need: (1) one bind per PRESENT drive only — a bind to an absent path makes the app unstartable (K3-4: 500 „error while creating mount source path … permission denied”); (2) the media apps recreated without the drive BEFORE a safe removal unmounts it (R-1044); (3) a returned drive restarts every container that binds it, FileBrowser included (K5: 2–10 s per app); (4) „restart now” cuts a playing stream (K5-4: cut, back in 22 s) — check Plex/Jellyfin sessions first or offer „later”; (5) the stale view is found with NO disk I/O: each container's `/proc/<pid>/mountinfo` shows the old device with `shutdown` (K4). Narrowed 2026-10-14 night. | **NARROWED** — filed 2026-10-14; every drive event measured (`15` §10); design complete for a build | — (decision 245, option A) | A build task from `15` §10 and the build plan in `REPORT-night-2026-10-14.md` | CC |
| **R-1031** | Storage & devices | P2 | **The build must not ask a media app for one drive.** Today every media template carries a required `HDD_PATH` field („Médiatár útvonal”, `locked_after_deploy`), so the wizard makes the household pick ONE drive — the opposite of `09` §3 decision 237 — and the drive gate, removal and backup key on that one drive (`15` §4, §8). The test rig kept the field only because the deploy needs it. | **READY** — filed 2026-10-14 | R-1023 | In the build: a media app (`15` §3 marker) has no drive field; its own config stays on the system SSD; its library binds come from the enrolled drives | CC |
| **R-1032** | Storage & devices | P2 | **The delete safety list still names the old folder layout.** `ProtectedHDDPaths` (`felhom-controller/controller/internal/stacks/delete.go:240`) protects `<drive>/media` and `<drive>/Dokumentumok` — the layout before `userdata/` — and NOT `<drive>/userdata`, `userdata/media` or `userdata/documents`. That is why removing a Plex deleted `userdata/media` (R-1027). It touches every app with a drive bind, not only media apps. | **READY** — filed 2026-10-14 | — | Protect the current skeleton roots (`userdata` and its top folders) and keep the old names; a test that fails when a skeleton root is missing from the list (red-proof first). Fix with R-1027 | CC |
| **R-1038** | Storage & devices | P2 | **After a drive comes back, the file browser (and every app that binds it) still shows the DEAD drive: „I/O error”.** MEASURED 2026-10-14 on Tester 1 (`audits/media-all-drives-2026-10-14/S5-S6/`): Media B's disk was pulled at 20:10:23 and re-attached at 20:41:00. The guest kept a dead ext4 mount of `/mnt/felhom-drives/media_b` the whole time (`mountpoint` = yes, `ls` = Input/output error); on return the agent bound the new disk ON TOP of it (two stacked mounts), the controller logged „drive RETURNED … restarted gate-stopped apps” and „FileBrowser sync — no config/compose change, ensured running without recreate” — so FileBrowser kept the dead mount: `ls /srv/media_b/media/tv` → I/O error, 4 minutes after the drive was back. The same was true for all six media apps until they were stopped and started. During the pull the box also tried to rebuild the skeleton ON the dead mount („chmod … input/output error”), because the drive-absent gate asks „is it a mountpoint?” and a dead mount answers yes. Today's product: any household whose USB drive drops and returns hits this in FileBrowser. **And the household cannot fix it:** FileBrowser is a protected stack — the dashboard answers `POST /api/stacks/filebrowser/stop` and `/start` with 403 „cannot stop protected stack filebrowser” (measured 20:46) — so only a restart of the whole box clears it. | **READY** — filed 2026-10-14 | — | On drive return, recreate FileBrowser (and every container that binds the drive) — stop+start, not `up -d` (R-1026); on drive loss, make the guest's mount go away (or treat an I/O-error mount as absent) so the gate and the skeleton see the truth; a test with a dead mount | CC |
| **R-1038** | Storage & devices | P2 | **After a drive comes back, the file browser (and every app that binds it) still shows the DEAD drive: „I/O error”.** MEASURED 2026-10-14 on Tester 1 (`audits/media-all-drives-2026-10-14/S5-S6/`): Media B's disk was pulled at 20:10:23 and re-attached at 20:41:00. The guest kept a dead ext4 mount of `/mnt/felhom-drives/media_b` the whole time (`mountpoint` = yes, `ls` = Input/output error); on return the agent bound the new disk ON TOP of it (two stacked mounts), the controller logged „drive RETURNED … restarted gate-stopped apps” and „FileBrowser sync — no config/compose change, ensured running without recreate” — so FileBrowser kept the dead mount: `ls /srv/media_b/media/tv` → I/O error, 4 minutes after the drive was back. The same was true for all six media apps until they were stopped and started. During the pull the box also tried to rebuild the skeleton ON the dead mount („chmod … input/output error”), because the drive-absent gate asks „is it a mountpoint?” and a dead mount answers yes. Today's product: any household whose USB drive drops and returns hits this in FileBrowser. **And the household cannot fix it:** FileBrowser is a protected stack — the dashboard answers `POST /api/stacks/filebrowser/stop` and `/start` with 403 „cannot stop protected stack filebrowser” (measured 20:46) — so only a restart of the whole box clears it. **Night 2026-10-14 (K1, K4, `audits/media-drive-events-2026-10-14/`):** the DEAD mount is what keeps a household's libraries safe — every app treats its I/O errors as „unavailable” and deletes nothing (K1); an EMPTY folder in its place could read as „all files deleted”. So the fix must NOT replace the dead mount by an empty folder under a running app. The no-I/O check is `/proc/self/mountinfo` super options containing `shutdown` (K4 check A); a timed `stat` said „ok” on the dead drive from the cache (check B — unreliable, do not use). Narrowed 2026-10-14 night. | **NARROWED** — the detection is measured; the safe direction is fixed | — | With R-1023: on return restart every container that binds the drive; gate and skeleton read `shutdown` from mountinfo; never an empty folder under a running media app | CC |
| **R-330** | Storage & devices | P3 | **Disk health Phase 2 — the three SMART attributes the wire does not carry.** The failing drive's most telling counter was **187 `Reported_Uncorrect`**, sitting at normalized **1** against threshold **0** with a raw count of **1001** — one point from failing and structurally unable to get there. Also wanted: **199 `UDMA_CRC_Error_Count`** (cabling) and **188 `Command_Timeout`**. None are on the agent→controller wire today, so v0.215.0's ladder could not use them. Phase 2 also persists periodic SMART **samples** (the right home is `metrics.MetricsStore`, NOT the Phase-1 state file, which is one record per disk and must stay that way). **This is a declared WIRE change, so under the G-1 gate the hub must model the new fields in the SAME session** — that is precisely why it was kept out of Phase 1, where it would have turned a one-word severity fix into a three-repo change | **READY** — **2026-10-12: the wire half is CLOSED in this row** — released in agent v0.150.0 (boxes run 0.154.0), controller and hub decode 187/188/199. **Only open work:** the verdict slice (use the three counters in the disk verdict and the household's words) and persisting samples. **READY (M) — NEW 2026-08-14** **2026-10-06 night: the wire half BUILT on main (unreleased):** the agent sends SMART 187 `reported_uncorrect`, 188 `command_timeout` (raw, vendor-packed on some drives — carried as reported), 199 `udma_crc_errors` (pointer + omitempty: unknown is absent, never 0); the controller decodes them and the hub's host-report mirror models them (G-1 wire gate green; it convicted the agent half alone). **Carried only** — no verdict, banner, mail or alarm reads them (`TestR330_CountersChangeNoVerdictYet`); using them changes what a household is told and is the next slice, with persisting samples. Red-proofs `audits/night-burndown-2026-10-06/r330/`. Ships with agent v0.150.0 and the next controller and hub releases. | R-328 (closed) | The verdict slice: 187/188/199 into the disk verdict with tests; then persist samples | CC |
| **R-332** | Storage & devices | P3 | **The new Hiba-from-counters path has never fired on real hardware.** v0.215.0's whole point is a verdict the product could not previously reach, and it is proven only against the committed fixture's values in unit tests (12 scenario groups, 11 of 12 red-proofs failing as required). The live validation on demo-hp proved the **negative** — three healthy disks still read Rendben across the deploy, no false alert — and the **severity wire** end to end, but no live disk has actually reached Hiba. **This is the honest gap and it must not be closed by pointing at the fixture tests**: the drive that produced the fixture is in DooPlex, which is Tier 2 and never a drill target, and the demo boxes are all-flash and healthy | **WATCHING — NEW 2026-08-14, NARROWED same day.** One item originally in this gap is now PROVEN LIVE: the **persisted state surviving a controller restart**. The v0.215.0→v0.216.0 redeploy destroyed and rebuilt the container, and the new one read back a `changed_at` written by the PREVIOUS version (`2026-08-14T07:23:14.640216851Z`, still intact at 09:31:35Z) instead of re-baselining — Scenario L on real hardware, not just the production-path unit test. **What remains unproven is the verdict itself, plus the stronger restart half: an already-ALERTED disk not re-alerting** | a real degrading disk, or an injection harness | **Closing condition:** a live disk reaching Hiba from counters, OR a deliberate injection through the REAL pipeline (agent `/disks` → controller check → hub event), not a hand-set verdict | CC |
| **R-331** | Storage & devices | P4 | **Disk health Phase 3 — growth-rate detection, and retiring the static 64.** The v0.215.0 count backstop (64 unreadable sectors → Hiba) is **a judgement from ONE drive**: the observed benign excursion peaked at 16 and cleared inside an hour, and the terminal run passed 64 at 13 Aug 11:28 and never came back. It is deliberately a backstop BEHIND the sustain rule, not the primary signal, but it is still a magic number tuned on a single sample and it will be wrong for some drive. With Phase 2's history the box can ask the question that actually matters — *is this count climbing, and how fast* — which distinguishes a drive with eight stable aging sectors from one adding forty a day, something no static threshold can do. Revisit 64 when that exists | **READY (M) — NEW 2026-08-14** | R-330 | Growth-rate rule over persisted samples; re-derive or delete the static 64 | CC |
| **R-1044** | Storage & devices | P2 | **„Safe removal” of a media drive is not safe while the media apps run.** MEASURED 2026-10-14 night on Tester 1 (`audits/media-drive-events-2026-10-14/``K3-3-eject.txt`): `POST /api/storage/eject` for Media C made the agent detach the guest's bind (the guest then shows an EMPTY folder) and keep the raw host mount, and the controller deregistered the drive — but the running media containers still HELD the filesystem and read its files after the „safe” removal. So pulling the disk then is a pull of a mounted, in-use filesystem. Also: after re-attaching, the agent mounted it again but the drive stayed unregistered until „Meglévő meghajtó csatolása” (`register-mounted`) — a household step after every safe removal. Restarting an app after the eject failed (K3-4: the bind source is gone → 500). | **OPEN** — filed 2026-10-14 night | R-1023 | Safe removal = pause that drive's torrents → recreate the media apps without its bind → unmount; keep the drive registered as „removed safely” so its return needs no household step; a test on the order of the three | CC |
## Security & access — 20 rows (P1 2, P2 3, P3 10, P4 5)
## Security & access — 21 rows (P1 2, P2 4, P3 10, P4 5)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -227,6 +231,7 @@ stopping line that lies.
| **R-779** | Security & access | P4 | **[P3-LOW] Part A's "two outside addresses seen as two" is proven through the simulated tunnel only; on the REAL tunnel the second outside address (ep0, one request allowed) was refused by Cloudflare's edge with 403 and never reached the box.** Measured 2026-10-01 19:51 UTC (`audits/visitors-2026-10-01/A/L2-demo-hp-real-tunnel.txt`): no log line on demo-hp; demo-hp's box has no geo restriction in its settings, so a Cloudflare ZONE rule (country or bot, not read) refused a German datacenter address. DooPlex's own address on the real tunnel was seen as itself. **Needs:** one sign-in from a second Hungarian address (the operator's phone off wifi) while DooPlex is locked out — 2 minutes; and say which Cloudflare rule refused ep0. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (a phone), CC reads the logs** **Re-ranked 2026-10-03: P3→P4: a proof gap on the real tunnel; operator-only follow-up.** | — | — | CC + operator |
| **R-904** | Security & access | P4 | **Cloudflare can read every household's app traffic; replacing it with our own relay is a later item.** Facts (reviewer discussion 2026-10-08; `01`): app traffic and the dashboard reach the box through the Cloudflare Tunnel (`01` §5 trust table, rows end-user ↔ apps and customer ↔ controller UI; §7), and the tunnel's public end is Cloudflare's edge, where TLS ends — so Cloudflare can technically read that traffic (the FAQ says so since 2026-10-08, R-900; „TLS ends at the edge" is not written in `01` — add it there). What Cloudflare gives today, free: inbound reach with no router setup, the CGNAT answer (`01` §4, §7); certificates (`01` §7, the free tier covers one level below a zone); the geo-WAF the hub enforces (`01` §5 last row, §7); flood protection (not in `01`). The alternative named: our own EU relay over WireGuard with TLS passthrough by SNI, certificates on the box, the geo-block on the relay. Its costs: one more machine the operator keeps up, and a single point of reach for every box; weaker flood protection; about a week of work after a spike. Operator ruling 2026-10-08 09:07 (`09` §3 decision 184): a later item. | **DEFERRED** — **2026-10-10: the asked sentence is in `01` §7** („TLS ends at Cloudflare's edge …”); the spike stays deferred. **DEFERRED — after the first customers (operator ruling 2026-10-08 09:07)** | — | A spike after the first customers (the relay's reach, cost and flood behaviour, measured) | operator |
| **R-1040** | Security & access | P4 | **Until the household makes Sonarr's or Radarr's first admin, any container on the box can read the app's API key.** Measured on the bench 2026-10-14 with the R-1030 seed in place: `AuthenticationRequired=Enabled`, `AuthenticationMethod=None` — `/initialize.json` from another container answers 200 with `apiKey`. Outsiders are blocked by the box's setup gate in that window; a compromised other app is not. | **OPEN** — filed 2026-10-14 | — | Seed the API key at install (`SONARR__AUTH__APIKEY`, measured to work) so the box knows it, and close the window by telling the household in the first steps; or seed a Forms user | CC |
| **R-1045** | Security & access | P2 | **An unclaimed Plex answers everything without a token to a private address — and through the tunnel every request comes from one.** MEASURED 2026-10-14 night on a throwaway `plex-k6` on Tester 1 (`audits/media-drive-events-2026-10-14/``K6-1-unclaimed-plex.txt`): with no claim, `/library/sections`, `/:/prefs` and `/myplex/account` answer 200 with NO token from the Docker network. Through cloudflared, Plex sees cloudflared's private address, so a publicly routed unclaimed Plex would be open to anyone — server settings and every library. R-1028's late code leaves exactly such a server. NOT measured over the public path (the throwaway had no route). Harm if true: a household's media and Plex settings open to the internet. | **OPEN** — filed 2026-10-14 night | — | Measure on a throwaway with a public route on a Tier-0 box (P1 if it holds); the build: no public route until `PlexOnlineToken` is set | CC |
## Box system & updates — 11 rows (P2 1, P3 7, P4 3)
@@ -245,7 +250,7 @@ stopping line that lies.
| **R-1010** | Box system & updates | P3 | **The agent's stale-lock janitor cannot remove a half-removed `vzdump` snapshot: Proxmox's delete fails on the first missing volume („Failed to find logical volume pve/snap_vm-9201-disk-0_vzdump") and the janitor retries the same call every 10 min forever, leaving the other volume's snapshot and the snapshot entry.** Seen 2026-10-14 after a backup ran out of space on a full host root (LVM could not write its metadata; `audits/power-cut-fixes-2026-10-14/README.md` C4). Fixed by hand with `pct delsnapshot 9201 vzdump --force`. | **READY** — filed 2026-10-14 | — | CC: on that error, retry once with `--force` (a sudoers line or the API's `force=1`), with a test that replays the error text; next agent release | CC |
## Monitoring & notifications — 9 rows (P2 1, P3 5, P4 3)
## Monitoring & notifications — 10 rows (P2 1, P3 6, P4 3)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -258,6 +263,7 @@ stopping line that lies.
| **R-724** | Monitoring & notifications | P3 | **[P3-LOW] The status pages disagree with each other in small ways a household notices.** MEASURED 2026-09-29 on a fresh box: Beállítások reads „Mentés ütemezés 02:30 / 03:00" while Biztonsági mentés says 02:30 / 03:30 / 04:15 / 04:30–08:30; Beállítások shows a raw `2026-09-29T19:22:30Z`; its „Helyi cím (LAN)" and „Átjáró" read „nem állapítható meg" on the page the household is asked to read out for remote help; the backups overview still says „Következő mentés — 0 órája" (the age of the LAST run, under the word "next" — noted 2026-09-14, never filed); the dashboard shows the backup at 19:33 where the backup pages say 21:33 (R-500, still reproducing). **FIXED 2026-09-30 (controller v0.283.0):** Beállítások shows the real schedule and a local time; the dashboard's last backup is local time (R-500); „az előző N órája készült" replaces „0 órája". **NARROWED — remaining:** „Helyi cím (LAN)" / „Átjáró" read through the file-sharing container, so a box without it says „nem állapítható meg" — not a text fix (the read needs another path). | **NARROWED — the LAN/gateway read only; owner: CC** **2026-10-06 night: confirmed not a controller-only fix** — the only host-network container is samba (`infra/samba.go:123`) and the agent's local API has no guest-network route; the fix is a new agent route (e.g. the PVE lxc interfaces read) + a controller reader — a two-repo design. | — | — | CC |
| **R-285** | Monitoring & notifications | P4 | **A planned, supervised reinstall pages the operator as if the machine had died — there is no notion of expected downtime anywhere.** During the 2026-08-09 rehearsal the hub sent, all `status: sent` to the operator channel: `host_stale` 08:58 UTC, `node_stale` 09:00, **`host_down` 09:28 (error)**, **`node_down` 09:30 (error)**, `host_leaf_changed` 09:31, `host_recovered` 09:31, `node_recovered` 09:34, `offsite_delivery_stuck` 09:34 — eight operator mails for work that was deliberate, attended and announced. **This is the OPPOSITE gap from the one R-281 filed:** the alarms are not missing, they are indiscriminate. `host_stale` at 30 min and `host_down` at 60 min (`monitor/host_staleness.go:22-23`, `downAfter = 2 * threshold`) cannot distinguish a wiped-on-purpose box from a dead one, and `host_leaf_changed` firing on a reinstall is correct-but-expected. **Note the interaction with the mute used on 2026-08-09 evening:** blocking a customer silences everything, so today the only two settings are *page me for planned work* and *tell me nothing at all*. **What is owed is a middle:** a maintenance window, or an operator-set expected-downtime flag, that suppresses staleness and leaf-change while leaving genuine faults audible | **READY (M) — NEW 2026-08-09** | — | The evidence is the operator's mailbox plus `events`/`notification_log` for 2026-08-09 | CC |
| **R-1005** | Monitoring & notifications | P4 | **A recovery mail says how long the box was „stale", not how long it was gone: after a 51-minute power cut demo-hp's `host_recovered` read „was stale for 8m" and `node_recovered` „23m".** An operator reading only the recovery mail under-reads the outage (`audits/night-power-2026-10-13/` R6). Same kind, the other way: the off-site mail of 2026-10-14 02:18 was titled „3 of 3 apps failed to back up (offsite run)" while 11 other apps were backed up in that run — only the 3 flagged apps were counted. | **READY** — filed 2026-10-14 | — | CC: add the time since the last report before the gap to both recovery messages, and count every app of the run in the off-site subject, with a test that asserts each text; next hub release | CC |
| **R-1049** | Monitoring & notifications | P3 | **A pulled drive mails the operator „unexpectedly disconnected” (error), and nothing ever mails that it came back.** MEASURED 2026-10-14 night (`audits/media-drive-events-2026-10-14/K8-hub-mails.txt`, the hub DB with its WAL from the running pod, and the mailbox as the second channel): two pulls → two `storage_disconnected` mails; the hub RECEIVED both `storage_reconnected` and both `health_recovered` (severity info) and logged no notification for any of them — they are not in `recoveredPairedDownTypes` (`hub/internal/notify/dispatcher.go`), so the severity gate drops them. The R-97a shape: told it broke, never told it healed — the operator cannot tell a returned drive from one still gone without opening the hub. | **READY** — filed 2026-10-14 night | — | Add `storage_reconnected` → `storage_disconnected` (and `health_recovered` → `health_degraded`, if the down mailed) to the recovery pairs; a test that the pair mails both edges | CC |
## Hub & operator — 12 rows (P3 7, P4 5)
@@ -303,7 +309,7 @@ stopping line that lies.
|---|---|---|---|---|---|---|---|
| **R-992** | Process & tooling | P3 | **The drill-catalog route that `09` §6.5 documents cannot be followed: `admin/app-catalog-drill` is PRIVATE and no box has catalog credentials.** Measured 2026-10-12 while publishing the Usenet pair: the box's clone fails with `fatal: could not read Username for 'https://gitea.dooplex.hu'` (exit 128), the Gitea API reports the drill repo `private=true` and the live catalog `private=false`, and NEITHER the current controller.yaml on 9202 NOR any of its 30 saved copies has ever carried `git.username` or `git.token` (the controller supports both — `internal/config/config.go` GitConfig). The route worked for the campaigns of 2026-10-10 and the torrent pair earlier the same day, so the repository's visibility changed between then and now. **Worked around, not fixed:** that campaign staged its two templates in the box's own catalog cache (`audits/usenet-2026-10-12/tools/stage_in_cache.py`), which is where the sync copies a catalog change anyway, with the sync interval raised to 12h for the duration and rescan used in place of sync. The real fix is an operator decision: either a read-only catalog credential on the scratch box (a secret on a Tier-0 guest) or making the drill repository readable. Until then every new-app campaign hits this. | WAITING-ON-OPERATOR | the operator's choice between a box credential and a readable drill repo | Decide; then either set `git.username`/`git.token` on 9202 from the credentials store, or flip the drill repo, and correct `09` §6.5 either way | operator |
| **R-1017** | Process & tooling | P3 | **A comment names a guard test that does not exist.** `felhom-controller/controller/internal/appbackup/paths.go:58` says „`TestNoBareDrivePathToUserdataDir` is the guard that keeps the count from growing”; no test of that name (or `NoBareDrive*`) exists in the repo (grep 2026-10-14; positive control: `TestRemoveStack_R800_UserdataKeptIsNamed` is found). A comment asserting an invariant with no test pinning it — the class in the `felhom-testing` skill. | **READY** — filed 2026-10-14 | — | Write the guard (a test that fails when a bare drive path reaches `UserdataDir`), red-proof it, or correct the comment | CC |
| **R-1022** | Process & tooling | P3 | **Tester 1 follows the drill catalog and carries two test drives — teardown owed (operator ruling (e), 2026-10-14).** Steps, only on the operator's word: (1) remove the test apps (Sonarr, Radarr, qBittorrent, Transmission, Plex, Jellyfin) through the dashboard WITHOUT „delete data” (R-1027); (2) decommission Media A and Media B through Tester 1's dashboard; (3) `repoint.py restore` — `controller.yaml` from `controller.yaml.pre-media-2026-10-14`, read back byte-identical, `repo_url` the live catalog; remove `drill-catalog.git` from the controller volume; (4) on demo-hp: `qm set 341 --delete scsi2,scsi3`, then delete the two volumes BY NAME (`nvme-scratch:341/vm-341-disk-3.raw`, `-disk-4.raw`) — never `qm destroy`; (5) VM memory unchanged (8192, not raised); (6) drill repo reset to live `main`. Tools: `audits/media-all-drives-2026-10-14/``tools/`. | **WAITING-ON-OPERATOR** — filed 2026-10-14 | the operator's teardown word | Run the six steps; quote each read-back | CC |
| **R-1022** | Process & tooling | P3 | **Tester 1 follows the drill catalog and carries two test drives — teardown owed (operator ruling (e), 2026-10-14).** Steps, only on the operator's word: (1) remove the test apps (Sonarr, Radarr, qBittorrent, Transmission, Plex, Jellyfin) through the dashboard WITHOUT „delete data” (R-1027); (2) decommission Media A and Media B through Tester 1's dashboard; (3) `repoint.py restore` — `controller.yaml` from `controller.yaml.pre-media-2026-10-14`, read back byte-identical, `repo_url` the live catalog; remove `drill-catalog.git` from the controller volume; (4) on demo-hp: `qm set 341 --delete scsi2,scsi3`, then delete the two volumes BY NAME (`nvme-scratch:341/vm-341-disk-3.raw`, `-disk-4.raw`) — never `qm destroy`; (5) VM memory unchanged (8192, not raised); (6) drill repo reset to live `main`. Tools: `audits/media-all-drives-2026-10-14/``tools/`. **Added 2026-10-14 night:** (4b) Media C — `qm set 341 --delete scsi4`, then the volume `nvme-scratch:341/vm-341-disk-5.raw` by name (decommission it on the dashboard first; it holds 4 test files); (7) the throwaway Plex `plex-k6` on Tester 1 (`docker rm -f plex-k6`, `docker volume rm plex-k6-config`) after the morning claim step; (8) drill commit `925f3fd` (media_c binds) goes with step 6; Prowlarr and the test drive tag „driva-a” go with step 1. Tools also in `audits/media-drive-events-2026-10-14/tools/`. | **WAITING-ON-OPERATOR** — filed 2026-10-14 | the operator's teardown word | Run the six steps; quote each read-back | CC |
| **R-1034** | Process & tooling | P3 | **Gate 17 checks the FAQ JSON-LD on two pages only, by a hard-coded list — a FAQPage anywhere else is unchecked.** `scripts/site_gates.py` gate 17 loops `for p in ("gyik.html", os.path.join("en", "faq.html"))`, so its „JSON-LD equals the visible questions and answers” guarantee stops at those two files. **Since 2026-10-14 two more pages carry a FAQPage block the gate never reads:** `/sajat-felho-tarhely` and `/en/own-cloud-storage`. Their JSON-LD was *derived* from the visible headings and paragraphs by a script and then verified verbatim against the rendered text, so it is correct today — but nothing stops the next copy edit moving the visible text and leaving the structured data behind, which is exactly the failure gate 17 exists to catch, and the one Google penalises. **Why it is not a one-line fix:** gate 17's extractor is written for the FAQ pages' accordion markup (`<button class="faq-question">` … `<div class="faq-answer-inner">`); the new pages use plain `<h2>` + `<h3>`/`<p>` sections, so widening the scope needs a second extractor beside the first. **Scope is a fact** (repo `CLAUDE.md`: prefer a walk over a hand-maintained list) — the gate should scan **every page containing a FAQPage block**, not a named pair, or the next page to carry one is unguarded in the same way. A decoy is owed for the widened gate (R-421). | **OPEN** | — | widen gate 17 to every page carrying a FAQPage block, second extractor + decoy | CC |
| **R-987** | Process & tooling | P4 | **The 53 catalog app images have never been scanned for known vulnerabilities.** Fix: a monthly trivy pass over the images the catalog pins, reported, not gating. | OPEN | — | Add to the monthly re-test | CC |
| **R-986** | Process & tooling | P3 | **No dependency or secret scanner runs on any push, so a known-vulnerable library or a committed key is found only by a review like this one.** Proposed gate: govulncheck (called vulns only), gitleaks on the diff, trivy on our own images; start as WARN with an accepted-hits file, then FAIL. Tools and pinned versions: `audits/security-review-2026-10-12/SCANNERS.md`. Note: gitleaks' default rules did not find R-908's key. | OPEN | — | Build the gate, warn-first | CC |
@@ -7,6 +7,11 @@ guarded Update if the catalog offers one, removal with "delete my data", and a c
surprise is a register row before the next step. An app with no non-browser front door is recorded,
not faked. Tick with the date; the next night takes the first unticked app.
**Every night, first: `python3 scripts/https_only_check.py`** (R-1033, P1, since 2026-10-14). It asks every public name
of the three Tier-0 boxes over plain http and convicts any that does not answer 301/308 to the same https URL; its own
negative and positive controls run first. Exit 1 is a P1 regression: file it before the app of the night. A new app
installed tonight is covered by the next run, because the names are read from the box.
**The nine standing apps of demo-hp come first.** They cannot be a throwaway on guest 9201 (same stack
name), so they are walked on the **scratch guest 9202** (R-481, built 2026-09-13: under the demo-hp
customer, hub off, tunnel off, `https://192.168.0.114` with the same Host names and password).
+11
View File
@@ -1,3 +1,14 @@
## 2026-10-14 (night) — https_only_check.py: the box-walk check for „https only” (R-1033)
- New `scripts/https_only_check.py`. Reads each box's public names from the box (traefik labels + dynamic files, the
script sent on stdin so the Go template's `$` survives ssh + pct), adds `felhom.<domain>` and one name that exists
nowhere, and asks `http://<name>/r1033-check?q=1` with no redirect following: 301/308 to the same https URL or the box
is convicted. A browser-like User-Agent (Cloudflare 403s Python's default — measured on the first run).
- Controls every run: NEGATIVE — a local stub answering 200 must be convicted, or the run stops (exit 2); POSITIVE — the
first box's dashboard name must pass. Exit 0 / 1 / 2. Not a push gate (it needs the network and SSH). First run:
29 names on Tester 1, demo-hp, demo-felhom all OK
(`documentation/audits/https-only-2026-10-14/1B-4-box-walk-check.txt`).
## 2026-10-14 — build-hub.sh v1.24.0: refuses a stale or dirty tree (R-1021)
- Fetches, then REFUSES (exit 1, naming the leftovers' home and the own-clone route) unless the tree is clean, the