Files
felhom.eu/documentation/audits/update-arc-2026-09-21/00-upstream-drift-raw.txt
T
admin 0c263c77f2
gates / gates (push) Successful in 24s
Update arc resumed: the state measured, R-524/R-520/R-589/R-469 closed, seven questions put to the operator
Phase 0 — measured, never estimated:
- both demo boxes: 10 apps, 0 behind, 0 unknown
- 46 of 58 exact catalog pins are behind upstream; 39 within a major, 7 across
- 6 of 7 measurable floating pins have been repushed since the catalog set them
  (R-446 is no longer theoretical)
- the "23 of 66 floating pins" figure repeated in four places was STALE; recounted
  to 10, with the definition written down beside it

Three claims in the brief corrected, named first:
- R-589 was NOT open — it shipped in v0.258.0; only the row was stale
- the chaos-night canary is NOT a defect — both gates refused to certify by design
- the hub half of the report confirmed, with the nuance that the raw payload is
  stored whole, so Slice 7 is cheaper than the row implies

Closed: R-524 (controller v0.260.0, proven live in both languages), R-520 (power cut
during a REAL version change — the pin goes back, the app runs, the page says so),
R-589, R-469 (MariaDB half). Filed: R-605, R-606. R-462's stale scope corrected.

09 gains §3 decision 10 (decided by CC unattended — operator may reverse), §3b with
the seven questions in the decision shape, §6.2/6.3 the two open slices, and §6.4 an
update night costed from R-462's real numbers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-21 13:13:23 +02:00

193 lines
15 KiB
Plaintext

