Files
ducoterra f44a617ef9 phase: 04_llm_chart_readability
**Phase 04 final verification pass — all tasks already in `complete/`; verified + fixed 3 defects found in verification.**

- Verified `/llm` live (both engines, gufo-only instance on :8099, `llm_monitor` on :8095) in a real browser; dev server left running/healthy.
- Completed task-04's truncated layout fix: `#engines` now carries `.items-start` (the CSS rule existed but nothing used it) — gufo 544 px vs vLLM 715 px, no blank card; pinned by `test_llm_engine_panels_are_not_stretched_to_their_tallest_sibling`.
- Fixed: event rows said the subject twice ("gufo gufo is answering again"), and `/ups` mangled mid-message names ("sent to apc: OK" → "sent to  OK") → shared `Dash.eventText()` (strips `UpstreamError: ` + a *leading* name only, mirroring `alerts._clean_error`) used by `/system`, `/llm`, `/ups`; new test.
- Fixed: count sparklines autoscaled rollup averages (queue max 0.1379) into full-height spikes → `sparkline({minSpan})`, `minSpan: 1` on sessions/queued (spike 30 px → 4 px); assertions added.
- Tests: `bash .agents/validate.sh` → **EXIT=0** (`uv run pytest --cov --cov-fail-under=94`: **485 passed, 7 skipped**, coverage **96.87%**; `ruff check src tests agent`: All checks passed; `pyright`: 0 errors; `node --check` all static JS clean; repo hygiene clean; `uv pip list --outdated` empty). `uv run pytest -m live --live` → **7 passed**.
- Completion criteria: heroes largest per engine ✔ (38.4 px vs 16.8 px row values); sparkline per cell + selected window ✔ (5/5 gufo, 7/7 vLLM; 6 h chip moved KV max 53 %→58 %); mean+p95 without hover ✔ (243 / 48.8 / 285 ms feet); provenance tag ✔ (`Δ10.0s`/`Δ8.0s` + `title`=exact source); single-engine ✔ (1 panel, totals hidden, zero red); screenshots ✔ `data/logs/llm-verify-{both-engines,charts-and-slots,single-engine,monitor-reference}.png` + `NOTES-chart-set.md`; pytest/cov/ruff/pyright ✔; earlier phases unchanged-behaviour ✔ (all 01–03 tests pass).
- Deviation (documented, not code): throughput heroes stay **neutral ink** — `severity.py` has no throughput row and 0 tok/s idle is healthy; colour comes from rated cells (KV) + reachability. Kept per `NOTES-chart-set`.
- Deviation: could not append the task-04 written verdict to `NOTES-chart-set.md` (it lives in `todo/`, which I must not edit). Verdict: ours reads better than `:8095` — bigger throughput numbers, per-cell shape over the selected window, percentiles inline; `llm_monitor` only sparklines decode+KV and has no window control.
- Docs: AGENTS.md updated (485 test count, `sparkline` `minSpan` rule, `Dash.eventText` event-row rule, `/llm` panel `items-start`); README reviewed in full — commands, config table (all `config.py` vars present), architecture bullets, page descriptions verified accurate; no other inconsistencies found.
- Note for the harness: `.agents/phases/todo/03…/NOTES-verify.md` and `todo/04…/NOTES-chart-set.md` are untracked notes left behind by their phases (task files moved, notes did not).
- Next pending phase: `05_ups_hero_battery_glyph`.
2026-10-17 07:03:58 -04:00

3.1 KiB

Phase 04 — LLM page is readable again

Source: TODO.md L6 — "LLM usage drifed from initial request to copy Experimental/llm_monitor. The charts got less useful. Need simplified and more readable." Story: n/a Context: .agents/PLAN.md → Anchors (hand-rolled SVG only), ~/Projects/Experimental/llm_monitor/static/index.html (the reference implementation), src/dashboards/web/static/page-llm.js (CELLS, makeCharts), src/dashboards/web/static/charts.js (sparkline, LineChart), src/dashboards/sources/llm.py

Objective

The LLM page drifted into a 14-cell grid where everything is the same size and nothing shows recent shape. Bring back what made llm_monitor legible — big throughput numbers, a sparkline in each metric cell, percentiles as foot lines — without losing what this project added since: per-engine provenance tags, history windows, and severity colour.

llm_monitor is the design reference, not a dependency. It is a separate app on :8095 and stays that way; nothing here imports from it.

Dependencies

  • 01_severity_language (todo) — KV-cache pressure and queue depth get coloured from the API verdict, not a per-page threshold.
  • 03_system_per_host_panels (todo) — touches charts.js first; this phase builds on the same shared helpers and must not fight it for them.

Tasks

  1. 01_chart_set_decision.md — read both implementations side by side and write the decision note (which cells live, which get sparklines, what is demoted).
  2. 02_sparkline_upgrade.md — bring DashCharts.sparkline() up to llm_monitor's drawSpark behaviour: right-aligned growth, fixed max, current/max labels, severity colour.
  3. 03_llm_layout_simplified.md — restructure llm.html + page-llm.js: hero throughput, compact sparkline cells, percentile foot lines, conditional alarm cells.
  4. 04_side_by_side_verification.md — verify against llm_monitor on :8095 with the same live engines.

Testing & Quality

  • Python: none expected beyond the phase-01 severity fields; /api/llm/* stays as-is (additive-only anchor).
  • uv run pytest -m live --live must stay green — test_engine_still_publishes_the_series_we_parse is the assertion that the numbers on screen are backed by resolved upstream series.
  • Browser: both engines live (gufo on deskwork:8731, vLLM on driveripper:8000), plus the single-engine case: with one *_BASE_URL unset the page must show one clean half rather than a red panel.
  • Coverage: ≥94% overall maintained.

Completion Criteria

  • decode and prompt throughput are the two largest numbers per engine, colour-coded
  • every remaining metric cell carries a sparkline showing the selected window
  • latency cells show mean and p95 without needing a hover
  • a source-provenance tag is still visible on every throughput number (AGENTS.md: never invent a number)
  • /llm with only one engine configured still renders cleanly
  • screenshots of this page and llm_monitor side by side in data/logs/, plus NOTES-chart-set.md
  • uv run pytest green, coverage ≥94%, ruff + pyright clean
  • no behavior change in completed phases