Commit Graph

389 Commits

Author SHA1 Message Date
admin 55b8c8a147 wger: lifecycle hidden until R-762 and R-763 are fixed (operator ruling 2026-10-01)
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 16:09:40 +02:00
admin dc0ab8b2a8 New-app checklist: reviewed, a gate (onboarding), the wger pilot record, the existing apps' gap page
gates / gates (push) Successful in 2s
NEW-APP-CHECKLIST.md: the reviewer's draft reviewed - 60 rows in 10 groups, each with how/why and a since date;
7 rows added, 16 sharpened, 9 wrong claims fixed. onboarding/_TEMPLATE.md (one line per id), onboarding/wger.md
(the pilot, exempt app, 11 open rows each a register row), onboarding/EXISTING-APPS-GAPS.md (read only, from
scripts/onboarding_gaps.py). Gate onboarding (scripts/check-onboarding.py) in --fast: a template directory not
among the 53 published before 2026-10-01 needs a complete record; decoys in test_gate_decoys.py (16 cases, 5 gate
mutants seen red). CLAUDE.md, REUSE.md 5, README point to it. No template changed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 15:20:52 +02:00
admin 6d72c091e0 Merge branch 'main' of https://gitea.dooplex.hu/admin/app-catalog-felhom.eu
gates / gates (push) Successful in 2s
2026-10-01 14:49:19 +02:00
admin 6f18f74e6b new app checklist 2026-10-01 14:48:25 +02:00
admin 9c5eae9999 CHANGELOG + REPORT: calibre-web generated login name (decision 61); an installed app's template is not frozen (R-757)
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 13:29:50 +02:00
admin e9f50b5496 calibre-web: the admin login name is generated at install (09 decision 61, R-752)
gates / gates (push) Successful in 2s
after_install renames admin to the generated ADMIN_USER in app.db, sets the password with cps.py -s, and proves both
before its success line. Proven on 9202: 40 wrong tries on admin, the household still in at once (form and OPDS).
Hungarian freeze re-captured for the five changed calibre-web strings only.
Evidence: felhom.eu/documentation/audits/calibre-name-and-prune-2026-10-01/A/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 13:19:02 +02:00
admin ed6df4b46b CHANGELOG + REPORT: wger lockout fix, three apps measured (R-752)
gates / gates (push) Successful in 3s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 12:49:39 +02:00
admin 82fff329a4 wger: a stranger locks only the name they try, for 5 min — not every household member for 30 (R-752, 09 decision 58 — decided by CC unattended, operator may reverse)
gates / gates (push) Successful in 2s
django-axes keyed on ip_address, and behind the tunnel every visitor has the tunnel container's address (R-753).
Measured on 9202 (felhom.eu/documentation/audits/lockouts-2026-10-01/B/): live template — 10 wrong tries on admin
locked the second member too; with AXES_LOCKOUT_PARAMETERS=username, AXES_COOLOFF_TIME=5 and the database handler —
the second member unaffected, admin in again at 7.5 min after one retry during the lock, a wrong password still
refused. Settings only: no image moves, no ladder entry (gates OK).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 12:46:58 +02:00
admin 83636352ea REPORT: the first full monthly re-test, mealie's lockout, R-744/R-746/R-749
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 10:21:00 +02:00
admin a4597cd005 mealie: lockout 1 hour instead of 24 (R-747, 09 decision 57 — decided by CC unattended, operator may reverse)
gates / gates (push) Successful in 2s
mealie locks the ACCOUNT after 5 wrong logins and its login names (admin, changeme@example.com) are public, so a
stranger could lock the household out for a day. Measured on 9202 with SECURITY_USER_LOCKOUT_TIME=1: the right
password answered 423 for 120 min (the hourly job lifts it after the hour), then 200; a wrong one still 401.
Evidence: felhom.eu/documentation/audits/rulings-2026-10-01/C/. CHANGELOG also records today's re-test run and fixes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 10:18:17 +02:00
admin 9fc705209d outline fixture: read Outline 1.10's __Host-csrfToken cookie (R-744)
gates / gates (push) Successful in 2s
Outline 1.10 names the CSRF cookie __Host-csrfToken on a secure request and csrfToken over plain HTTP (server/utils/
csrf.ts getCookieName); 1.9.1 always said csrfToken. Proven on 9202 at the live pin 1.10.1: installation.create 302,
cookie __Host-csrfToken, apiKeys.create, a published document read back, unknown id and wrong key refused
(felhom.eu/documentation/audits/rulings-2026-10-01/D/D2-outline-fixture-9202.txt). The old pattern cannot match that
header line (the red: 2026-09-30, both venues).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 08:19:19 +02:00
admin 804884a749 image_digest.resolve honours a @digest: asks the registry for THAT manifest (R-746)
gates / gates (push) Successful in 2s
The digest was dropped and the tag's current digest returned, so 'is this digest still served' got a false yes
(measured: redis:7-alpine@sha256:000…0 resolved to the tag's digest; now HTTP 404). A malformed digest is refused
without a request. test_image_digest.py (no network); red-proof: the pre-fix resolver fails 3 of 4 cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 07:54:39 +02:00
admin 1a37032f99 sonarr: re-test of the same tag at a new digest (decision 52, R-740)
gates / gates (push) Successful in 2s
STEP sonarr: the superseded step {'sonarr': 'lscr.io/linuxserver/sonarr:4.0.20'} keeps its definition at steps/bf0bfeab9db53720.yml
STEP sonarr: … and its .felhom.yml at steps/bf0bfeab9db53720.felhom.yml
WROTE sonarr: RE-TEST {'sonarr': 'lscr.io/linuxserver/sonarr:4.0.20'} -> {'sonarr': 'lscr.io/linuxserver/sonarr:4.0.20'} peak 13.9% marks {'files_may_change': False, 'needs_person': None, 'memory_tight': False} digest {'sonarr': 'sha256:a5c1a5fecbef946927ab90ad68df319ac5fe644057e5fc18cd993f01ac07b2b2'} -> {'sonarr': 'sha256:f247545d23ba8b233d6604575347e48a623fe6ad75dda02348bf81917f3b5c06'}

Evidence: felhom.eu/documentation/audits/retest-2026-10/sonarr
2026-10-01 07:53:44 +02:00
admin 3b59dfb1bc nextcloud: re-test of the same tag at a new digest (decision 52, R-740)
gates / gates (push) Successful in 2s
STEP nextcloud: the superseded step {'nextcloud': 'nextcloud:34.0.4-apache', 'nextcloud-db': 'mariadb:12.3', 'nextcloud-redis': 'redis:7-alpine'} keeps its definition at steps/61e93c3e1a1806df.yml
STEP nextcloud: … and its .felhom.yml at steps/61e93c3e1a1806df.felhom.yml
WROTE nextcloud: RE-TEST {'nextcloud': 'nextcloud:34.0.4-apache', 'nextcloud-db': 'mariadb:12.3', 'nextcloud-redis': 'redis:7-alpine'} -> {'nextcloud': 'nextcloud:34.0.4-apache', 'nextcloud-db': 'mariadb:12.3', 'nextcloud-redis': 'redis:7-alpine'} peak 23.7% marks {'files_may_change': False, 'needs_person': None, 'memory_tight': False} digest {'nextcloud': 'sha256:a5ace30c695afe48c2c406e940ee7886a81e13fa382e57cd68b2416d1a66914c', 'nextcloud-db': 'sha256:805c8e104bd563d5bfa24fadd3f31cd419ea859cb5277f32b5dbf2db714f9ed1', 'nextcloud-redis': 'sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499'} -> {'nextcloud': 'sha256:37b109885aa3cba3e056362a899556a625c986f2c17cd2c0cc157d21c789f53b', 'nextcloud-db': 'sha256:805c8e104bd563d5bfa24fadd3f31cd419ea859cb5277f32b5dbf2db714f9ed1', 'nextcloud-redis': 'sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499'}

Evidence: felhom.eu/documentation/audits/retest-2026-10/nextcloud
2026-10-01 07:37:51 +02:00
admin 9e53205938 retest-floating: check what the bench brings (docker, python3), not what the sync puts there (R-749)
gates / gates (push) Successful in 1s
The check asked for /opt/upg/upgrade-test.py before sync_bench() copies it, so a bench freshly created by the
runbook was refused in one minute (2026-10-01). After the sync, the file is now required.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 07:17:49 +02:00
admin efd492d0bb CHANGELOG + REPORT: same-tag re-tests (decision 52), wger's key, wanderer on the bench
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 23:23:16 +02:00
admin 6a3ead9ebe Same-tag security fixes as tested steps (09 decision 52, R-740): re-test entries, their gates, the monthly command
gates / gates (push) Successful in 2s
- A RE-TEST entry: from == to, digest = the registry's new digest, digest_from = the tested one, box_evidence.
  ladder.check_entry refuses one with no new digest, no digest_from or no box proof; check-test-record rule 2b
  ties digest_from to the previous entry's digest; check-test-record-move now judges re-tests too (they change
  .felhom.yml only — the gate looked at compose moves alone) and refuses a digest the registry no longer serves.
  Decoys: 8 cases in test_gate_decoys.py, seen red with the rules switched off.
