Files
felhom.eu/documentation/runbooks/publish-train-rules.md
T

65 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Publish-train rules — coupled controller/agent releases
Standing gates for every artifact publish train (agent binary + controller golden + Day-0 manifest +
floor). Each rule cites the incident that created it. The box-level backstop (rule 4) exists because
rules 13 are operator discipline and discipline fails; the rules stay the primary control.
## 1. Manifest before floor (the GL-1 rule, restated)
Publish and vouch the artifacts in the Day-0 manifest **before** any floor movement. A floor that
points at an unvouched (or unpublished) version bricks self-updates: boxes are told to move to a
version they cannot verify. (GL-1 supply-chain arc; see the go-live package records.)
## 2. The manifest screen carries the LIVE DB floor — save the floor field LAST
The hub's Day-0 manifest UI also persists the global floor as a DB row
(`hub_settings.min_controller_version``hub/internal/store/store.go`,
`GetGlobalMinControllerVersion`). **The DB row overrides the env floor and acts immediately on the
next report cycle** — it is not staged by the manifest vouch.
**Incident:** publish train 0.81/0.113 (2026-07-11,
`documentation/pilot/RUNBOOK-publish-0.81-0.113-2026-07-11.md`): the operator saved the manifest
screen with the floor field filled; the floor acted at once and controller 0.113.0 reached Peti's
box ~9 minutes **before** agent 0.81.0 — the exact forbidden skew, benign only because the box had
zero NAS shares.
**Rule:** fill the floor field **last**, in a separate save, only after rule 3's fleet check passes.
## 3. MinAgent fleet gate — HUB-ENFORCED PER-BOX since hub v0.45.0
A controller release that depends on coupled agent behavior declares `MinAgent: X.Y.Z` in its
CHANGELOG entry header line (felhom-controller convention, since v0.114.0; retroactively, 0.113.0's
effective MinAgent was 0.81.0 for the NAS add). The floor may not effectively push a box past a
controller whose MinAgent that box's agent does not yet meet.
**Hub-enforced per-box since hub v0.45.0 (the manual fleet check is retired):** the operator sets
the golden's **`MinAgent`** in the Day-0 artifact manifest (Configuration → Day-0 artifacts →
"Min agent"; blank = uncoupled release, no gating). At report-ACK time the hub compares each box's
reported `hosts.agent_version` against that MinAgent
(`store.ResolveManagedFloor`, `hub/internal/store/store.go`): agent ≥ MinAgent → the controller
floor is served; agent below MinAgent **or unknown** → the floor is **HELD** (the ACK omits the
directive) and the box is flagged on the Hosts dashboard (`floor held: agent <v> < MinAgent <w>`) —
a held box is visible, never silently stale. The operator still SETS MinAgent at manifest time; the
hub does the per-box gating. This mechanises the "agent BEFORE controller floor" ordering that rule
2's incident violated by hand.
Effective-floor visibility (same v0.45.0): the floor card shows the resolved value + its source
(DB `hub_settings` vs env `DEFAULT_MIN_CONTROLLER_VERSION`, both raw values when they differ), and
the floor save is behind a type-to-confirm dialog stating the live below-floor blast radius — so
rule 2's "the floor acts immediately" is impossible to miss.
## 4. Box-level backstop: the controller's capability gate
Since controller v0.114.0, a coupled feature entry point probes the agent's capability
(`controller/internal/agentapi/features.go` — route probe: 2xx ⇒ supported, 404 ⇒ older agent,
transport/5xx ⇒ indeterminate, never "too old") and refuses up front with an honest Hungarian
message instead of failing mid-pipeline. This turns a violated ordering into a graceful refusal —
it does **not** license sloppy trains: rules 13 remain the primary control.
Convention for new coupled features: add a row to the `featureProbes` table AND the `featureMinAgent`
table + a `Supports` gate call at the feature's entry point, and declare MinAgent per rule 3. Since
controller v0.115.0 + agent v0.82.0 the agent reports its version in the `X-Felhom-Agent-Version`
response header, so `Supports` decides by version comparison when the version is known and only
falls back to the route probe for header-less (≤0.81) agents — capability detection is now explicit,
not probe-inferred.