hub v0.72.0 — R-70 + R-71c: offsite delivery-state detector, card, stuck event, R-39(a)-guarded self-heal restage
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NKSN3gSg4TKVBBqkwW2djR
This commit is contained in:
@@ -1,5 +1,47 @@
|
||||
# Felhom Hub — Changelog
|
||||
|
||||
## v0.72.0 — R-70 + R-71(c): the offsite last mile becomes visible, and burned credentials heal themselves (2026-07-23)
|
||||
|
||||
Origin: `documentation/audits/DIAG-f10-demo-hp-offsite-2026-07-23.md` — demo-hp sat 2 days with the
|
||||
customer card claiming "Provisioned … delivered to the controller once" (static copy) while the box
|
||||
had NOTHING: the day-0 managed update killed the apply-bridge after password-consume, and the hub —
|
||||
holding both signals (`one_time_secrets.consumed_at`, 153 offbox-less reports) — read neither.
|
||||
|
||||
**One detector, four consumers:**
|
||||
|
||||
- **Detector** (`internal/offsite/delivery.go`, `DeliveryStateFor`): per-customer
|
||||
`OffsiteDeliveryState` from the secret row × report offsite-presence — `applied` (precedence:
|
||||
the box's own report wins) / `consumed_awaiting_apply` (the burned-credential shape) /
|
||||
`staged_awaiting_consume` / `no_secret`. The applied+stale-staged edge (demo-felhom's live
|
||||
shape: key-auth-first never consumes) stays `applied` PLUS a visible stale-staged flag. New
|
||||
store reads: `GetOneTimeSecretInfo` (timestamps only, value never selected),
|
||||
`LatestReportOffsitePresence`, `CountReportsOffsiteSince`, `LastEventAt`, + a test-only
|
||||
timestamp back-dater (the PBSDR seam pattern).
|
||||
- **Customer card** (`config_form_body.html` + `deliveryViewFor`): the static "delivered once"
|
||||
claim is GONE; the card renders the derived state with its age (badge idiom `n-ok/n-warn/
|
||||
n-neutral`; consumed goes amber past 30 min; the stale-staged info line names the specimen's
|
||||
age). Render test per branch (the v0.70.1 template-gate rule).
|
||||
- **Loud event**: `offsite_delivery_stuck` (WARNING → operator email; severity gate untouched —
|
||||
explicit tests pin that info would be silent) when consumed_awaiting_apply persists ≥ 1 h;
|
||||
per-customer 24 h cooldown, DURABLE via `LastEventAt` over the events table (a hub restart
|
||||
neither floods nor resets).
|
||||
- **Self-heal (R-71c)**: `OffsiteDeliveryChecker` (shared 60 s ticker) invokes the EXISTING
|
||||
Re-issue path (`web.Server.ReissueOffsiteForCustomer` behind the narrow `monitor.OffsiteReissuer`
|
||||
interface — the pbsdrheal precedent; armed only when the provisioner is configured) when the
|
||||
shape is unambiguous: consumed ≥ 1 h + ≥ 4 consecutive offbox-less reports since consume + zero
|
||||
offbox evidence. One restage per customer per 24 h (durable); every firing surfaces as
|
||||
`offsite_credential_restaged` (WARNING → operator) — repeats are repeating events, never a
|
||||
silent retry loop. **The R-39(a) guard**: `SaveOneTimeSecret` clobbers by design (Re-issue
|
||||
depends on supersede), so the heal RE-READS the secret row immediately before acting and refuses
|
||||
unless it is still a consumed row — the TOCTOU (operator Re-issue landing mid-tick) is the shape
|
||||
the guard kills. Red-proofs run and recorded (guard removed → the operator's fresh secret gets
|
||||
clobbered, test fails on `reissue calls = 1`; both rate limits removed → duplicate fire).
|
||||
|
||||
Companion: felhom-controller v0.161.0 (the box-side truthful empty state). The self-heal ships
|
||||
unit-proven + red-proofed, NOT live-fired — no broken box exists and none was broken for it; it
|
||||
arms on the next natural occurrence (or a staged drill). R-71(a) (day-0 ordering) stays open —
|
||||
separate spec.
|
||||
|
||||
## v0.71.0 — paired recovery mails, prefs seeding at claim, priority headers, operator test leg (2026-07-22)
|
||||
|
||||
Origin: `documentation/audits/AUDIT-power-outage-recovery-2026-07-22.md` F11 (recovery is silent),
|
||||
|
||||
Reference in New Issue
Block a user