**Phase 21 final verification pass** (all 3 task files already in `complete/`, working tree carries the implementation)
- **Verified** task 01: `#pause`/`Space`/`setPaused`/`_paused` gone — `grep -ri pause src/dashboards/web/` empty, 0 pause hits in all 8 served pages + 10 static assets; re-ran `data/logs/21-task01-nopause.cjs` → 30/30 PASS (hidden tab: 0 data fetches in 22 s, one poll 2 ms after return).
- **Verified** task 02: re-ran `21-task02-gpu-values.cjs` on the live fleet → all PASS (deskwork/driveripper show Model/VRAM/Pool/Temp at 16.3 px; gateway = 5 heroes, slot `hidden`, no `n/a`; hero order unchanged; GPU history chart still builds per host).
- **Verified** task 03: re-ran `21-task03-scroll.cjs` → 14/14 PASS (`class="data scroll"`, scrollWidth 1021 vs clientWidth 292 at 360 px, Rotate/Revoke/bundle reachable and hit-testable; unchanged at 1280 px). Screenshots refreshed in `data/logs/`.
- **Gate**: `uv run pytest` → **1471 passed, 15 skipped**; `--cov --cov-fail-under=94` → **98.94%**; `ruff check src tests agent` clean; `pyright` **0 errors**; `bash .agents/validate.sh` → **EXIT 0** (incl. `node --check`); `uv run pytest -m live --live` → **11 passed**; `/api/health` all 9 sources `ok`.
- **Docs fixed** (pre-existing + this phase): "all **eight** signed-in pages" was a miscount of `MARKUP_PAGES` (7 = 5 dashboards + `/settings` + `/certs`; `/login` is the 8th, unsigned) → corrected in `README.md`, `AGENTS.md` (×2) and the `tests/test_api.py` docstring/comment; `AGENTS.md` Commands hermetic tally 1470 → **1471**.
- **Docs reviewed, consistent**: Quickstart/commands/flags (`install-agent.sh`, `capture-fixtures.sh`, `dev-server.sh`), the env table vs `config.py`, every documented route vs the served route table, masthead/`/system` GPU/`/certs` scroll descriptions vs code, and all `data/logs/*` + `tests/fixtures/*` references.
- **Deviation**: `validate.sh`'s advisory `fastapi 0.153.0 → 0.156.4` left alone — no dependency was touched this phase, so AGENTS rule 8 ("check after touching dependencies") is not triggered; upgrading here would be an unrelated behaviour change.
- No live-infra changes made (repo-side + browser verification only).
- **Next pending phase**: `22_disks_hide_unconfigured`.
4.7 KiB
Phase 21 — Page cleanups: pause, GPU values, certs scroll
Source: TODO.md L7, L9, L12 — "remove the pause button, GPU data as its own values, /certs table horizontal scroll"
Story: n/a
Context: src/dashboards/web/pages/{disks,llm,system,ups}.html line 25 (the #pause button, the only one in the served markup — /, /certs and /settings have none), src/dashboards/web/static/app.js (lines 587–615 the poll() _paused plumbing, lines 773–783 the #pause binding plus the Space shortcut), src/dashboards/web/static/dash.css line 203 (the comment naming the pause button), src/dashboards/web/static/page-system.js (lines 150–156 gpuSub() — the dense sub-line the TODO quotes, lines 164–188 renderGpuSlot(), line 72 the data-k="gpus" hero slot), tests/test_api.py (line 1425 — the six-heroes pin: "exactly six heroes: CPU, MEM, TEMP, DISK, GPU, NET", asserted over the three captures: discrete GPU, APU, no-GPU), src/dashboards/web/pages/certs.html line 81 (<table class="data" id="agents-table"> — no .scroll modifier; dash.css gives table.data a scroll container only with the .scroll class), src/dashboards/web/static/page-certs.js (lines 55–56 — the table element references)
Objective
Three small page-level cleanups, one per workstream: the pause button is gone from every page (the hidden-tab skip stays — a background tab idling its polls is not the operator's pause), the /system GPU data is split out of the dense sub-line into its own labelled values and a host with no GPU omits the slot instead of printing n/a, and the /certs agents table scrolls horizontally so the right-hand columns are reachable on a phone. No API surface changes; the pins that name the old behaviour (six heroes incl. an n/a GPU slot, the unpinned pause button) are rewritten, not left rotting.
Dependencies
20_masthead_nav_polish(todo) — the pause button lives in the masthead row task 01.01 reflows, and the/systemhero row is re-measured under the new bar; landing 20 first keeps 21's diff confined to the page bodies.
Tasks
01_remove_pause_button.md— delete the button, theSpaceshortcut, thesetPaused/_pausedplumbing and the CSS comment; the hidden-tab skip survives02_gpu_own_values.md— the densegpuSub()line becomes four labelled values per card; a GPU-less host omits the slot (five heroes, non/a)03_certs_table_scroll.md—#agents-tablegets the.scrollmodifier so its right-hand columns are reachable at phone width
Testing & Quality
- Unit/integration:
tests/test_api.py— the served-page pins: the pause button absent from the four pages (a return of#pausefails a test), the six-heroes pin rewritten (GPU-present host: six, GPU-absent host: five with nodata-k="gpus"slot), the#agents-table.scrollpin;tests/test_system_contract.py+tests/card_contract.pystay green (the API fields are unchanged — only the page's reading of them moves) - Coverage: >90% on new/modified code (the phase is markup + JS + CSS; the gate applies to the changed Python test files)
- 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.mdandAGENTS.mdin 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/systemparagraph ("a missing number or verdict — gateway's CPU temp, any host's absent GPU — printsn/auncoloured") is the one rule this phase inverts for the GPU slot (the CPU-tempn/astays — the TODO quotes the GPU line only); the sentence is split, the GPU half rewritten to the omission rule, and the pause button's mention in the masthead comment dropped.
Completion Criteria
- no page serves a
#pausebutton or binds theSpacekey; a hidden tab still skips its polls (served-bytes pin + a CDPvisibilitychangecheck) /system's GPU slot prints model / VRAM / pool / temp as four labelled values; a GPU-less host (the no-GPU capture, gateway) renders five heroes with no GPU slot and non/ain it (screenshots indata/logs/)- at 360 px the
/certsagents table scrolls horizontally to its last column (screenshot indata/logs/) uv run pytestgreen, coverage not down,ruff+pyrightcleanbash .agents/validate.shgreen (includingnode --checkof the modified page scripts)- no behavior change in completed work: the six-hero order on GPU hosts, the hidden-tab skip, the GPU history charts, the
/certsrow contents and the event pager are all unchanged