phase: 08_events_paging_and_copy
All green. Final report:
**Verified (phase 08 — both task files already in `complete/`; this was the final verification pass)**
- `Dash.eventsPager()` in `app.js` (50/page, `1–50 of N` strip, aria-labelled `‹ prev`/`next ›` disabled at the ends, `WeakMap` page state, reset only when the event *set* changes, `EVENT_FEED_LIMIT`=200) with three call sites; `ul.events` bounded to 320px + `overflow-y:auto`; `/api/events` untouched (`le=500`, no silent clamp).
- Live browser against the real fleet: `/system` `1–50 of 121`, `/llm` `1–50 of 200`, `/ups` `1–50 of 200`; container 320px vs scrollHeight 1543/2368; page 2 → `51–100 of 200` and survived two polls; no empty `.sub`/`.faint` container visible on any page; footers carry only measurements (`rates over Δ11.9s · poll 10s`). Fresh artifacts: `data/logs/08-final-{system-head,llm-page,index-page,ups-feed-page2}.png` (32 phase screenshots already present).
- Grep of live served bytes for all 13 deleted flavour fragments + `actions = -`: none survive in HTML or JS.
- `AGENTS.md` carries both new UI-convention rules (flavour-text rule with the `TODO.md:7` cited examples; the event-feed-window rule) and the updated test count.
**Tests / lint (full project 100% green)**
- `bash .agents/validate.sh` → **EXIT=0**: `uv run pytest --cov --cov-fail-under=94` → **624 passed, 9 skipped, coverage 97.91%**; `ruff check src tests agent` → All checks passed; `pyright` → 0 errors; `node --check` ×5 clean; repo hygiene clean.
- `uv run pytest -m live --live` (`.env.dev` sourced) → **9 passed**; `uv pip list --outdated` → empty. Re-ran pytest/ruff/pyright/node after the doc edits → all exit 0.
**Completion criteria**: bounded scroll + 50/page + count footer ✅ (all three feeds, live) · no removed flavour string ✅ · AGENTS.md rule ✅ · `validate.sh` green + screenshots in `data/logs/` ✅.
**Documentation**: full README/AGENTS review against code (env table vs `config.py`/`.env*.example`, script flags, Containerfile uid 10001/8090, chart heights 120/110/160, test count, coverage) — one inaccuracy fixed: README said "Every page's event feed" (the overview has none) → now "The three event feeds (`/system`, `/llm`, `/ups`)"; also restored the missing trailing newline in `TODO.md`. Everything else verified consistent.
**Notes**: paging stays client-side (no API change); the task-02 defect fix in `/ups` setup copy (`NUT_HOST`/`NUT_PORT`, `LISTEN 127.0.0.1`, one `instcmds` per command, never `actions = -`) re-verified against README and live bytes. Pre-existing items intentionally left to their own phases: `ups.test.result: "Done and passed"` rated `warn` (operator's `TODO.md` entry) and the dev-DB `database is locked` retention issue.
**Next pending phase**: `.agents/phases/todo/09_disks_smartctl/`
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
All green. Final report:
|
||||
|
||||
**Verified (phase 08 — both task files already in `complete/`; this was the final verification pass)**
|
||||
- `Dash.eventsPager()` in `app.js` (50/page, `1–50 of N` strip, aria-labelled `‹ prev`/`next ›` disabled at the ends, `WeakMap` page state, reset only when the event *set* changes, `EVENT_FEED_LIMIT`=200) with three call sites; `ul.events` bounded to 320px + `overflow-y:auto`; `/api/events` untouched (`le=500`, no silent clamp).
|
||||
- Live browser against the real fleet: `/system` `1–50 of 121`, `/llm` `1–50 of 200`, `/ups` `1–50 of 200`; container 320px vs scrollHeight 1543/2368; page 2 → `51–100 of 200` and survived two polls; no empty `.sub`/`.faint` container visible on any page; footers carry only measurements (`rates over Δ11.9s · poll 10s`). Fresh artifacts: `data/logs/08-final-{system-head,llm-page,index-page,ups-feed-page2}.png` (32 phase screenshots already present).
|
||||
- Grep of live served bytes for all 13 deleted flavour fragments + `actions = -`: none survive in HTML or JS.
|
||||
- `AGENTS.md` carries both new UI-convention rules (flavour-text rule with the `TODO.md:7` cited examples; the event-feed-window rule) and the updated test count.
|
||||
|
||||
**Tests / lint (full project 100% green)**
|
||||
- `bash .agents/validate.sh` → **EXIT=0**: `uv run pytest --cov --cov-fail-under=94` → **624 passed, 9 skipped, coverage 97.91%**; `ruff check src tests agent` → All checks passed; `pyright` → 0 errors; `node --check` ×5 clean; repo hygiene clean.
|
||||
- `uv run pytest -m live --live` (`.env.dev` sourced) → **9 passed**; `uv pip list --outdated` → empty. Re-ran pytest/ruff/pyright/node after the doc edits → all exit 0.
|
||||
|
||||
**Completion criteria**: bounded scroll + 50/page + count footer ✅ (all three feeds, live) · no removed flavour string ✅ · AGENTS.md rule ✅ · `validate.sh` green + screenshots in `data/logs/` ✅.
|
||||
|
||||
**Documentation**: full README/AGENTS review against code (env table vs `config.py`/`.env*.example`, script flags, Containerfile uid 10001/8090, chart heights 120/110/160, test count, coverage) — one inaccuracy fixed: README said "Every page's event feed" (the overview has none) → now "The three event feeds (`/system`, `/llm`, `/ups`)"; also restored the missing trailing newline in `TODO.md`. Everything else verified consistent.
|
||||
|
||||
**Notes**: paging stays client-side (no API change); the task-02 defect fix in `/ups` setup copy (`NUT_HOST`/`NUT_PORT`, `LISTEN 127.0.0.1`, one `instcmds` per command, never `actions = -`) re-verified against README and live bytes. Pre-existing items intentionally left to their own phases: `ups.test.result: "Done and passed"` rated `warn` (operator's `TODO.md` entry) and the dev-DB `database is locked` retention issue.
|
||||
|
||||
**Next pending phase**: `.agents/phases/todo/09_disks_smartctl/`
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 11%]
|
||||
........................................................................ [ 22%]
|
||||
........................................................................ [ 34%]
|
||||
........................................................................ [ 45%]
|
||||
...........................sssssssss.................................... [ 56%]
|
||||
........................................................................ [ 68%]
|
||||
........................................................................ [ 79%]
|
||||
........................................................................ [ 90%]
|
||||
......................................................... [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% 28
|
||||
src/dashboards/alerts.py 166 0 100%
|
||||
src/dashboards/api.py 193 0 100%
|
||||
src/dashboards/app.py 107 6 94% 50-51, 56, 58, 60, 127
|
||||
src/dashboards/collectors.py 142 5 96% 97-98, 102-103, 120
|
||||
src/dashboards/config.py 113 0 100%
|
||||
src/dashboards/debug.py 14 0 100%
|
||||
src/dashboards/poller.py 165 3 98% 192-194, 279
|
||||
src/dashboards/prom.py 105 5 95% 107, 144, 158, 161, 164
|
||||
src/dashboards/rates.py 37 1 97% 51
|
||||
src/dashboards/severity.py 49 0 100%
|
||||
src/dashboards/sources/__init__.py 0 0 100%
|
||||
src/dashboards/sources/host.py 199 1 99% 147
|
||||
src/dashboards/sources/llm.py 150 1 99% 228
|
||||
src/dashboards/sources/nut.py 389 20 95% 128, 142, 148, 160, 166, 178, 186, 199, 270-271, 273, 489, 501, 536, 569, 573, 630-631, 636, 648
|
||||
src/dashboards/sources/nut_sim.py 134 0 100%
|
||||
src/dashboards/store.py 178 2 99% 243-244
|
||||
------------------------------------------------------------------
|
||||
TOTAL 2158 45 98%
|
||||
Required test coverage of 94% reached. Total coverage: 97.91%
|
||||
624 passed, 9 skipped, 1 warning in 53.90s
|
||||
== 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 ==
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
**Implemented (task 01 — event feeds: scrollable and paginated)**
|
||||
- `Dash.eventsPager(el, events, opts)` in `app.js`: one shared pager — 50 rows/page, `1–50 of N` footer with `‹ prev` / `next ›` (aria-labelled for direction, `disabled` at the ends), strip hidden when the feed fits, page state in a `WeakMap` keyed by the `<ul>`, rows re-written only when their markup changed (reader's scroll survives), reset to page 1 **only when the event set changes**. No default row renderer (a mis-wired feed says so rather than escaping nothing).
|
||||
- Three call sites (`page-system.js`, `page-llm.js`, `page-ups.js`) keep their own row markup (`Dash.eventText()`, `/ups`'s runtime footnote) and their own empty sentence; `loading…`/empty behaviour unchanged. `/api/events` untouched — no `page`/`limit` vocabulary grew.
|
||||
- `Dash.EVENT_FEED_LIMIT` = 200 (was 20/25/40 — *below* one page, so page 2 could never exist); `dash.css`: `ul.events` bounded to 320px + `overflow-y: auto` + `overscroll-behavior: contain`, `.events-pager` strip, `button.ghost:disabled`.
|
||||
- `tests/test_api.py`: 5 new served-byte pins (shared pager + no per-page pager, 50/page and fetch>page, footer count/aria/disabled, scrollable container + the three `id="events"`, page-1-reset rule); existing `source=system` pin widened for the templated URL.
|
||||
|
||||
**Green** (`bash .agents/validate.sh` → EXIT=0): `uv run pytest --cov --cov-fail-under=94` → **609 passed, 9 skipped, coverage 97.91%** · `ruff check src tests agent` → All checks passed · `pyright` → 0 errors · `node --check` all 5 scripts · `.env.dev` + `uv run pytest -m live --live` → **9 passed** · dev server restarted, `/api/health` ok (6/6 sources).
|
||||
|
||||
**Docs**: `AGENTS.md` → UI conventions gained the feed-window rule (shared pager, 320px scroll box, 50/page, fetch-limit-must-outgrow-a-page invariant, reset semantics, API unchanged); `README.md` → one sentence on the paged feeds in the page description.
|
||||
|
||||
**Decisions/deviations**: the "fixture-events render check" ran as a throwaway node + DOM-stub harness in `/tmp` (29 assertions: 120 events → 50 rows, `1–50 of 120`, prev disabled on page 1, `51–100`, tail `101–120`, new events → page 1, empty/no-row-renderer states) and was **not** committed, because PLAN.md locks "JS tests: None added"; the same behaviour was then proven live. Browser DoD screenshots (`data/logs/events-pager-{system,llm,ups}-{page1,page2,full}.png`, `…-ups-page2-after-poll.png`): `/system` `1–50 of 101`, `/ups` `51–100 of 200` after clicking next, container 320px vs scrollHeight 2307, page 2 + scroll offset survive two 5s polls.
|
||||
**Pre-existing defect noticed, not fixed (out of scope)**: the dev DB (~480 MB, 60 MB WAL) had logged `OperationalError: database is locked (the poll succeeded; the store refused it)` 79× in the last 500 events; none since the restart — deserves its own retention/checkpoint phase.
|
||||
|
||||
**Next pending task**: `.agents/phases/todo/08_events_paging_and_copy/02_strip_flavor_text.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 11%]
|
||||
........................................................................ [ 23%]
|
||||
........................................................................ [ 34%]
|
||||
........................................................................ [ 46%]
|
||||
............sssssssss................................................... [ 58%]
|
||||
........................................................................ [ 69%]
|
||||
........................................................................ [ 81%]
|
||||
........................................................................ [ 93%]
|
||||
.......................................... [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% 28
|
||||
src/dashboards/alerts.py 166 0 100%
|
||||
src/dashboards/api.py 193 0 100%
|
||||
src/dashboards/app.py 107 6 94% 50-51, 56, 58, 60, 127
|
||||
src/dashboards/collectors.py 142 5 96% 97-98, 102-103, 120
|
||||
src/dashboards/config.py 113 0 100%
|
||||
src/dashboards/debug.py 14 0 100%
|
||||
src/dashboards/poller.py 165 3 98% 192-194, 279
|
||||
src/dashboards/prom.py 105 5 95% 107, 144, 158, 161, 164
|
||||
src/dashboards/rates.py 37 1 97% 51
|
||||
src/dashboards/severity.py 49 0 100%
|
||||
src/dashboards/sources/__init__.py 0 0 100%
|
||||
src/dashboards/sources/host.py 199 1 99% 147
|
||||
src/dashboards/sources/llm.py 150 1 99% 228
|
||||
src/dashboards/sources/nut.py 389 20 95% 128, 142, 148, 160, 166, 178, 186, 199, 270-271, 273, 489, 501, 536, 569, 573, 630-631, 636, 648
|
||||
src/dashboards/sources/nut_sim.py 134 0 100%
|
||||
src/dashboards/store.py 178 2 99% 243-244
|
||||
------------------------------------------------------------------
|
||||
TOTAL 2158 45 98%
|
||||
Required test coverage of 94% reached. Total coverage: 97.91%
|
||||
609 passed, 9 skipped, 1 warning in 51.50s
|
||||
== 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 ==
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Done. Everything is green.
|
||||
|
||||
**Implemented (task 02 — strip the flavour text)**
|
||||
- `index.html`: deleted the footer sentence ("every number is scraped from the box it belongs to · `null` renders as `n/a`") + its spacer; trimmed the design-narrating second sentence out of the all-clear state.
|
||||
- `system.html`: deleted the *Per host* sub-line ("agent-reported values; rates are measured over the Δ window in the footer…") and the "numbers are measured, not inferred" footer narration; `#foot-note` (the measured `Δ…· poll …`) stays.
|
||||
- `llm.html` + `page-llm.js`: deleted the provenance-narrating footer line and the `· rates over the Δ window in each tag` half-sentence (the per-rate `provenance()` tags are untouched); dropped the "a server you do not run should not have a red panel" clause; trimmed `— an incident, not a stat` / `— mean, with the p95 under it` tooltip tails.
|
||||
- `ups.html` + `page-ups.js`/`page-index.js`: deleted "commands are the only write path in this app…" narration; **defect fix** — the empty state told operators to write `PORT 3493` and `actions = -` (AGENTS.md/README say never `actions = -`, and this upsd is on 3051), so it now names `NUT_HOST`/`NUT_PORT`, `LISTEN 127.0.0.1` and one `instcmds` line per command; the command banners now name `instcmds` too.
|
||||
- Removed the three event feeds' content captions (the kept empty-state sentences already say it); no empty `.sub`/`.faint` containers left, no dead CSS (`.pagefoot`/`.spacer`/`.sub` all still used).
|
||||
- Kept by the act-differently test and now pinned present: units, `Δ` provenance, `fleet.seams`, *sums only engines answering now*, queued-request note, SIMULATED banners, empty-state setup instructions, `Last good values` tooltip, metric-definition tooltips.
|
||||
|
||||
**Tests / lint (full suite 100% green)**
|
||||
- `uv run pytest` → **624 passed, 9 skipped**; `uv run pytest --cov --cov-fail-under=94` → **97.91%**; `uv run ruff check src tests agent` → All checks passed; `uv run pyright` → 0 errors; `node --check` on all 5 scripts → clean; `uv run pytest -m live --live` (`.env.dev` sourced) → **9 passed**; `bash .agents/validate.sh` → **EXIT=0**.
|
||||
- New pins in `tests/test_api.py`: `test_no_page_narrates_its_own_pipeline` (13 deleted fragments absent from all 4 pages + all 5 assets), `test_pages_leave_no_empty_narration_container`, `test_the_copy_the_operator_acts_on_survives_the_audit` (functional copy present, `instcmds` named, `actions = -` gone).
|
||||
- Browser DoD against live data (`./scripts/dev-server.sh restart`, 6/6 sources ok): `data/logs/flavour-strip-{index,system,llm,ups}-{head,full,footer}.png`, `…-ups-feed.png`, `…-{index,ups}-empty.png` — page heads clean, feed still `1–50 of 200`, no empty containers, no console errors.
|
||||
|
||||
**Docs**: `AGENTS.md` → UI conventions gained the **Flavour text is not helpful information** rule (act-differently test, the two TODO-quoted lines as cited examples, what survived and why, the test pins) and the test-count line; `README.md` → the `web/` bullet says pages carry no narration.
|
||||
|
||||
**Decisions**: deleted each feed's header caption as duplicate narration (info preserved in the kept empty-state sentence); kept hover metric definitions (they define what a summed/lifetime number counts — the rule-2 family); fixed the `/ups` setup guidance defect inside this audit rather than leaving actively wrong copy. Not fixed (out of scope, already logged in `TODO.md` by the operator): `ups.test.result: "Done and passed"` classifies as `warn` in `sources/nut.py` — needs its own phase.
|
||||
|
||||
**Next pending task**: none in phase 08 (this completes it); next is `.agents/phases/todo/09_disks_smartctl/01_agent_smartctl_collection.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 11%]
|
||||
........................................................................ [ 22%]
|
||||
........................................................................ [ 34%]
|
||||
........................................................................ [ 45%]
|
||||
...........................sssssssss.................................... [ 56%]
|
||||
........................................................................ [ 68%]
|
||||
........................................................................ [ 79%]
|
||||
........................................................................ [ 90%]
|
||||
......................................................... [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% 28
|
||||
src/dashboards/alerts.py 166 0 100%
|
||||
src/dashboards/api.py 193 0 100%
|
||||
src/dashboards/app.py 107 6 94% 50-51, 56, 58, 60, 127
|
||||
src/dashboards/collectors.py 142 5 96% 97-98, 102-103, 120
|
||||
src/dashboards/config.py 113 0 100%
|
||||
src/dashboards/debug.py 14 0 100%
|
||||
src/dashboards/poller.py 165 3 98% 192-194, 279
|
||||
src/dashboards/prom.py 105 5 95% 107, 144, 158, 161, 164
|
||||
src/dashboards/rates.py 37 1 97% 51
|
||||
src/dashboards/severity.py 49 0 100%
|
||||
src/dashboards/sources/__init__.py 0 0 100%
|
||||
src/dashboards/sources/host.py 199 1 99% 147
|
||||
src/dashboards/sources/llm.py 150 1 99% 228
|
||||
src/dashboards/sources/nut.py 389 20 95% 128, 142, 148, 160, 166, 178, 186, 199, 270-271, 273, 489, 501, 536, 569, 573, 630-631, 636, 648
|
||||
src/dashboards/sources/nut_sim.py 134 0 100%
|
||||
src/dashboards/store.py 178 2 99% 243-244
|
||||
------------------------------------------------------------------
|
||||
TOTAL 2158 45 98%
|
||||
Required test coverage of 94% reached. Total coverage: 97.91%
|
||||
624 passed, 9 skipped, 1 warning in 59.18s
|
||||
== 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 ==
|
||||
Reference in New Issue
Block a user