The last six PostgreSQL apps, by day (2026-09-30)
Brief: the 2026-09-30 day brief (Parts 0, A–F). Architecture read first: architecture/09-update-architecture.md
§3 (decisions 16, 35, 37–39, 42–43), §6.4 parts 7 and 10, §6.4.2, §6.5; 07-backup-architecture.md §6.1.
Baselines (verified live 12:00): controller d48da6c v0.283.1 · agent d766666 v0.138.0 · felhom.eu 2de56ce ·
catalog 6446197. No controller, agent or hub release in this session.
Part 0 — Tester-2 (read only, hub GET /configs + GET /hosts, P0/)
- The customer record
Tester-2(sajatfelhom.hu) exists, its config isv0.283.1 MANAGED. - No box has registered: status and version read
—, and/hostslists no Tester-2 host. - So no apps and no
app_update.unattendedvalue exist yet to read.
Part A — the upstream table (A1, read 2026-09-30; raw notes and URLs in A1/upstream-notes.md)
Rule (decision 42): the newer major only when the app's own upstream runs it; else the newest major its stack documents.
| app | pinned app | pinned engine | upstream engine (pinned tag / newest release) | documented range | outcome | reason | EOL of the major it is on after today |
|---|---|---|---|---|---|---|---|
| outline | 1.9.1 | postgres:16-alpine |
docs self-host compose: postgres:18 at /var/lib/postgresql (the repo's own compose is dev-only) / v1.10.1 same |
PostgreSQL 14+ | → 18, moved | upstream runs 18 | 18: 2030-11-14 |
| rallly | 4.11.1 | postgres:16-alpine |
postgres:18-alpine at /var/lib/postgresql (v4.11.1 compose) / v4.15.3 same |
18 for fresh installs (rallly-selfhosted README) | → 18, moved | upstream runs 18 at the pinned tag | 2030-11-14 |
| sparkyfitness | v0.17.3 | postgres:15-alpine |
postgres:18.3-alpine at /var/lib/postgresql (v0.17.3 docker-compose.prod.yml) / v1.7.3 same |
upstream guide "PostgreSQL Upgrade (15 to 18.3)" | → 18, moved | upstream pairs this very tag with 18 | 2030-11-14 |
| zipline | 4.6.1 | postgres:16-alpine |
postgres:16 / v4.8.0 postgres:16 |
only "PG 14 supported until 2026-11-12"; nothing on 17/18 | stay 16 | upstream runs the same major | 16: 2028-11-09 |
| adventurelog | v0.13.0 (= newest) | postgis/postgis:16-3.5-alpine |
postgis/postgis:16-3.5 / same |
not documented (Django 5.2.13, psycopg2) | stay 16 | upstream runs the same major | 2028-11-09 |
| immich | v3.2.2 | …/postgres:16-vectorchord0.4.3-pgvectors0.2.0 |
…/postgres:14-vectorchord0.4.3-pgvectors0.2.0 / v3.2.4, v3.3.0-rc.0 same |
>= 14, < 20 |
stay 16 | upstream runs an OLDER major (14) than ours | 2028-11-09 |
A2 (the special images), measured from the registries and upstream source — no build, both stay:
- immich: the only PostgreSQL 18 images carry VectorChord 0.5.3+ and no pgvecto.rs; PostgreSQL 17 carries only pgvecto.rs 0.3.0. So any major move of ours would also swap an extension version → the stop rule would apply. It does not arise: upstream runs 14, so the rule says stay. Recorded in R-463.
- adventurelog (PostGIS): every candidate tag is PostGIS 3.x; a dump/load is PostGIS's own "hard upgrade" (the dump
carries
CREATE EXTENSION postgis, nopostgis_extensions_upgrade()needed). Moot: stay 16.
Part A — per-app outcome (the part-10 method: bench → 9202 → --write-ladder → one commit)
| app | bench (LXC 9401, harness v4) | box 9202 (controller 0.283.1, the guarded Update) | undo case on 9202 (the load fails: adminpack) |
memory (anon peak, 10 min) | catalog |
|---|---|---|---|---|---|
| rallly | converted 21.4 s (dump 0.54 s / 92 kB, load 1.05 s), 31 tables equal, poll read back | CONVERTED 16 → 18 in 7.1 s (2 dbs, 31 tables, 138 rows equal), done 32.9 s, poll read back | undone in 57.5 s, back on 16, poll read back | app 61.6 %, db 2.1 % | 25ffd89 |
| outline | converted 26.7 s (dump 0.58 s / 128 kB, load 1.68 s), 42 tables equal, document read back | CONVERTED 16 → 18 in 7.9 s (2 dbs, 42 tables, 312 rows equal), done 41.1 s, document read back | undone in 57.5 s, back on 16, document read back | app 48.9 %, db 5.4 % | aeb0cd6 |
| sparkyfitness | converted 13.3 s (dump 0.69 s / 378 kB, load 3.99 s), 94 tables equal, weight read back | CONVERTED 15 → 18 in 9.8 s (2 dbs, 94 tables, 261 rows equal), done 58.5 s, weight read back | (after a reinstall at 15) undone in 74.9 s, back on 15, weight read back | server 31.3 %, db 1.8 % | 1666572 |
No step is memory_tight; no limit moved; no per-box cost. Evidence: bench/apps/<app>/bench/, box/<app>/{prep,move,undo,undo-setup}.txt,
box/<app>/{box-verdict,undo-verdict}-*.json. Fixtures: catalog e6f3ec2. The engine gate printed ALLOWED for all three on push.
Seed routes — all three are the app's own front door; decision 52 was NOT needed and is not recorded:
sparkyfitness (better-auth sign-up + a check-in), outline (installation.create, its self-hosted first-run route, + an API
key + a document), rallly (sign-up, then the six-digit e-mail code READ from its own verifications row in place of a mailbox,
verify-email, polls.make). Negative control on every read-back.
Part B — the demo boxes
Neither demo box has rallly, outline or sparkyfitness installed (demo-hp 9201: adventurelog, bentopdf, bookstack,
calibre-web, docmost, kimai, opengist, paperless-ngx, privatebin, romm; demo-felhom: opengist). Nothing installed for this.
Part F's moves (bookstack, kimai) ARE on demo-hp: their conversion-free steps ran through the chain press of Part C — see C/.