diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fe852..029f73d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## (no version bump) — a comment that claimed the hub reads a field it has no field for (2026-08-08, R-260) + +Comment-only; no behaviour, no wire change, nothing to rebuild. + +`HostReport.SelfUpdatePending` / `SelfUpdatePendingVersion` carried the sentence *"The hub reads an +absent field as pending=false, the correct default."* **The hub has no field for either**, so it reads +nothing — present or absent — and `encoding/json` discards them on arrival. The sentence described an +intent rather than the code and read as settled for long enough that a class sweep had to find it. + +The emission is correct and stays: the agent reports the truth, and the fault is entirely in the +receiving. The missing consumer is tracked as **R-264** (OPEN), and +`felhom.eu/scripts/wire_contract_gate.py` now refuses any NEW field of this shape while recording the +existing ones as explicit, reasoned allowlist entries rather than silence. + ## v0.127.0 — a mount Felhom itself made is not "something else" (2026-08-06, R-220) **After a rebuild the customer's own drives could not be re-attached, and the refusal named an action diff --git a/internal/hub/report.go b/internal/hub/report.go index 78df5c1..f22bd48 100644 --- a/internal/hub/report.go +++ b/internal/hub/report.go @@ -68,8 +68,14 @@ type HostReport struct { // report is stored opaquely hub-side, so these additive fields need no hub-schema change. // Both are `omitempty` (the Wireguard precedent): in the steady state (no update in flight) // they are absent — which keeps the cross-repo host-report golden contract byte-stable without - // a hub change. They appear only while an update is pending. The hub reads an absent field as - // pending=false, the correct default. + // a hub change. They appear only while an update is pending. + // + // ⚠ CORRECTED 2026-08-08 (R-260). This comment used to end "The hub reads an absent field as + // pending=false, the correct default." THE HUB HAS NO FIELD FOR EITHER OF THESE, so it reads + // nothing — present or absent — and encoding/json discards them on arrival. The sentence + // described an intent, not the code, and it read as settled for long enough that a sweep had to + // find it. The emission is correct and stays; the missing consumer is tracked as R-264, and + // `felhom.eu/scripts/wire_contract_gate.py` now refuses any NEW field of this shape. SelfUpdatePending bool `json:"selfupdate_pending,omitempty"` SelfUpdatePendingVersion string `json:"selfupdate_pending_version,omitempty"`