Files
felhom.eu/documentation/runbooks/publish-train-rules.md
T
admin 4eaabb21d4 docs: publish-train rules — coupled-release gates codified (option-2)
manifest-before-floor; floor field LAST (hub_settings DB row overrides env, acts
immediately — the 0.81/0.113 9-minute skew incident); MinAgent fleet gate
(controller CHANGELOG header convention from ctrl v0.114.0); the controller
capability gate as box-level backstop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-11 13:55:37 +02:00

2.9 KiB
Raw Blame History

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_versionhub/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

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 rise past a controller version whose MinAgent is not yet met fleet-wide: check the hub dashboard — every reporting box must show agent ≥ MinAgent before the floor save. Manual at the current fleet size; hub-enforced per-box gating is the deferred option-3.

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 + a Supports gate call at the feature's entry point, and declare MinAgent per rule 3. When the agent someday reports an explicit version in its envelope, Supports should prefer the version comparison (roadmap).