06 system_page_gpu_verdicts — GPU stops carrying a verdict, GPU temp on the hero row, per-host history charts collapsed behind a toggle (TODO L3/L4/L9) 07 llm_monitor_style_pages — /slots schema pinned from the live server, broken slot table removed, fleet totals block, stats strip, slot grid (full restyle; TODO L5) 08 events_paging_and_copy — event feeds scrollable + paginated, flavour text stripped, rule pinned in AGENTS.md (TODO L6/L7) 09 disks_smartctl — smartctl physical-disk collection in the host agent, 5-minute disks source/poller/store, /api/disks + severity rows, /disks page + nav tab + overview entry (TODO L8) LLM-Generated: true
4.1 KiB
Phase 09 — A /disks page for physical disk health (smartctl)
Source: TODO.md L8 — "a truly physical disk monitoring page": "Add a 'disks' tab dedicated to smartctl and per-disk metrics. Note: not per-partition, but truly a physical disk monitoring page that collects data about all my physical disks across my fleet (should only be deskwork and driveripper right now)."
Story: n/a
Context: agent/host_agent.py (physical whole disks via /sys/block, ~L400 — already partition-free; stdlib-only, ProtectSystem=strict), src/dashboards/config.py (env only, sources default to unset), src/dashboards/poller.py (one task per source, stale/last-good, events under the dashboard name), src/dashboards/store.py (WAL, rollups raw→1m→1h, retention — rule 9), src/dashboards/api.py (GETs, 404-when-unconfigured without dialling), the three existing dashboards + / overview (a new tab joins the nav and the overview's "which of the three" table)
Objective
A fourth dashboard: /disks — one card per physical disk (the agent's whole-
/sys/block enumeration, never partitions), each carrying smartctl health: overall
health, temperature, power-on hours, and the sector/wear alarms. Its own disks source
and poller task at a slow 5-minute cadence (SMART is not a per-second signal), its own
API (/api/disks/snapshot, /api/disks/history), rollups and retention, and a page that
reads n/a for what smartctl cannot see — never red for a missing binary.
- ASSUMPTION (phase, confirmed): the agent reads SMART directly (
smartctlas the agent user, e.g.diskgroup) — no sudo — andDISKS_INTERVAL_SECONDSdefaults to 300 s.smartctlabsent or a disk unreadable → that disk'ssmartisnullwith an error entry; the page says "smartctl not available" dimmed (invariants 3/4: unconfigured is not broken; a dead source must not blink another).
Dependencies
08_events_paging_and_copy(todo) — sequence only: it settlesapp.js/dash.css(the pager + copy audit) that the new page builds on; no hard code dependency.
Tasks
01_agent_smartctl_collection.md—host_agent.pygains asmartctlpass over its existing whole-disk list (per-devicesmartctl -i -A -H, stdlibsubprocess, timeout-bounded); fixture from the real disks; deploy docs.02_disks_source_poller_store.md— thediskssource (payload +disk.*@devsamples), its own poller job atDISKS_INTERVAL_SECONDS(default 300), rollups + retention instore.py.03_disks_api_and_config.md—/api/disks/snapshot+/api/disks/history, config wiring,404 {"configured": false}without dialling, severity rows for the health/temperature metrics.04_disks_page_and_overview.md— the/diskspage (per-disk cards, alarm chips, per-host history charts), nav tab + overview entry + header status dot.
Testing & Quality
- Hermetic: fixture-driven agent tests (
tests/test_agent.py+ recordedsmartctloutput),tests/test_disks_source.py(new),tests/test_api.pykey-path pins (with and without config),node --check. - Live:
uv run pytest -m live --live— the agent on deskwork/driveripper answerssmartfields for its real disks; live tests must not write (nosmartctl -t, no self-test on hardware something is plugged into). - Browser (DoD): screenshots in
data/logs/— per-disk cards on live data, the "smartctl not available" state, the overview with the new tab. - Coverage: >90% on new/modified code, ≥94% overall gate maintained.
Completion Criteria
GET /api/disks/snapshotanswers per-disksmartdata for every physical disk the agents report;404 {"configured": false}with no agents configured, without dialling/api/disks/historyserves thedisk.*@devseries through the existing rollups- the
/diskspage renders one card per physical disk (never per-partition) with health, temp, power-on hours and non-zero alarm chips - a host without
smartctl(or a denied read) shows dimmedn/acards, never a red page bash .agents/validate.shgreen; screenshots indata/logs/