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,44 @@
|
||||
# Phase 08 — Event feeds page; the flavour text goes
|
||||
|
||||
**Source:** `TODO.md` L6, L7 — "page the event tables; strip the flavour text": "All the events tables need to be scrollable and paginated. They are causing the page to be massive." · "Get rid of most of the flavor text and add a note to AGENTS.md to not add it unless necessary. It just comes off as LLM generated slop, not helpful information."
|
||||
**Story:** n/a
|
||||
**Context:** the three `ul.events` feeds (`src/dashboards/web/pages/system.html` L58, `llm.html` L103, `ups.html` L70-72), `Dash.eventText()` in `src/dashboards/web/static/app.js`, the page-head sub-lines with the quoted flavour text (`system.html` L45, `index.html` L73), `AGENTS.md` → *UI conventions*, `tests/test_api.py` (served-bytes pins, orphan-`id` rule)
|
||||
|
||||
## Objective
|
||||
|
||||
A dead host's 500-event history must not make `/system` take a page to scroll: every
|
||||
event feed becomes a bounded, scrollable, paginated window. The descriptive copy that
|
||||
explains the app to the operator ("agent-reported values; rates are measured over the Δ
|
||||
window…") goes away page by page, and `AGENTS.md` records the rule so the slop does not
|
||||
crawl back in.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `07_llm_monitor_style_pages` (todo) — same page files and `app.js`/`dash.css`; this
|
||||
phase lands on the restructured `/llm` page, not the phase-04 one.
|
||||
- `06_system_page_gpu_verdicts` (todo) — rewrites `/system`'s panel structure; event-feed
|
||||
work must not fight it for the same markup.
|
||||
|
||||
## Tasks
|
||||
|
||||
1. `01_paginate_event_feeds.md` — one shared pager: the three `ul.events` become scrollable containers with a 50-per-page window and a prev/next + count footer; no API change.
|
||||
2. `02_strip_flavor_text.md` — audit all four pages and the page scripts for descriptive copy, delete what is not functional, and pin the rule in `AGENTS.md`'s UI conventions.
|
||||
|
||||
## Testing & Quality
|
||||
|
||||
- Hermetic: `tests/test_api.py` served-bytes pins (pager markup, no removed flavour
|
||||
strings still present), `node --check` on touched scripts, the orphan-`id` rule
|
||||
(the pager introduces `id`s — every one must be referenced).
|
||||
- Live: `uv run pytest -m live --live` — the event endpoints still answer; a feed with
|
||||
more than 50 stored events (the real event table has history) paginates instead of
|
||||
dumping.
|
||||
- Browser (DoD): screenshots in `data/logs/` — a long feed bounded and scrollable, page
|
||||
2 reachable, the removed sub-lines gone from the page heads.
|
||||
- Coverage: **>90%** on modified code, ≥94% overall gate maintained.
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
- [ ] all three feeds scroll in a bounded container and paginate 50-per-page with a count footer
|
||||
- [ ] no removed flavour string survives in served HTML or JS
|
||||
- [ ] `AGENTS.md` carries the flavour-text rule under UI conventions
|
||||
- [ ] `bash .agents/validate.sh` green; screenshots in `data/logs/`
|
||||
@@ -0,0 +1,56 @@
|
||||
# Task 01 — Event feeds: scrollable and paginated
|
||||
|
||||
**Phase:** `08_events_paging_and_copy` · **Source:** `TODO.md:6` — "All the events tables need to be scrollable and paginated. They are causing the page to be massive."
|
||||
**Story:** n/a
|
||||
|
||||
## Objective
|
||||
|
||||
Every event feed (`/system`, `/llm`, `/ups`) renders a bounded, scrollable window over the
|
||||
events instead of a growing `ul` that makes the page take a scroll to read. One shared
|
||||
helper, three call sites — a pager that only works on one page is the bug this shape
|
||||
prevents.
|
||||
|
||||
## Work
|
||||
|
||||
1. `src/dashboards/web/static/app.js` — add `Dash.eventsPager(el, events, opts)`: renders
|
||||
the visible page of `events` into the feed's `ul` (keeping the existing
|
||||
`Dash.eventText()` row rendering and per-row subject-once rule untouched), with a
|
||||
footer: `1–50 of N` and prev/next controls (disabled at the ends, `aria`-labelled).
|
||||
Page size defaults to 50; the feed container is the scrollable element, the page
|
||||
stays short.
|
||||
2. Call sites — `page-system.js`, `page-llm.js`, `page-upts.js` → `page-ups.js`: each
|
||||
replaces its direct `ul#events` population with the pager (the "loading…" / empty /
|
||||
not-configured states keep their current behaviour; pagination only applies when there
|
||||
is more than one page of data). On a refresh that brings new events, the pager resets
|
||||
to the first page (an operator reading page 3 of stale history should not silently land
|
||||
on page 3 of the new set).
|
||||
3. `src/dashboards/web/static/dash.css` — `.events` gets a bounded height (scrollable
|
||||
container, existing token vocabulary); the pager footer styled as a quiet `.faint`
|
||||
strip. No new palette.
|
||||
4. No API change: `/api/events` keeps answering exactly what it does (server-side list,
|
||||
no `page`/`limit` params added — the feeds are page-local and the endpoint's
|
||||
contract is pinned by `tests/test_api.py`).
|
||||
5. `tests/test_api.py` — pin the served markup (the three feeds keep their `id`s; the
|
||||
pager's new `id`s/`aria-*` are all referenced — the orphan rule stays green), and
|
||||
`node --check` on all touched scripts.
|
||||
|
||||
- ASSUMPTION: **client-side** pagination (50-per-page, scrollable container) is the
|
||||
confirmed reading — the event tables grow with history and the server already serves
|
||||
the list; a server-side `page`/`limit` API change would re-open a pinned endpoint
|
||||
contract for a page-local problem.
|
||||
|
||||
## Testing & Quality
|
||||
|
||||
- Unit: `tests/test_api.py` (markup pins), `node --check`; a fixture-events render check
|
||||
(page 1 of 3 pages, footer counts, disabled prev on page 1).
|
||||
- Live: `uv run pytest -m live --live` — event endpoints unchanged.
|
||||
- Browser (DoD): screenshot in `data/logs/` — a feed with >50 events bounded and
|
||||
scrollable, page 2 showing rows 51–100.
|
||||
- Coverage: **>90%** on modified code; overall gate (94%) maintained.
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
- [ ] all three feeds paginate 50-per-page with a `1–50 of N` footer and prev/next
|
||||
- [ ] the page height no longer grows with event history; the container scrolls
|
||||
- [ ] refresh resets to page 1; loading/empty/not-configured states unchanged
|
||||
- [ ] `uv run pytest` green; `uv run ruff check src tests agent && uv run pyright` clean
|
||||
@@ -0,0 +1,56 @@
|
||||
# Task 02 — Strip the flavour text; pin the rule in AGENTS.md
|
||||
|
||||
**Phase:** `08_events_paging_and_copy` · **Source:** `TODO.md:7` — "Get rid of most of the flavor text and add a note to AGENTS.md to not add it unless necessary. It just comes off as LLM generated slop, not helpful information. Like 'agent-reported values; rates are measured over the Δ window in the footer, and each panel's charts cover only that host' or 'every number is scraped from the box it belongs to · null renders as n/a'"
|
||||
**Story:** n/a
|
||||
|
||||
## Objective
|
||||
|
||||
The pages stop narrating themselves. Copy that explains the app's own design to the
|
||||
operator ("agent-reported values; rates are measured over the Δ window…", "every number is
|
||||
scraped from the box it belongs to · null renders as n/a") is deleted; copy that is
|
||||
*functional* — a source tag, a `Δ10.0s` provenance, a "not configured" explanation, the
|
||||
SIMULATED badge, an error that says why a panel is empty — stays. `AGENTS.md` records
|
||||
the rule so it is a convention, not a mood.
|
||||
|
||||
## Work
|
||||
|
||||
1. Audit, page by page: `src/dashboards/web/pages/index.html`, `system.html`, `llm.html`,
|
||||
`ups.html` and the `src/dashboards/web/static/page-*.js` / `app.js` strings. The two
|
||||
lines the TODO quotes (the `system.html` L45 sub-line, the `index.html` L73 sub-line)
|
||||
are confirmed deletions; every other candidate is judged on one test: *would the
|
||||
operator act differently without it?* No → delete. Kept by default: the `Δwindow`
|
||||
footnotes (measurements, rule: "a Δ label is a measurement, never a config value"),
|
||||
the per-rate provenance tags ("scraped / measured Δcounter/Δt / estimated" — dropping a
|
||||
tag is a regression, not a simplification), `n/a`-and-why states, the "queued (deferred)
|
||||
requests are not in /slots" note, and any string a test pins as functional.
|
||||
2. Delete the confirmed flavour from markup *and* from JS that injects the same copy;
|
||||
a sub-line that becomes empty removes its container, not an empty `<span>`.
|
||||
3. `tests/test_api.py` — where a deleted string was pinned, update the pin; add an
|
||||
assertion that the two quoted strings (and the other confirmed deletions) are **absent**
|
||||
from served bytes, so the slop cannot creep back in silently.
|
||||
4. `AGENTS.md` → *UI conventions* — add the rule: **Flavour text is not helpful
|
||||
information.** Pages do not narrate their own data pipeline or design; copy exists
|
||||
only when the operator needs it to act (a why-this-panel-is-empty, a provenance tag,
|
||||
a measurement label). The two deleted lines are the cited examples. (DoD: AGENTS.md
|
||||
updates with rule changes — this is the task that does it, not the conversion.)
|
||||
5. `node --check` on every touched script.
|
||||
|
||||
- ASSUMPTION: "most of the flavour text" = the audit rule above (act-differently test),
|
||||
with the two quoted lines as the floor of deletions — the operator's examples, not the
|
||||
ceiling. If a borderline string survives the audit, it survives because it is a
|
||||
measurement or a why, and the audit notes say which.
|
||||
|
||||
## Testing & Quality
|
||||
|
||||
- Unit: `tests/test_api.py` (absence pins for the deleted strings; served-bytes shape
|
||||
unchanged otherwise), `node --check`.
|
||||
- Browser (DoD): screenshot in `data/logs/` — the four page heads without the removed
|
||||
sub-lines; no empty containers.
|
||||
- Coverage: **>90%** on modified code; overall gate (94%) maintained.
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
- [ ] the two quoted lines (and the rest of the audit's deletions) are gone from served HTML and JS
|
||||
- [ ] functional copy (provenance tags, Δ footnotes, empty-state explanations) intact
|
||||
- [ ] `AGENTS.md` carries the flavour-text rule with the deleted lines as cited examples
|
||||
- [ ] `uv run pytest` green; `uv run ruff check src tests agent && uv run pyright` clean
|
||||
Reference in New Issue
Block a user