# Verification notes — `/system` on every host shape **Date:** 2026-10-17 (dev loop: tunnels 9121/9122/9123 + upsd 3494 all OK; dev-server `/api/health` all six sources `ok` before and after verification) ## What was checked, on live data Verified against `http://127.0.0.1:8090/system` with all three real agents answering, in a real browser (headless Chromium/Playwright), DOM assertions plus screenshots. | Host (shape) | Result | Screenshot | | --- | --- | --- | | `driveripper` (discrete Radeon AI PRO R9700) | GPU hero: `3 %` ok, `.sub` = "Radeon AI PRO R9700 · VRAM 30.5 GiB / 31.9 GiB · pool 33 %"; util/net/GPU charts all present inside the panel | `system-driveripper.png` (dark), `system-driveripper-light.png` | | `deskwork` (Strix Halo APU, two memory pools) | GPU hero busy went 82 % ok → 85 % warn → 99 % fail across the session, so threshold colour visibly moves; `.sub` = "Radeon 8060S Graphics · VRAM 172.7 MiB / 512.0 MiB · pool 78 %" — small dedicated VRAM and high shared pool read as two facts, not a contradiction; MEM 91 % and TEMP ~83 °C amber | `system-deskwork.png` | | `gateway` (no GPU, no CPU temp sensor) | CPU TEMP `n/a` with **no** severity class; GPU slot = `n/a` + "No GPU reported by this agent", uncoloured; **no** GPU chart and no hole where one would be | `system-gateway.png` (dark), `system-gateway-light.png` | Full-page shapes: `system-shapes-dark.png`, `system-shapes-light.png`. Failure path: stopped only the gateway tunnel (same commands `dev-tunnels.sh stop` runs, scoped to the 9123 entry; remote agent stopped too). After 15 poll failures the panel kept its last-good heroes (MEM 32 %, DISK 61 %, NET rates — nothing zeroed, nothing `n/a`), its dot turned red, the header read `stale 2.1m`, and the card dimmed via `.stale`. The other two panels stayed green ("one dead source must not blink another"). Store recorded exactly one `unreachable` and, after `./scripts/dev-tunnels.sh start`, one `reachable` event. Screenshot: `system-stale-gateway.png` (+ `system-stale-overview.png` full page). Restored; `dev-tunnels.sh status` and `/api/health` back to all-OK. Accessibility pass: - hero values are real selectable text (`div.value > span.num/span.unit`, no SVG paths) — asserted in-page for every hero on all three panels; - colour is never the only signal: each hero prints the number, the NET slot is deliberately colourless, staleness reads as text (`updated Ns` / `stale 2.1m`); - charts — **defect found**: the SVGs were anonymous (`aria-label` absent on container and svg). Fixed: `LineChart` gained an `ariaLabel` option that sets `role="img"` + `aria-label` on the ``, and every `/system` chart now names its host and metrics (e.g. "driveripper — utilisation over the selected window: CPU, memory and worst disk in per cent"). Pinned by `tests/test_api.py::test_every_system_chart_names_itself_for_assistive_tech`. The `/llm` and `/ups` charts can adopt the same option in phases 04/05. Both themes checked via the header toggle (severity colours come from theme tokens; the light-theme deskwork fail-red and warn-amber read clearly — see `system-shapes-light.png`, `system-gateway-light.png`). Note for the next shooter: set `prefers-color-scheme` or seed `localStorage['dash-theme']`; Playwright defaults to light, which silently mislabels a "dark" screenshot. `curl "localhost:8090/api/system/history?hosts=driveripper&metrics=cpu.usage_pct@core7&range=1h"` → 354 points: dropping the per-core plot did not drop the data. ## Defects found and fixed during verification 1. **Unlabelled charts** (above) — fixed in `charts.js` + `page-system.js`, test-pinned, re-screenshotted. 2. **`/system` Events panel was permanently empty** — the poller stores transition events under the *dashboard* name (`system`) while the page queried `/api/events?source=host`, so the feed said "No host transitions recorded yet" even with the deliberate gateway outage in the store. Fixed to `source=system` (with a comment on the naming trap); `tests/test_api.py::test_system_event_feed_queries_the_source_transitions_are_stored_under` pins it; the re-shot full-page screenshots show the feed populated with the outage and recovery. Pre-existing since the first commit, not introduced by phase 03. ## After the fixes `bash .agents/validate.sh` → exit 0: 460 passed + 7 skipped, coverage 96.86 % (≥ 94), ruff + pyright clean, `node --check` clean. `uv run pytest -m live --live` → 7 passed. Console stayed error-free throughout.