Rulings 2026-10-01 built: report, STATUS (standing monthly line), decision 57 (mealie lockout, decided by CC unattended), R-747 narrowed, evidence
gates / gates (push) Successful in 26s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-01 10:20:44 +02:00
parent daacf84e30
commit a6a9f0b245
10 changed files with 333 additions and 42 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.
> **2026-10-01 — the three rulings built; decision 57 decided by CC unattended (operator may reverse).** 54/55: the first
> full monthly re-test — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written (~17 min per app);
> `retest-floating.py` fixed for a fresh bench (R-749). 56: controller v0.285.0 (keeps running + previous controller image,
> previous from the swap record); R-751 nil-stack crash fixed; floor 0.285.0; demo-hp 84 → 2 and N100 76 → 2 controller
> images; golden 0.285.0 baked + vouched (gate OK). **57 (R-747):** mealie `SECURITY_USER_LOCKOUT_TIME=1` (catalog
> `a4597cd`) — measured 120 min lock on 9202. R-746 digest resolver `804884a`; R-744 outline fixture `9fc7052`.
> Opened R-749..R-752 (R-752: calibre-web-automated, wger, Grafana, BookStack lockable by strangers — read, not measured).
> Report: `REPORT-rulings-2026-10-01.md`.
> **Rulings 2026-10-01 (operator) — `09` §3 decisions 54–56, recorded before the work.** **54 (R-743 1A):** the monthly
> re-test is run by a CC session the operator starts with the standing brief `claude/MONTHLY-security-retest.md` (project);
> STATUS carries "Monthly security re-test: last run <date>, next due <date>". **55 (R-743 2A):** it covers every app with a
+90
View File
@@ -0,0 +1,90 @@
# REPORT — the operator's three rulings of 2026-10-01 built (day session)
Evidence: `documentation/audits/rulings-2026-10-01/` (A–D, T, tools) · `documentation/audits/retest-2026-10/` (the monthly
run) · golden: `documentation/tests/golden-0.285.0-2026-10-01/`.
Architecture read: `09` §3 decisions 30, 45, 52, 53 and §6.5; `03-host-agent.md` (the controller swap) with agent
`internal/localapi/controllerswap.go`; `07` (R-698); `runbooks/monthly-floating-retest.md`; `audits/night-rulings-2026-09-30/`.
Baselines (live Gitea ~07:10 CEST): controller `a70c398` (0.284.2), agent `d766666` (0.138.0), felhom.eu `3159892`, catalog
`efd492d`. Register 383 rows by `register_shape_gate`'s method; highest id R-748; last decision 53.
## The Part table
| Part | done / not done / changed | why |
|---|---|---|
| **Rulings 54–56** | **done** — recorded first in `09` §3 and CONTEXT (`2076bf9`) | before any work |
| **A — the full re-test** | **done** — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written, pushed through the pre-push gates | first start refused in one minute: the script checked the bench for its own files before copying them (R-749, fixed `9e53205`) |
| A1 runbook | **done** — every app by default, `--engines-only` the switch, the standing brief, cost | — |
| A4 linuxserver cost | **done** — see below | — |
| A5 STATUS standing line | **done** — "last run 2026-10-01, next due ~2026-11-01" | — |
| **B — two controller versions** | **done — controller v0.285.0**, floor 0.285.0 (MinAgent 0.131.0 declared) | measured first: the agent rolls back to the RUNNING image |
| B3 live | **done** on 9202 (version-order fallback) and both demo boxes (the swap record) | 9202's self-update is off (no hub), so the record path was shown on the demo boxes |
| — R-751 | **added** — a nil-stack panic in the update clean-up, found by the full suite, fixed in the same release | a panic in a goroutine ends the controller |
| **C — mealie** | **done — decided by CC unattended (decision 57):** `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; 9202 proof 120 min | no fix stops an hourly renewal without changing the login name (option d, left open) |
| C other apps | **done (read, not measured)** — four more lockable: R-752 | source reading by a sub-agent at each pinned tag |
| **D1 — R-746** | **done** `804884a`, red-proofed (unit + live registry) | — |
| **D2 — R-744** | **done** `9fc7052`, proven on 9202 at 1.10.1 | outline has no newer release, so no step |
| **E — release, floor, golden** | **done** — demo boxes on 0.285.0 within ~6 s; golden 0.285.0 baked, round-trip identical, vouched; the gate prints **OK** | — |
## Claims in the brief that turned out wrong (or right)
1. **"`previousImage` … handed to the agent's `SwapController`"** — **wrong.** `SwapController(ctx, target)` carries the
target only; `previousImage` goes into `update-state.json`. The agent reads `/etc/felhom-controller-image` when the swap
begins and rolls back to THAT — the running image. On all three boxes it equals `<image>:<current version>`, so the
practical outcome matches; the mechanism does not.
2. **"The sweep skips every controller image today"** — **right**, twice over: the sweep's repositories never include the
controller's, and it skips any repo containing `felhom-controller`.
3. **"nextcloud and sonarr still differ"** — **right**, and only those two (bookstack, radarr, code-server did not differ today).
4. **"mealie's lock is per account"** — **right** (`login_attemps` / `locked_at` on the user). Also: the lock outlives its
hours until mealie's HOURLY job resets the counter, so `1` means 1–2 h (measured 120 min).
5. **"The golden's image is not needed after first boot"** — right **after the first swap**; until then it IS the running
image (kept as such). A whole-guest restore brings its own Docker store (`mp0 backup=1`).
6. **"Is an old controller tag still in the registry?"** — **no, below 0.213.0** (2026-08-12): `0.201.0` answers 404. Nobody
recorded what removed them (R-750). This session deleted no registry tag.
7. "Live on 9202 … after the release" for the record path — 9202 has self-update off; the record path ran on the demo boxes.
## Part A — the run
| app | result | bench | box |
|---|---|---|---|
| nextcloud `34.0.4-apache` | **DONE** — written `3b59dfb` | 05:19–05:32 UTC (proven, peak 23.7 %) | ~5 min: old digest installed, seeded, the guarded Update ran the re-test step, new digest running, read back, badge "Naprakész" |
| sonarr `4.0.20` (linuxserver) | **DONE** — written `1a37032` | 05:38–05:50 (proven, peak 13.9 %) | ~3 min, same steps |
**Monthly cost.** ~17 min per app (bench ~13 incl. the 10-minute watch, box ~4) plus ~15 min to set up and tear down. The
four linuxserver apps with ladders (bookstack, radarr, sonarr, code-server) are rebuilt weekly, but the monthly run tests
only the day's digest — **at most 4 re-tests a month from them (~70 min of bench, ~16 min of 9202), not 16.** Acceptable.
## Part B — images before → after
| box | controller images | Docker images (`system df`) | `/var/lib/docker` used |
|---|---|---|---|
| 9202 | 5 → 2 | 3.17 → 3.10 GB (layers are shared) | 3.5 → 3.4 GB |
| demo-hp 9201 | 84 → 2 (82 deleted) | 15.2 → 11.65 GB | 18 → 15 GB |
| N100 9201 | 76 → 2 (74 deleted) | 6.07 → 1.11 GB | 6.0 → 1.2 GB |
Each kept 0.285.0 (running) and 0.284.2 (previous). Red-proofs (`B/B1-red-proofs.txt`): previous dropped → 0.284.2
deleted; record ignored → 0.283.1 deleted; no swap check → deleted while swapping; no in-use check → a used image deleted;
no success check → a failed swap's image named previous; no nil-stack check → panic. The first in-use red attempt
removed a line and did not build; redone with the condition disabled (recorded).
## Part C — mealie
Settings (v3.28.0 source): `SECURITY_MAX_LOGIN_ATTEMPTS` 5, `SECURITY_USER_LOCKOUT_TIME` 24 (hours), per account, lifted
by an hourly job; `POST /api/admin/users/unlock` exists but the only admin is the locked account. Fix and 9202 proof: see
decision 57 (`C/C1-mealie-lockout-1h.txt`: right password 200 → 5 wrong 401 → 423 → right password 423 for 120 min → 200;
a wrong one 401 after). Other apps (R-752): calibre-web-automated (per username, 3/min and 40/day), wger (per IP = traefik's,
30 min, everyone), Grafana (per account, 5 min), BookStack (e-mail|IP, 60 s); gokapi and claper cannot.
## Rows
**383 → 387.** Opened R-749 (re-test start), R-750 (old registry tags gone), R-751 (update clean-up crash), R-752 (four
lockable apps). Closed R-743, R-744, R-745, R-746, R-749, R-751. Narrowed R-747.
## Teardown
- **Machine:** 9202 back on the live catalog (`repo_url` read back), the same six containers as at the start, controller
0.285.0 (the release); the apps this session installed (nextcloud, sonarr, outline, mealie) removed through the product.
Bench 9401 destroyed with its template. Drill VM: CT 9100 destroyed, token/runner/log shredded, qemu exited, reverted to
`virgin`. Drill catalog reset to live (`a4597cd`), image lines identical.
- **Host:** demo-hp `pct list` = 9201, 9202 (as at the start); the N100 untouched except the floor's controller update.
- **Hub:** two form saves — the floor (0.285.0, MinAgent 0.131.0) and the vouch (golden 0.285.0); one floor attempt without
the credential answered 302 `/login` and stored nothing.
+88 -7
View File
@@ -1,9 +1,90 @@
# REPORT — 2026-09-27 evening: a restore and a drive move keep the app's records
# REPORT — the operator's three rulings of 2026-10-01 built (day session)
Evidence: `documentation/audits/records-carried-2026-09-27/` (README = the session record).
Evidence: `documentation/audits/rulings-2026-10-01/` (A–D, T, tools) · `documentation/audits/retest-2026-10/` (the monthly
run) · golden: `documentation/tests/golden-0.285.0-2026-10-01/`.
Architecture read: `09` §3 decisions 30, 45, 52, 53 and §6.5; `03-host-agent.md` (the controller swap) with agent
`internal/localapi/controllerswap.go`; `07` (R-698); `runbooks/monthly-floating-retest.md`; `audits/night-rulings-2026-09-30/`.
Baselines (live Gitea ~07:10 CEST): controller `a70c398` (0.284.2), agent `d766666` (0.138.0), felhom.eu `3159892`, catalog
`efd492d`. Register 383 rows by `register_shape_gate`'s method; highest id R-748; last decision 53.
- `07` §6.6: new paragraph "What a restore keeps from the app it replaces" (and: a drive move is not a restore).
- Register: 336 → 337 rows. Opened R-700 (WATCHING, live proof open), R-701 (demo-hp restore test refused for space); closed R-697 (to
`CLOSED-ITEMS.md`); R-691 annotated: (2) not built, and why.
- Hub: no code change; global floor 0.276.0 (MinAgent 0.131.0) via `POST /configuration/global-floor`.
- STATUS and CONTEXT updated. Capability map: not changed.
## The Part table
| Part | done / not done / changed | why |
|---|---|---|
| **Rulings 54–56** | **done** — recorded first in `09` §3 and CONTEXT (`2076bf9`) | before any work |
| **A — the full re-test** | **done** — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written, pushed through the pre-push gates | first start refused in one minute: the script checked the bench for its own files before copying them (R-749, fixed `9e53205`) |
| A1 runbook | **done** — every app by default, `--engines-only` the switch, the standing brief, cost | — |
| A4 linuxserver cost | **done** — see below | — |
| A5 STATUS standing line | **done** — "last run 2026-10-01, next due ~2026-11-01" | — |
| **B — two controller versions** | **done — controller v0.285.0**, floor 0.285.0 (MinAgent 0.131.0 declared) | measured first: the agent rolls back to the RUNNING image |
| B3 live | **done** on 9202 (version-order fallback) and both demo boxes (the swap record) | 9202's self-update is off (no hub), so the record path was shown on the demo boxes |
| — R-751 | **added** — a nil-stack panic in the update clean-up, found by the full suite, fixed in the same release | a panic in a goroutine ends the controller |
| **C — mealie** | **done — decided by CC unattended (decision 57):** `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; 9202 proof 120 min | no fix stops an hourly renewal without changing the login name (option d, left open) |
| C other apps | **done (read, not measured)** — four more lockable: R-752 | source reading by a sub-agent at each pinned tag |
| **D1 — R-746** | **done** `804884a`, red-proofed (unit + live registry) | — |
| **D2 — R-744** | **done** `9fc7052`, proven on 9202 at 1.10.1 | outline has no newer release, so no step |
| **E — release, floor, golden** | **done** — demo boxes on 0.285.0 within ~6 s; golden 0.285.0 baked, round-trip identical, vouched; the gate prints **OK** | — |
## Claims in the brief that turned out wrong (or right)
1. **"`previousImage` … handed to the agent's `SwapController`"** — **wrong.** `SwapController(ctx, target)` carries the
target only; `previousImage` goes into `update-state.json`. The agent reads `/etc/felhom-controller-image` when the swap
begins and rolls back to THAT — the running image. On all three boxes it equals `<image>:<current version>`, so the
practical outcome matches; the mechanism does not.
2. **"The sweep skips every controller image today"** — **right**, twice over: the sweep's repositories never include the
controller's, and it skips any repo containing `felhom-controller`.
3. **"nextcloud and sonarr still differ"** — **right**, and only those two (bookstack, radarr, code-server did not differ today).
4. **"mealie's lock is per account"** — **right** (`login_attemps` / `locked_at` on the user). Also: the lock outlives its
hours until mealie's HOURLY job resets the counter, so `1` means 1–2 h (measured 120 min).
5. **"The golden's image is not needed after first boot"** — right **after the first swap**; until then it IS the running
image (kept as such). A whole-guest restore brings its own Docker store (`mp0 backup=1`).
6. **"Is an old controller tag still in the registry?"** — **no, below 0.213.0** (2026-08-12): `0.201.0` answers 404. Nobody
recorded what removed them (R-750). This session deleted no registry tag.
7. "Live on 9202 … after the release" for the record path — 9202 has self-update off; the record path ran on the demo boxes.
## Part A — the run
| app | result | bench | box |
|---|---|---|---|
| nextcloud `34.0.4-apache` | **DONE** — written `3b59dfb` | 05:19–05:32 UTC (proven, peak 23.7 %) | ~5 min: old digest installed, seeded, the guarded Update ran the re-test step, new digest running, read back, badge "Naprakész" |
| sonarr `4.0.20` (linuxserver) | **DONE** — written `1a37032` | 05:38–05:50 (proven, peak 13.9 %) | ~3 min, same steps |
**Monthly cost.** ~17 min per app (bench ~13 incl. the 10-minute watch, box ~4) plus ~15 min to set up and tear down. The
four linuxserver apps with ladders (bookstack, radarr, sonarr, code-server) are rebuilt weekly, but the monthly run tests
only the day's digest — **at most 4 re-tests a month from them (~70 min of bench, ~16 min of 9202), not 16.** Acceptable.
## Part B — images before → after
| box | controller images | Docker images (`system df`) | `/var/lib/docker` used |
|---|---|---|---|
| 9202 | 5 → 2 | 3.17 → 3.10 GB (layers are shared) | 3.5 → 3.4 GB |
| demo-hp 9201 | 84 → 2 (82 deleted) | 15.2 → 11.65 GB | 18 → 15 GB |
| N100 9201 | 76 → 2 (74 deleted) | 6.07 → 1.11 GB | 6.0 → 1.2 GB |
Each kept 0.285.0 (running) and 0.284.2 (previous). Red-proofs (`B/B1-red-proofs.txt`): previous dropped → 0.284.2
deleted; record ignored → 0.283.1 deleted; no swap check → deleted while swapping; no in-use check → a used image deleted;
no success check → a failed swap's image named previous; no nil-stack check → panic. The first in-use red attempt
removed a line and did not build; redone with the condition disabled (recorded).
## Part C — mealie
Settings (v3.28.0 source): `SECURITY_MAX_LOGIN_ATTEMPTS` 5, `SECURITY_USER_LOCKOUT_TIME` 24 (hours), per account, lifted
by an hourly job; `POST /api/admin/users/unlock` exists but the only admin is the locked account. Fix and 9202 proof: see
decision 57 (`C/C1-mealie-lockout-1h.txt`: right password 200 → 5 wrong 401 → 423 → right password 423 for 120 min → 200;
a wrong one 401 after). Other apps (R-752): calibre-web-automated (per username, 3/min and 40/day), wger (per IP = traefik's,
30 min, everyone), Grafana (per account, 5 min), BookStack (e-mail|IP, 60 s); gokapi and claper cannot.
## Rows
**383 → 387.** Opened R-749 (re-test start), R-750 (old registry tags gone), R-751 (update clean-up crash), R-752 (four
lockable apps). Closed R-743, R-744, R-745, R-746, R-749, R-751. Narrowed R-747.
## Teardown
- **Machine:** 9202 back on the live catalog (`repo_url` read back), the same six containers as at the start, controller
0.285.0 (the release); the apps this session installed (nextcloud, sonarr, outline, mealie) removed through the product.
Bench 9401 destroyed with its template. Drill VM: CT 9100 destroyed, token/runner/log shredded, qemu exited, reverted to
`virgin`. Drill catalog reset to live (`a4597cd`), image lines identical.
- **Host:** demo-hp `pct list` = 9201, 9202 (as at the start); the N100 untouched except the floor's controller update.
- **Hub:** two form saves — the floor (0.285.0, MinAgent 0.131.0) and the vouch (golden 0.285.0); one floor attempt without
the credential answered 302 `/login` and stored nothing.
+36 -34
View File
@@ -2,54 +2,56 @@
**Ready for the first real tester (Tester-2): yes. You confirmed the tunnel route and the connect mails (2026-09-30).**
**Updated 2026-09-30 (late evening). Both demo boxes run controller 0.284.2 and host agent 0.138.0. Hub 0.126.0. New installs get golden 0.284.2 with agent 0.138.0.**
**Updated 2026-10-01. Both demo boxes run controller 0.285.0 and host agent 0.138.0. Hub 0.126.0. New installs get golden 0.285.0 with agent 0.138.0.**
**Tester-2 — read only, from the hub.** The customer record exists. Tester-2's box has not registered yet.
## Your two decisions of tonight — built
## A decision I took myself (you may reverse it)
- **Security fixes under the same name (your A).** The catalog can now re-test a database image's new fix and record
it as a tested step. A box then takes it at night by itself. Tested from start to end on the scratch box: the night
run took the fix, the app kept its data, and the page went back to "up to date". **Today there was nothing to re-test**
for the database and redis images.
- **Old program files on the disk (your A).** A box now keeps each app's current program and the one before it, and
deletes the older ones. It never deletes one that another app still uses. On the first start it cleaned up once:
**the HP demo box freed 11 GB**, the scratch box 21 GB. All apps kept running.
- **mealie: a stranger can now lock the household out for 1 to 2 hours, not a whole day.** mealie locks the account after
five wrong passwords, and its login name is public. I set the lock to mealie's shortest time (1 hour; its hourly
clean-up makes it up to 2). Tested on the scratch box: locked for 2 hours, then the right password worked. The guard
against password guessing stays. **What it does not fix:** a stranger can lock it again every hour. The other way would
be a secret login name, but that changes what the household types — so I did not do it.
## Your three decisions of today — built
- **The monthly security re-test covers every tested app (your 2A).** First full run today: **nextcloud and sonarr** had
a new build under the same name. Both passed on the test bench and on the scratch box, and are now in the catalog. Boxes
take them at night. It took about 17 minutes per app.
- **You start the monthly run (your 1A).** Give the standing brief `MONTHLY-security-retest.md` to CC once a month. The
runbook now says so.
- **A box keeps only two controller versions (your 3A).** The new controller 0.285.0 deletes the older ones. The HP demo
box went from 84 versions to 2 (Docker images 15.2 → 11.7 GB). The N100 went from 76 to 2 (6.1 → 1.1 GB). All apps kept
running. I checked first: if an update fails, the box goes back to the version it was running, and that one is always kept.
## What else I did, and it worked
- **The short login risk is closed.** After an install, an app with a known default password is now closed to
strangers until the box has changed that password. Tested on two apps: no stranger got in.
- **wger's phone app can log in** now (its missing key is made at the first start).
- **New controller 0.284.2** is on both demo boxes, and **a new golden 0.284.2** is baked and vouched. The golden check
is green (not just waived).
- **A crash fixed.** The image clean-up after an app update could crash the controller if the app was removed right
after. The test suite found it. Fixed in 0.285.0.
- **Two test-tool fixes:** the digest check now refuses an image build that is gone, and the outline test works with
outline's newest version.
- **New controller 0.285.0** is on both demo boxes, and **a new golden 0.285.0** is baked and vouched. The golden check is
green.
## What broke, and what I did
- **The clean-up first missed most images.** Two mistakes, both found on the scratch box before any demo box got the
release: it did not run on the Remove button, and it could not see images stored without a name. Both fixed and
tested. That is why the version is 0.284.2 (0.284.0 and 0.284.1 never went out).
- **wanderer** can now run on the test bench, but its update is not tested yet: I could not create test data in it.
Also found: its search engine needs one extra setting before any update, or it refuses to start.
- **Two exact versions were rebuilt by their makers under the same name** (nextcloud and sonarr). The monthly re-test
finds them. Tonight I only did the database images, as you ruled.
- **mealie locks the account after five wrong passwords** — also when a stranger types them. Written down.
- **Old controller versions** still pile up on each box (about 50). Your rule covered apps only. Written down.
- **The monthly re-test could not start on a fresh test bench.** It checked for its own files before it copied them. Fixed.
- **Four more apps can be locked by strangers like mealie:** calibre-web (up to a day), wger (30 minutes, and everyone at
once), Grafana (5 minutes), BookStack (1 minute). I read this in their code; not tested on a box yet. Written down.
- **Very old controller versions are gone from our own registry** (everything before mid-August). Nothing needs them
today. I do not know what removed them. Written down.
**Rows.** Tonight: 5 closed, 3 narrowed, 6 opened. The list went from 377 to 383 rows (counted with every row, including three whose number has a letter — the old check skipped those).
**Rows.** Today: 6 closed, 1 narrowed, 4 opened. The list went from 383 to 387 rows.
## What needs you
1. **Who presses the monthly re-test?** It is one command, but it needs the test bench and the scratch box set up
first, so it cannot run by itself (the steps are written down). Options: CC does it in a monthly session, or you
start it. If nobody presses it, same-name security fixes wait until the next time we move that app.
2. **Should the monthly re-test cover every app, or only databases?** Exact versions get rebuilt too (nextcloud,
sonarr). If you do nothing, only databases are re-tested.
3. **Old controller versions:** keep only the current and the previous one? If you do nothing, about 150 MB per release
keeps piling up.
4. **No golden bake is due** — tonight's bake carries the newest controller.
1. **Nothing urgent.** If you want the household to be safe from the hourly re-lock in mealie, say so: then I give it a
secret login name, and the app page shows it. If you do nothing, a stranger who keeps trying can keep mealie locked.
2. **Do you know what removed the old controller versions from the registry?** If you do nothing, I look at the Gitea
settings next time (read only).
## Standing steps
- **Monthly:** the same-name security re-test (runbook `monthly-floating-retest.md`).
- **Weekly:** the golden bake (around 7 October).
- **Monthly security re-test: last run 2026-10-01, next due ~2026-11-01.** (You start it with the standing brief.)
- **Weekly:** the golden bake (around 8 October).
@@ -621,6 +621,21 @@ R-636's louder repeated alarm.
**Why:** about 50 old controller versions sat on each demo box (R-745); a release is ~400 MB unpacked and several ship
a day. Registry tags are never deleted by this.
### 2026-10-01 — decided by CC unattended, operator may reverse
57. **mealie's account lock lasts 1 hour (in practice 1–2 h), not 24** — *decided by CC unattended 2026-10-01 (R-747) —
operator may reverse.* **Question:** how long may a stranger's five wrong passwords lock the household out of mealie?
**Options:** (a) keep mealie's default 24 h — the strongest guard against guessing, and a stranger who knows the public
login (`admin` / `changeme@example.com`) locks the household out for a day; (b) `SECURITY_USER_LOCKOUT_TIME=1` — the
unit's minimum; mealie's hourly job lifts it, so 1–2 h; still 5 tries per lock against guessing; (c) no lock (a huge
attempt limit) — strangers cannot lock anyone out, and nothing slows guessing but the hash; (d) rename the login to
something unguessable after install — the guard stays and strangers cannot aim it, but it changes what the household
types and what the app page shows. **Why (b):** the brief prefers a short lockout over none; a household would not
notice the weaker guard (5 tries per 1–2 h against a generated 30-character first password); (d) changes a promise on
the page and stays open as an option. **Measured on 9202:** 5 wrong → the right password 423 for 120 min, then 200; a
wrong one 401 after. **Limit, stated:** the lock is per account and the name is public, so a stranger can renew it
every hour. Catalog `a4597cd`.
### 2026-09-30 (day) — operator notes, recorded before the work
- **The day brief runs by day.** Every backup and automatic-update test is started by hand — the night chain's debug
@@ -28,3 +28,64 @@
06:34:53 +18 min right password: 423
06:36:53 +20 min right password: 423
06:38:53 +22 min right password: 423
06:40:53 +24 min right password: 423
06:42:53 +26 min right password: 423
06:44:53 +28 min right password: 423
06:46:53 +30 min right password: 423
06:48:53 +32 min right password: 423
06:50:53 +34 min right password: 423
06:52:53 +36 min right password: 423
06:54:53 +38 min right password: 423
06:56:53 +40 min right password: 423
06:58:53 +42 min right password: 423
07:00:53 +44 min right password: 423
07:02:53 +46 min right password: 423
07:04:53 +48 min right password: 423
07:06:53 +50 min right password: 423
07:08:53 +52 min right password: 423
07:10:53 +54 min right password: 423
07:12:53 +56 min right password: 423
07:14:53 +58 min right password: 423
07:16:53 +60 min right password: 423
07:18:53 +62 min right password: 423
07:20:53 +64 min right password: 423
07:22:53 +66 min right password: 423
07:24:53 +68 min right password: 423
07:26:54 +70 min right password: 423
07:28:54 +72 min right password: 423
07:30:54 +74 min right password: 423
07:32:54 +76 min right password: 423
07:34:54 +78 min right password: 423
07:36:54 +80 min right password: 423
07:38:54 +82 min right password: 423
07:40:54 +84 min right password: 423
07:42:54 +86 min right password: 423
07:44:54 +88 min right password: 423
07:46:54 +90 min right password: 423
07:48:54 +92 min right password: 423
07:50:54 +94 min right password: 423
07:52:54 +96 min right password: 423
07:54:54 +98 min right password: 423
07:56:54 +100 min right password: 423
07:58:54 +102 min right password: 423
08:00:54 +104 min right password: 423
08:02:54 +106 min right password: 423
08:04:54 +108 min right password: 423
08:06:54 +110 min right password: 423
08:08:54 +112 min right password: 423
08:10:54 +114 min right password: 423
08:12:54 +116 min right password: 423
08:14:54 +118 min right password: 423
08:16:55 +120 min right password: 200
08:16:55 RESULT: locked for 120 min (last answer 200)
08:16:55 right password again: 200 | a wrong one after: 401
08:16:58 INFO 2026-10-01T10:12:54 - [192.168.0.180:0] 423 Locked "POST /api/auth/token HTTP/1.1"
ERROR 2026-10-01T10:14:54 - User is locked out from 192.168.0.180
ERROR 2026-10-01T10:14:54 - User is locked out from 192.168.0.180
INFO 2026-10-01T10:14:54 - [192.168.0.180:0] 423 Locked "POST /api/auth/token HTTP/1.1"
INFO 2026-10-01T10:16:22 - locked users reset
10:17:00 [X] stop -> 200 {'ok': True, 'message': 'Stack mealie stop completed'}
10:17:32 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'mealie', 'volumes_removed': ['mealie_mealie_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalm
10:17:40 [X] after remove: deployed=False leftovers='/opt/docker/stacks/mealie'
08:17:40 removed: False
@@ -0,0 +1,13 @@
# The operator's three rulings of 2026-10-01 built (day session)
Report and Part table: `felhom.eu/REPORT-rulings-2026-10-01.md`. Monthly run evidence: `../retest-2026-10/`. Golden:
`documentation/tests/golden-0.285.0-2026-10-01/`.
| folder | what |
|---|---|
| `A/` | the bench created (60 GB, swap 0), the drill reset, 9202 pointed at the drill, 9202's containers before |
| `B/` | controller image retention: `B0` the boxes before, `B1` red-proofs, `B2` 9202 deploy + pass (`B2-9202-selfupdate.txt` is empty: that attempt found self-update off on 9202 and was stopped), `B3`/`B4`/`B5` demo boxes before, the floor, after |
| `C/` | mealie: `C0` the drill-only commit, `C1` the 1-hour lock measured as a stranger (120 min) |
| `D/` | `D1` R-746 digest resolver (unit red + live registry), `D2` R-744 outline fixture on 9202 |
| `T/` | teardown: bench destroyed, 9202 back on live, drill reset |
| `tools/` | `walk.py`, `repoint.py` (this folder's paths), `b_9202.py`, `b_selfupdate.py`, `c_mealie.py`, `d_outline.py` |
@@ -0,0 +1,15 @@
git:
branch: main
repo_url: https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
sync_interval: 15m
token: <redacted>
username: ""
hub:
0
felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.285.0
filebrowser gtstef/filebrowser:1.3.3-stable
paperless-postgres postgres:18-alpine
paperless-redis redis:7-alpine
paperless-webserver ghcr.io/paperless-ngx/paperless-ngx:2.20.15
traefik traefik:v3.6.7
@@ -0,0 +1,5 @@
# drill reset 2026-10-01T08:18:54Z
drill before: df5a2a2; live: a4597cd
df5a2a2 DRILL mealie: SECURITY_USER_LOCKOUT_TIME=1 (R-747 proof on 9202)
drill after: a4597cd
image lines IDENTICAL
+1 -1
View File
@@ -858,7 +858,7 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
| **R-744** | **[P3-LOW] outline's fixture cannot seed outline 1.10.1: no `csrfToken` cookie after `installation.create`.** MEASURED 2026-09-30 on both venues (bench and 9202, the end-to-end re-test's first attempt): `POST /api/installation.create` answered 302 with the session, and `GET /home` set no `csrfToken` cookie (1.9.1 did; the 1.9.1 → 1.10.1 step read back that afternoon because its read-back uses the API key made at 1.9.1). So the NEXT outline step, and any re-test of outline, stops at C1 with „no csrfToken cookie from GET /home". **Needs:** the fixture reads outline 1.10.1's CSRF the way its page does (measure first). `audits/night-rulings-2026-09-30/A/e2e/*outline-attempt*` **-- 2026-10-01:** Outline 1.10 names the cookie `__Host-csrfToken` on a secure request (`server/utils/csrf.ts`); the fixture accepts both names (catalog `9fc7052`). Proven on 9202 at the live pin 1.10.1: seed, read back, unknown id and wrong key refused. Outline has no newer release than 1.10.1, so no step. `audits/rulings-2026-10-01/D/D2-outline-fixture-9202.txt` | **CLOSED 2026-10-01 — fixture fixed, proven on 9202** |
| **R-745** | **[P3-LOW] Old CONTROLLER images are never deleted: ~50 versions on each demo box.** MEASURED 2026-09-30 after v0.284.2's one-time sweep: every image no container uses on demo-hp and on the N100 is a `felhom-controller` tag (0.201.0 … 0.283.1); the N100 still reads 3.6 GB reclaimable. Decision 53 covers APP images, and the sweep leaves the controller's own images alone on purpose (the self-update may need the previous one). A release is ~150 MB and there are several a day. **Needs:** the same rule for the controller — keep the running and the previous tag — as a decision (the self-update's rollback reads which image?). `audits/night-rulings-2026-09-30/E/` **-- 2026-10-01:** Decision 56 built: controller v0.285.0 keeps the running image + the previous (the swap record; version order as fallback), deletes older/untagged ones. **Measured first:** the agent rolls back to the RUNNING image (what `/etc/felhom-controller-image` named), never to a previous one the controller hands it. After the floor: demo-hp 84 → 2 controller images (Docker images 15.2 → 11.65 GB), the N100 76 → 2 (6.07 → 1.11 GB), 9202 5 → 2. `audits/rulings-2026-10-01/B/` | **CLOSED 2026-10-01 — controller v0.285.0, floor 0.285.0** |
| **R-746** | **[P3-LOW] `image_digest.resolve` ignores a `@digest` in its argument — it answers the TAG's current digest.** MEASURED 2026-09-30: `resolve('redis:7-alpine@sha256:000…0')` returned `sha256:858f…` (the tag's), while a manifest request for that digest answers 404. Every gate today passes it a plain tag, so no gate is wrong; a caller that passes `ref@digest` to ask "is THIS digest still served" gets a false yes. **Needs:** refuse a digest-carrying ref, or ask for the manifest by digest (with a test). `scripts/image_digest.py` **-- 2026-10-01:** `resolve()` asks the registry for the manifest BY DIGEST when the ref carries one; a malformed digest is refused without a request (catalog `804884a`, `scripts/test_image_digest.py`; red: the old resolver fails 3 of 4). Live: `redis:7-alpine@sha256:000…0` → HTTP 404 (was the tag's digest). `audits/rulings-2026-10-01/D/D1-r746-digest.txt` | **CLOSED 2026-10-01 — catalog 804884a** |
| **R-747** | **[P3-LOW] A stranger can lock the household out of mealie with five wrong logins.** MEASURED 2026-09-30 on 9202 (the R-741 proof): after the install hold opened, a stranger's default-login tries were refused (401) and after five of them mealie answered 423 (locked) to every login — the generated, correct password included. mealie's own brute-force guard, on an app published on the internet; the setup gate and the install hold do not cover an app after its first setup. Not measured: how long the lock lasts. **Needs:** measure the lock's length; decide whether the page tells the household what to do. `audits/night-rulings-2026-09-30/C/C3-mealie-poll.txt` | **READY — rank P3-LOW; owner: CC** |
| **R-747** | **[P3-LOW] A stranger can lock the household out of mealie with five wrong logins.** MEASURED 2026-09-30 on 9202 (the R-741 proof): after the install hold opened, a stranger's default-login tries were refused (401) and after five of them mealie answered 423 (locked) to every login — the generated, correct password included. mealie's own brute-force guard, on an app published on the internet; the setup gate and the install hold do not cover an app after its first setup. Not measured: how long the lock lasts. **Needs:** measure the lock's length; decide whether the page tells the household what to do. `audits/night-rulings-2026-09-30/C/C3-mealie-poll.txt` **-- 2026-10-01:** Measured at v3.28.0 (source + 9202): 5 wrong logins lock the ACCOUNT (not the IP) for `SECURITY_USER_LOCKOUT_TIME` hours (default 24); the lock is lifted by an hourly job; an admin can unlock others via `POST /api/admin/users/unlock`, but the household's only admin is the locked account. Both login names are public (`admin`, `changeme@example.com`). **Fixed** (`09` §3 decision 57, decided by CC unattended — operator may reverse): `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; on 9202 the right password answered 423 for 120 min, then 200; a wrong one still 401 (`audits/rulings-2026-10-01/C/`). **Left:** a stranger can renew the lock every hour (per account, public name — option (d) in decision 57 would end that); the page does not tell the household why it is locked; an INSTALLED mealie takes the new setting only when its compose is rendered again (not measured which act does that). | **NARROWED — the lock is 1–2 h; renewal and the page remain; owner: CC** |
| **R-748** | **[P3-LOW] The register-shape gate skipped every row whose id has a letter suffix — so R-88a, R-88b and R-209a were never shape-checked, and its count read 3 short.** FOUND 2026-09-30 (late) while counting the register: `register_shape_gate.py` matched `R-\d+` only; the brief's „the reviewer's regex undercounted by 3” is the same three rows. Fixed the same session: `R-\d+[a-z]?`; decoy `suffix-row-eaten-state` (a suffixed row with its state cell eaten) seen passing with the old pattern and convicted with the new. The register is **382** rows by either count now. | **CLOSED 2026-09-30 — `scripts/register_shape_gate.py`** |
| **R-749** | **[P3-LOW] `retest-floating.py` could never start on a fresh bench: it checked for `/opt/upg/upgrade-test.py` on the bench BEFORE the step that copies it there.** FOUND 2026-10-01 at the first full monthly run (decision 55): bench 9401 freshly created by the runbook, the run answered „CANNOT START — missing: the bench LXC 9401 on demo-hp with /opt/upg” in one minute. The runbook says the command syncs the bench itself — it does, but only after the check. On 2026-09-30 the bench had been synced by hand earlier, so nobody saw it. **Needs:** the check asks for what the bench must bring (docker, python3), the sync then provides `/opt/upg`. `audits/rulings-2026-10-01/A/` **-- 2026-10-01:** Fixed the same session (catalog `9e53205`): the check asks for docker + python3; after the sync `/opt/upg/upgrade-test.py` is required. The re-run started at once and finished both apps. | **CLOSED 2026-10-01 — catalog 9e53205** |
| **R-750** | **[P3-LOW] The registry no longer holds controller releases older than 0.213.0 (2026-08-12) — something removed them, and nothing records what.** MEASURED 2026-10-01 (anonymous registry API, `audits/rulings-2026-10-01/B/`): `felhom-controller` has 91 tags, the oldest release 0.213.0; `0.201.0` answers 404; Gitea's package list starts 2026-08-12. No runbook, row or memory names a clean-up. Today nothing needs those versions: a box runs a newer one, a whole-guest restore brings the guest's own Docker store back (mp0 `backup=1`), and decision 56 deletes only on the box. **But** a box or a backup that names a removed version cannot pull it again (R-698's shape, for the controller). **Needs:** find what removed them (a Gitea clean-up rule?), and record the rule — or say it was a one-time act. Read-only on DooPlex. | **OPEN — rank P3-LOW; owner: operator (Gitea settings), CC measures** |