phase: 07_llm_monitor_style_pages
**Phase 07 final verification pass — all tasks already in `complete/`; every criterion re-verified live.**
- **Old slot table gone**: no `#slots-card`/`#slots-table`/`renderSlots` in HTML/JS/CSS (only the new grid's `.slots-empty` *class*); pinned by `test_the_broken_slot_table_is_gone_from_html_js_and_css`.
- **`tests/fixtures/slots_gufo.json`**: present; live `GET ${GUFO_BASE_URL}/slots` this pass matches it key-for-key (row + `next_token[0]`), so the capture is reproducible; drift proven to fail (mutation tests + live `test_gufo_slots_answer_the_pinned_shape`, 9 live tests pass).
- **Aggregate block**: live page shows `2 of 2 engines`, running/waiting/prompt/decode/total-tokens straight from `fleet_totals()`, dot `ok`, no verdict colour; on a throwaway single-engine instance (:8091, private temp DB) `#fleet` is `hidden`, one full-width strip card + one panel, zero banners → "one clean half".
- **Strip + slot grid on live data**: 2 `.card.stat` (KV bars `bar ok` 13 %/0 %), gufo grid rendered real cards incl. a busy slot (`#2189`, 67849 prompt tok, 99 % cache share, `processing`), vLLM note-only with no grid; no `NaN`/`undefined` anywhere. Screenshots: `data/logs/llm-phase07-final-live-{two-engines,single-engine}.png`, `ups-charts-aria-labels.png`.
- **Defect found in earlier work and fixed**: `/ups`' four `LineChart`s shipped no `ariaLabel`, violating AGENTS.md's "every chart names itself for assistive tech" (`/system`+`/llm` were pinned, `/ups` wasn't) → added labels to `page-ups.js` and `test_every_ups_chart_names_itself_for_assistive_tech`; browser-verified `role="img"` + label on all four.
- **Gate**: `bash .agents/validate.sh` → **exit 0**; `uv run pytest --cov --cov-fail-under=94` → **604 passed, 9 skipped, coverage 97.91 %**; `uv run ruff check src tests agent` → All checks passed; `uv run pyright` → **0 errors**; `node --check` every page script ok; `uv run pytest -m live --live` → **9 passed**; `uv pip list --outdated` empty.
- **Docs**: README + AGENTS.md reviewed end-to-end; fixed test count (582→604), `/llm` source column + both architecture diagrams now name gufo `/slots`, AGENTS.md agent line gained `GET /schema` + status page, ariaLabel convention now covers all three chart pages, README Testing block now lists `bash .agents/validate.sh`. Env-var table, agent/install flags, Containerfile facts, `/api/*` shapes, range chips, remote URL all verified accurate — no other changes needed.
- **Live-infra**: no fleet/host/config change; the temp :8091 instance, its temp DB and the fake processes are removed; dev server restarted and `/api/health` `ok` (all 6 sources ok). One thing I deliberately did **not** touch: the gitignored local `.env.dev` still carries a comment claiming the NUT `[dashboards]` account has only battery-test `instcmds`, whereas AGENTS.md/README record `instcmds = all` (verified on hardware 2026-10-17) — operator-owned file, flag for the operator to reword.
- **Next pending phase**: `08_events_paging_and_copy`.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
**Phase 07 final verification pass — all tasks already in `complete/`; every criterion re-verified live.**
|
||||
|
||||
- **Old slot table gone**: no `#slots-card`/`#slots-table`/`renderSlots` in HTML/JS/CSS (only the new grid's `.slots-empty` *class*); pinned by `test_the_broken_slot_table_is_gone_from_html_js_and_css`.
|
||||
- **`tests/fixtures/slots_gufo.json`**: present; live `GET ${GUFO_BASE_URL}/slots` this pass matches it key-for-key (row + `next_token[0]`), so the capture is reproducible; drift proven to fail (mutation tests + live `test_gufo_slots_answer_the_pinned_shape`, 9 live tests pass).
|
||||
- **Aggregate block**: live page shows `2 of 2 engines`, running/waiting/prompt/decode/total-tokens straight from `fleet_totals()`, dot `ok`, no verdict colour; on a throwaway single-engine instance (:8091, private temp DB) `#fleet` is `hidden`, one full-width strip card + one panel, zero banners → "one clean half".
|
||||
- **Strip + slot grid on live data**: 2 `.card.stat` (KV bars `bar ok` 13 %/0 %), gufo grid rendered real cards incl. a busy slot (`#2189`, 67849 prompt tok, 99 % cache share, `processing`), vLLM note-only with no grid; no `NaN`/`undefined` anywhere. Screenshots: `data/logs/llm-phase07-final-live-{two-engines,single-engine}.png`, `ups-charts-aria-labels.png`.
|
||||
- **Defect found in earlier work and fixed**: `/ups`' four `LineChart`s shipped no `ariaLabel`, violating AGENTS.md's "every chart names itself for assistive tech" (`/system`+`/llm` were pinned, `/ups` wasn't) → added labels to `page-ups.js` and `test_every_ups_chart_names_itself_for_assistive_tech`; browser-verified `role="img"` + label on all four.
|
||||
- **Gate**: `bash .agents/validate.sh` → **exit 0**; `uv run pytest --cov --cov-fail-under=94` → **604 passed, 9 skipped, coverage 97.91 %**; `uv run ruff check src tests agent` → All checks passed; `uv run pyright` → **0 errors**; `node --check` every page script ok; `uv run pytest -m live --live` → **9 passed**; `uv pip list --outdated` empty.
|
||||
- **Docs**: README + AGENTS.md reviewed end-to-end; fixed test count (582→604), `/llm` source column + both architecture diagrams now name gufo `/slots`, AGENTS.md agent line gained `GET /schema` + status page, ariaLabel convention now covers all three chart pages, README Testing block now lists `bash .agents/validate.sh`. Env-var table, agent/install flags, Containerfile facts, `/api/*` shapes, range chips, remote URL all verified accurate — no other changes needed.
|
||||
- **Live-infra**: no fleet/host/config change; the temp :8091 instance, its temp DB and the fake processes are removed; dev server restarted and `/api/health` `ok` (all 6 sources ok). One thing I deliberately did **not** touch: the gitignored local `.env.dev` still carries a comment claiming the NUT `[dashboards]` account has only battery-test `instcmds`, whereas AGENTS.md/README record `instcmds = all` (verified on hardware 2026-10-17) — operator-owned file, flag for the operator to reword.
|
||||
- **Next pending phase**: `08_events_paging_and_copy`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 11%]
|
||||
........................................................................ [ 23%]
|
||||
........................................................................ [ 35%]
|
||||
........................................................................ [ 46%]
|
||||
.......sssssssss........................................................ [ 58%]
|
||||
........................................................................ [ 70%]
|
||||
........................................................................ [ 82%]
|
||||
........................................................................ [ 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%
|
||||
604 passed, 9 skipped, 1 warning in 52.69s
|
||||
== 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 ==
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
**Task 01 complete — all green.**
|
||||
|
||||
**Implemented**
|
||||
- `scripts/capture-fixtures.sh`: gufo `/slots` capture (→ `tests/fixtures/slots_gufo.json`), `/v1/slots` fallback in the collector's order, atomic tmp+mv, clean skip when `GUFO_BASE_URL` unset; scrubber now blanks busy-slot `prompt` (user request text) in `slots_*.json`.
|
||||
- Deleted the broken slot table end-to-end: `#slots-card`/`#slots-table`/`#slots-empty` markup (`llm.html`), `renderSlots()` + call (`page-llm.js`), dead `.chip.info` rule (`dash.css`).
|
||||
- New `tests/slots_contract.py` (`assert_slot_shape`, required/optional row fields, `id_task`/`task_id` alias, `next_token[]` sub-fields, id uniqueness, `is_processing`/`state` consistency) + `tests/test_llm_slots_contract.py` (fixture-driven, mutation tests proving drift fails, deletion pins on served bytes); `test_llm_source.py` passthrough now uses the captured rows; live twin `test_gufo_slots_answer_the_pinned_shape` added to `test_live_fleet.py`.
|
||||
- Fixture recorded from live gufo (idle 2-slot shape); full re-capture also refreshed agent/NUT fixtures (volatile-value drift only, suite green). Verified `/llm` in a real browser against live data: 2 engine cards, zero JS errors (screenshot in `data/logs/`).
|
||||
|
||||
**Gate** — `bash .agents/validate.sh` exit 0: `uv run pytest --cov` **578 passed, 9 skipped, coverage 97.91%** (floor 94); `ruff check src tests agent` clean; `pyright` 0 errors; `node --check` clean; `uv pip list --outdated` empty. `uv run pytest -m live --live` **9 passed** (incl. the new live `/slots` contract).
|
||||
|
||||
**Docs** — AGENTS.md (test-count 578/9, capture-script line, testing-policy entry for the slots contract + prompt privacy) and README.md (capture commands, contract paragraph).
|
||||
|
||||
**Decisions**: `/slots` capture runs without `--with-llm` (the task names only the GUFO_BASE_URL skip and reproducibility via the bare script; it's one tiny request the hermetic test needs). `prompt` treated as user content: captured blanked, never rendered (pinned).
|
||||
|
||||
**Next pending task**: `07_llm_monitor_style_pages/02_fleet_totals_block.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 12%]
|
||||
........................................................................ [ 24%]
|
||||
........................................................................ [ 36%]
|
||||
.......................................................sssssssss........ [ 49%]
|
||||
........................................................................ [ 61%]
|
||||
........................................................................ [ 73%]
|
||||
........................................................................ [ 85%]
|
||||
........................................................................ [ 98%]
|
||||
........... [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%
|
||||
578 passed, 9 skipped, 1 warning in 51.48s
|
||||
== 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 ==
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
**Implemented**
|
||||
- `/llm` now opens with the `llm_monitor` aggregate block (`#fleet`): reachability dot, `all engines`, an `N of M engines` tag, the note *"sums only engines answering now"*, then **running / waiting / prompt tok/s / decode tok/s / total tokens** — every number straight from `fleet_totals()` (`/api/llm/snapshot` → `fleet`); the counts-only `#totals` card (`f-live`/`f-total`/`f-active`/`f-waiting`) is deleted, ids and all.
|
||||
- `FLEET_FIELDS` is a list of API paths only (page sums nothing); hidden below two engines; a dead engine is dropped from every sum, dims the tag (shared `.stale`) and is named in its tooltip; `fleet.seams` rides on the prompt sum as a tooltip; an `n/a` sum clears its unit; no severity/`hero()` anywhere on the block.
|
||||
- `dash.css`: new `fleet totals` section built only from existing vocabulary (`.card.flat`, `.metrics`, `.dot`, `.chip`, `.stale`) — no new palette, no verdict tokens.
|
||||
- `tests/test_api.py`: replaced the phase‑04 totals-card pin with 5 fleet-block tests (markup/order + old ids gone; `fleet` key paths with both engines configured and with neither → 404 `configured:false`; injected-payload test proving a dead engine contributes nothing and null sums never print 0; no-verdict colouring; provenance) + `_fleet_tag`/`_fleet_render_path`/`_fleet_field_metrics`/`FLEET_BLOCK_PATHS` helpers.
|
||||
|
||||
**Gate** — `bash .agents/validate.sh` exit 0: `uv run pytest --cov --cov-fail-under=94` **582 passed, 9 skipped, coverage 97.91%**; `ruff check src tests agent` clean; `pyright` 0 errors; `node --check` on all page scripts clean. `uv run pytest -m live --live` **9 passed**. `uv pip list --outdated` empty (no dependency change).
|
||||
|
||||
**Docs** — AGENTS.md (`/llm` UI-conventions paragraph now describes the fleet block + her test count 582) and README.md (same, plus "single engine → one clean half").
|
||||
|
||||
**Decisions / deviations**
|
||||
- The task asked for a status dot while also requiring "no severity colour anywhere on the block": the dot is the shared *reachability* dot (as the nav and every card header), and the tests pin that no `severity`/`hero()` reaches the block and its CSS uses no `--ok/--warn/--fail`.
|
||||
- Browser-verified live (screenshots in `data/logs/`): `llm-fleet-block-two-engines.png` (sums hand-checked: decode 10.8 = gufo 10.8 + vLLM 0.0, total tokens 177.55 M = 172.56 M + 4.98 M), `llm-fleet-block-single-engine.png` (block absent, one clean half), `llm-fleet-block-partial.png` (vLLM down → tag "1 of 2 engines" dimmed, dot amber, sums = gufo only). Those used two throwaway local instances on :8091/:8092 with private temp DBs, killed afterwards; no fleet/config change, dev server restarted and all sources `ok`.
|
||||
|
||||
**Next pending task**: `.agents/phases/todo/07_llm_monitor_style_pages/03_engine_stats_strip.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 12%]
|
||||
........................................................................ [ 24%]
|
||||
........................................................................ [ 36%]
|
||||
...........................................................sssssssss.... [ 48%]
|
||||
........................................................................ [ 60%]
|
||||
........................................................................ [ 73%]
|
||||
........................................................................ [ 85%]
|
||||
........................................................................ [ 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% 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%
|
||||
582 passed, 9 skipped, 1 warning in 49.72s
|
||||
== 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 @@
|
||||
**Implemented (task 03 — per-engine stats strip)**
|
||||
- `llm.html`: new `#strip` section (`aria-label="Engine summary"`, ships empty+hidden) between `#fleet` and `#engines`.
|
||||
- `page-llm.js`: new `STRIP_ROWS` table (key **is** the `cellValue()` key), `stripCard()`/`renderStripCard()`/`stripRowsFor()`/`pruneEngines()`; card = dot + name + age stamp, KV-cache bar, prompt/decode tok/s with `Δ<window>` tags, total tokens, `slots busy` (gufo, counted from `sessions.list` `is_processing`, falls back to `sessions.active` + API `detail` — never a 0 counted from no rows), `running`/`waiting`, `prefix cache hit`, `spec accept` (gufo), `queue time` + `p95` foot (vLLM), alarm chips.
|
||||
- Panel cell list demoted to heroes + TTFT/TPOT (`spark:` list shrank 8→2): sessions, queued, KV, cache-hit, spec-accept, queue-mean, token footnote and the alarm container all left the panel — one value, one home. `HISTORY_SERIES` = explicit `CHART_SERIES` + `SPARK_CELLS`.
|
||||
- `dash.css`: new "engine stats strip" section built only from existing vocabulary (`.card`, `.kv`, `.bar`, `.chip.fail`, `.prov`; `.prov:empty` collapses; only `warn`/`fail` paint text), including the fix that moves the `.kv` grid *inside* the row wrapper.
|
||||
- `tests/test_api.py`: 9 new strip tests (placement/hidden/aria, shared-vocabulary markup + the `.kv` layout rule, `only` scoping, every row a cell the capture-parsed engines publish, slot-count rule-2 rule, KV colour from `severity` only, provenance-without-colour, strip/panel disjointness, no peak-ctx row) + 3 phase-04 pins restated for the new split.
|
||||
- Browser-verified live: `data/logs/llm-stats-strip-two-engines.png`, `-single-engine.png` (one full-width card, fleet block hidden), `-alarm-chip.png` (`.chip.fail` "Preemptions 3" on the incident card only) — the last two used throwaway local instances on :8091/:8092 plus a local fixture-backed fake engine, all killed afterwards; no fleet/config change, dev server restarted and `status: ok`.
|
||||
|
||||
**Gates:** `uv run pytest` → 591 passed, 9 skipped · `bash .agents/validate.sh` exit 0 (coverage 97.91%, floor 94) · `ruff check src tests agent` All checks passed · `pyright` 0 errors · `node --check` every script ok · `uv run pytest -m live --live` 9 passed · `uv pip list --outdated` empty (deps untouched).
|
||||
|
||||
**Docs:** README page tour rewritten for strip-then-panels; `AGENTS.md` gained the strip conventions paragraph (payload-only rows, KV colour, session-row shaping, alarms on the strip, `HISTORY_SERIES` composition, `pruneEngines`) and the `minSpan` sentence reworded.
|
||||
|
||||
**Decisions/deviations**
|
||||
- Task item 2 (strip gets vLLM "queue time") and item 6 (panel keeps "queue mean") conflict; satisfied the hard criterion "no value printed twice" by giving queue time — mean *and* p95 — to the strip, panel keeps TTFT/TPOT.
|
||||
- "No value twice" applied to the cell lists; the two throughput heroes stay in both components because items 1 and 6 both demand it (llm_monitor does the same) — pinned as the explicit exemption.
|
||||
- Alarm chips moved to the strip card per item 3 (phase overview's older wording kept them in the panel); panel alarm container deleted, asserted not to come back.
|
||||
- Observation: `llamacpp:n_tokens_max` (llm_monitor's peak-ctx cell) *is* in our gufo payload, contrary to the phase assumption's wording; followed the task (no peak-ctx cell) and pinned that the page never reads it.
|
||||
- `minSpan` now has no page caller (count rows are numbers, not sparks); kept in `charts.js` where the component contract test still pins it.
|
||||
|
||||
**Next pending task:** `07_llm_monitor_style_pages/04_slot_grid.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 12%]
|
||||
........................................................................ [ 24%]
|
||||
........................................................................ [ 36%]
|
||||
....................................................................ssss [ 48%]
|
||||
sssss................................................................... [ 60%]
|
||||
........................................................................ [ 72%]
|
||||
........................................................................ [ 84%]
|
||||
........................................................................ [ 96%]
|
||||
........................ [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%
|
||||
591 passed, 9 skipped, 1 warning in 50.69s
|
||||
== 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 ==
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
**Implemented (task 07/04 — gufo slot grid)**
|
||||
- `page-llm.js`: `SLOT_FIELDS` table (one fixture key per cell, `path:'next_token'` → `next_token[0]`), `slotValue()` as the only row accessor, `slotCard()`/`renderSlotCard()`/`renderSlotGrid()` keyed by slot `id` in `state.slots` (built once, text-patched, `appendChild` keeps slot order, gone slots + pruned engines cleaned up); `slotSection()` puts `sessions (GET /slots)` (`<h4>`) + `role=list` grid + the queued/deferred note in the gufo panel, and vLLM only the one-line note (with `sessions.detail` as tooltip) — no grid.
|
||||
- Cells: request (`id_task`, `-1`→`idle`), prompt tok (+`processed …`), cache hit (+`% of prompt`), generated (+`p=` when published), remaining (`-1`→`n/a`), context, model `+spec`. No per-slot speed cell (capture has no rate key; a JS Δ would be an unlabelled measurement). Busy marker = accent border + `○/●` + the word `processing`, no verdict token.
|
||||
- Empty states: no `/slots` answer → the API's own `sessions.detail`; answer with no rows → “engine reports 0 slots”; grid ships `hidden`.
|
||||
- `dash.css`: new “engine slot grid” section from existing tokens only (no `--ok/--warn/--fail`).
|
||||
- `tests/slots_contract.py`: canonicalised the request id (`CANONICAL_TASK_ID_FIELD="id_task"` required; `task_id` captured, never rendered) and made `next_token[0].n_remain` the single remaining path — replacing `llm_monitor`’s `a ?? b` chains.
|
||||
- `tests/test_api.py`: 9 new tests (markup order + hidden defaults, style-is-a-marker, every printed key resolves against the capture in both directions, no invented speed/sentinel leaks, keyed+patched-in-place+pruning, both empty states, vLLM note-only, capture→`/api/llm/snapshot`→cell-keys end-to-end); `tests/test_llm_slots_contract.py` updated for the canonical/alias rules.
|
||||
|
||||
**Gates:** `bash .agents/validate.sh` exit 0 → `603 passed, 9 skipped`, coverage **97.91 %** (floor 94) · `uv run ruff check src tests agent` All checks passed · `uv run pyright` 0 errors · `node --check` every script ok · `uv run pytest -m live --live` **9 passed** · `uv pip list --outdated` empty (deps untouched).
|
||||
|
||||
**Browser (live, `data/logs/`):** `llm-slots-idle.png`, `llm-slots-one-busy.png`, `llm-slots-two-busy.png` (real ids/tokens/cache share), `llm-slots-no-slots-answer.png`, `llm-slots-vllm-only.png`; DOM-node tagging proved cards survive polls (`survived: true`, numbers changing), console clean, no `NaN`/`undefined`. Dev server restarted (`status: ok`); throwaway :8091/:8092 instances, the fake engine and their temp DBs removed; no fleet/config change (two short gufo completions only, to photograph busy slots).
|
||||
|
||||
**Docs:** `AGENTS.md` — new slot-grid UI-conventions paragraph + testing-policy rewrite of the `/slots` contract (canonical key per fact); `README.md` — `/llm` page tour now covers the grid, sentinels, empty state and the vLLM line, plus the canonical-key note.
|
||||
|
||||
**Deviations:** (1) no per-slot speed cell, despite the task listing “per-slot speed” — the pinned capture publishes no rate key, so rendering it would be a permanent dead cell or an unlabelled page-side Δ (rule 2); decision and reason are in the code comment, AGENTS.md and a test. (2) `tests/slots_contract.py` gained the canonical task-id rule that task 04’s ASSUMPTION requires, so one task-01 test (`neither task_id alias answered`) was replaced by canonical-must-exist + alias-is-optional.
|
||||
|
||||
**Next pending task:** none — this was the last task in `07_llm_monitor_style_pages` (harness may complete the phase).
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
== uv run pytest --cov (hermetic: no network, live tests skip) ==
|
||||
........................................................................ [ 11%]
|
||||
........................................................................ [ 23%]
|
||||
........................................................................ [ 35%]
|
||||
........................................................................ [ 47%]
|
||||
......sssssssss......................................................... [ 58%]
|
||||
........................................................................ [ 70%]
|
||||
........................................................................ [ 82%]
|
||||
........................................................................ [ 94%]
|
||||
.................................... [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%
|
||||
603 passed, 9 skipped, 1 warning in 51.25s
|
||||
== 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