phase: 20_masthead_nav_polish

**Phase 20 final verification pass — all four tasks already complete; verified in full.**

- Verified: three-row masthead CSS (`.masthead` flex-wrap + two `flex-basis: 100%`, `min-height`, no `margin-inline-start`), un-sticky `position: relative` + `z-index: 40`, 180 ms `visibility/opacity/transform` slide (closed `nav.tabs` / open `.is-open`, both states in the file's single reduced-motion block), both admin links on all 8 signed-in pages, `/login` neither.
- `uv run pytest` → **1464 passed, 15 skipped** · `uv run pytest --cov --cov-fail-under=94` → **98.94%** (floor 94, unchanged) · `ruff check src tests agent` clean · `pyright` 0 errors · **`bash .agents/validate.sh` EXIT=0** (incl. `node --check` + repo hygiene) · `uv run pytest -m live --live` → **11 passed**.
- Browser (live dev server, invariant 10): `20-task01-rows.cjs` 121 PASS/0 FAIL · `20-task02-unsticky.cjs` 81/0 · `20-task03-slide.cjs` 32/0 · `20-task04-admin-links.cjs` 87/0 · phase-18 `nav-final-pass.cjs` 45/45, `nav-task03-verify` 77, `nav-task04-verify` 24/24 · phase-19 scripts 11/22/24/29 all pass. Screenshots refreshed in `data/logs/` (`masthead-rows*`, `masthead-unsticky*`, `slide-*`, `admin-links-*`). Dev server restarted; `/api/health` all nine sources `ok`.
- Completion criteria: 3-row bar @1280/360 ✓ · scroll leaves bar behind + dropdown under whole bar ✓ · slide out/in 180 ms, reduced-motion snap ✓ · `/certs`→`⚷ Certs`, `/settings`→`⚙ Account` before theme toggle, outside `.tabs` ✓ · pytest/coverage/ruff/pyright ✓ · validate ✓ · no regression in tab structure, token reveal, safe-area padding, four close paths, status dots, theme toggle ✓.
- Docs: **AGENTS.md** gap 12 still said phase 20 was "in `todo/`… admin-link half has landed" and attributed the wrap to the old fixed 58 px row — rewritten to the completed state (three rows/un-sticky/slide/both links; 24 still todo; 21's `/certs` `.scroll` noted as not reaching `/`'s table). **README.md** `web/` bullet enumerated the controls row without `⏸ Pause` and omitted `/login` from the two-row list — both fixed. Everything else (setup, commands, env table vs `config.py`, routes vs `api.py`, agent/installer flags, testing policy) verified consistent.
- Deviations: no dependency bump — `uv pip list --outdated` still reports the pre-existing advisory `fastapi 0.153.0 → 0.156.4` (deps untouched this phase, validate treats it as advisory); `NOTES.md` is empty in the working tree from an operator edit outside these tasks (both items live in phases 20/24) — left as-is; no live-infra changes made or needed.
- Next pending phase: `21_page_cleanups` (pause button removal, `/system` GPU values, `/certs` table scroll).
This commit is contained in:
2026-10-20 22:49:37 -04:00
parent 95df8b695b
commit 6444a158f2
32 changed files with 960 additions and 106 deletions
@@ -0,0 +1,9 @@
**Phase 20 final verification pass — all four tasks already complete; verified in full.**
- Verified: three-row masthead CSS (`.masthead` flex-wrap + two `flex-basis: 100%`, `min-height`, no `margin-inline-start`), un-sticky `position: relative` + `z-index: 40`, 180 ms `visibility/opacity/transform` slide (closed `nav.tabs` / open `.is-open`, both states in the file's single reduced-motion block), both admin links on all 8 signed-in pages, `/login` neither.
- `uv run pytest` → **1464 passed, 15 skipped** · `uv run pytest --cov --cov-fail-under=94` → **98.94%** (floor 94, unchanged) · `ruff check src tests agent` clean · `pyright` 0 errors · **`bash .agents/validate.sh` EXIT=0** (incl. `node --check` + repo hygiene) · `uv run pytest -m live --live` → **11 passed**.
- Browser (live dev server, invariant 10): `20-task01-rows.cjs` 121 PASS/0 FAIL · `20-task02-unsticky.cjs` 81/0 · `20-task03-slide.cjs` 32/0 · `20-task04-admin-links.cjs` 87/0 · phase-18 `nav-final-pass.cjs` 45/45, `nav-task03-verify` 77, `nav-task04-verify` 24/24 · phase-19 scripts 11/22/24/29 all pass. Screenshots refreshed in `data/logs/` (`masthead-rows*`, `masthead-unsticky*`, `slide-*`, `admin-links-*`). Dev server restarted; `/api/health` all nine sources `ok`.
- Completion criteria: 3-row bar @1280/360 ✓ · scroll leaves bar behind + dropdown under whole bar ✓ · slide out/in 180 ms, reduced-motion snap ✓ · `/certs`→`⚷ Certs`, `/settings`→`⚙ Account` before theme toggle, outside `.tabs` ✓ · pytest/coverage/ruff/pyright ✓ · validate ✓ · no regression in tab structure, token reveal, safe-area padding, four close paths, status dots, theme toggle ✓.
- Docs: **AGENTS.md** gap 12 still said phase 20 was "in `todo/`… admin-link half has landed" and attributed the wrap to the old fixed 58 px row — rewritten to the completed state (three rows/un-sticky/slide/both links; 24 still todo; 21's `/certs` `.scroll` noted as not reaching `/`'s table). **README.md** `web/` bullet enumerated the controls row without `⏸ Pause` and omitted `/login` from the two-row list — both fixed. Everything else (setup, commands, env table vs `config.py`, routes vs `api.py`, agent/installer flags, testing policy) verified consistent.
- Deviations: no dependency bump — `uv pip list --outdated` still reports the pre-existing advisory `fastapi 0.153.0 → 0.156.4` (deps untouched this phase, validate treats it as advisory); `NOTES.md` is empty in the working tree from an operator edit outside these tasks (both items live in phases 20/24) — left as-is; no live-infra changes made or needed.
- Next pending phase: `21_page_cleanups` (pause button removal, `/system` GPU values, `/certs` table scroll).
@@ -0,0 +1,65 @@
== uv run pytest --cov (hermetic: no network, live tests skip) ==
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 14%]
........................................................................ [ 19%]
........................................................................ [ 24%]
........................................s............................... [ 29%]
........................................................................ [ 34%]
........................................................................ [ 38%]
........................................................................ [ 43%]
........................................................................ [ 48%]
........................................................................ [ 53%]
........................................................................ [ 58%]
........................................................................ [ 63%]
........................................................................ [ 68%]
.....sssssssssss........................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 92%]
.....................................................sss................ [ 97%]
....................................... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/dashboards/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.4-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------------------
src/dashboards/__init__.py 3 0 100%
src/dashboards/__main__.py 14 1 93% 32
src/dashboards/alerts.py 176 0 100%
src/dashboards/api.py 436 0 100%
src/dashboards/app.py 185 0 100%
src/dashboards/auth.py 265 0 100%
src/dashboards/certs.py 292 0 100%
src/dashboards/collectors.py 205 5 98% 284-285, 289-290, 307
src/dashboards/config.py 120 0 100%
src/dashboards/debug.py 14 0 100%
src/dashboards/poller.py 165 3 98% 192-194, 279
src/dashboards/prom.py 112 5 96% 126, 163, 177, 180, 183
src/dashboards/rates.py 73 0 100%
src/dashboards/severity.py 49 0 100%
src/dashboards/sources/__init__.py 0 0 100%
src/dashboards/sources/disks.py 134 0 100%
src/dashboards/sources/host.py 209 0 100%
src/dashboards/sources/llm.py 178 1 99% 285
src/dashboards/sources/nut.py 413 20 95% 153, 172, 186, 198, 204, 217, 225, 241, 319-320, 322, 579, 591, 626, 657, 661, 718-719, 724, 736
src/dashboards/sources/nut_sim.py 134 0 100%
src/dashboards/store.py 313 2 99% 553-554
------------------------------------------------------------------
TOTAL 3490 37 99%
Required test coverage of 94% reached. Total coverage: 98.94%
1464 passed, 15 skipped, 1 warning in 156.47s (0:02:36)
== uv run ruff check src tests agent ==
All checks passed!
== uv run pyright ==
0 errors, 0 warnings, 0 informations
== node --check src/dashboards/web/static/*.js ==
advisory: dependencies are out of date (AGENTS.md rule 8 — update on purpose):
fastapi 0.153.0 0.156.4 wheel
@@ -0,0 +1,21 @@
All green. Final state:
**Implemented**
- `src/dashboards/web/static/dash.css` — the masthead is now **three left-justified rows at every width** (row 1 brand + `#nav-toggle` + tabs, row 2 `#nav-status` dots, row 3 the `.masthead-right` controls), CSS-only, no markup change: `.masthead` gained `flex-wrap: wrap` + `gap: .35rem 1.1rem` and `height: var(--header-h)` → `min-height`; `#nav-status` and `.masthead-right` each got `flex-basis: 100%` + `justify-content: flex-start`; `.masthead-right` lost `margin-inline-start: auto`. (The task's `flex-direction: column` first option cannot ship — it splits brand and tabs onto separate rows — so the file's own named `flex-wrap` fallback shipped, measured in a browser per the phase-18 rule.)
- ≤640px block re-cut: dropped its `height: auto` / `min-height` / `flex-wrap` machinery (one declaration now, no drift), kept the token reveal, `#nav-status { flex-wrap: nowrap }`, `.masthead-right > * { flex: none }`, the `env(safe-area-inset-top)` line and the dropdown; comments rewritten to the three-row reality. `position: sticky`/`z-index: 40` untouched (task 02's job).
- `tests/test_api.py` — `test_the_masthead_is_three_left_justified_rows_at_every_width` (+ `_rule_body`/`_declarations` helpers) and `test_the_mobile_masthead_block_declares_no_second_bar_height`, both on **served** bytes; mutation-tested (re-adding `height: var(--header-h)`, dropping `#nav-status`'s `flex-basis`, or re-declaring `min-height` in the mobile block each fails the matching test).
- Browser evidence: `data/logs/20-task01-rows.cjs` (7 pages × 1280 px/360 px: row order, left justification, no clipping, no overflow, dropdown under the **whole** bar) — ALL CHECKS PASS; screenshots `data/logs/masthead-rows{1280,360}-*.png` (+ dropdown, login, 768 px). No horizontal overflow at 360/480/641/768/900/1024/1440.
**Tests / lint / coverage**
- `uv run pytest` → **1460 passed, 15 skipped**; `uv run pytest --cov` → **98.94%** (floor 94%, unchanged); `uv run ruff check src tests agent` → clean; `uv run pyright` → 0 errors; `bash .agents/validate.sh` → **EXIT=0** (incl. `node --check`); `uv run pytest -m live --live` → **11 passed**; `data/logs/nav-final-pass.cjs` → **45/45**.
- Pre-existing advisory from validate: `fastapi 0.153.0 → 0.156.4`. Not touched — this task moved no dependencies (AGENTS rule 8 checks apply after dependency changes).
**Docs**
- `AGENTS.md`: new "The masthead is three left-justified rows at every width" paragraph (mechanism, why not `column`, the single `min-height`), and the phase-18 hamburger paragraph rewritten (block now tightens gaps instead of wrapping the bar; dropdown sits under the whole bar; nav-final-pass desktop leg noted).
- `README.md`: the `web/` bullet's "above it the masthead stays the one row it has always been" replaced with the three-row description.
**Decisions/deviations**
- Shipped the task's `flex-wrap` fallback (measured) rather than `flex-direction: column`; `/login` (theme toggle only) now renders a 2-row bar — unavoidable without markup changes, verified clean at both widths.
- Updated the gitignored `data/logs/nav-final-pass.cjs` desktop bound (`<80` → `80–140 px`) since the one-row bar it asserted no longer exists; nav behaviour assertions unchanged and passing.
**Next pending task:** `.agents/phases/todo/20_masthead_nav_polish/02_unsticky_masthead.md`
@@ -0,0 +1,65 @@
== uv run pytest --cov (hermetic: no network, live tests skip) ==
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 14%]
........................................................................ [ 19%]
........................................................................ [ 24%]
....................................s................................... [ 29%]
........................................................................ [ 34%]
........................................................................ [ 39%]
........................................................................ [ 43%]
........................................................................ [ 48%]
........................................................................ [ 53%]
........................................................................ [ 58%]
........................................................................ [ 63%]
........................................................................ [ 68%]
.sssssssssss............................................................ [ 73%]
........................................................................ [ 78%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 92%]
.................................................sss.................... [ 97%]
................................... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/dashboards/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.4-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------------------
src/dashboards/__init__.py 3 0 100%
src/dashboards/__main__.py 14 1 93% 32
src/dashboards/alerts.py 176 0 100%
src/dashboards/api.py 436 0 100%
src/dashboards/app.py 185 0 100%
src/dashboards/auth.py 265 0 100%
src/dashboards/certs.py 292 0 100%
src/dashboards/collectors.py 205 5 98% 284-285, 289-290, 307
src/dashboards/config.py 120 0 100%
src/dashboards/debug.py 14 0 100%
src/dashboards/poller.py 165 3 98% 192-194, 279
src/dashboards/prom.py 112 5 96% 126, 163, 177, 180, 183
src/dashboards/rates.py 73 0 100%
src/dashboards/severity.py 49 0 100%
src/dashboards/sources/__init__.py 0 0 100%
src/dashboards/sources/disks.py 134 0 100%
src/dashboards/sources/host.py 209 0 100%
src/dashboards/sources/llm.py 178 1 99% 285
src/dashboards/sources/nut.py 413 20 95% 153, 172, 186, 198, 204, 217, 225, 241, 319-320, 322, 579, 591, 626, 657, 661, 718-719, 724, 736
src/dashboards/sources/nut_sim.py 134 0 100%
src/dashboards/store.py 313 2 99% 553-554
------------------------------------------------------------------
TOTAL 3490 37 99%
Required test coverage of 94% reached. Total coverage: 98.94%
1460 passed, 15 skipped, 1 warning in 153.92s (0:02:33)
== uv run ruff check src tests agent ==
All checks passed!
== uv run pyright ==
0 errors, 0 warnings, 0 informations
== node --check src/dashboards/web/static/*.js ==
advisory: dependencies are out of date (AGENTS.md rule 8 — update on purpose):
fastapi 0.153.0 0.156.4 wheel
@@ -0,0 +1,14 @@
**Task 02 complete — masthead is no longer sticky.**
- `dash.css` `.masthead`: `position: sticky; top: 0` → `position: relative` (kept `z-index: 40`, so the dropdown's `41` still means "one above the bar"); rewrote the two comments that called the bar sticky (header block + the `nav.tabs.is-open` anchor note). Table-head `sticky; top: 0` (now line 848) untouched.
- `tests/test_api.py`: new `test_the_masthead_scrolls_away_and_stays_the_dropdown_anchor` in the phase-20 layout-pin section — served CSS asserts `position: relative`, no `position: sticky` value, **no `top`**, `z-index: 40`, and that the ≤640px dropdown is still `absolute; top: 100%` stacking above the bar. No pre-existing pin named the declaration, so this is the added one.
- Browser proof (invariant 10): new `data/logs/20-task02-unsticky.cjs` → **80 checks PASS / 0 FAIL** — 7 pages × 1280 px & 360 px, bar scrolls off the top (plus a squeezed-height leg for pages that fit a tall viewport), nothing pinned to the viewport but a `thead`, 360 px dropdown still opens flush under the whole three-row bar, is anchored to `.masthead`, and still hangs off it after a scroll. Screenshots `data/logs/masthead-unsticky*.png` + log.
- Fixed task 01's stale verification script (`data/logs/20-task01-rows.cjs` still demanded `position === "sticky"`) and a dangling "At" task 01 left in README's `web/` bullet.
**Results:** `uv run pytest` → **1461 passed, 15 skipped**; `bash .agents/validate.sh` → **EXIT=0** (coverage **98.94%** vs 94% floor, `ruff check src tests agent` clean, `pyright` 0 errors, `node --check` of `web/static/*.js` clean); `uv run pytest -m live --live` → **11 passed**.
**Docs:** AGENTS.md masthead paragraph now records the un-stick (why `relative` not `static`, the menu scrolls with the bar, the only remaining sticky is a table head, the "Chrome computes `top: 0px` either way" note explaining why the offset is a CSS pin), and cites three phase-20 tests + the new script. README's `web/` bullet says the bar is not sticky and why the dropdown stays anchored.
**Decisions/deviations:** `uv pip list --outdated` still lists `fastapi 0.153.0 → 0.156.4` — pre-existing, deps untouched by this task, so validate treats it as advisory; deliberately not bumped mid-phase.
**Next pending task:** `20_masthead_nav_polish/03_hamburger_slide.md` (180 ms dropdown slide, stilled under `prefers-reduced-motion`).
@@ -0,0 +1,65 @@
== uv run pytest --cov (hermetic: no network, live tests skip) ==
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 14%]
........................................................................ [ 19%]
........................................................................ [ 24%]
.....................................s.................................. [ 29%]
........................................................................ [ 34%]
........................................................................ [ 39%]
........................................................................ [ 43%]
........................................................................ [ 48%]
........................................................................ [ 53%]
........................................................................ [ 58%]
........................................................................ [ 63%]
........................................................................ [ 68%]
..sssssssssss........................................................... [ 73%]
........................................................................ [ 78%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 92%]
..................................................sss................... [ 97%]
.................................... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/dashboards/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.4-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------------------
src/dashboards/__init__.py 3 0 100%
src/dashboards/__main__.py 14 1 93% 32
src/dashboards/alerts.py 176 0 100%
src/dashboards/api.py 436 0 100%
src/dashboards/app.py 185 0 100%
src/dashboards/auth.py 265 0 100%
src/dashboards/certs.py 292 0 100%
src/dashboards/collectors.py 205 5 98% 284-285, 289-290, 307
src/dashboards/config.py 120 0 100%
src/dashboards/debug.py 14 0 100%
src/dashboards/poller.py 165 3 98% 192-194, 279
src/dashboards/prom.py 112 5 96% 126, 163, 177, 180, 183
src/dashboards/rates.py 73 0 100%
src/dashboards/severity.py 49 0 100%
src/dashboards/sources/__init__.py 0 0 100%
src/dashboards/sources/disks.py 134 0 100%
src/dashboards/sources/host.py 209 0 100%
src/dashboards/sources/llm.py 178 1 99% 285
src/dashboards/sources/nut.py 413 20 95% 153, 172, 186, 198, 204, 217, 225, 241, 319-320, 322, 579, 591, 626, 657, 661, 718-719, 724, 736
src/dashboards/sources/nut_sim.py 134 0 100%
src/dashboards/store.py 313 2 99% 553-554
------------------------------------------------------------------
TOTAL 3490 37 99%
Required test coverage of 94% reached. Total coverage: 98.94%
1461 passed, 15 skipped, 1 warning in 155.60s (0:02:35)
== uv run ruff check src tests agent ==
All checks passed!
== uv run pyright ==
0 errors, 0 warnings, 0 informations
== node --check src/dashboards/web/static/*.js ==
advisory: dependencies are out of date (AGENTS.md rule 8 — update on purpose):
fastapi 0.153.0 0.156.4 wheel
@@ -0,0 +1,15 @@
**Task 03 complete — the ≤640px menu slides out and back in.**
- `dash.css`: `nav.tabs` is now the **closed** dropdown (geometry + `visibility: hidden; opacity: 0; transform: translateY(-8px); pointer-events: none` + `transition: opacity 180ms ease, transform 180ms ease, visibility 0s linear 180ms`); `.is-open` flips only those four to their visible counterparts with the `visibility` delay dropped — the `brain_of_reese` `.app-nav` pair. `display: none` had to go (an unrendered box has no intermediate state).
- Merged `nav.tabs, nav.tabs.is-open { transition: none; }` into the file's **only** `prefers-reduced-motion` block (both states named, phase-46 lesson); `app.js` unchanged except one stale comment.
- Tests: 3 new served-CSS pins (closed start / visible end / both-states reduced motion + "no `display: none` may come back") and a `_cascade` helper; two stale pins (phase-18 `display:none`, task-02 dropdown geometry) updated to where the declarations now live.
- Browser (invariant 10): new `data/logs/20-task03-slide.cjs` → **all checks pass** (computed closed state, mid-transition frame at ≈60 ms in *both* directions, 4 close paths + Esc focus, reduced-motion snaps `prop=none`, desktop tabs untouched, hidden menu adds **no** scroll area); screenshots `data/logs/slide-*.png`.
- Also repaired four stale verification probes the change invalidated: `nav-final-pass.cjs` 45/45, `nav-task03-verify.cjs` 77, `nav-task04-verify.cjs` 24, `20-task01-rows.cjs` all pass.
**Results:** `uv run pytest` → **1464 passed, 15 skipped**; `bash .agents/validate.sh` → **EXIT=0** (coverage **98.94%** vs 94% floor, `ruff check src tests agent` clean, `pyright` 0 errors, `node --check web/static/*.js` clean); `uv run pytest -m live --live` → **11 passed**.
**Docs:** AGENTS.md nav paragraph rewritten (one box / two states, why `visibility` not `display`, the delayed-then-undelayed `visibility`, both-states reduced motion, the new pins + script; test count 1458→1464); README's `web/` bullet now says the menu slides 180 ms and stills under `prefers-reduced-motion`.
**Decisions/deviations:** followed the task's prescribed visibility pattern rather than `@starting-style`/`allow-discrete` (wider support, it is the referenced implementation); the explicit reduced-motion pair is redundant with the universal `* …!important` rule and kept deliberately — the task mandates naming both states. `uv pip list --outdated` still lists `fastapi 0.153.0 → 0.156.4`: pre-existing, deps untouched, not bumped mid-phase.
**Next pending task:** `20_masthead_nav_polish/04_admin_links_visible.md`.
@@ -0,0 +1,65 @@
== uv run pytest --cov (hermetic: no network, live tests skip) ==
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 14%]
........................................................................ [ 19%]
........................................................................ [ 24%]
........................................s............................... [ 29%]
........................................................................ [ 34%]
........................................................................ [ 38%]
........................................................................ [ 43%]
........................................................................ [ 48%]
........................................................................ [ 53%]
........................................................................ [ 58%]
........................................................................ [ 63%]
........................................................................ [ 68%]
.....sssssssssss........................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 92%]
.....................................................sss................ [ 97%]
....................................... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/dashboards/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.4-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------------------
src/dashboards/__init__.py 3 0 100%
src/dashboards/__main__.py 14 1 93% 32
src/dashboards/alerts.py 176 0 100%
src/dashboards/api.py 436 0 100%
src/dashboards/app.py 185 0 100%
src/dashboards/auth.py 265 0 100%
src/dashboards/certs.py 292 0 100%
src/dashboards/collectors.py 205 5 98% 284-285, 289-290, 307
src/dashboards/config.py 120 0 100%
src/dashboards/debug.py 14 0 100%
src/dashboards/poller.py 165 3 98% 192-194, 279
src/dashboards/prom.py 112 5 96% 126, 163, 177, 180, 183
src/dashboards/rates.py 73 0 100%
src/dashboards/severity.py 49 0 100%
src/dashboards/sources/__init__.py 0 0 100%
src/dashboards/sources/disks.py 134 0 100%
src/dashboards/sources/host.py 209 0 100%
src/dashboards/sources/llm.py 178 1 99% 285
src/dashboards/sources/nut.py 413 20 95% 153, 172, 186, 198, 204, 217, 225, 241, 319-320, 322, 579, 591, 626, 657, 661, 718-719, 724, 736
src/dashboards/sources/nut_sim.py 134 0 100%
src/dashboards/store.py 313 2 99% 553-554
------------------------------------------------------------------
TOTAL 3490 37 99%
Required test coverage of 94% reached. Total coverage: 98.94%
1464 passed, 15 skipped, 1 warning in 156.99s (0:02:36)
== uv run ruff check src tests agent ==
All checks passed!
== uv run pyright ==
0 errors, 0 warnings, 0 informations
== node --check src/dashboards/web/static/*.js ==
advisory: dependencies are out of date (AGENTS.md rule 8 — update on purpose):
fastapi 0.153.0 0.156.4 wheel
@@ -0,0 +1,15 @@
**Task 04 complete — both admin links stay visible on the admin pages.**
- `pages/certs.html`: added `⚷ Certs` (order is clock → `⚷ Certs` → `⚙ Account` → theme) and rewrote the comment that justified its absence; also gave its theme toggle the `aria-pressed="false"` the other seven pages carry (pre-existing markup drift, now pinned).
- `pages/settings.html`: added `⚙ Account` between Certs and the theme toggle; comment now says "this one included".
- `tests/test_api.py::test_every_page_links_to_both_admin_pages` rewritten: **one** loop over all eight signed-in pages asserting both full tags, both before `id="theme-toggle"`, Certs-before-Account, neither inside `.tabs`, and an identical theme-toggle tag; the two "links to itself" assertions deleted; added the `/login`-renders-neither assertion via an unsigned client (mutation-checked: removing the link fails with "no route to the certificate authority").
- Browser (invariant 10): new `data/logs/20-task04-admin-links.cjs` → **86/86 PASS** (cluster rendered + in order at 1280 px and 360 px, self-link click = exactly one `200` document, no redirect, page/cluster unchanged, cross-links still navigate, `/login` neither link); screenshots `data/logs/admin-links-{1280,360}-{certs,settings}.png` (the pair is byte-identical — the clusters now are) + `admin-links-login.png`.
- Fixed a stale probe from task 02 (`20-task02-unsticky.cjs`): its fixed 700 ms sleep raced first paint and reported "max scroll 0"; it now settles on document height and asserts the bar rides the scroll by exactly the scrolled distance — 3 consecutive green runs. `20-task01/03`, `nav-final-pass` (45/45), `nav-task04-verify` (24/24) also re-run green.
**Results:** `uv run pytest` → **1464 passed, 15 skipped**; coverage **98.94 %** (floor 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**; dev server restarted, `/api/health` all nine sources `ok`.
**Docs:** AGENTS.md — both admin-page paragraphs rewritten to the new rule (self-link is a no-op; one loop over eight; `/login` the exception), gap 11's `/certs` line and gap 12's "which that phase is the decision on" resolved. README — intro, *The account page*, and the `web/` masthead bullet now say both links are on all eight signed-in pages.
**Deviations:** touched the `/certs` theme toggle's `aria-pressed` (defect fix, in service of "identical controls"; no behaviour change); `uv pip list --outdated` still lists `fastapi 0.13 → 0.156` — pre-existing advisory, deps untouched, not bumped mid-phase.
**Next pending task:** `21_page_cleanups/01_remove_pause_button.md` (phase 20 is now complete).
@@ -0,0 +1,65 @@
== uv run pytest --cov (hermetic: no network, live tests skip) ==
........................................................................ [ 4%]
........................................................................ [ 9%]
........................................................................ [ 14%]
........................................................................ [ 19%]
........................................................................ [ 24%]
........................................s............................... [ 29%]
........................................................................ [ 34%]
........................................................................ [ 38%]
........................................................................ [ 43%]
........................................................................ [ 48%]
........................................................................ [ 53%]
........................................................................ [ 58%]
........................................................................ [ 63%]
........................................................................ [ 68%]
.....sssssssssss........................................................ [ 73%]
........................................................................ [ 77%]
........................................................................ [ 82%]
........................................................................ [ 87%]
........................................................................ [ 92%]
.....................................................sss................ [ 97%]
....................................... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/dashboards/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.4-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------------------
src/dashboards/__init__.py 3 0 100%
src/dashboards/__main__.py 14 1 93% 32
src/dashboards/alerts.py 176 0 100%
src/dashboards/api.py 436 0 100%
src/dashboards/app.py 185 0 100%
src/dashboards/auth.py 265 0 100%
src/dashboards/certs.py 292 0 100%
src/dashboards/collectors.py 205 5 98% 284-285, 289-290, 307
src/dashboards/config.py 120 0 100%
src/dashboards/debug.py 14 0 100%
src/dashboards/poller.py 165 3 98% 192-194, 279
src/dashboards/prom.py 112 5 96% 126, 163, 177, 180, 183
src/dashboards/rates.py 73 0 100%
src/dashboards/severity.py 49 0 100%
src/dashboards/sources/__init__.py 0 0 100%
src/dashboards/sources/disks.py 134 0 100%
src/dashboards/sources/host.py 209 0 100%
src/dashboards/sources/llm.py 178 1 99% 285
src/dashboards/sources/nut.py 413 20 95% 153, 172, 186, 198, 204, 217, 225, 241, 319-320, 322, 579, 591, 626, 657, 661, 718-719, 724, 736
src/dashboards/sources/nut_sim.py 134 0 100%
src/dashboards/store.py 313 2 99% 553-554
------------------------------------------------------------------
TOTAL 3490 37 99%
Required test coverage of 94% reached. Total coverage: 98.94%
1464 passed, 15 skipped, 1 warning in 155.86s (0:02:35)
== uv run ruff check src tests agent ==
All checks passed!
== uv run pyright ==
0 errors, 0 warnings, 0 informations
== node --check src/dashboards/web/static/*.js ==
advisory: dependencies are out of date (AGENTS.md rule 8 — update on purpose):
fastapi 0.153.0 0.156.4 wheel