docs(v0.215.0): CHANGELOG, CONTEXT decisions, README feature, REUSE entries
gates / gates (push) Successful in 10s
gates / gates (push) Successful in 10s
- CHANGELOG leads with the severity fix and the live warning-vs-warn proof. - CONTEXT records the settled decisions so they are not re-litigated: Hiba is the label for predicted failure (no fourth word); sustain before count and why; the provenance of 64/55/60; phase 2 owns the new SMART attributes because they are a wire change under G-1; phase 1 state is one record per disk, not a series. - README documents the 14-row ladder, the persisted state, the hourly cadence and the five message shapes. - REUSE pins the severity wire contract on PushEvent — the defect's real home, so the next typo'd severity is caught at the table rather than in production — and records priorFor vs cardPriorFor, which differ by one observation and make the chip disagree with the email if mixed up.
This commit is contained in:
+40
-10
@@ -261,21 +261,51 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated
|
||||
|
||||
## Features
|
||||
|
||||
### Disk health — "Lemezek állapota" card + degradation alert (v0.169.0)
|
||||
### Disk health — "Lemezek állapota" card + degradation alert (v0.169.0; severity ladder v0.215.0)
|
||||
|
||||
The dashboard shows a per-physical-disk health card driven by the agent's SMART summary (serialized
|
||||
into `/disks` from agent v0.94.0 — no new smartctl load; the controller only reads it). One pure
|
||||
verdict function (`agentapi.DiskVerdictFor`) is the shared truth for the card chip and the check:
|
||||
verdict function (`agentapi.DiskVerdictFor`) is the shared truth for the card chip and the check.
|
||||
|
||||
**Why it does not trust `smart_status.passed`:** attributes 187/197/198 all carry `thresh: 0` and a
|
||||
normalized SMART value floors at 1, so a drive's own overall verdict is **structurally incapable** of
|
||||
failing on unreadable sectors — the real failing drive read `PASSED` at 352 pending sectors. The ladder
|
||||
reads the raw counters instead. Evidence:
|
||||
`felhom.eu/documentation/audits/DIAG-smart-passed-trap-2026-08-14.md`.
|
||||
|
||||
**Four labels, and there will not be a fifth** — a predicted failure is „Hiba", the same word a
|
||||
self-reported failure gets:
|
||||
|
||||
- **Rendben** — clean.
|
||||
- **Figyelmeztetés** — a first sighting of unreadable sectors below the bar, reallocated sectors, NVMe
|
||||
media errors, `percentage_used ≥ 90`, or `temperature_c ≥ 55`.
|
||||
- **Hiba** — the drive reports FAILING, **or** (v0.215.0) unreadable sectors are **sustained** across
|
||||
two consecutive checks, unreadable sectors sit alongside reallocation, the count reaches **64**,
|
||||
`temperature_c ≥ 60`, NVMe's `critical_warning` is set, or `percentage_used ≥ 100`.
|
||||
- **Nincs adat** — nil/UNKNOWN/old agent. Never alarms, and never erases a disk's stored history.
|
||||
|
||||
`DiskVerdictFor(smart, prior)` takes an `agentapi.DiskPrior`; a zero prior is the fail-safe, so a first
|
||||
sighting can only reach Figyelmeztetés. The full 14-row truth table, evaluated top-down, is documented
|
||||
in `internal/agentapi/diskverdict.go` together with the provenance of 64 / 55 / 60.
|
||||
|
||||
- **Rendben** (PASSED, clean) · **Figyelmeztetés** (PASSED but reallocated/pending/offline-uncorrectable
|
||||
or NVMe critical/media/percentage-used ≥ 90) · **Hiba** (FAILING) · **Nincs adat** (nil/UNKNOWN/old
|
||||
agent — never alarms).
|
||||
- The card fetches `/disks` through a **60 s TTL cache** (dashboard refresh-spam can't smartctl-storm
|
||||
the host); an unreachable agent renders "Nincs adat" and the page still loads.
|
||||
- A **6-hourly `disk-health-check`** emits `disk_health_degraded` (warn/critical) **only on a
|
||||
degradation** vs an in-memory baseline — first run baselines silently, recovery/UNKNOWN never notify,
|
||||
and a controller restart re-baselines silently. **No global banner** (deliberate): the card + email
|
||||
carry it. The hub allowlist must include `disk_health_degraded`.
|
||||
the host); an unreachable agent renders "Nincs adat" and the page still loads. The card replays the
|
||||
prior that produced the stored verdict (`diskRecord.PriorSawUncorrectable`) so the chip and the email
|
||||
cannot disagree.
|
||||
- An **hourly `disk-health-check`** (v0.215.0; was 6-hourly — the real drive's benign excursion lasted
|
||||
about one hour, and `/disks` measures ~0.82 s) emits `disk_health_degraded` against **persisted**
|
||||
per-disk state in `disk-health-state.json` under `cfg.Paths.DataDir`. It fires on an escalation
|
||||
against the **last alerted** verdict, and re-alerts a disk already at Hiba once it has **both**
|
||||
doubled its unreadable-sector count **and** waited out a 24 h cooldown. A disk's first verdict
|
||||
baselines silently; recovery and UNKNOWN never notify; a disappeared disk is forgotten. A restart no
|
||||
longer re-baselines — that is why the state is persisted. Every cycle logs a positive observable
|
||||
(`disk-health check complete: N disk(s) evaluated, M alert(s)`).
|
||||
- **Severity is a wire contract:** the alert emits `warning` / `critical` — the hub coerces anything
|
||||
outside `{info, warning, error, critical}` to `info` and never emails it. `DiskAlertKind.Severity()`
|
||||
is the single mapping. The hub allowlist must include `disk_health_degraded`.
|
||||
- Five message shapes (`notify.DiskAlert`), because the customer's action differs: Figyelmeztetés,
|
||||
drive-reported FAILING, Hiba-from-sector-count, Hiba-from-heat, and the still-worsening re-alert.
|
||||
- **No global banner** (deliberate): the card + email carry it.
|
||||
|
||||
### 1. App Management
|
||||
|
||||
|
||||
Reference in New Issue
Block a user