v0.234.0: a known limitation written on 2026-09-02 was a defect by the next morning
gates / gates (push) Successful in 18s

The operator looked at demo-felhom and found OpenGist - up 15 hours, running
exactly the catalog pin, showing no badge at all. 09-update-architecture.md had
recorded that as an accepted limitation the day before: 'the fleet view fills in
gradually'. On a quiet box gradually means never, and a feature that fills itself
in on an event nobody triggers is, on the quiet installations, not shipped. That
limitation row is now struck with the reason kept.

The living document gains slice 1b, the two admission rules of the backfill (it
never overwrites, and it refuses to seed a partial observation because the badge
reads a service-count mismatch as BEHIND), and the note that the same field having
two writers with two different admission rules is deliberate.

Live evidence added: all nine apps already had records by the time 0.234.0 was
ready, so the natural fleet state could no longer exercise the new code - said
plainly rather than papered over. The pre-0.233.0 shape was recreated on demo-hp
by stripping two records; the backfill re-seeded exactly those two with digests
matching independently-read ground truth and left the other seven alone.

The refusal half was deliberately NOT staged live: it needs a degraded app, and
manufacturing one risks the false-customer-email class that already cost 61 mails
(R-330). Unit-tested with a red-proof, and recorded as unproven-live.

R-457: a test that hardcodes a date and asserts an age derived from it is green
only on the day it is written. Mine was, and it went red overnight. Six other
files carry both a date literal and time.Now() - named as candidates, not accused.
This commit is contained in:
2026-09-03 12:01:44 +02:00
parent 7941b0c159
commit bc47dd4ef9
6 changed files with 112 additions and 12 deletions
@@ -215,6 +215,59 @@ The badge is wired to nothing.
future-dated, and all 53 catalog apps now carry a valid one. Covered by `TestGroupF`, which walks
absent, blank, `tegnap`, `18/07/2026`, `2026-13-45` and a future date.
## 4b. v0.234.0 — the startup backfill, PROVEN LIVE 2026-09-03
**Why it exists.** §4 of this file, written 2026-09-02, recorded *"the record only appears after the
next lifecycle action"* as an accepted limitation. The operator looked at **demo-felhom** the next
morning and found **OpenGist** — up 15 hours, running exactly the catalog pin, showing **no badge at
all**. On a quiet box "fills in gradually" means "never".
### The staging, and why it was needed
By the time v0.234.0 was ready, **all nine deployed apps on demo-hp and the one on demo-felhom already
had records** — the overnight backup cycle had restarted them and v0.233.0's recorder had fired on
every one (opengist's record is stamped `2026-09-03T00:31:11Z`). **So the natural fleet state could no
longer exercise the new code**, and saying that plainly matters more than a green log line.
The pre-0.233.0 shape was therefore recreated on **demo-hp** (Tier 0): the `installed_images:` block
was deleted from `privatebin` (1 service) and `romm` (**3** services) — a record, never data — and the
controller restarted. Ground truth was read from the containers first, independently.
### The result
```
09:59:45 installed.go:519: [INFO] installed-images backfill: privatebin recorded 1 service(s) (privatebin=privatebin/pdo:2.0.5 (sha256:8a2cac16eff6…))
09:59:45 installed.go:519: [INFO] installed-images backfill: romm recorded 3 service(s) (romm=rommapp/romm:5.0.0 (sha256:91f6611eca5a…), romm-db=mariadb:11.4 (sha256:4f1d8d202fcf…), romm-redis=redis:7-alpine (sha256:ff02b58f971e…))
09:59:45 installed.go:525: [INFO] installed-images backfill: 2 app(s) recorded, 7 already had a record, 0 left unrecorded
```
- **Exactly the two stripped apps were seeded**, and **the other seven were not touched** — the
never-overwrite rule, observed rather than asserted.
- **Every digest matches the ground truth** read from the containers beforehand:
`privatebin/pdo@sha256:8a2cac16eff6caed4dc622e7b3ebd0c0ffcb28dfc0eba0b9c335636552eadac1`,
`rommapp/romm@sha256:91f6611eca5a4dafc4f4a1d72a1ed7dd66a11375d939f28410dc1d1de0b80b1b`,
`mariadb@sha256:4f1d8d202fcf7bcb3902f63af09f9c1a050c2922a89652f22abaec0d4f015e83`.
- The re-seeded records are identical to the ones stripped, apart from `at` — which is correct: it
records when THIS observation was first made.
- **`/stacks` on demo-hp then carried „Naprakész" ×9** — one for every deployed app — with the
negative control `zzz-never-present` at **0** and `napja` at **0** (nothing is behind on that box).
- On **demo-felhom** the operator's own case renders:
`<span class="tag tag-ok" …>Naprakész</span>` on `/stacks?filter=running` **and** on `/apps/opengist`.
### What was NOT proven live, and why the choice was made
**The refusal half — that a partial observation is not seeded — was not staged on a live box.** Doing
so means stopping one container of a multi-service app to make it degraded, and a degraded app is a
dead-app alarm candidate; **this project has already paid for 61 false customer e-mails from exactly
that class (R-330), and manufacturing one to demonstrate a guard is a bad trade.** It is covered by
`TestGroupG_BackfillRefusesAPartialObservation` **with a companion red-proof** — removing the guard
makes it fail with *"backfilled 1, want 0"*. Stated as unproven-live rather than left unmentioned.
### Teardown
The two `app.yaml` backups taken on the box were removed. **Nothing was provisioned** and no app was
started, stopped or upgraded at any point.
## 5. End state — nothing left broken, nothing provisioned
```