09 §3 decisions 247-249 (operator 2026-10-15): bake first (supersedes decision 7); D1=A Plex own token at use; D2=A HSTS one day. Rule file, CLAUDE.md, manual-build + publish-train runbooks follow; R-1041/R-1046 closed (decided); R-1050 dated HSTS check
gates / gates (push) Successful in 6m46s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 08:21:08 +02:00
parent 3e5b92225d
commit 3302a33cf5
8 changed files with 46 additions and 16 deletions
+4 -2
View File
@@ -44,8 +44,10 @@ it **first** in the morning note. A decision you cannot write in that shape is o
Throwaway apps only; the standing apps and `bentopdf` stay.
5. **Evidence off the machine at the end of each phase**, before any revert (R-320).
6. **One release per repo per session**, with a CHANGELOG entry (controller: with its `MinAgent`
line), REPORT overwritten, floor raised to deliver it. **No golden unless a drill or fresh install
needs one** (the waiver, R-468). **No `--no-verify`.**
line) and REPORT overwritten. **A controller release is RELEASED only when its golden is baked:
bake → the operator vouches → the operator raises the floor** (operator ruling 2026-10-15, `09` §3
decision 247, which supersedes decision 7). Never ask for a floor for a version with no golden; CC
never vouches and never moves a floor. **No `--no-verify`.**
7. **An enumerated gap becomes a row in the same session — or, if it is small, is fixed in it** (the size rule).
Prose is not a record.
8. **Hungarian text is searched with ASCII fragments**, with a positive and a negative control.
+4 -3
View File
@@ -138,9 +138,10 @@ something, not only sessions that touch `documentation/` — which is why it is
- **Root `STATUS.md`** — at the end of every session in which something shipped, broke or was
decided. It is a **view** of `OPEN-ITEMS.md`; nothing may exist only there. One screen, written for
the operator in plain language, and deliberately **not** `CONTEXT.md`.
- **The golden, on its cadence** (operator ruling 2026-09-13): **weekly, and before ANY drill or
fresh install**, bake + vouch + raise the floor per `documentation/runbooks/RUNBOOK-manual-build.md`
§4.1. Not per release. Between bakes the dated waiver (§4.2, `documentation/tests/golden-waiver.yml`,
- **The golden — bake first** (operator ruling 2026-10-15, `09` §3 decision 247, superseding the 2026-09-13
weekly cadence for releases): **a controller release is RELEASED only when its golden is baked** — bake → the
operator vouches → the operator raises the floor, per `documentation/runbooks/RUNBOOK-manual-build.md` §4.1. Never
ask for a floor for a version with no golden. Also before ANY drill or fresh install. Between bakes the dated waiver (§4.2, `documentation/tests/golden-waiver.yml`,
≤ 14 days) keeps `golden_currency_gate.py` advisory; **when it expires the gate is red and stays
red until someone bakes or renews — that is the mechanism, so do not `--no-verify` past it.** A
nightly or drill session that starts on a fresh install checks the golden FIRST.
+1 -3
View File
@@ -38,12 +38,10 @@
| 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).
- **https only for every box (controller 0.312.0):** CC bakes its golden first (your rule of 2026-10-15: bake → vouch → floor); then you vouch the golden and raise the floor. CC tells you when the golden is ready.
- **Remove the test server „plex-k6” from your Plex account** (plex.tv → Settings → Authorized Devices). The claim test passed and the server is gone from Tester 1. If not: a dead server stays listed in your Plex apps.
- 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.
@@ -168,8 +168,8 @@ These are rulings, not proposals. Anything specced against a different assumptio
### 2026-09-13 (afternoon) — the floor carries a release without a golden, and every backup counts
7. **A floor carries a release past the vouched golden when the release's MinAgent is declared with
it** (R-472; hub v0.112.0). Inside the golden the manifest's MinAgent governs, as before. Above it,
7. ~~**A floor carries a release past the vouched golden when the release's MinAgent is declared with
it**~~ **SUPERSEDED by decision 247 (operator, 2026-10-15): bake → vouch → floor; never a floor for a version with no golden.** The hub mechanism below still exists; the PROCESS no longer uses it. (R-472; hub v0.112.0.) Inside the golden the manifest's MinAgent governs, as before. Above it,
the MinAgent the operator declares with the floor — read from the release's CHANGELOG header, which
`minagent_header_gate.py` now guarantees — goes into the same per-box agent comparison. An
undeclared floor above the golden is still HELD, and both floor forms refuse to save one. **Why:** a
@@ -915,6 +915,20 @@ its length, and both fixes cost something the household would notice — operato
127. **The agent's three by-design abilities (`03` §3.1) stay for now**; revisited before the first paying customer.
*Operator ruling 2026-10-05.* (R-861)
### 2026-10-15 (07:48–08:20) — bake first; Plex through its own key; HSTS one day (recorded before the media build)
247. **Bake first.** A controller version is RELEASED only when its golden is baked. The order is always: bake the golden
→ the operator vouches it in the Day-0 manifest → the operator raises the floor. No report, STATUS line or brief may
ask the operator to raise a floor for a version with no golden. **Supersedes decision 7 (2026-09-13).** Why: a floor
above the golden left a fresh install on an older controller than the fleet, and a release with no golden could not
be vouched. *Operator ruling 2026-10-15 07:48.*
248. **D1 = A (R-1046): the box drives Plex with the server's own `PlexOnlineToken`**, read from the server's
`Preferences.xml` at the moment of use: never stored by the controller, never logged, never in evidence, never sent
anywhere but `http://<plex container>:32400`. Plex's „allowed without auth" list is NOT used. *Operator ruling
2026-10-15.*
249. **D2 = A (R-1041): HSTS stays one day now**; raised to one year after a month with no https trouble; never preload,
never `includeSubDomains`. *Operator ruling 2026-10-15.*
### 2026-10-14 (22:13) — https-only is P1; drive events = option A (recorded before the night run)
244. **R-1033 is P1.** Every public name of every box must answer only over https; plain `http://` (login pages
+7
View File
@@ -26,6 +26,13 @@
---
## 2026-10-15 — operator rulings D1 and D2 (media build brief)
| Row | What | Closed | Evidence |
|---|---|---|---|
| **R-1041** | **Decide how long browsers must remember „https only” (HSTS), and whether to preload** (P3) | CLOSED 2026-10-15 — DECIDED: `09` §3 decision 249 (D2 = A): one day now, one year after a month with no trouble (R-1050), never preload, never includeSubDomains | full text `git show 3e5b9222:documentation/backlog/OPEN-ITEMS.md` |
| **R-1046** | **The box can drive Plex only with the household's Plex account token** (P3) | CLOSED 2026-10-15 — DECIDED: `09` §3 decision 248 (D1 = A): the server's own `PlexOnlineToken`, read from `Preferences.xml` at use, never stored, logged or sent anywhere but the Plex container; „allowed without auth” is NOT used | full text `git show 3e5b9222:documentation/backlog/OPEN-ITEMS.md` |
## 2026-10-14 — the media folders meet in the live catalog
| Row | What | Closed | Evidence |
+4 -4
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 — 19 rows (P2 1, P3 13, P4 5)
## Apps & catalog — 18 rows (P2 1, P3 12, P4 5)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -144,7 +144,6 @@ stopping line that lies.
| **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 |
@@ -207,7 +206,7 @@ stopping line that lies.
| **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 — 21 rows (P1 2, P2 4, P3 10, P4 5)
## Security & access — 21 rows (P1 2, P2 4, P3 9, P4 6)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -218,7 +217,6 @@ stopping line that lies.
| **R-976** | Security & access | P3 | **A family member's session can be copied out of a family-gated app, and a dashboard password reset does not end family or gate sessions; so a stolen session keeps working for up to 30 days.** Fix: give each app its own derived token instead of the session itself, and end every family and gate session on a reset. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN | — | Fix with tests in a controller release | CC |
| **R-970** | Security & access | P2 | **Whoever holds a box's own hub API key — the hub, or anyone with a copy of the hub database — can read the box's settings file with every secret in it and replace that file through the internet; the box does not check that such a change is signed.** This contradicts `01` §4 (the box exposes no control endpoint) and §10 (a hub compromise alone cannot forge commands). Nothing in the product calls this route any more. Fix: remove the route, or require an operator-signed op for it. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN — confirmed by a second reader | — | Remove the route with a test that it is gone; release the controller | CC |
| **R-954** | Security & access | P2 | **We cannot tell whether anyone used the old hub operator key (R-950) or the open hub read routes (R-951) before 2026-10-12; if someone did, they could have read every box's break-glass root credential and every customer's box report.** The exposure began in February 2026; the logs that could show it cover only 2026-10-12 from about 09:54 and one day in June, so about 238 days are not visible. Fix (operator decision): change the break-glass root password of every box (tester-1 holds a real person's data), or accept the risk; either way, keep ingress access logs long enough to answer this next time. | WAITING-ON-OPERATOR — filed 2026-10-12 by the security review; the log search was not completed in-session | operator decision | Decide: rotate every box's break-glass root password now, or accept | operator |
| **R-1041** | Security & access | P3 | **Decide how long browsers must remember „https only” (HSTS), and whether to preload.** Since controller v0.312.0 every box sends `Strict-Transport-Security: max-age=86400` (one day), no `includeSubDomains`, no preload — the night brief's limit (R-1033, decision 244). A longer value protects the first visit after a day away; preload makes even the first visit ever safe but is hard to undo (a browser list) and binds every subdomain of the customer's domain. | **WAITING-ON-OPERATOR** — filed 2026-10-14 | the operator | Choose: keep one day; or e.g. 180 days without preload; or preload (all subdomains https forever) | operator |
| **R-1042** | Security & access | P3 | **The boxes' Cloudflare keys cannot change zone settings, so Cloudflare's own „Always Use HTTPS” cannot be switched on.** Measured 2026-10-14 on all three zones (`audits/https-only-2026-10-14/``1A-1-zones-and-keys.txt`): each `cf_api_token` is valid and sees only its own zone, but GET/PATCH `settings/always_use_https`, `ssl`, `security_header` answer 403; the redirect and transform rule phases too. The https-only fix therefore lives on the box (decision 246). A second layer at Cloudflare needs „Zone Settings: Edit” (and, for headers, „Transform Rules”) added to each customer's key — the hub's zone-reach check stays. | **WAITING-ON-OPERATOR** — filed 2026-10-14 | a key permission only the operator can grant | Optional: widen each customer key, then switch „Always Use HTTPS” on per zone | operator |
| **R-955** | Security & access | P4 | **The cross-box check of the hub API is done in source and tests but not fully proven: if a later check masks a missing id check, a box's key could read or change another box's hub record without any test noticing.** Read 2026-10-12: every box-facing `/api/v1` route takes the box from its own key or refuses a different id; 14 routes already had a refusal test, 5 got one (`crossbox_refusal_test.go`). Left: red-prove the 4 new tests that were not red-proved (as the restore-directive one was), and the live read-only check with one demo box's key against the other demo box's id. | OPEN — filed 2026-10-12 by the security review | — | Red-prove the 4 tests; run the live GET check on the two demo boxes | CC |
| **R-924** | Security & access | P2 | **The operator signing keys exist only on DooPlex, with no passphrase and in no backup — a loss of DooPlex means no box ever accepts a signed agent update, config bundle or OS step again without an on-site re-enrollment.** MEASURED 2026-10-09: `/mnt/5_hdd/felhom.eu/felhom-op-operational`, `felhom-rec-recovery`, `felhom_op_ed25519` (0600 `kisfenyo`); `ssh-keygen -y -P ''` opens all three (no passphrase); `/mnt/5_hdd/felhom.eu` is in no backup set, the off-site job does not carry them. `04` §1 says the operational key is "passphrase-protected" and the recovery key "kept offline" — today neither holds (custody ruling 1 of 2026-09-16 put both on DooPlex for this phase; `04` §3.1). Both keys share one fate, so the cold key cannot do its one job (re-pin after losing the operational key). `runbooks/total-loss-of-dooplex.md` S6. | **NARROWED 2026-10-09 — operator ruling: option A** (print both AND copy them). The three key files and their public halves ride the nightly encrypted DooPlex→ep0 copy (`scripts/dooplex-offsite/`, a missing key refuses the push); the Sunday restore test proves each private key still derives its own public half (never printed). **LEFT:** the operator prints S6a/S6b (`runbooks/break-glass-sheet.md`); the keys still have no passphrase (custody ruling 1 of 2026-09-16 stands until the first sale). | operator: print | Operator: print the two keys; then close | operator |
@@ -232,6 +230,7 @@ stopping line that lies.
| **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 |
| **R-1050** | Security & access | P4 | **Raise HSTS to one year on or after 2026-11-15, if no https trouble was reported.** `09` §3 decision 249 (D2 = A, operator 2026-10-15): HSTS stays `max-age=86400` now; after a month with no https trouble it becomes one year (`31536000`); never preload, never `includeSubDomains`. The value is `HSTSMaxAgeSeconds` in `felhom-controller/controller/internal/infra/infra.go`, pinned by `TestRenderForwardedHeaders_HTTPSOnly`. „Trouble” = any report of a name that will not open, or a box answering http after the floor. | **WATCHING** — filed 2026-10-15 | the date | On or after 2026-11-15: read the register and the operator's mail for https trouble since 2026-10-15; none → a controller release with one year (test updated), bake → vouch → floor | CC |
## Box system & updates — 11 rows (P2 1, P3 7, P4 3)
@@ -344,6 +343,7 @@ stopping line that lies.
|---|---|---|
| R-887 | 2026-10-19 | no CI job lost in the 7 days after the S21 DooPlex change (act-runner fetch timeout + crawler rate limit); detail in the R-887 row |
| R-435 | 2026-10-20 | Tester 1's weekly off-site clean-up ran inside a hub window with no drop alarm (box log + mailbox); detail in the R-435 row |
| R-1050 | 2026-11-15 | HSTS one year if no https trouble since 2026-10-15; detail in the R-1050 row |
| R-1035 | 2026-11-11 | „felhő tárhely” + „saját felhő tárhely” impressions and average position, and the new page's own impressions/clicks/position, 4 weeks after publishing; operator supplies the read; detail in the R-1035 row |
| R-528 | 2026-11-12 | no failed oom_check / unexplained app_oom since 2026-10-12; detail in the R-528 row |
| R-1035 | 2026-12-09 | the same three numbers 8 weeks after publishing, compared with the 4-week read; a null at 4 weeks is not a verdict, both reads are needed; detail in the R-1035 row |
@@ -98,8 +98,9 @@ the manifest vouches the target FIRST; any MinAgent must be satisfied fleet-wide
boxes below it automatically, and flags them); **save the floor LAST** — the DB row acts immediately
on every box below it, on their next report.
**Raise the floor to a release with no golden (hub v0.112.0+, R-472).** Between bakes this is the
normal route — do not hand-deploy.
**Raise the floor to a release with no golden (hub v0.112.0+, R-472).** **⚠ NOT USED SINCE 2026-10-15 (`09` §3
decision 247): bake → vouch → floor; never ask for a floor for a version with no golden.** The mechanism is kept
here because the hub still has it.
1. Build and push the controller image (above). Do not install it on any box.
2. Read the MinAgent from the release's header: `grep -m1 -A3 '^## v<VER>' CHANGELOG.md` shows
@@ -251,6 +252,10 @@ after reading the dry-run; nothing schedules it. The August 2026 `--keep 7` run
### 4.2 Cadence — goldens are WEEKLY and before any install, not per release (operator ruling 2026-09-13)
> **⚠ SUPERSEDED for releases on 2026-10-15 (`09` §3 decision 247):** every controller release gets its golden before
> its floor — bake → the operator vouches → the operator raises the floor. The weekly bake and the before-any-install
> bake below still hold for weeks with no release; the waiver keeps the gate's own mechanism.
**What was measured before the ruling:** 25 goldens in 26 days in August, almost one per release,
because `golden_currency_gate.py` trips on every release by design and the only honest ways past it
were a bake or a declared `--no-verify` (thirteen of those by 2026-09-01 — R-404/R-417). **The
@@ -10,6 +10,9 @@ Publish and vouch the artifacts in the Day-0 manifest **before** any floor movem
points at an unvouched (or unpublished) version bricks self-updates: boxes are told to move to a
version they cannot verify. (GL-1 supply-chain arc; see the go-live package records.)
**⚠ Since 2026-10-15 (`09` §3 decision 247) the process never uses a floor above the golden: bake → vouch → floor.**
The mechanism below stays in the hub and is described for reading the hub, not as a route.
**Since hub v0.112.0 (operator ruling 2026-09-13, R-472): the manifest leads the floor inside the
golden; above it, the release's own declared MinAgent does.** A controller image is pulled by tag from
the registry, so a floor above the golden does not need a golden to be delivered — it needs to know