v0.313.0: media apps on every drive, drive events, a real restart, Plex without the race — release notes (MinAgent 0.155.0); golden next (bake → vouch → floor)
gates / gates (push) Successful in 44s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 10:48:58 +02:00
parent f327bc53a9
commit cac92a407e
4 changed files with 71 additions and 13 deletions
+6 -3
View File
@@ -1,7 +1,10 @@
## Unreleased → v0.313.0 (2026-10-15, in progress) — the media build, part 1: a real restart, media apps on every drive ## v0.313.0 — media apps on every drive; drive events; a real restart; Plex without the race (R-1023, R-1024, R-1026, R-1027, R-1028, R-1031, R-1032, R-1037, R-1038, R-1044, R-1045, R-1047) (2026-10-15)
Not released yet (bake → vouch → floor, `09` §3 decision 247). Design: felhom.eu `architecture/15-media-library.md` §2, **MinAgent: 0.155.0** (unchanged — the eject, guest-attach and disk calls already exist). **Hub:** v0.151.0 mails a returned
§3, §7–§10. drive (R-1049; deployed separately, on the operator's „yes"). **Catalog:** `0188430`, `b6986eb`, `0f1e78b` (the
`media_library` marker, `after_start`). Released only with its golden (bake → vouch → floor, `09` §3 decision 247).
Design: felhom.eu `architecture/15-media-library.md` §2, §3, §7–§10. Proven on Tester 1 (rc.1–rc.3) and demo-hp 9201
(rc.4): felhom.eu `documentation/audits/media-build-2026-10-15/`.
- **A real restart (R-1026).** `RestartStack` runs `up -d --force-recreate` with the stack's environment, reads every - **A real restart (R-1026).** `RestartStack` runs `up -d --force-recreate` with the stack's environment, reads every
container's start time before and after, logs what started again, and FAILS when nothing started again (it logged container's start time before and after, logs what started again, and FAILS when nothing started again (it logged
+11 -1
View File
@@ -7,7 +7,17 @@
> >
> Ask Claude Code: "Please update CONTEXT.md with what we did today" > Ask Claude Code: "Please update CONTEXT.md with what we did today"
Last updated: 2026-10-04 (v0.293.0 — the Docker-socket self-heal, R-860) Last updated: 2026-10-15 (v0.313.0 — media apps on every drive, R-1023)
> **2026-10-15 — v0.313.0, the media build (R-1023 and the rows under it; `09` §3 decisions 245, 247, 248).** Media apps bind
> every PRESENT drive through an owned `docker-compose.override.yml` (`media_library:` marker in the template); a real
> restart (force-recreate + start times); the drive wiring (`internal/mediawire`, keys read at use — Plex's own token,
> decision 248; Jellyfin's key named „felhom"); drive events with the notice, „restart now/later" and a stream check; safe
> removal keeps the drive; Plex's code asked after the start (`after_start`). Released only with golden 0.313.0 (bake →
> vouch → floor, decision 247). Traps found on Tester 1 and fixed: qBittorrent 5 logs in with 204; the agent's disk
> `state` stays „attached" for a pulled registered disk (presence = backing device); the drive gate raced a safe removal.
> A Plex status probe (`/library/sections`, 401) OPENED an unclaimed Plex while Plex started — removed within the hour;
> never gate on a status a starting app also returns.
> **2026-10-14 (night) — v0.312.0, https only (R-1033, P1; `09` §3 decision 244).** DECIDED BY CC UNATTENDED — operator > **2026-10-14 (night) — v0.312.0, https only (R-1033, P1; `09` §3 decision 244).** DECIDED BY CC UNATTENDED — operator
> may reverse: the redirect lives in traefik on the box (`felhom-https-only` in the `felhom-forwarded` chain), not in > may reverse: the redirect lives in traefik on the box (`felhom-https-only` in the `felhom-forwarded` chain), not in
+31 -9
View File
@@ -1,11 +1,33 @@
# REPORT — v0.312.0: every public name answers only over https (R-1033, P1, 2026-10-14 night) # REPORT — v0.313.0: media apps on every drive, drive events, a real restart, Plex without the race (2026-10-15)
Baseline `9b95e8e` (0.311.0). Design: felhom.eu `09` §3 decision 244 + the unattended decision recorded there (traefik on Baseline `8bc7ec5` (0.312.0). Design: felhom.eu `architecture/15-media-library.md` §2, §3, §7–§10; `09` §3 decisions 245,
the box, because the box keys cannot change Cloudflare zone settings). Evidence: felhom.eu 247, 248. Evidence: felhom.eu `documentation/audits/media-build-2026-10-15/` (A = Plex gate, G = Tester 1, G7 = demo-hp).
`documentation/audits/https-only-2026-10-14/`.
- `forwarded.yml`: `felhom-forwarded` = chain [`felhom-https-only` (redirectScheme https, 301), `felhom-forwarded-headers` ## What changed
(clean-up + HSTS 86400)]; catch-all router for unknown names over http. traefik.yml unchanged, no traefik restart. - `internal/stacks/media_library.go` — per-drive binds for `media_library:` templates, only present drives; dead-drive
- Tests red-proofed (three mutations, each seen failing). Green gate: build, vet, test all OK. check `system.MountIsShutdown`; R-1031 (no drive question), R-1027/R-1032 (removal never deletes shared/`:ro`; safety
- Delivered by hand to Tester 1, demo-hp 9201 and demo-felhom 9201 for the proof (Tier 0). **Not vouched, floor not list knows userdata).
moved** — the operator's morning step. - `RestartStack` — a real restart (R-1026).
- `internal/mediawire` — the drive wiring (R-1024, R-1037), the old-install repair (R-1047), safe-removal pause/resume,
the stream count.
- `internal/web/media_events.go` + `media_notice.html` — the notice, restart now/later, safe removal that keeps the drive
(R-1044), the returned drive's file browser recreate (R-1038), the Plex claim (R-1028) and „Kész" refused while
unclaimed (R-1045). `after_start` deploy fields.
## Proven
- Tester 1 (rc.1–rc.3): existing apps moved to the marker binds with every stored path, library item, watch mark and file
identical; Media D added → notice → restart → wired in every app, second run writes nothing; Media B pulled → nothing
lost, the file browser let go and came back at once, one restart cured the apps; Media D safely removed with torrents →
only its torrents paused, every app let go before the unmount, the drive came back by itself, torrents resumed with no
re-check; 13 hardlink pairs intact.
- demo-hp 9201: the marker ignored by 0.312.0; rc.4 wired qBittorrent + Sonarr from the live catalog; a fresh Plex with
no code stays gated and „Kész" is refused while unclaimed.
## Tests (each seen failing once)
`TestRestartStack_R1026_*`, `TestMediaLibrary_*`, `TestMountIsShutdown_K4`, `TestRemoveStack_R1027_*`,
`TestProtectedHDDPaths_R1032_*`, `TestR1031_*`, `TestAfterStartField_*`, `TestRun_SecondRunWritesNothing`,
`TestRepairOldRoot_K7`, `TestMediaEvents_*`, `TestEjectStep_G4`, `TestPlanDriveGates_SkipsSafelyRemovedDrive`,
`TestSetupDoneProbe_AcceptJSON_Plex`, `TestPlexClaimBox_RendersPerBranch`, `TestPlexDonePress_RefusedWhileUnclaimed`.
## Fixed without a row (found on the boxes this session)
qBittorrent 5's 204 login; the gate racing a safe removal; presence read from the agent's `state`.
+23
View File
@@ -3307,6 +3307,29 @@ The household sees lost files (name, date taken) on the app page until dismissed
`app_repaired_after_crash` with counts only. Immich is the first user (`09` §3 decision 236: Immich's own job queue — `app_repaired_after_crash` with counts only. Immich is the first user (`09` §3 decision 236: Immich's own job queue —
no key into the household's account). Code: `internal/stacks/after_unclean_boot.go`, `internal/aftercrash/`. no key into the household's account). Code: `internal/stacks/after_unclean_boot.go`, `internal/aftercrash/`.
### 8c. Media apps on every drive and the drive events (v0.313.0, R-1023)
- **Every drive.** A template with `media_library:` (`folder:`, `read_only:`) gets one bind per PRESENT enrolled drive —
`<drive>/userdata/media[/<folder>]` at the same path — in `docker-compose.override.yml` (header-marked, ours),
rewritten before every `compose up`. An absent drive (not a mountpoint), a dead one (`shutdown` in
`/proc/self/mountinfo`) and a safely removed one are never bound. Network shares never. The wizard does not ask a
media app for a drive; its config goes on the default drive. `internal/stacks/media_library.go`.
- **A real restart.** `RestartStack` = `up -d --force-recreate` with the stack's env; start times before/after; an
error when nothing started again.
- **Wiring** (`internal/mediawire`): after a media app comes up (debounced 60 s), after the media restart, and on
„Bekötés most": qBittorrent categories + automatic management, Transmission's incomplete folder off, Sonarr/Radarr tag,
root folder, download clients, minimum free space, Prowlarr → Sonarr/Radarr, Plex libraries + „scan on change" (the
server's own token, read at use), Jellyfin libraries (the API key named „felhom", read at use from its database).
Idempotent; keys never stored or logged. Old Sonarr/Radarr installs (`/media/<kind>`) are repaired once, no file moved.
- **Drive events** (`internal/web/media_events.go`, `/api/storage/media/{status,restart,wire}`): added / removed /
returned are recorded on the drive; the storage page and the dashboard show the notice with „Újraindítás most"
(stream check first) and „Később" (03:30), and per drive „restarted since". A returned drive recreates the file
browser at once; a dead or removed drive is not bound into it. **Safe removal** with media apps: pause that drive's
torrents → recreate the apps and the file browser without it → unmount → keep it registered; its return needs no
household step, and the torrents resume after the restart.
- **Plex:** the claim code is an `after_start` field — asked on the Plex page once Plex runs (`POST /apps/plex/plex-claim`);
the gate opens only when Plex says claimed, and „Kész" is refused before that.
### 9. Central Hub Reporting ### 9. Central Hub Reporting
#### Operator actions (`internal/report/opactions.go`, `09` §3 decision 185) #### Operator actions (`internal/report/opactions.go`, `09` §3 decision 185)