v0.234.0: seed installed_images at startup, so the label appears on an app nobody touched
gates / gates (push) Successful in 13s

The operator looked at demo-felhom the morning after v0.233.0 and found OpenGist
- up 15 hours, running exactly the catalog pin - showing no badge at all.
v0.233.0 wrote the record only from the four bring-up paths, so an app nobody
restarts carried no record indefinitely. On a quiet box that is every app, which
is the box we most want to see. The known limitation WAS the feature not working.

BackfillInstalledImages runs once at startup, beside BackfillDesiredState and
before the boot reconciler. It READS containers: starts nothing, restarts
nothing, writes no compose file. It never overwrites an existing record.

And it REFUSES to seed a partial observation, which is why this is not a
three-line loop: the badge reads a service-count mismatch as BEHIND, so seeding a
degraded app from what is visible would render 'Frissites elerheto' over an app
that is perfectly current. The bring-up paths may write a partial because they
follow a successful up -d where a gap is real news; a backfill meets any state.
Same data, two writers, two admission rules - deliberately.

Also fixes a calendar bomb of mine: the render test hardcoded catalog_since and
the string '46 napja', but the render path reads time.Now(), so it was green on
the day it was written and red the next morning. Now derived. Filed as R-457
with six other candidate files named as unchecked, not accused.

+5 tests (1724 -> 1729), 28 packages green. Red-proof of the partial guard run
and reverted; the wiring and its ORDER pinned by an AST walk.
This commit is contained in:
2026-09-03 11:56:43 +02:00
parent 32da46cd64
commit 38d28b5b62
8 changed files with 402 additions and 5 deletions
+53
View File
@@ -1,3 +1,56 @@
## v0.234.0 — the label now appears on an app nobody has touched (2026-09-03, update arc slice 1b)
**Found by the operator on demo-felhom the morning after v0.233.0, and it is a real gap, not a
misunderstanding:** OpenGist had been up 15 hours, was running exactly what the catalog pins, and
showed **no badge at all**. v0.233.0 wrote the record only from the four bring-up paths, so an app
nobody restarts carried no record — and therefore no label — **indefinitely**. On a quiet box that is
every app, which is the box we most want to be able to see. v0.233.0's own architecture note called
this a known limitation; a day of it showed the limitation was the feature not working.
### `Manager.BackfillInstalledImages` — seed the absences, once, at startup
`controller/internal/stacks/installed.go`, called from `cmd/controller/main.go` beside
`BackfillDesiredState` and before the boot reconciler.
**It READS. It starts nothing, restarts nothing, upgrades nothing and writes no compose file.** That
is what makes a backfill safe here, and it is the same shape R-166's desired-state backfill already
uses — with one deliberate difference:
- **It never overwrites an existing record.** The bring-up paths own updates; this only fills gaps.
An app that already has a record is not even observed.
- **It REFUSES to seed a partial observation, and that is the whole reason this is not a three-line
loop.** `compareInstalledToTemplate` reads a service-count mismatch as BEHIND, so seeding what can
be seen on a degraded or crash-looping app would render „Frissítés elérhető" over an app that is
perfectly current — **a confident wrong answer, which is worse than the silence it replaces.** The
bring-up paths do not have this problem: they run right after a SUCCESSFUL `compose up -d`, where a
missing container is real news and already logs a WARN. A backfill meets whatever state a box is in
at boot, so it is stricter. An app it cannot observe COMPLETELY keeps no record — unknown, which
renders nothing, which is the honest answer.
- Protected and undeployed stacks are skipped, and the summary line is a **positive observable**:
`N recorded, M already had a record, K left unrecorded`.
**Nothing else changed.** No behaviour, no new endpoint, no auto-update, buttons byte-identical.
### A test of mine was a calendar bomb, and it went off overnight
`TestGroupD_BadgeRendersOnBothSurfaces` hardcoded `catalog_since: "2026-07-18"` **and** asserted
`"Frissítés elérhető — 46 napja"`. The pure tests inject a clock; **the RENDER path calls the funcmap
entry, which uses `time.Now()`.** So the test was green on the day it was written (2026-09-02) and
**red the next morning** — 47 days, not 46. It is now derived: the fixture's `catalog_since` is
computed as *today minus 46 days*, so it asserts the real number through the real clock and cannot
rot. **Filed as R-457** — six other test files mix a hardcoded date with `time.Now()` and are named
there as unchecked candidates, not accused.
### Tests
+5 (1724 → 1729). 28 packages green, 0 FAIL. **Companion red-proof (run 2026-09-03):** delete the
`observationCoversTemplate` guard and `TestGroupG_BackfillRefusesAPartialObservation` fails with
*"backfilled 1, want 0 — a partial observation must NOT be seeded"*. Reverted.
**Wiring:** `TestGroupG_BackfillIsWiredAtStartup` walks the **AST** of `cmd/controller/main.go` for
the call and asserts its ORDER — after the desired-state backfill, before the boot reconciler — because
a backfill nothing invokes seeds nothing, and a `strings.Contains` would match a commented-out call.
## v0.233.0 — the box writes down what it installed, and one label says whether it is current (2026-09-02, update arc slices 1 & 2)
**Neither slice changes any behaviour.** The Frissítés button, the restart path, the sync and the boot