Files
dashboards/.agents/phases/todo/04_llm_chart_readability/00_phase.md
T
ducoterra 4b4962d7fb chore(agent): phase roadmap from TODO.md, 5 phases
The five UI items in TODO.md become an executable pipeline. Planning files
only — no application code changed.

- 01_severity_language: one Python threshold table + `severity` on the
  values the pages colour, plus the .hero style. Today the thresholds are
  magic numbers at six JS call sites (75/90 here, 80/92 there), which is
  exactly how "same colour, four meanings" happens.
- 02_overview_fleet_and_alerts: /api/summary gains a derived `alerts`
  list; the page drops to fleet + warnings. Unconfigured sources must not
  alert — that is invariant 3, tested.
- 03_system_per_host_panels: per-host hero cards, no per-core, shared
  multi-host charts and the detail picker deleted. The six card metrics
  already exist in the payload, so the first task pins them with tests
  instead of inventing fields.
- 04_llm_chart_readability: charts.js already exports sparkline() and no
  page calls it — that is why the page reads flat. Port llm_monitor's
  drawSpark behaviour (fixed max, right growth, p95 foots) and keep the
  provenance tags.
- 05_ups_hero_battery_glyph: charge/load/runtime hero + an SVG battery
  whose fill is the charge, verified against both real UPSes and the
  low-charge/on-battery states only the simulator can produce.

PLAN.md records the ratified anchors and the deviation worth knowing:
severity vocabulary is ok|warn|fail, matching dash.css and nut.py, not the
"danger" wording in the proposal — one synonym for one colour.

TODO.md cleared to a bare heading; the items are now phases. .gitignore
stops ignoring all of .agents/ (the roadmap is project history) while
keeping phase-sessions/ and pipeline.log out. deploy/nut-sudoers rewritten:
its header still blamed a port mystery that is solved; the remaining need
is reading upsd.users so adding a scoped dashboards user does not delete
the accounts upsmon authenticates as.

LLM-Generated: true
2026-10-16 20:10:23 -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