v0.233.0: record what each compose service actually installed, and badge whether it is current
gates / gates (push) Successful in 12s

Update arc slices 1 and 2. NEITHER CHANGES ANY BEHAVIOUR — no new endpoint, no
auto-update, the three lifecycle buttons byte-identical.

Slice 1 — app.yaml gains installed_images, keyed by compose SERVICE name, each
entry carrying ref + repo digest + first-seen timestamp. Written by
Manager.recordInstalledImages after a successful compose up from StartStack,
RestartStack, UpdateStack and runComposeDeploy. Read from the CONTAINER, never
from docker-compose.yml: the syncer overwrites a deployed app's compose on a
15-minute cycle and the two disagreed for 25 minutes in the spike's own
measurement. A failed write NEVER refuses the action - the deliberate opposite
of SetDesiredState, because this is an observation and that is an intent. Not
called from StartStackServices (the R-47 DB-only window). Its own docker seam
with a context and a 30s timeout, which neither existing exec helper has.

Slice 2 — .felhom.yml gains optional catalog_since; web.updateBadge compares the
recorded ref per service against what the current template pins and returns a
*MetaBadge through the EXISTING meta_badge partial. No new markup, no new CSS.
NO RECORD RENDERS NOTHING: absent means unknown and never means current. No
version number reaches the customer and no registry is queried.

Known limitation, filed not hidden: 23 catalog pins float, so those apps can read
Naprakesz when the image behind the tag has moved.

+17 tests (1707 -> 1724), 28 packages green. Wiring proven through a real
RestartStack plus an AST walk of the four call sites. Three companion red-proofs
run and reverted.
This commit is contained in:
2026-09-02 20:18:01 +02:00
parent 960d29b061
commit 8025304acc
14 changed files with 1637 additions and 9 deletions
+29 -1
View File
@@ -7,7 +7,35 @@
>
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
Last updated: 2026-09-01 (v0.232.0 — R-411/R-408/R-407 the lock family, R-414 reachability, R-412a wording)
Last updated: 2026-09-02 (v0.233.0 — update arc slices 1 & 2: the installed-images record + the update badge)
> **2026-09-02 — v0.233.0. TWO DECISIONS, AND ONE LIMITATION THAT IS NOT A DEFECT.**
>
> **1. `installed_images` is an OBSERVATION, so a failed write NEVER refuses the action — deliberately
> the opposite of `desired_state`.** `SetDesiredState` refuses the act when the record fails, because
> intent that could not be recorded recreates the exact ambiguity R-166 closed. `recordInstalledImages`
> does the reverse: refusing to start a customer's app because we could not write down which version
> it is trades a real outage for a bookkeeping gap. **The rule is "refuse on intent, log on
> observation", and the reason is in both code comments** so neither gets "made consistent" later.
>
> **2. THE RECORD READS THE CONTAINER, NEVER THE COMPOSE FILE — and the file is not a lesser source,
> it is a WRONG one.** The catalog syncer overwrites a deployed app's `docker-compose.yml` on a
> 15-minute cycle with no deployed check at all; the spike measured the file saying `v2.8.5` while the
> container ran `v2.8.6` for 25 minutes. Anything derived from that file answers "what will happen
> next time something runs `up -d`", which is a different question from "what is running".
>
> **3. THE LIMITATION, STATED: 23 catalog pins FLOAT, so „Naprakész" CAN BE FALSE.** The comparison is
> reference-to-reference and queries no registry (a box must not need eight upstream registries to
> render a page). For `postgres:16-alpine`, `mariadb:11.6` and 21 others the ref can be identical while
> the image behind it has moved — the spike caught `mariadb:11.4` and `mariadb:12.3` already moved.
> **This is a known gap with a register row, not an oversight.** Digest-level comparison needs a
> registry query and is deferred.
>
> **Nothing about updating changed.** No behaviour, no new endpoint, no auto-update, and the three
> lifecycle buttons are byte-identical (`TestScenarioE_TheUpdateButtonIsUntouched`). The behaviour work
> is slice 3 and needs an operator ruling. The whole arc's reasoning now has a home:
> `felhom.eu/documentation/architecture/09-update-architecture.md` (R-438 — its absence was a finding).
> **2026-09-01 — v0.232.0. THREE RULINGS.**
>