upstream image drift audit — app-catalog-felhom.eu — 2026-09-21
======================================================================
Read-only measurement, run from DooPlex against public registries only
(Docker Hub, ghcr.io, lscr.io, registry.gitlab.com). Nothing was queried
from a customer/demo box. The catalog repo was not modified and nothing
was committed.
PRE-EXISTING REPO STATE NOTE: at the start of this session `git status
--porcelain` in app-catalog-felhom.eu already showed 3 modified files
(CLAUDE.md, scripts/check-engine-major.py, scripts/test_gate_decoys.py) —
an in-progress, uncommitted R-469 change (MariaDB major-upgrade gate)
that predates this session. This audit did not touch those files and
made no edits/commits anywhere in the repo; flagging only because the
task said 'do not modify' and the tree was already not clean.
1. INVENTORY
----------------------------------------------------------------------
Apps (templates/*/docker-compose.yml): 53
Total `image:` lines across all composes: 79
Unique image refs (pins): 66
floating (DB-engine family tag, e.g. postgres:16-alpine, mariadb:11.6,
redis:7-alpine, postgis:16-3.5-alpine): 8
pinned-semver (full app release tag): 58
App classification (from compose + .felhom.yml, not memory):
database = has a postgres/mariadb/mysql/mongo sidecar image
file-leg = binds host media/library paths (HDD_PATH / USERDATA_PATH),
no DB sidecar
other = neither
database: 14 apps -> bookstack, calcom, claper, docmost, immich, kimai, nextcloud, outline, paperless-ngx, rallly, romm, sparkyfitness, tandoor, zipline
file-leg: 9 apps -> audiobookshelf, calibre-web, emby, jellyfin, komga, navidrome, plex, radarr, sonarr
other: 30 apps -> actualbudget, adventurelog, bentopdf, code-server, crafty-controller, ghost, gitea, glance, gokapi, grafana, gramps-web, home-assistant, homebox, homepage, mealie, n8n, onlyoffice, opengist, papra, plant-it, privatebin, recipe-importer, seerr, termix, uptime-kuma, vaultwarden, vikunja, wanderer, wger, wishlist
EDGE CASE flagged, not silently folded in: `adventurelog` runs a
postgis/postgis (postgres-derivative) DB sidecar, but the string
'postgis' does not contain 'postgres'/'mariadb'/'mysql'/'mongo', so by
the literal substring rule it lands in 'other', not 'database'. If you
want postgis apps folded into 'database', adventurelog is the one app
that moves (other: 30->29, database: 14->15).
2. DEAD-IMAGE CHECK (does the pin still resolve at all)
----------------------------------------------------------------------
Ran the repo's own gate, unmodified, exactly as documented in CLAUDE.md:
$ python3 scripts/check-image-resolvable.py --all
Result: 65 of 66 pins verified via `docker manifest inspect`, ALL resolve.
NO dead images among those checked.
The 1 unchecked: msdeluise/plant-it:0.10.0 (app `plant-it`,
lifecycle: abandoned). The gate calls it INCONCLUSIVE (rc=0 but
stderr contains 'denied'/'unauthorized', which its own trap-1 logic
refuses to read as success). Independently: hub.docker.com's own
catalog API returns {"message":"object not found"} for the whole
msdeluise/plant-it repository (not just the tag), and the upstream
GitHub repo msdeluise/plant-it now 404s too — two positive signals the
image is gone, stronger than the registry gate alone captures, but I'm
stating both rather than asserting 'dead' from a registry API that
itself only said INCONCLUSIVE. This matches its already-documented
`lifecycle: abandoned` state — expected, not a new incident.
3. PINNED-SEMVER: IS THERE A NEWER TAG UPSTREAM
----------------------------------------------------------------------
pinned-semver pins evaluated: 58
behind: 46
no-newer-or-unparsed: 10
error: 1
internal-not-upstream: 1
Of the 46 pins with a newer upstream tag: 7 cross a MAJOR version,
39 are MINOR/PATCH steps (same leading version number).
NOTE ON THE MAJOR/MINOR RULE: 'major' = the first dot-separated numeric
component changed. This is literal, not semantic — it correctly reads a
real major bump for apps like nextcloud/claper/paperless-ngx, but for
calendar-versioned images (home-assistant: YYYY.MM.PATCH,
actualbudget: YY.MM.PATCH) the 'first number' is a year, so a same-year
update is correctly minor/patch and would only misread as 'major' at a
year rollover — noted, not a defect found in this sweep's data.
4. APPS BEHIND ON A PINNED-SEMVER IMAGE, sorted furthest-behind first
----------------------------------------------------------------------
STEP IMAGE REPO CURRENT NEWEST APP(S) PINNED SINCE
MAJOR nextcloud 34.0.1-apache 35.0.0-apache nextcloud 2026-07-18
MAJOR f0rc3/gokapi v1.9.6 v2.2.4 gokapi 2026-07-18
MAJOR ghcr.io/gethomepage/homepage v1.13.2 v2.4.0 homepage 2026-07-18
MAJOR codewithcj/sparkyfitness_server v0.17.3 v1.7.2 sparkyfitness 2026-07-18
MAJOR codewithcj/sparkyfitness v0.17.3 v1.7.2 sparkyfitness 2026-07-18
MAJOR ghcr.io/paperless-ngx/paperless-ngx 2.20.15 3.2.1 paperless-ngx 2026-07-18
MAJOR ghcr.io/claperco/claper 2.5 3.0 claper 2026-07-18
minor/patch plexinc/pms-docker 1.41.4.9463-630c9f557 -> 1.43.4.10903-e5521bd8c plex 2026-02-15
minor/patch emby/embyserver 4.10.0.20 4.11.0.1 emby 2026-07-18
minor/patch getmeili/meilisearch v1.36.0 v1.54.0 wanderer 2026-07-21
minor/patch ghost 6.53.0-alpine 6.64.0-alpine ghost 2026-07-18
minor/patch n8nio/n8n 2.31.3 2.40.4 n8n 2026-07-18
minor/patch lscr.io/linuxserver/code-server 4.129.0 4.138.0 code-server 2026-07-18
minor/patch ghcr.io/mealie-recipes/mealie v3.20.1 v3.27.0 mealie 2026-07-18
minor/patch lukevella/rallly 4.11.1 4.15.1 rallly 2026-07-18
minor/patch ghcr.io/lukegus/termix 2.5.0 2.8.0 termix 2026-07-12
minor/patch vikunja/vikunja 2.3.0 2.6.0 vikunja 2026-07-18
minor/patch ghcr.io/home-assistant/home-assistant 2026.7.2 2026.9.3 home-assistant 2026-07-18
minor/patch actualbudget/actual-server 26.7.0 26.9.0 actualbudget 2026-07-18
minor/patch gotson/komga 1.25.0 1.27.0 komga 2026-07-18
minor/patch rommapp/romm 5.0.0 5.2.0 romm 2026-07-18
minor/patch ghcr.io/immich-app/immich-server v3.0.3 v3.2.2 immich 2026-07-18
minor/patch ghcr.io/immich-app/immich-machine-learning v3.0.3 v3.2.2 immich 2026-07-18
minor/patch louislam/uptime-kuma 2.4.0 2.5.5 uptime-kuma 2026-07-18
minor/patch lscr.io/linuxserver/radarr 6.3.0 6.4.4 radarr 2026-07-18
minor/patch vaultwarden/server 1.36.0-alpine 1.37.3-alpine vaultwarden 2026-07-18
minor/patch grafana/grafana 13.1.0 13.2.2 grafana 2026-07-18
minor/patch ghcr.io/advplyr/audiobookshelf 2.35.1 2.36.1 audiobookshelf 2026-07-18
minor/patch docmost/docmost 0.95.0 0.96.0 docmost 2026-07-18
minor/patch outlinewiki/outline 1.9.1 1.10.1 outline 2026-07-18
minor/patch ghcr.io/cmintey/wishlist v0.66.0 v0.67.0 wishlist 2026-07-19
minor/patch ghcr.io/seanmorley15/adventurelog-backend v0.12.1 v0.13.0 adventurelog 2026-07-18
minor/patch ghcr.io/seanmorley15/adventurelog-frontend v0.12.1 v0.13.0 adventurelog 2026-07-18
minor/patch ghcr.io/diced/zipline 4.6.1 4.7.0 zipline 2026-07-18
minor/patch deluan/navidrome 0.63.2 0.64.0 navidrome 2026-07-18
minor/patch registry.gitlab.com/crafty-controller/crafty-4 4.10.7 4.11.0 crafty-controller 2026-06-26
minor/patch lscr.io/linuxserver/bookstack 26.05.2 26.05.5 bookstack 2026-07-18
minor/patch gitea/gitea 1.27.0 1.27.3 gitea 2026-07-18
minor/patch ghcr.io/alam00000/bentopdf v2.8.6 v2.8.8 bentopdf 2026-07-12
minor/patch ghcr.io/thomiceli/opengist 1.13 1.15 opengist 2026-07-18
minor/patch ghcr.io/tandoorrecipes/recipes 2.6.13 2.6.15 tandoor 2026-07-18
minor/patch glanceapp/glance v0.8.5 v0.8.6 glance 2026-07-18
minor/patch ghcr.io/papra-hq/papra 26.6.1-rootless 26.6.2-rootless papra 2026-07-12
minor/patch privatebin/pdo 2.0.5 2.0.6 privatebin 2026-09-14
minor/patch lscr.io/linuxserver/sonarr 4.0.19 4.0.20 sonarr 2026-07-18
minor/patch wger/server 2.6 2.7 wger 2026-07-19
5. BY APP CLASS
----------------------------------------------------------------------
database (14 apps, 23 unique pins):
floating: 7 pinned-semver: 16
of pinned-semver -> behind: 14 (major: 5, minor/patch: 9), up to date: 2, other: 0
file-leg (9 apps, 9 unique pins):
floating: 0 pinned-semver: 9
of pinned-semver -> behind: 7 (major: 0, minor/patch: 7), up to date: 2, other: 0
other (30 apps, 34 unique pins):
floating: 1 pinned-semver: 33
of pinned-semver -> behind: 25 (major: 2, minor/patch: 23), up to date: 6, other: 2
6. FLOATING PINS — has the tag's digest moved since the catalog set it
----------------------------------------------------------------------
Method: compare each floating tag's registry-reported last-push date
(Docker Hub API tag metadata; ghcr.io has no equivalent public
timestamp API reachable anonymously) against the app's own
`catalog_since` (the date THIS repo last moved that pin — CLAUDE.md's
own definition of 'when we set it').
mariadb:11.4 apps=romm catalog_since=2026-07-18 registry last push=2026-09-18T02:36:29.445608Z
mariadb:11.6 apps=kimai, nextcloud catalog_since=2026-07-18 registry last push=2025-02-04T13:35:57.325706Z
mariadb:12.3 apps=bookstack catalog_since=2026-07-18 registry last push=2026-09-18T02:37:26.402424Z
postgres:15-alpine apps=sparkyfitness catalog_since=2026-07-18 registry last push=2026-09-21T07:07:40.622579Z
postgres:16-alpine apps=8 apps (see below) catalog_since=2026-07-18 registry last push=2026-09-21T04:07:46.010722Z
redis:7-alpine apps=6 apps (see below) catalog_since=2026-07-18 registry last push=2026-09-18T03:04:58.155237Z
postgis/postgis:16-3.5-alpine apps=adventurelog catalog_since=2026-07-18 registry last push=2026-08-31T11:37:24.0266Z
Verdict (comparing dates above): 6 of 7 Docker-Hub-hosted floating pins
have had their tag repushed (new digest) at least once since the catalog
set them (mariadb:11.4, mariadb:12.3, postgres:15-alpine,
postgres:16-alpine, redis:7-alpine, postgis:16-3.5-alpine — pushes on or
after 2026-08-31, vs. catalog_since 2026-07-18 for all of them). Only
mariadb:11.6 (kimai, nextcloud) has NOT been repushed since pinning —
its last Docker Hub push was 2025-02-04, well before catalog_since.
ghcr.io/immich-app/postgres:16-vectorchord0.4.3-pgvectors0.2.0 (immich):
COULD NOT TELL. ghcr.io's anonymous v2 API exposes no last-modified
timestamp, and I did not have an authenticated GitHub Packages token to
query the versions API. Digest resolved today:
sha256:1a078b237c1d9b420b0ee59147386b4aa60d3a07a8e6a402fc84a57e41b043a4
but I have no earlier digest recorded anywhere to compare it to, so
'has it moved since catalog_since' is unmeasured for this one pin —
stated as unmeasured rather than guessed.
7. REPRODUCIBLE COMMANDS
----------------------------------------------------------------------
Dead-image check (the repo's own gate, unmodified):
cd app-catalog-felhom.eu && python3 scripts/check-image-resolvable.py --all
Newer-tag-upstream check (this audit's script, not part of the repo,
kept in the scratchpad — reuses the registry-v2 anonymous-bearer-token
auth flow from scripts/check-image-resolvable.py, but lists the full
upstream tag set per repo instead of testing one ref):
python3 /tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/5f83c0fb-b1bf-404e-b99e-2e3b28a31615/scratchpad/drift.py
(writes results.json next to it; apps.json/pins.json are the inventory
extracted from the catalog's compose/.felhom.yml files)
Floating-tag last-push check (Docker Hub API only, no docker CLI):
curl -s https://hub.docker.com/v2/repositories/<ns>/<repo>/tags/<tag>