- upgrade-test.py --retest <app> [svc]: FROM the ladder head's tested digest TO the registry's current one, the
  full method; --write-ladder writes a re-test entry (plain refs + digest_from), refusing without the box venue or
  when the registry moved again. Writer tests, red-proofed.
- scripts/retest-floating.py — ONE command: --dry-run lists, --engines-only is the ruled start; bench, box
  (retest_box.py on 9202 via the drill catalog), writer, gates, one commit per app. box_walk.py moves the box
  client into the catalog. Run today: nothing to re-test on the database/redis lines.
- End to end on 9202 (drill): docmost at the OLD redis digest, the re-test, "run tonight's chain now" -> the leg
  pressed it, the new digest runs, read back, badge current.
- Also: upgrade-test.py BENCH_ENV_OVERRIDES (R-739, wanderer's DB address on the bench, recorded per verdict);
  test_gate_decoys.py read kimai's tag and date from the clone (red on main since kimai moved).

Evidence: felhom.eu/documentation/audits/night-rulings-2026-09-30/A/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 23:06:09 +02:00
admin 45d84827ad wger: its app login API gets its JWT key pair (R-737)
gates / gates (push) Successful in 2s
The template set no JWT_PRIVATE_KEY/JWT_PUBLIC_KEY, so the app login (the mobile app's route) answered 500
on a CORRECT password. The deploy's generators cannot make an RSA pair, so the start command makes it ONCE
with wger's own `manage.py generate-jwt-keys`, keeps it 0600 on wger's data volume (a restore brings it
back), and loads it before the image's own entrypoint. Measured on the bench (2.7): right password 200 with
an access token that reads the API (200); wrong password 400 (allauth's answer); the key survives a
restart. No image moves.

Evidence: felhom.eu/documentation/audits/night-rulings-2026-09-30/D/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 22:27:13 +02:00
admin d18116539a CHANGELOG + REPORT: twelve more steps, six first ladders (R-462, R-738, R-742, R-732)
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 20:26:54 +02:00
admin fb8703020e zipline: 4.7.0 -> 4.8.0, its second ladder step, both venues proven (R-462, R-742)
gates / gates (push) Successful in 2s
The route 4.8.0 itself asks for (its prisma -> drizzle migration needs 4.7.x first). Bench 9401
(harness v4, swap 0; two earlier attempts stopped at the FROM pull because the bench's own disk was
full — images removed by name, no prune): the user logs in before and after, 10-min watch 0 kills
(anon peak 34.3 %); the abort starts and serves. Box 9202: done in 32.8 s, the user logs in.
4.7.0 keeps its definition in steps/. Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 20:22:53 +02:00
admin a9700e2b4c zipline: 4.6.1 -> 4.7.0, its first ladder step, both venues proven (R-462, R-742)
gates / gates (push) Successful in 2s
4.8.0 cannot be reached in one step: it refuses to start until the database has run the release
before it (prisma -> drizzle; measured on both venues; the box undid it by itself in 20 s). So the
first step is 4.7.0. Bench 9401 (harness v4, swap 0): the first user made through /api/setup and
logging in before and after, 10-min watch 0 kills (anon peak 41.7 %); the abort starts and serves.
Box 9202: done in 103.6 s through the setup gate, the user logs in. PostgreSQL 16 does not move.
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 20:05:42 +02:00
admin 84de9a9254 harness: zipline's readback logs in with the right password first (its login limit answered 429 after the wrong-password control; R-742)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 20:05:31 +02:00
admin 48440ce01c immich: step v3.0.3 -> v3.2.2 (0b8272068aab36bf) re-proven at 768M; its definition rewritten by the writer (R-732)
gates / gates (push) Successful in 2s
That step still pinned immich-postgres at 512M. It re-runs the geodata import (v3.0.3 ships geodata
dated 2026-07-13, v3.2.2 2026-08-30 — read inside both images), the load R-732 measured at ~575 MB.
Re-proof on bench 9401, swap 0, on the step's OWN definition with only the limit changed (768M;
mem_limit 4096M -> 4480M): `Starting geodata import` ... `Geodata import completed` in 17 s, the
database's kill counter 0 from its birth, the album read back, 10-min watch 0 kills (anon peak 29.6 %).
Written by upgrade-test.py --restep; the ladder entry is untouched. No box reporting to the hub runs
immich (hub /apps, same day).

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/D/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 19:34:08 +02:00
admin 8d3a35a720 rallly: 4.11.1 -> 4.15.3, within-major step, both venues proven (R-462)
gates / gates (push) Successful in 2s
The app half only; PostgreSQL 18 does not move. Bench 9401 (harness v4, swap 0): sign-up with the
e-mail code from its own table, a poll seeded and read back before and after, 10-min watch 0 kills
(anon peak 60.6 %); putting 4.11.1 back after the migration loses the poll (recorded; the box's undo
restores the pre-update copy). Box 9202: done in 64.7 s through the setup gate, the poll read back.
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 19:18:24 +02:00
admin b0b25148a4 outline: 1.9.1 -> 1.10.1, within-major step, both venues proven (R-462)
gates / gates (push) Successful in 3s
The app half only; PostgreSQL 18 and redis 7 do not move. Bench 9401 (harness v4, swap 0): the
self-hosted workspace + a document seeded and read back before and after, 10-min watch 0 kills (anon
peak 33.5 %); the abort starts and serves. Box 9202: done in 89.2 s through the setup gate, the
document read back. Written by upgrade-test.py --write-ladder; the PG 18 step keeps its definition.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 19:14:09 +02:00
admin 63a96b0ef4 harness: --restep rewrites one superseded step's definition from a re-proof; zipline's readback waits on its health route
gates / gates (push) Successful in 2s
- upgrade-test.py --restep <verdict> --definition <dir> --catalog <c> --evidence <rel>: the only way a
  superseded step's own files (steps/<key>.yml + .felhom.yml) change after the fact (Part D: immich's
  step 0b8272068aab36bf still pins 512M). Refuses a non-proven or OOM-killing re-proof, the head entry,
  and a definition whose images are not the step's; leaves the ladder entry untouched (digests, box
  evidence, the box's failed-step fingerprint). Two tests; the gate accepts the result.
- zipline's verify waited on `/` for 200/302/307; on 9202 it answers 301 and the readback returned
  False with no line — it now waits on /api/healthcheck like its seed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:53:17 +02:00
admin 35dd5cf03c uptime-kuma: 2.4.0 -> 2.5.5, its first ladder step, both venues proven (R-462)
gates / gates (push) Successful in 1s
A new front-door fixture: the app's own socket.io messages over plain HTTP polling (setup, login,
addStatusPage), read back through its public /api/status-page/<slug>, with an absent-slug control.
Bench 9401 (harness v4, swap 0): proven, 10-min watch 0 kills (anon peak 43.3 %); the abort starts
and serves. Box 9202: done in 33.9 s through the setup gate, the status page read back.
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:51:17 +02:00
admin e1f0179d7a crafty-controller: 4.10.7 -> 4.11.0, its first ladder step, both venues proven (R-462)
gates / gates (push) Successful in 2s
A new front-door fixture: crafty's own API v2 (login as admin, a role created and read back, a
wrong-token control), reached over its own HTTPS port on the bench as traefik reaches it on a box.
Bench 9401 (harness v4, swap 0): proven, 10-min watch 0 kills (anon peak 2.7 % of 2048M); the abort
starts and serves. Box 9202: done in 51.3 s, the role read back. Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:41:02 +02:00
admin 4ad32aa768 wger: 2.6 -> 2.7, its first ladder step, both venues proven (R-462, R-738)
gates / gates (push) Successful in 2s
A new front-door fixture: the web login, then a weight entry through the app's own API, read back
with a no-session and a never-entered-weight control. Both venues ran on the R-738 template (7a4ff48,
migrations at start): bench 9401 proven, its migrations ran, 10-min watch 0 kills (anon peak 49.8 %);
box 9202 done in 46.2 s, the migrations ran, the entry read back. The first box walk WITHOUT the fix
failed (login 500, 12 migrations unapplied) and wrote nothing. Putting 2.6 back after the migration
loses the entries (recorded, as always; the box's undo restores the pre-update copy instead).
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:25:51 +02:00
admin 5b1972b7f9 harness: five new front-door fixtures, gitea's installer, HTTPS backends, per-file change names (R-462, R-624, R-735)
gates / gates (push) Successful in 2s
- fixtures (upgrade_fixtures_box.py): calibre-web (Upload form -> OPDS readback + the served EPUB),
  wger (web login -> weight entry API), crafty-controller (API v2 roles), uptime-kuma (socket.io
  polling: setup, login, addStatusPage -> public /api/status-page/<slug>); gitea posts its own
  first-run installer form (R-624's fixable case) and keeps the admin CLI for an installed one.
  calibre-web and wger run the template's own after_install on the bench, which has none.
- R-735: the bench's `password:N:special` now has the controller's shape (randomWithSpecial);
  test seen failing first (length 32, no special), then 45/45.
- upgrade_boxport / the memory watch: a backend traefik reaches over https (loadbalancer.server.scheme)
  is reached over https on the bench too (crafty-controller).
- upgrade-test: files-before/after-detail.json and `files_changed_detail` NAME the files behind a
  files_may_change mark (R-734's method, now in the harness); test ChangedFiles.
- test_catalog_gates: the gate count was stale (9, the runner has 10) and red on main; now 10.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:16:45 +02:00
admin 53a4a1ddf7 calibre-web: v4.0.6 -> v4.0.8, its first ladder step, both venues proven (R-462)
gates / gates (push) Successful in 1s
A new front-door fixture: a book uploaded through the app's own Upload form and read back through
its OPDS feed (listed, and the served EPUB carries the marker), with a wrong-password and an
absent-title control. Bench 9401 (harness v4, swap 0): proven, 10-min watch 0 kills (anon peak
19.3 %); the harness saw the household books folder's tree hash change, so the step carries
files_may_change (a night press needs a fresh whole copy). Box 9202: done in 64.6 s, the book read
back, and not one file in the books folder changed (per-file hashes before/after).
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:15:49 +02:00
admin 7a4ff48590 wger: run the database migrations at start (R-738)
gates / gates (push) Successful in 2s
wger's image runs `manage.py migrate` only when DJANGO_PERFORM_MIGRATIONS=True (entrypoint.sh).
Without it, 2.6 -> 2.7 through the guarded Update on 9202 ended `done` and left 12 migrations
unapplied: the web login answered 500 (no such column: core_userprofile.time_zone). With the switch,
the same step on 9202 ran the migrations and the seeded weight entry read back. No image moves here;
no box reporting to the hub runs wger.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/box/wger/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:05:48 +02:00
admin 15f4d5969a home-assistant: 2026.9.3 -> 2026.9.4, within-major step, both venues proven (R-462)
gates / gates (push) Successful in 2s
Bench 9401 (harness v4, swap 0): the onboarding owner seeded and logged in before and after,
10-min memory watch 0 kills (anon peak 32.0 %); the abort starts and serves. Box 9202: the guarded
Update done in 113.8 s through the setup gate, the owner logs in. The old head was a backfilled
harness-v1 entry; this step carries the memory watch. Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 18:05:31 +02:00
admin 9a78e3b757 ghost: 6.65.0-alpine -> 6.67.0-alpine, within-major step, both venues proven (R-462)
gates / gates (push) Successful in 2s
Bench 9401 (harness v4, swap 0): the site set up through /ghost/api/admin/authentication/setup/,
its title read back before and after, 10-min memory watch 0 kills (anon peak 26.7 %); the abort
starts and serves. Box 9202: the guarded Update done in 107.7 s through the setup gate, read back.
Written by upgrade-test.py --write-ladder.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 17:46:01 +02:00
admin 3e4aa7707e emby: 4.11.0.3 -> 4.11.0.4, within-major step, both venues proven (R-462)
gates / gates (push) Successful in 2s
Bench 9401 (harness v4, swap 0): the startup-wizard user seeded and read back before and after,
10-min memory watch 0 kills (anon peak 4.7 %); the abort starts and serves. Box 9202: the guarded
Update done in 23.6 s through the setup gate, read back. Written by upgrade-test.py --write-ladder;
the superseded step keeps its definition in steps/.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 17:45:40 +02:00
admin d7ba60c409 gitea: 1.27.0 -> 1.27.3, its first ladder step, both venues proven (R-462, R-624)
gates / gates (push) Successful in 2s
Bench 9401 (harness v4, swap 0): the first-run installer form posted, a repo seeded and read back
before and after, 10-min memory watch 0 kills (anon peak 26.6 %, cgroup 52.9 %). Box 9202: the
guarded Update done in 21.6 s through the setup gate, the repo read back. Written by
upgrade-test.py --write-ladder. 28.0.0 is a major (2026-09-02 ruling) and is not touched.

Evidence: felhom.eu/documentation/audits/more-night-apps-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 17:16:56 +02:00
admin 4c552cf56b CHANGELOG + REPORT: immich 768M + v3.2.4 (R-732)
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 16:17:17 +02:00
admin 56c4888f5e immich: v3.2.2 -> v3.2.4 with immich-postgres 512M -> 768M (R-732)
gates / gates (push) Successful in 2s
The ONLY image move in this commit; the limit rides it (09 decision 39's precedent), because the step
itself re-runs immich's geodata import (228 294 -> 228 571 places) — the load that killed the database.
Cause, measured on the bench (audits/immich-first-start-2026-09-30/A-cause.md): the first-start import
runs up to 9 concurrent 5000-row INSERTs; the database then needs ~400 MB anon + ~170 MB touched
shared_buffers (the image's own postgresql.conf fixes 512MB). At 512M with no swap: 61 kills; with 512 MB
swap: 0 (swapped ~70 MB) — why 9202 passed; shared_buffers 128MB alone: still killed; 1024M: 0; 768M: 0.
Proof at the new definition, fresh install from birth, no swap: bench x2 (anon 409/412 MB = 53 %, 0 kills,
import 8.1 s) and box 9202 (anon 368 MB = 48 %, 0 kills, swap.peak 0).
Step, written by upgrade-test.py --write-ladder: bench (harness v4) proven, 10-min watch 0 kills 0
restarts, anon peak 51.1 %; box 9202 through the guarded Update: done 58.5 s, album read back, the running
database limit 805306368 after. The step carries `files_may_change` (the harness saw only immich's six
13-byte `.immich` folder markers rewritten at start) — the night leg takes it only with a whole copy.
Per-box cost: +256 MB on immich-postgres; `mem_limit` 4096M -> 4480M (the old figure was already 128 MB
under the sum of the four limits). Header comment corrected (it said postgres 256M).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 16:13:36 +02:00
admin 06e804b824 CHANGELOG + REPORT: the last six PostgreSQL apps, Part F; zipline's fixture tries /api/setup first (R-624)
gates / gates (push) Successful in 2s
zipline 4's first-run route is POST /api/setup (measured on the bench 2026-09-30, v4.6.1: GET ->
{"firstSetup":true}, POST {username,password} -> 200 SUPERADMIN, the login works). The two paths the
fixture tried stay as fallbacks. No image moves in this commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:45:02 +02:00
admin 403a8f537a komga: within-major step, both venues proven (R-462, Part F)
gates / gates (push) Successful in 2s
{'komga': 'gotson/komga:1.27.1'} -> {'komga': 'gotson/komga:1.28.0'}
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder (catalog gates rc=0):
- bench LXC 9401 (harness v4): the seed read back before and after; 10-minute memory watch:
  komga anon 64.5 % (cgroup 67.5 %); 0 kills, 0 restarts; the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 44.2 s, the seed
  read back through the app's own front door.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/komga/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:30:27 +02:00
admin 2acfbf1e95 grafana: within-major step, both venues proven (R-462, Part F)
{'grafana': 'grafana/grafana:13.2.2'} -> {'grafana': 'grafana/grafana:13.2.3'}
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder (catalog gates rc=0):
- bench LXC 9401 (harness v4): the seed read back before and after; 10-minute memory watch:
  grafana anon 47.1 % (cgroup 100.0 %); 0 kills, 0 restarts; the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 23.6 s, the seed
  read back through the app's own front door.
  The box walk was run TWICE: the first read back 401 because the instrument lost the deploy's
  admin password between two processes (box/grafana/step-attempt1-instrument-401.txt); fixed in the
  walk tools, grafana reinstalled at 13.2.2 from the drill catalog, seeded, stepped: read back.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/grafana/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:26:47 +02:00
admin 6d91495756 navidrome: within-major step, both venues proven (R-462, Part F)
{'navidrome': 'deluan/navidrome:0.64.1'} -> {'navidrome': 'deluan/navidrome:0.64.2'}
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder (catalog gates rc=0):
- bench LXC 9401 (harness v4): the seed read back before and after; 10-minute memory watch:
  navidrome anon 6.9 % (cgroup 9.4 %); 0 kills, 0 restarts; the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 14.4 s, the seed
  read back through the app's own front door.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/navidrome/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:26:43 +02:00
admin 9f075a47ce n8n: within-major step, both venues proven (R-462, Part F)
gates / gates (push) Successful in 2s
{'n8n': 'n8nio/n8n:2.41.2'} -> {'n8n': 'n8nio/n8n:2.42.1'}
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder (gates rc=0):
- bench LXC 9401 (harness v4): the seed read back before and after; 10-minute memory watch: n8n anon 23.0 % | migration: [2Kn8n  | Migrations in progress, please do NOT stop the process.;
  0 kills, 0 restarts; the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 122.1 s, the seed
  read back through the app's own front door.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/n8n/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:12:00 +02:00
admin 7425ebd6b2 audiobookshelf: within-major step, both venues proven (R-462, Part F)
{'audiobookshelf': 'ghcr.io/advplyr/audiobookshelf:2.36.1'} -> {'audiobookshelf': 'ghcr.io/advplyr/audiobookshelf:2.37.1'}
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder (gates rc=0):
- bench LXC 9401 (harness v4): the seed read back before and after; 10-minute memory watch: audiobookshelf anon 10.5 % | migration: [2Kaudiobookshelf  | [2026-09-30 13:52:16.057] INFO: [MigrationManager] No migr;
  0 kills, 0 restarts; the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 24.6 s, the seed
  read back through the app's own front door.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/audiobookshelf/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 14:11:57 +02:00
admin d75d1fd524 kimai: apache-2.57.0 -> 2.67.0 (within major 2), both venues proven (R-462, Part F)
gates / gates (push) Successful in 3s
The ONLY image move in this commit. Upstream stopped the `apache-` tag prefix after 2.57.0;
MEASURED 2026-09-30 on Docker Hub: `2.67.0`, `2`, `stable` and `apache` all resolve to ONE digest
(sha256:3084f1e5…), while `fpm`/`latest` are another — so the plain tag IS the Apache variant.
Written by upgrade-test.py --write-ladder:
- bench LXC 9401 (harness v4, box fixture Kimai via boxport): the seeded user read back before
  and after, Doctrine migrations ran (to Version20260804090000), 10-minute memory watch: kimai
  anon 6.0 % (cgroup 91.7 % = file cache, decision 22), kimai-db anon 45.0 %, 0 kills, 0 restarts;
  the abort starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 82.1 s, the
  seeded user read back through the app's own CLI.
The superseded step keeps its definition at steps/def18c0c25cf49f7.{yml,felhom.yml}.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/kimai/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 13:27:45 +02:00
admin 54ca055efd bookstack: 26.05.5 -> 26.09.1 (within the line), both venues proven (R-462, Part F)
gates / gates (push) Successful in 2s
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder:
- bench LXC 9401 (harness v4, the bench's own BookStack fixture): FROM settled, the seeded admin
  read back, migrations ran, read back after, 10-minute memory watch peak 43.7 % (anon), 0 kills,
  0 restarts; the abort (old image back) starts and serves the data;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): done in 64.6 s, the
  seeded admin read back through the app's own CLI.
The superseded step keeps its definition at steps/fdb7afbec5ea4dbc.{yml,felhom.yml} (09 §6.4 part 5).
The database half only, as before (R-460). MariaDB 12.3 does not move.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/F/ and .../box/bookstack/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 13:14:12 +02:00
admin 1666572fd0 sparkyfitness: PostgreSQL 15 -> 18, converted by the box (R-463)
gates / gates (push) Successful in 2s
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder from both venues:
- bench LXC 9401 (harness v4): converted 15 -> 18 in 13.3 s, check equal over 94 tables, the seeded
  check-in weight read back, 10-minute memory watch peak 31.3 % (anon), 0 kills, 0 restarts;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): CONVERTED 15 -> 18 in
  9.8 s (2 databases, 94 tables, 261 rows equal), done in 58.5 s, PG_VERSION 18, the weight read
  back through the front door. Undo case on 9202 (after a reinstall at 15): the load failing
  (adminpack) -> undone in 74.9 s, back on 15, the weight read back.
Target 18: SparkyFitness's own upstream compose pairs v0.17.3 with postgres:18.3-alpine at
/var/lib/postgresql (09 decision 42's rule). PGDATA is left as it was (/var/lib/postgresql/data/pgdata),
now a folder inside the moved volume — the definition both venues tested. Only the header comment
changes beside the image and its mount.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 12:58:34 +02:00
admin aeb0cd6989 outline: PostgreSQL 16 -> 18, converted by the box (R-463)
gates / gates (push) Successful in 2s
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder from both venues:
- bench LXC 9401 (harness v4): converted 16 -> 18 in 26.7 s, check equal over 42 tables, the seeded
  document read back, 10-minute memory watch peak 48.9 % (anon), 0 kills, 0 restarts;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): converted, done in
  41.1 s, PG_VERSION 18, the document read back through the front door. Undo case on 9202 first:
  the load failing (adminpack) -> undone in 57.5 s, back on 16, the document read back.
Target 18: Outline's official self-host compose (docs.getoutline.com, Docker) runs postgres:18 at
/var/lib/postgresql (09 decision 42's rule); Outline documents PostgreSQL 14+.
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 12:54:31 +02:00
admin 25ffd89ea6 rallly: PostgreSQL 16 -> 18, converted by the box (R-463)
The ONLY image move in this commit. Written by upgrade-test.py --write-ladder from both venues:
- bench LXC 9401 (harness v4): converted 16 -> 18 in 21.4 s, check equal over 31 tables, the seeded
  poll read back, 10-minute memory watch peak 61.6 % (anon), 0 kills, 0 restarts;
- box 9202 (controller 0.283.1, the product's guarded Update, drill catalog): converted, done in
  32.8 s, PG_VERSION 18, the poll read back through the front door. Undo case on 9202 first: the
  load failing (adminpack, which 18 lacks) -> undone in 57.5 s, back on 16, the poll read back.
Target 18: rallly's own upstream compose runs postgres:18-alpine at /var/lib/postgresql at
v4.11.1 (09 decision 42's rule). The data mount moves with the image (pg_mounts_for).
Evidence: felhom.eu/documentation/audits/pg-last-six-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 12:54:11 +02:00
admin e6f3ec2087 Fixtures: sparkyfitness, rallly and outline seed through their own front door (R-462, R-624)
- Sparkyfitness: better-auth sign-up/sign-in, a check-in weight stored and read back; a wrong
  password and an empty date must read as absent. Waits out the app's own 429 (one client
  address behind traefik).
- Rallly: sign-up, the six-digit e-mail code READ (select only) from the app's own
  verifications row in place of a mailbox, verify-email, sign-in, polls.make, readback by the
  public polls.get; an unknown id must be not found.
- Outline: the self-hosted first-run route installation.create (workspace + admin, refused once a
  team exists), an API key with Outline's own CSRF pair, a document, readback by documents.info;
  an unknown id must 404 and a wrong key 401.
- outline and rallly leave the NoRoute list: both had a front-door route after all.

Measured on the bench (LXC 9401) and on 9202 2026-09-30:
felhom.eu/documentation/audits/pg-last-six-2026-09-30/

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-30 12:53:35 +02:00