REPORT: v0.234.0 — the backfill proven live, and a test of mine that went red overnight
gates / gates (push) Successful in 12s

Adds section 6b (the startup backfill on both demo boxes: all nine apps already
had records by the time it was ready, so the pre-0.233.0 shape had to be
recreated on demo-hp - said plainly rather than papered over; two seeded with
digests matching independently-read ground truth, seven untouched, nine badged)
and 6c (the render test hardcoded a date and an age, was green the day it was
written and red the next morning, now derived; R-457 names six candidate files).

Also records what was deliberately NOT staged live: the backfill's refusal of a
partial observation needs a degraded app, and manufacturing one risks the false
customer email class that already cost 61 mails.
This commit is contained in:
2026-09-03 12:02:30 +02:00
parent 38d28b5b62
commit 998aa31958
+62 -3
View File
@@ -1,8 +1,17 @@
# REPORT — v0.233.0, update arc slices 1 & 2 (2026-09-02)
# REPORT — v0.234.0, update arc slices 1, 1b & 2 (2026-09-03)
*Overwritten each run. This records the most recent implementation only.*
> **Read this first: one claim in the task turned out to be wrong, and it is a path, not a fact.**
> **v0.234.0 (2026-09-03) — read this first.** v0.233.0 shipped with *"the record only appears after
> the next lifecycle action"* written down as an ACCEPTED LIMITATION. **The operator found it the next
> morning and it was a defect:** OpenGist on demo-felhom, up 15 hours, running exactly the catalog pin,
> showing **no badge at all**. On a quiet box "fills in gradually" means "never", and a feature that
> fills itself in on an event nobody triggers is, on the quiet installations, **not shipped**.
> `Manager.BackfillInstalledImages` now seeds the absences at startup by READING containers — it
> starts nothing, restarts nothing and writes no compose file. **Proven live on both demo boxes**
> (§6b). **A test of mine also went red overnight** and that is §6c.
>
> **Read this second: one claim in the task turned out to be wrong, and it is a path, not a fact.**
> The task cites source as `internal/stacks/deploy.go`, `internal/web/funcmap.go` and so on. **The Go
> module lives under `controller/`** — every one of those is `controller/internal/...`. **Every line
> number in the task was EXACT against the baseline** (`AppConfig` 99, `runComposeDeploy` 395,
@@ -41,16 +50,18 @@ tolerance WARN), `controller/internal/web/funcmap.go`, `controller/internal/web/
| repo | commit | what |
|---|---|---|
| felhom-controller | **`8025304acc0a6737`** | v0.233.0 — the record and the badge |
| felhom-controller | **`38d28b5b624c`** | **v0.234.0 — the startup backfill + the calendar-bomb fix** |
| app-catalog-felhom.eu | `69761cf91bfc` | `catalog_since` on all 53 apps + the `CLAUDE.md` rule |
| app-catalog-felhom.eu | `8220f8dc…` | the catalog's own REPORT |
| felhom.eu | `6035dfcc3ae1` | `09-update-architecture.md`, the register, roadmap, capability map, STATUS, live evidence |
| felhom.eu | `e86cf42e0ba5` | R-454..R-456, filed because the observations gate refused a report that filed none |
| felhom.eu | `bc47dd4ef997` | v0.234.0 docs: the living architecture doc's limitation 3 struck, R-457, capability map, STATUS |
No branches. All three gate runs passed on push (controller: 13 gates OK + 1 advisory, see §9).
## 4. Tests, and both companion red-proofs
**1707 → 1724 test functions (+17). 28 packages, 0 FAIL**, `go build ./... && go vet ./... && go test ./...`.
**1707 → 1729 test functions (+22; +17 in v0.233.0, +5 in v0.234.0). 28 packages, 0 FAIL**, `go build ./... && go vet ./... && go test ./...`.
| group | what it pins |
|---|---|
@@ -212,10 +223,58 @@ observable on the shipped artifact, and **not** a rendered page:
healthy. **This run provisioned nothing** — no guest, no storage, no hub record — so there is no
teardown to report on any of the three layers.
## 6b. v0.234.0 — the startup backfill, proven live on both boxes
**The honest complication first:** by the time 0.234.0 was ready, **all nine deployed apps on demo-hp
and the one on demo-felhom already carried records** — the overnight backup cycle had restarted them
and v0.233.0's recorder fired on every one (`opengist` is stamped `2026-09-03T00:31:11Z`). **The
natural fleet state could no longer exercise the new code.**
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.
```
09:59:45 installed-images backfill: privatebin recorded 1 service(s) (privatebin/pdo:2.0.5 (sha256:8a2cac16eff6…))
09:59:45 installed-images backfill: romm recorded 3 service(s) (rommapp/romm:5.0.0 (sha256:91f6611eca5a…),
mariadb:11.4 (sha256:4f1d8d202fcf…), redis:7-alpine (sha256:ff02b58f971e…))
09:59:45 installed-images backfill: 2 app(s) recorded, 7 already had a record, 0 left unrecorded
```
- **Exactly the two stripped apps were seeded; the other seven were untouched** — the never-overwrite
rule observed, not asserted.
- **Every digest matches the independently-read ground truth.**
- **`/stacks` then carried „Naprakész" ×9**, one per deployed app, negative control `zzz-never-present`
at **0**.
- On demo-felhom the operator's own case renders the badge on `/stacks?filter=running` and
`/apps/opengist`.
- Backups removed from the box; **nothing provisioned**, no app started, stopped or upgraded.
**NOT staged live, and the choice is the point:** the refusal half — that a partial observation is not
seeded — needs a degraded app, and manufacturing one is a dead-app alarm candidate. **This project has
already paid for 61 false customer e-mails from that class (R-330)**, so it is covered by
`TestGroupG_BackfillRefusesAPartialObservation` **with a companion red-proof** (remove the guard →
*"backfilled 1, want 0"*) and recorded here as unproven-live.
## 6c. A test of mine was a calendar bomb, and the suite caught it
`TestGroupD_BadgeRendersOnBothSurfaces` hardcoded a fixture `catalog_since: "2026-07-18"` **and** the
expected string `"Frissítés elérhető — 46 napja"`. The pure badge tests inject a clock; **the render
test cannot** — it goes through the production templates, which call the funcmap entry, which reads
`time.Now()`. Green on 2026-09-02, **red on 2026-09-03** with *"the behind badge is missing"* on both
surfaces, because the true answer had become 47.
Fixed by **deriving** the fixture: `catalog_since` is computed as *today minus 46 days*, so it asserts
the real number through the real clock and cannot rot. **FILED: R-457**, which also names six other
test files carrying both a date literal and `time.Now()` — as unchecked candidates, not accusations,
because mixing the two is only a defect where the literal feeds a clock-evaluated assertion.
## 7. NOT yet live-validated — an explicit list
**Everything the task asked to be validated live, was.** What remains:
0. **The backfill's REFUSAL of a partial observation** — §6b explains why it was not staged live.
1. **The fourth badge state, „Frissítés elérhető" WITHOUT an age.** It needs an app whose
`catalog_since` is absent, malformed or future-dated, and all 53 catalog apps now carry a valid one.
Covered by `TestGroupF` (absent, blank, `tegnap`, `18/07/2026`, `2026-13-45`, future-dated).