Upgrade harness: four fixtures and seven real upstream edges from the update night (R-462)
gates / gates (push) Successful in 1s

Test code only — no template changed and no image: line moved.

The update night walked real within-a-major upstream edges on scratch guest 9202 through the
product's own guarded Update, against a PRIVATE DRILL CATALOG; the live catalog was never
touched. This brings the expensive half of that work — the seed routes — back into the harness
so the same edges can be run here WITH their ABORT step, which the box deliberately does not
offer (09 6.1: whether the old image starts on migrated data is per-app and unpredictable).

- upgrade_fixtures.py: ActualBudget, Navidrome, AudiobookShelf, Vikunja. Each seeds through the
  app's OWN interface (R-156); each carries a negative control run on every verify(), so a
  readback that has broken into always succeeding fails instead of passing everything.
- upgrade-test.py: edges U1..U7, all real upstream moves existing 2026-09-21 that this catalog
  has NOT made, each holding its database engine constant.
- Limitations kept: Navidrome and AudiobookShelf seed the DATABASE half only, and say so.

OWED, stated so it is not mistaken for done: the U1..U7 harness RUNS, and with them the per-app
ABORT answers. The code is in; the runs are not.

Gates: catalog_gates.py --fast — image-pins, engine-major, catalog-since, copy-i18n all OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-21 21:00:50 +02:00
parent f5f6a152b5
commit 4463243f2e
4 changed files with 320 additions and 61 deletions
+32
View File
@@ -81,6 +81,38 @@ EDGES = {
"E3b": dict(app="bookstack", note="AUTHORED step: engine half alone",
frm={"bookstack": "lscr.io/linuxserver/bookstack:26.05.2", "bookstack-db": "mariadb:11.6"},
to={"bookstack": "lscr.io/linuxserver/bookstack:26.05.2", "bookstack-db": "mariadb:12.3"}),
# --- added 2026-09-21 by the update night (R-462's widening) -------------------------------
# Every one of these was run BOX-SIDE FIRST, through the product's own guarded Update on guest
# 9202, with the data read back through the app's own front door before and after. They are
# here so the same edge also gets its ABORT step, which the box deliberately does not offer
# (`09` §6.1: the box never puts the old version back by itself, because whether the old image
# starts on migrated data is per-app and cannot be predicted).
#
# These are REAL UPSTREAM MOVES that existed on 2026-09-21 and that the catalog has NOT made.
# They are candidates the operator may promote; the harness is where the abort answer for each
# of them comes from.
"U1": dict(app="privatebin", note="real upstream move 2.0.5 -> 2.0.6; file-backed, no database",
frm={"privatebin": "privatebin/pdo:2.0.5"},
to={"privatebin": "privatebin/pdo:2.0.6"}),
"U2": dict(app="docmost", note="real upstream move 0.95.0 -> 0.96.0; PostgreSQL CONSTANT across it",
frm={"docmost": "docmost/docmost:0.95.0", "docmost-postgres": "postgres:16-alpine"},
to={"docmost": "docmost/docmost:0.96.0", "docmost-postgres": "postgres:16-alpine"}),
"U3": dict(app="bookstack", note="real upstream move 26.05.2 -> 26.05.5; MariaDB CONSTANT across it",
frm={"bookstack": "lscr.io/linuxserver/bookstack:26.05.2", "bookstack-db": "mariadb:12.3"},
to={"bookstack": "lscr.io/linuxserver/bookstack:26.05.5", "bookstack-db": "mariadb:12.3"}),
"U4": dict(app="actualbudget", note="real upstream move 26.7.0 -> 26.9.0; SQLite in its own volume",
frm={"actualbudget": "actualbudget/actual-server:26.7.0"},
to={"actualbudget": "actualbudget/actual-server:26.9.0"}),
"U5": dict(app="navidrome", note="real upstream move 0.63.2 -> 0.64.0; DATABASE HALF ONLY",
frm={"navidrome": "deluan/navidrome:0.63.2"},
to={"navidrome": "deluan/navidrome:0.64.0"}),
"U6": dict(app="audiobookshelf", note="real upstream move 2.35.1 -> 2.36.1; DATABASE HALF ONLY",
frm={"audiobookshelf": "ghcr.io/advplyr/audiobookshelf:2.35.1"},
to={"audiobookshelf": "ghcr.io/advplyr/audiobookshelf:2.36.1"}),
"U7": dict(app="vikunja", note="real upstream move 2.3.0 -> 2.6.0; the app migrates its own SQLite",
frm={"vikunja": "vikunja/vikunja:2.3.0"},
to={"vikunja": "vikunja/vikunja:2.6.0"}),
}