Files
dashboards/.agents/phases/complete/22_disks_hide_unconfigured/00_phase.md
T
ducoterra 895f309f8e phase: 22_disks_hide_unconfigured
All green. Final report:

**Verified (phase 22 final pass — both task files already in `complete/`)**
- `api._disk_visible` (`is not False`) is the single gate, applied to the assembled host list in `/api/disks/snapshot` **and** `/api/summary`'s disks block before the fleet sum and the rows; `sources/disks.py`, `page-disks.js`, `poller.py`, `store.py` and `alerts.py` are byte-unchanged (`git diff --stat`: only `api.py`, `test_api.py`, docs).
- Re-ran the live browser pass `data/logs/22-task02-disks-live.cjs` against the running dev server: **34/34 PASS** — no gateway card/why-line, `2/2 hosts answering`, fleet header reads the API's `2 of 2` / `17-17-0-1`, deskwork `nvme0n1` OK 47 °C/19 202 h/11 %, driveripper 16 live cards + `13 uncorrectable` chip, both aria-labelled plots, `/` still 3 fleet rows. Screenshots + `22-task02-api.json` refreshed.
- `./scripts/dev-server.sh status`: all **nine sources `ok`**, `disks:gateway` included; live `/api/events?source=disks` still carries gateway transitions (10 of 45), proving the README/AGENTS claim the gate hides a row and not the job's history.

**Completion criteria**
- `false` host absent from both endpoints, `None` + `unreachable` stub present, fleet ≡ row count: **PASS** (6 pins in `tests/test_api.py`, incl. the single-hidden-host = 200-with-empty-list leg).
- Live `/disks` = deskwork + driveripper, header 2 hosts, cards unchanged, screenshot in `data/logs/`: **PASS** (re-run above).
- `uv run pytest` → **1477 passed, 15 skipped**; `--cov --cov-fail-under=94` → **98.94 %** (`api.py` 100 %); `ruff check src tests agent` → all passed; `pyright` → 0 errors; `bash .agents/validate.sh` → **EXIT 0**. `uv run pytest -m live --live` → **11 passed**.
- No behaviour change in completed work: **PASS** (unchanged files above; live numbers match the pre-phase fleet record).

**Docs** — README: `/disks` page-table row + the agent SMART paragraph now distinguish "cannot read drives" (dimmed cards kept) from "no smartctl" (host absent from the page/API lists). AGENTS.md: hermetic tally 1471→**1477**, and the `collectors.py`/`api.py` passages now note the `false` arm never reaches the `/disks` why-line while an overview alert from a hidden host's `disks` job still names it. Everything else (routes vs served table, env table vs `config.py`, commands, scripts/fixtures/tests references, masthead/POLL_MS/threshold/retention claims) **verified consistent**.

**Deviations** — `NOTES.md` left empty by the task runs (both notes are tracked: mTLS → phase 24 `todo/`, the admin-links bug → fixed in phase 20 task 04); `/disks`' `#hosts-empty` copy left as pinned markup (it already names smartmontools + the disk group, so an all-hidden fleet is still told the fix); validate's advisory `fastapi 0.153.0 → 0.156.4` untouched (no dependency changed this phase). No live fleet writes of any kind.

**Next pending phase:** `23_llm_rate_responsiveness`.
2026-10-21 03:27:08 -04:00

4.6 KiB
Raw Blame History

Phase 22 — /disks hides hosts without smartctl

Source: TODO.md L13 — "VMs that don't have smartctl enabled disks should not show up. Gateway shouldn't even be a host on the disks page." Story: n/a Context: src/dashboards/api.py (disks_router() at line 791 — /api/disks/snapshot answering one entry per configured host; the /api/summary disks block at lines 640–704 — disks_hosts built from job.state.payload or _disks_stub(...) at line 640, fleet_disk_summary(disks_hosts) at line 693; _disks_stub() at line 771 — smartctl_available: None for a never-answered host), src/dashboards/sources/disks.py (smartctl_available() at line 142 — the three-way flag: True a disk answered, False the agent said the binary is not installed, None an agent predating the pass or --no-smart), src/dashboards/web/static/page-disks.js (the per-host cards + the fleet_disk_summary header, hidden below two hosts), tests/test_api.py (the /api/disks/* pins — "one entry per configured host", the smartctl_available three-way, "with and without targets configured", the fleet_disk_summary key paths)

Objective

A host whose agent answered smartctl_available: false (the binary is not installed — gateway's VM, no smartmontools behind vda) is not a host on the /disks page at all: it is absent from /api/disks/snapshot, from the fleet block and from /api/summary's disks rows, and the fleet header counts only the hosts that are shown. The three-way flag itself is unchanged in sources/disks.py (the agent still reports it, the /disks page's null-case why-line still exists for None hosts, and an unreachable host keeps its dimmed stub row — a dead agent is a different fact from a missing binary, invariant 3). The filter is one API-level decision, so the source, the store and the health records see nothing new.

Dependencies

  • 21_page_cleanups (todo) — both phases touch the /disks page markup (task 21.01 removes the page's #pause button); landing 21 first keeps this phase's diff confined to the host list.

Tasks

  1. 01_hide_smartctl_false_hosts.md — the one API-level visibility gate (explicit False only) over /api/disks/snapshot, /api/summary's disks block and the fleet summary; the pins rewritten
  2. 02_verification.md — browser + API verification against the live fleet: gateway absent, deskwork/driveripper intact, fleet header consistent, screenshots

Testing & Quality

  • Unit/integration: tests/test_api.py — the rewritten /api/disks/snapshot pin (one entry per configured host whose agent can read its drives — a smartctl_available: false payload is absent, a None payload is present, an unreachable stub is present), the /api/summary disks-block pin (fleet counts over the visible hosts, per-host rows for the visible hosts only), the unchanged smartctl_available three-way pin in sources/disks.py's own tests (tests/test_disks.py or wherever the flag is pinned — grep smartctl_available in tests/ first)
  • Coverage: >90% on new/modified code
  • The phase is "Complete" only when the entire project test suite passes 100% (every test in the project, not just this phase's)

Documentation & Consistency

  • The final pass reviews README.md and AGENTS.md in full against the project as it stands after this phase — fixing every inconsistency found, including pre-existing ones not caused by this phase. AGENTS.md's sources/disks.py bullet (the three-way flag's False arm — "so the page can say install smartmontools") and the /disks UI paragraph (the .banner.info why-line for false) are rewritten: the false arm's page-side consequence is now absence, and the three-way flag keeps its agent-side meaning; the "gateway answers smartctl_available: false" fleet fact gains the "and is therefore not a host on the disks page" clause.

Completion Criteria

  • /api/disks/snapshot and /api/summary's disks block carry no entry for a host whose agent answered smartctl_available: false; a None host and an unreachable stub both remain (pinned both ways in tests/test_api.py)
  • the /disks page on the live fleet shows deskwork + driveripper only, the fleet header counts 2 hosts, and the per-host cards are unchanged (screenshot in data/logs/)
  • uv run pytest green, coverage not down, ruff + pyright clean
  • bash .agents/validate.sh green
  • no behavior change in completed work: the agent's SMART pass, the disks:<host> job's health record, the stored disk.* series, the None-case why-line and the unreachable stub are all untouched