d0d431b42b
gates / gates (push) Successful in 25s
Recounted at catalog 18a6d2d8: 66 unique pins — 48 full X.Y.Z, 6 two-part lines, 4 major lines (10 float), 8 exact versions wearing a variant suffix. The '23' carried since v0.233.0 matches no definition the catalog supports. Definition written down beside the number so it can be rechecked. Also: CONTEXT said the fleet floor was 0.257.0; the hub says 0.259.0. Comment and doc only — no behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
100 lines
7.2 KiB
Markdown
100 lines
7.2 KiB
Markdown
# REPORT — controller v0.260.0: a box ahead of the catalog, and a pin that never moves backwards
|
|
|
|
**R-524 (P2).** Base `19ef0329ab66` → **v0.260.0** (`8f8a64cad7a5`). MinAgent 0.131.0 unchanged.
|
|
Architecture read first and named: `felhom.eu/documentation/architecture/09-update-architecture.md`
|
|
(§3 the nine decisions, §5.4 the render table, §6.1 slice 4 as shipped, §8 the limitations).
|
|
|
|
## What was wrong
|
|
|
|
**Measured, not imagined** — BIGNIGHT Phase 6, 2026-09-15, VM 333. privatebin was updated
|
|
2.0.5 → 2.0.6 through the guarded Update; the catalog was then reverted to 2.0.5. At 22:13:37Z the
|
|
box read `installed privatebin/pdo:2.0.6`, `catalog privatebin/pdo:2.0.5`, and the app page showed
|
|
„**Frissítés elérhető — ma**" with a title inviting the household to press Frissítés. The comparison
|
|
asked only *does the installed reference DIFFER?*, so **a catalog revert — an operator act on our
|
|
side — presented itself to a customer as an update**, and the guarded Update behind it would have
|
|
advanced the pin 2.0.6 → 2.0.5, onto a datadir the newer version may already have migrated, with §4's
|
|
ruling saying that cannot be undone.
|
|
|
|
## What shipped
|
|
|
|
- **`stacks.CatalogOrder`** (`controller/internal/stacks/updateorder.go`) — the comparison gains a
|
|
fourth verdict (Unknown / Current / Behind / **Ahead**) and **moves out of `web`**. That move is the
|
|
substance: two callers must reach the same verdict — the badge and `Manager.UpdatePreflight` — and a
|
|
comparison implemented twice is a comparison that drifts. `web.compareInstalledToTemplate` is now a
|
|
thin wrapper and keeps every property it had (absent means UNKNOWN and never „Naprakész"; it reads
|
|
`CatalogImages` and never `TemplateImages`; it queries no registry).
|
|
- **The badge.** Ahead reads „Naprakész" / "Up to date", `tag-ok` — the same word and class as level,
|
|
because there is nothing for the household to do — with a title that says why
|
|
(`badge.update.ahead.title`, born as a key in both bundles). No version number reaches the customer.
|
|
- **The refusal.** `UpdatePreflight` returns reason `downgrade`, HTTP 409,
|
|
„Ez a változat újabb a katalógusban lévőnél — visszalépés csak az üzemeltető kérésére.", logged with
|
|
both image maps. **The API now renders update refusals through `errText`** — without that one line
|
|
the new key would have been a seam built and never wired, which is a documented failure class here.
|
|
- **Ahead is the NARROW arm.** Every differing service must be orderable AND newer; one older, one
|
|
unorderable, and the verdict falls back to Behind — i.e. to v0.233.0..v0.259.0 behaviour. This gate
|
|
can BLOCK an update, so it errs towards letting one run.
|
|
- **Ordering is `util.Version.Compare` and nothing else** (house rule: one comparator). The new code
|
|
is a tag NORMALISER in front of it.
|
|
|
|
## What the fixture caught that the design did not
|
|
|
|
**The first implementation called every real catalog tag unorderable.** It accepted only bare
|
|
`X.Y`/`X.Y.Z`, and the test fixture uses `nextcloud:31.0.14-apache` — the real catalog pin. The
|
|
refusal test failed with `got nil`, and the cause was the code being right about a rule that was
|
|
wrong. The rule now takes the version at the FRONT of the tag and requires the trailing suffix to be
|
|
**identical on both sides**, so `31.0.14-apache → 31.0.15-apache` orders while `26.05.2-ls310 →
|
|
-ls311` (a build number with no rule), `postgres:16-alpine` (a major LINE, not a version),
|
|
`kimai/kimai2:apache-2.57.0` (version at the back), a date stamp and a digest pin all stay
|
|
unorderable. **Measured against the real catalog: 8 of 66 pins float and one puts its version last.**
|
|
|
|
## Red-proofs — three, each SEEN to fail
|
|
|
|
| # | the mutation | what failed |
|
|
|---|---|---|
|
|
| 1 | make `CatalogOrder`'s Ahead arm unreachable | `TestR524_PreflightRefusesDowngrade/ahead` — *"this update must be REFUSED with reason \"downgrade\", got nil"*. The update is ALLOWED and the next thing it does is move the pin back. |
|
|
| 2 | treat an UNORDERABLE pair as ahead (`cmp < 0` with the `ok` dropped) | the floating-tag, different-image and digest-pin cases all fail with Ahead — the verdict that would suppress a real „Frissítés elérhető" on the floating pins |
|
|
| 3 | delete the ahead arm from `localeFuncs` | `TestUpdateBadgeFollowsTheLanguage` — *"an app ahead of the catalog must carry a badge"* |
|
|
|
|
An honest note on #1: the first attempt deleted the preflight block and failed to BUILD (an unused
|
|
import), which proves nothing. It was redone by neutering the Ahead arm instead, and that failed for
|
|
the right reason.
|
|
|
|
## A claim in the brief that was wrong, named
|
|
|
|
**R-589 was NOT open.** The brief said, reviewer-verified, that `updatebadge.go` builds the badge
|
|
from four raw Hungarian literals with no key and that R-589 is therefore open. The literals are real;
|
|
the conclusion does not follow. They are the Hungarian form and are deliberately frozen — that IS the
|
|
parity guarantee — and the ENGLISH form has been rebuilt from the bundle in `web.localeFuncs` since
|
|
**v0.258.0**, pinned by `TestUpdateBadgeFollowsTheLanguage` and proven live on a fresh box the same
|
|
morning (`DRILL-first-hour-en-0258-2026-09-20.md` item 9). The register row was stale, not the code;
|
|
it is closed with that citation. **The general lesson: a reviewer who reads one producer cannot see a
|
|
second producer that overrides it.** `updatebadge.go` now says so in its own comment, and v0.260.0's
|
|
new arm was written into BOTH producers with a test that fails if either is missing.
|
|
|
|
## Green gate and delivery
|
|
|
|
`go build ./... && go vet ./... && go test ./...` — **all green** (full suite, not a subset).
|
|
`controller_gates.py --fast` — **17 gates, all OK**; `go-parity` convicted first and was satisfied
|
|
properly, by registering both new keys as BORN-AS-KEYS in `i18n_go_keys.json` with the test that pins
|
|
each. No `--no-verify`; the pre-push hook ran and passed.
|
|
|
|
Image `gitea.dooplex.hu/admin/felhom-controller:0.260.0` built and pushed. **Deployed and healthy on
|
|
three guests**: demo-felhom 9201, demo-hp 9201, and demo-hp 9202 (the scratch guest, upgraded from
|
|
0.245.0 for the live proof).
|
|
|
|
**The fleet floor was NOT raised, and the number in the repo's own CONTEXT was stale.** CONTEXT.md
|
|
said the floor stood at 0.257.0; **the hub says 0.259.0** (read live from `/configs`, not from a
|
|
document — the operator raised it after that entry was written, which `felhom.eu/STATUS.md` records).
|
|
v0.260.0 therefore reaches the two demo boxes by hand and **no further**.
|
|
|
|
Stated rather than silently skipped: the standing rule asks for the floor to be raised to deliver a
|
|
release, and this session deliberately did not. **Why:** a floor raise reaches `peti-felhom`, a real
|
|
customer box, and the unprompted-work fence puts anything that changes risk to customer data behind
|
|
an operator word. The two preceding sessions recorded the raise as the operator's own act, and the
|
|
one that happened came after the operator asked for it. Put to the operator with what happens if they
|
|
do nothing: the fix stays on the two demo boxes and the rest of the fleet keeps offering a downgrade
|
|
as an update — which is a badge and a button, not data at risk, so waiting costs little.
|
|
|
|
Live proof, drift numbers and the state of the whole arc:
|
|
`felhom.eu/documentation/audits/UPDATE-ARC-STATE-2026-09-21.md` and `audits/update-arc-2026-09-21/`.
|