hub v0.82.0 (R-120): the vouch path REFUSES a golden the fleet has already outrun
The golden's version IS the controller it bakes (build-golden.sh:345 defaults GOLDEN_VERSION to the controller tag), so a golden behind the newest deployed controller means every FRESH install lands on stale application code. On the R-120 occurrence that stale code shipped a customer-facing falsehood: a box from the 0.185.1 golden told a customer whose backup drive had fallen out that the backup was on the same disk as the system -- false, the drive was gone -- and offered a different drive as the remedy. WHY A GATE, NOT A REMINDER. The gap has opened three times: R-111 (golden's agent 17 releases behind), R-115 (agent built and deployed, never published), R-120 (this). The first two were closed by re-baking and remembering; remembering then failed again. R-29 is the standing proof that a check nobody runs is worse than none because it reads as coverage -- hostinstall_gates.py sat RED and uninvoked across three version bumps and hub_confirm_gate.py has never run at all. So the property that matters is not whether a check exists but whether it BLOCKS. - Wired into handleSetArtifacts (internal/web/configs.go), immediately before the only write, on the sole UI path to SetArtifactManifest -- it runs on every vouch without anyone choosing to. A script in scripts/ would have been a fourth orphan. - It REFUSES (operator ruling, 2026-07-30), with a flash naming the remedy. - Signal: store.NewestReportedControllerVersion() over reports.controller_version, SEMVER-compared in Go -- MAX() in SQL ranks 0.99.0 above 0.186.0, a pair this fleet has shipped. No outbound call, no new credential. - Fail-open in exactly two deliberate cases: an empty golden field (clearing the manifest is legitimate) and an unknown fleet version (a new hub must vouch its first golden). NEAR-MISS RECORDED: the first draft read guests.controller_version, a column that exists in the schema and that NOTHING writes -- it would always have seen "" and failed open, i.e. inert, this gate's own failure shape. Caught by grepping for a writer before trusting the column. Blind spot stated rather than papered over: a controller no box has ever run is invisible to this signal. Not the failure that has bitten -- all three instances were deployed-newer-than-baked. 4 tests through the PRODUCTION handler over httptest, never an injected seam. The refusal asserts both the flash and that the manifest was NOT written, because a gate that redirects and saves anyway reads as enforcement while providing none. Red-proof: deleting the block makes the stale golden vouchable and both assertions fail. ROADMAP R-29's audit list now records this as the FIRST enforced gate, so the contrast with its three orphans is kept rather than lost. The orphans are unchanged. Suite rc=0 read separately from this commit.
This commit is contained in:
@@ -1,3 +1,51 @@
|
||||
## v0.82.0 — R-120: the vouch path refuses a golden the fleet has already outrun (2026-07-30)
|
||||
|
||||
**The mechanism half of R-120.** The golden's version *is* the controller it bakes
|
||||
(`felhom-agent configs/build-golden.sh:345` defaults `GOLDEN_VERSION` to `${CONTROLLER_IMAGE##*:}`), so a
|
||||
golden left behind the newest deployed controller means every **fresh install** lands on stale
|
||||
application code. On the R-120 occurrence that stale code shipped a customer-facing **falsehood**: a box
|
||||
installed from the 0.185.1 golden told a customer whose backup drive had fallen out that *"the backup is
|
||||
on the same disk as the system"* — false, the drive was gone — and offered a different drive as the
|
||||
remedy. 0.186.0 is the release that made that message true, and no new box had it.
|
||||
|
||||
**Why a gate and not a reminder.** This gap has opened **three times** — **R-111** (the golden's agent 17
|
||||
releases behind), **R-115** (an agent built and deployed but never published), **R-120** (this). The first
|
||||
two were closed by re-baking and remembering; remembering then failed again. And **R-29** is the standing
|
||||
proof that a check nobody runs is *worse* than none, because it reads as coverage:
|
||||
`hostinstall_gates.py` sat RED and invoked by nothing across three version bumps while every report said
|
||||
green, and `hub_confirm_gate.py` has never run at all.
|
||||
|
||||
So the distinguishing property is not *does a check exist* but **does it block**:
|
||||
|
||||
- It lives in **`handleSetArtifacts`** (`internal/web/configs.go`), immediately before the only write —
|
||||
the sole UI path to `store.SetArtifactManifest`. It therefore runs on every vouch **without anyone
|
||||
choosing to run it**. A script in `scripts/` asserting the same fact would have been a fourth orphan.
|
||||
- It **REFUSES** (operator ruling, 2026-07-30), with an operator-legible flash naming the remedy, rather
|
||||
than warning.
|
||||
- Signal: `store.NewestReportedControllerVersion()` — the highest controller version any box has
|
||||
reported, from `reports.controller_version` (the column `SaveReport` denormalises). **Semver-compared
|
||||
in Go, not `MAX()` in SQL**, which would rank 0.99.0 above 0.186.0 — a pair this fleet has actually
|
||||
shipped. No outbound call, no new credential.
|
||||
|
||||
**Fail-open in exactly two cases, both deliberate:** an empty golden field (clearing the manifest is a
|
||||
legitimate act) and an unknown fleet version (a new hub must be able to vouch its first golden).
|
||||
|
||||
**Known blind spot, stated rather than papered over:** a controller no box has ever run is invisible to
|
||||
this signal, so a golden baked behind an *unreleased* controller still passes. That is a real limit, and
|
||||
it is not the failure that has bitten — all three instances were "deployed newer than baked".
|
||||
|
||||
**A near-miss worth recording.** The first draft read `guests.controller_version` — a column that exists
|
||||
in the schema (`store.go:294`) and that **nothing writes**. That gate would always have seen `""` and
|
||||
failed open: inert, i.e. precisely the R-29 shape it exists to prevent. Caught by grepping for a writer
|
||||
before trusting the column.
|
||||
|
||||
**Tests: 4, through the production handler over `httptest`, never an injected seam** — because a gate
|
||||
that can be inert is the thing this gate exists to prevent, and three shipped defects in this project
|
||||
were fully green with the seam disconnected. Refusal asserts **both** the flash **and** that the manifest
|
||||
was not written (a gate that redirects and saves anyway reads as enforcement while providing none);
|
||||
plus the allow cases, both fail-open cases, and the semver-ordering case. Red-proof: deleting the block
|
||||
makes the stale golden vouchable and both refusal assertions fail.
|
||||
|
||||
## v0.81.0 — E-2: the absent backup target gets its own signal (2026-07-29)
|
||||
|
||||
**Hub half of E-2, and it ships FIRST by necessity:** an event type the hub does not allowlist makes
|
||||
|
||||
Reference in New Issue
Block a user