Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
7.2 KiB
REPORT — 2026-09-29 afternoon: the setup gate on the other 30 apps; "Done" asks the app first; open sign-up closed after the first admin; claper's password never in code
Architecture read first: 09 §3 decisions 45–47, 01-topology-and-trust.md §5, audits/login-gate-2026-09-29/B/B-VERDICT.md,
app-catalog-felhom.eu/FIRST-ADMIN.md, rows R-707, R-711, R-713. Controller v0.281.0 (one release). Floor 0.281.0;
both demo boxes run it. Catalog 6faf432. Evidence: documentation/audits/gate-rollout-2026-09-29/
(0 = Part 0, A, B = per-app, C = sign-up, D = claper, redproofs).
The Parts
| Part | Step | State | Note |
|---|---|---|---|
| — | decision 47 recorded first | done | 09 §3 + 01 §5 before any work |
| 0 | installed app never gated by a catalog change | done — holds | 9202: vikunja installed ungated and set up, then the drill catalog added setup_gate: true, synced, two loop ticks, a controller restart: still answered strangers, no gate file, no record (0/P0-1, P0-2). Code: the gate is set only in DeployStack. Pinned by TestSignupBlock_NeverOnAnAppThisBoxDidNotGate (RP23). After the live push, the demo boxes' installed class-4 apps (adventurelog, docmost, opengist, romm; opengist) got no gate and no block (0/P0-3) |
| A1 | "Done" asks the probe first | done | refuses while the app says not done and when it cannot be read (409 + the sentence). Live: zipline pressed before its setup → 409, twice (A/, B/B2-zipline-probe-before.txt) |
| A2 | confirm for an app without a probe | done | in-page felhomConfirm with the sentence (native confirm is banned by a gate) |
| A3 | tests + red-proofs | done | RP17, RP18 |
| B | the gate on the other 30 | done — 28 gated (25 fully proven, 3 opening not provable here), 2 not gated | per-app table below |
| C1 | spike: how sign-up can be closed | done, mechanism changed | opengist, wishlist: only in their own admin settings; vikunja: an env, but then no way to add a user but its CLI. Chosen: a box-side block of the app's own sign-up address + a household 15-minute window (CC-unattended decision, 09 §3 decision 47) |
| C2 | per app | done | 11 apps let a stranger sign up after the setup → blocked and refused; 11 more refuse by themselves; window proven (gitea, calcom, vikunja) and closes again (gitea, calcom) |
| C3 | apps that cannot close sign-up | 1: wanderer | not gated at all (R-714) — STATUS asks |
| D | R-713 | done | code-bound values refused; `${NAME |
Recommendation not followed, one line why (standing rule 4): the ruling says "only the admin adds people, from the app's own user page"; for apps with no such page (opengist, vikunja, termix, sparkyfitness, adventurelog) the page says to open sign-up for 15 minutes instead — the only way a family member can join those apps at all.
Part B / C — one row per app (9202, controller 0.281.0, drill catalog)
| app | gate proven (stranger refused · household reached setup · opened · answered after) | opened by | sign-up after the setup |
|---|---|---|---|
| actualbudget | yes | probe data.bootstrapped (M) |
refused by the app |
| komga | yes | probe isClaimed (M) |
refused by the app |
| jellyfin | yes | probe StartupWizardCompleted (M) |
refused by the app |
| romm | yes | probe SYSTEM.SHOW_SETUP_WIZARD (M) |
refused by the app |
| zipline | yes | probe /api/server/public firstSetup (M) |
refused by the app (userRegistration: false) |
| termix | yes | probe setup_required (M) |
was open → blocked |
| emby | yes | button | refused by the app |
| navidrome | yes | button (no JSON status) | refused by the app |
| ghost | yes | button (status is a list — R-715) | refused by the app |
| home-assistant | yes | button (status is a list — R-715) | refused by the app |
| gitea | yes | button | was open → blocked |
| docmost | yes | button | no public sign-up |
| calcom | yes | button | was open (a stranger's account was created) → blocked |
| tandoor | yes | button | "Sign Up Closed" by the app |
| gramps-web | yes | button (its status answers 405 — R-715) | answered 500 → blocked anyway |
| adventurelog | yes | button | was open → blocked |
| homebox | yes | button | was open → blocked |
| papra | yes | button | was open → blocked |
| sparkyfitness | yes | button | was open → blocked |
| vikunja | yes | button | was open → blocked; window let a family member in |
| opengist | yes | button | was open → blocked |
| wishlist | yes | button | was open → blocked |
| radarr, sonarr | yes | button | single user; their API key was public BEFORE the setup — the gate hides it |
| recipe-importer | yes | button | our own app, open until a password is set — the confirm says so |
| seerr | stranger refused, household reached setup | opening not proven (needs a media server) | not measured |
| outline | stranger refused, household reached setup | opening not proven (needs e-mail / SSO) | not measured |
| rallly | stranger refused, household reached setup | opening not proven (e-mail) | not measured |
| wanderer | not gated | — | open (R-714) |
| plant-it | not installable (lifecycle: abandoned); the template carries the gate |
— | — |
Claims in the brief that turned out wrong (or right), named
- "A catalog change never gates an installed app" — right (measured on 9202 and read on both demo boxes).
- "14 of the 34 have a probe" — wrong: 9 have a probe that works (3 from the morning, 6 today); 3 more have a
status the box cannot read (ghost, home-assistant — lists; gramps-web — 405, R-715); zipline's upstream route was
wrong (
/api/setupanswers 403 after the setup;/api/server/publicworks). - "The first admin is the first registered user on opengist and wishlist" — right (measured: the household's sign-up became the admin; after it, a stranger could still sign up).
- "Each app in R-711's list can close sign-up" — wrong as a per-app switch: opengist and wishlist keep it only in their admin settings, vikunja only as a start-up env; and wanderer cannot be closed at all today. The box-side block closes all but wanderer.
- "An env switch needs a restart" — right for vikunja (read at start); not used — the block needs no restart.
- "Register 346 rows" — was 350 at the start of this session (the morning session ended at 350).
Also found
- A probe that never flips blocks the household's press (fail closed; measured on gramps-web) → R-715.
- calcom created a stranger's account after the setup (measured) — closed.
- Apps installed before today keep their open sign-up (demo boxes only) → R-716, needs an operator word.
Rows
Closed: R-707, R-711, R-713. Opened: R-714 (wanderer), R-715 (probe shapes), R-716 (installed apps' sign-up, operator). Register 350 → 353 rows.
Teardown
Machines: 9202 — every test app removed through the product (the scratch drive keeps some app folders, R-442's
refusal as before); no gate or block file left; back on the live catalog; the drill catalog reset to live main.
Demo boxes — read only (plus the floor). Host: nothing. Hub: floor 0.281.0. ep0: untouched.