hub v0.97.0 — the floor stops being served past the agent it depends on (CAMPAIGN-11)
gates / gates (push) Successful in 8s

R-216, the hub half. ResolveManagedFloor's own comment says it exists to "never push a
controller past the agent it depends on", and it compared against ArtifactManifest.MinAgent
— which by ITS own comment describes the GOLDEN's controller. publish-train-rules.md rule 3
states the rule about the FLOOR's controller. Measured live: golden 0.192.0 / MinAgent
0.113.0, floor 0.200.0, agent 0.120.0 — served, and the box was pushed onto a controller
needing agent 0.125.0.

A floor ABOVE the vouched golden is now HELD with its own reason (HeldBeyondGolden), reusing
Part D's dashboard visibility. Nobody types a number twice: the vouched MinAgent keeps its
meaning, the guard stops applying it to versions it does not describe. An uncoupled release
is untouched; an unparseable golden degrades rather than gating.

R-222: the report ACK's escrow object gains superseded_present / superseded_at, counting only
rows that actually carry an identity blob. One boolean and one timestamp, for one message.
No read path — that link is still unbuilt.

Red-proof: removing the floor-above-golden branch reproduces the campaign's measurement.
This commit is contained in:
2026-08-05 17:49:04 +02:00
parent f45b1f6761
commit 7e1d2898bd
3 changed files with 212 additions and 7 deletions
+47
View File
@@ -1,3 +1,50 @@
## v0.97.0 — the floor stops being served past the agent it depends on (2026-08-05, CAMPAIGN-11)
**R-216, the hub half.** `ResolveManagedFloor` exists to *"never push a controller past the agent it
depends on"* — its own comment says so — and it compared the box's agent against
`ArtifactManifest.MinAgent`, which by ITS own comment is *"the MINIMUM host-agent version this
GOLDEN's controller requires"*. Those two sentences contradict each other, and
`publish-train-rules.md` rule 3 states the rule about the **floor's** controller, not the golden's.
They are the same number only while the floor sits at or below the golden — the arrangement rule 5's
ISO gate assumes. Raise a floor above the vouched golden (which the day-0 runbook explicitly
recommends after a golden rebuild, and which a per-customer override makes trivial) and the guard
compares against a version it is not serving.
**Measured live 2026-08-05 (CAMPAIGN-11 Phase 1):** golden 0.192.0 with MinAgent 0.113.0, a
per-customer floor of 0.200.0, a box on agent 0.120.0. `0.120.0 ≥ 0.113.0`, so the floor was served
and the box was pushed onto a controller needing agent 0.125.0 — whose customer was then told their
correct recovery code was wrong. **This is the tenth entry in `CLAUDE.md`'s comment-vs-code table, and
the first where the false invariant was a guard rather than a comment alone.**
**The fix, and why nobody types a number twice:** the hub cannot know the agent requirement of a
controller version it was never told about, so it must not pretend to. A floor ABOVE the vouched
golden is now **HELD**, with its own reason (`HeldBeyondGolden`), reusing Part D's existing dashboard
visibility — a held box is visible, never silently stale. The vouched MinAgent keeps its exact
meaning; the guard simply stops applying it to versions it does not describe. The operator's remedy is
the one the publish train already prescribes: vouch a golden carrying the floor's controller
(rule 1, *manifest before floor*).
**What this does NOT do:** with the guard corrected but the day-0 agent unchanged, a new box is
**held, not served**. It stops being lied to; the recovery feature still does not work for it until
agent 0.125.0 is vouched in the Day-0 manifest. That is an operator decision, not a code change.
Unchanged: an uncoupled release (no MinAgent vouched) is served exactly as before, above the golden or
not — a fleet must not be frozen by a comparison that now over-fires. An unparseable golden degrades to
the previous behaviour rather than gating.
**R-222.** The report ACK's `escrow` object gains `superseded_present` / `superseded_at`: whether the
hub is ALSO keeping an EARLIER sealed package for this host, and when it was set aside. It exists for
one message — the recovery screen cannot otherwise tell a genuinely wrong code from a code that is
RIGHT about a retained earlier package, because the unseal fails closed against the current package
either way. **Only rows that actually carry an identity blob count**: the pre-v0.93.0 rows are NULL and
retain nothing the screen could be talking about. It is a boolean and a timestamp; it grants **no read
path**, which is still unbuilt (R-199's inventory).
Tests: `managed_floor_test.go` — the campaign's exact numbers, held-regardless-of-agent, Scenario C
(uncoupled untouched), floor==golden unchanged, unparseable golden. **Red-proof: removing the
floor-above-golden branch reproduces the campaign's measurement exactly.**
## v0.96.0 — the hub answers a rebuilt box's request (2026-08-05, R-204 item 4 / R-193 / R-192)
The hub half of the last manual intervention the 2026-08-04 drill needed. The box declares