hub v0.75.0: R-81 — "no signal" is not "bad signal" (anchor the backup deadline check)

Third instance of one class (hub v0.12.0, v0.73.0, this), fixed as a class.
On 2026-07-26 03:00 UTC expected_backup_missed fired on demo-felhom, demo-hp
and drill-r50 at once; the demo-felhom one reached the CUSTOMER channel
claiming "newest backup is 176h0m0s old". Nothing was wrong — three vzdump
archives were on disk. Cause: the agent backup store is in-memory, so the
R-50 fleet restart emptied `backups` until the next run, and the hub read
empty as "no backup exists".

- assessBackupFreshness returns OK/UNKNOWN/MISSED instead of `missed bool`;
  absence is UNKNOWN until it outlives an anchored window. Still pure.
- store.GetHostReportsSince + monitor.newestBackupEvidence read the hubs own
  retained history (bounded 7-day lookback, early-exit on fresh evidence) —
  "when did I last SEE evidence of a backup?" The anchor was free: the hub
  already retains 90 days. No agent change, no new persisted state.
- store.GetFirstHostReportAt anchors absence at first contact, reusing the
  existing 26h threshold as the grace (no new knob, the v0.73.0 shape).
- Deferrals logged + counted; reason strings kept distinct.
- backupStaleAfter untouched; landmine recorded (a weekly PBS snapshot would
  alarm six days in seven) and owned by R-82.

Tests 493->508. Red-proofs A/B/C observed and restored; A reproduces the live
message verbatim. Replayed the real 03:00 reports (600/417/77 rows): all
three now silent.

Source: documentation/audits/DIAG-backup-missed-2026-07-26.md
This commit is contained in:
Claude Code
2026-07-26 11:44:15 +02:00
parent add5b9bbbb
commit f5a5e2b911
9 changed files with 843 additions and 28 deletions
+39
View File
@@ -3,6 +3,45 @@
> Created with the REUSE.md rollout (2026-07-03). Authoritative history: `hub/CHANGELOG.md` (hub),
> `website/CHANGELOG.md`, `scripts/CHANGELOG.md`; end-of-task detail in `REPORT.md`.
## Standing rulings
**S-1 — N.5 gains a third leg: architecture docs are same-session coupled (2026-07-26, R-81).**
Any task that changes an **architectural contract** — tiers, targets, cadences, trust boundaries —
updates the owning `documentation/architecture/*.md` in the **same session**, under exactly the same
coupling rule that already binds the capability map and the ROADMAP. Origin: R-80/R-81 found
`07-backup-architecture.md` still describing a backup model that the shipped code does not implement
(single target, single cadence), while being cited as authoritative. A stale architecture doc is
worse than a missing one, because it is trusted.
**S-2 — architecture docs carry an honest status header (2026-07-26, R-81).**
Every `documentation/architecture/*.md` opens with the version it was **verified against** and the
date. A doc more than a few trains behind its subject is marked **STALE** *in that header*, so a
reader meets the warning before the content, not after acting on it. Origin:
`07-backup-architecture.md` — DRAFT since 2026-07-14, verified against controller v0.132.0, now 41
versions stale (live v0.173.0), and cited as authoritative throughout the R-80 diagnostic. Ratifying
or retiring it is → **R-83**.
- **2026-07-26 — hub v0.75.0: R-81 SHIPPED — "no signal" is not "bad signal".** Third instance of
one class (hub v0.12.0 `expected_backup_missed` daily-for-everyone; hub v0.73.0 `offsite_stale`
minutes after a healthy repair; now this), fixed **as a class**, with the invariant written at the
head of `assessBackupFreshness` naming all three. `assessBackupFreshness` returns
OK/UNKNOWN/MISSED instead of `missed bool`; absence is UNKNOWN until it outlives an anchored
window. **The anchor was free** — Phase-0 probe found the hub retains 90 days of host-reports, so
`GetHostReportsSince` + `newestBackupEvidence` (7-day bounded lookback, early-exit on fresh
evidence) answer *"when did I last SEE evidence of a backup?"* rather than *"what does the latest
report say?"*; absence is graded from first contact (`GetFirstHostReportAt`) reusing the existing
26 h threshold as the grace — **no new knob, no agent change, no new persisted state**.
**Rulings:** absence is never silent (a genuinely dead box must still alarm — that is the half the
naive fix breaks, and `TestBackupFreshness_NoEvidenceBeyondAnchor_Alarms` is what makes the
suppression safe); reason strings stay distinct (the whole 07-26 diagnosis turned on reading the
exact string); deferrals are logged so quiet ≠ not-checked. Tests 493→508; red-proofs A/B/C
observed — A reproduces `newest backup is 176h0m0s old` **verbatim the mail demo-felhom sent**.
**Replayed against the real 03:00 reports** (600/417/77 rows): all three now silent. `backupStaleAfter`
deliberately untouched — ⚠️ it will alarm on a healthy WEEKLY PBS snapshot, landmine recorded,
owned by **R-82**. The real finding behind R-80 stands: the **PBS/offsite-DR tier has no schedule
at all** → R-82. Cause-fix (persist the agent store) → R-84. Evidence:
`documentation/audits/DIAG-backup-missed-2026-07-26.md`, `hub/CHANGELOG.md` v0.75.0.
- **2026-07-23 — hub v0.72.0 + controller v0.161.0: R-70 SHIPPED + R-71(c) PARTIAL (the offsite
last mile is visible; burned credentials self-heal).** One detector
(`offsite.DeliveryStateFor` — secret-row timestamps × report offsite-presence), four consumers: