Everything is verified and green. Final report: **Phase 34 final verification pass — complete** - Verified all 6 completed tasks' work against the live fleet and hermetic suite: `llm:radiance` job registered, `llm_engines()` registry drives 404 gate / history defaults / `/api/config` (additive, byte-identical gufo/vllm keys), radiance field map + `/stats` sidecar + 7-position spec curve, `/llm` strip/curve/rows. - **Defect found & fixed (pre-existing, task 05):** the vLLM-only sentence "vLLM exposes no per-slot JSON…" rendered on the **radiance** panel (`slotSection`'s non-gufo branch). Fix: vLLM line gated to `engine === 'vllm'`; radiance's panel slot section renders nothing (its session home is the strip) — `page-llm.js` + the served-byte pin in `tests/test_api.py` (now asserts the radiance branch is empty and the sentence can't leak). Browser-verified; re-shot `data/logs/34-llm-radiance-rest.png` (the 4.5-min wait found no in-flight request, so the busy shot remains the earlier pass's — its strip rows still stand; only the panel text predates the fix). - Tests: `uv run pytest` → **2031 passed, 19 skipped** (100%); `uv run pytest --cov` → **98.73%** (floor 94%; config 100%, llm 99%, collectors 98%, api 99%); `uv run ruff check src tests agent && uv run pyright` → clean; `node --check` OK; `uv pip list --outdated` → empty. - `uv run pytest -m live --live` → **13 passed, 2 skipped** (vLLM unset — correct; live-write opt-in — correct); the read-only radiance test passed. - Completion criteria: (1) engines `gufo`+`radiance`, `fleet.engines_live` 2, `config.llm.radiance.enabled` true — **pass (live curl)**; (2) unset → 404 no-dial + no job — **pass (spy-pinned, green)**; (3) fixtures present, both families (79 `radiance:` / 198 `vllm:` lines), drift pin — **pass**; (4) panel/curve/rows — **pass (re-shot rest screenshot)**; (5) live radiance test — **pass**; (6) suite/coverage/lint/`bash .agents/validate.sh` (exit 0) — **pass**; (7) docs — below; (8) gufo/vLLM behaviour unchanged — **pass (existing pins untouched)**. - Documentation: **README.md** full review — env table, LLM-engines section, architecture diagram, capture-script and `/llm` section all name radiance correctly; no inconsistencies found, no changes needed. **AGENTS.md** — the three task-06 fixes (fleet line, route row, module bullets) are in place and all other statements match reality; no changes needed. - Dev server healthy (`./scripts/dev-server.sh status`: all sources ok, `llm:radiance` answering); all changes left in the working tree for the harness. - Next pending phase: none — 34 was the last phase in `todo/`.
9.4 KiB
Phase 34 — Radiance is a first-class engine: a third /llm panel that says what its /metrics and /stats publish, nothing invented
Source: operator request, 2026-10-24 — "add support for a new llm engine 'radiance' which is running on driveripper now. Check it out at http://driveripper.reeselink.com:8000/ and come up with a plan." + the two decisions taken with them in that conversation: radiance replaced vLLM at driveripper:8000 (the dev config's VLLM_BASE_URL points at the engine that is now radiance, so the dev config moves to RADIANCE_BASE_URL; vLLM code stays — the API shape is additive-only and other deployments may run vLLM), and the per-position spec-acceptance curve is in (seven positions, each its own acceptance ratio).
Story: n/a
Context: src/dashboards/sources/llm.py (the gufo/vLLM field maps, the rule-2 throughput precedence, HISTORY_METRICS, _sessions(), fleet_totals(), SEVERITY_CELLS), src/dashboards/config.py (the *_BASE_URL/*_API_KEY engine settings, any_source_enabled), src/dashboards/collectors.py (fetch_engine, the best-effort /slots fetch, llm_jobs), src/dashboards/api.py (the llm_router 404 gate, /api/config's llm block, the summary's llm block, the history defaults), src/dashboards/alerts.py (the cell-driven _engine_alerts), src/dashboards/severity.py (the only threshold table), src/dashboards/web/static/page-llm.js + pages/llm.html (the only: scoping, strip cells, slot grid), tests/test_llm_source.py / tests/test_collectors.py / tests/test_api.py / tests/test_config.py / tests/test_live_fleet.py, scripts/capture-fixtures.sh, .env.dev / .env.dev.example, README.md.
Objective
The dashboard treats radiance (a vLLM-derived engine, v1.15.1, model juggernaut, on driveripper:8000) as a first-class third engine — llm:radiance — with its own field map pinned by a verbatim capture, its native windowed throughput gauges winning per rule 2, its /stats endpoint as the session source (radiance's answer to gufo's /slots), and a radiance strip on /llm (queue cap, version/uptime, per-card VRAM, the 7-bar spec-acceptance curve) — while gufo and vLLM keep their exact payloads, history names, and behaviour.
Scope decisions taken with the operator (binding for this phase)
| # | Decision | Consequence |
|---|---|---|
| 1 | Radiance replaced vLLM at driveripper:8000. | .env.dev's VLLM_BASE_URL line becomes RADIANCE_BASE_URL (same address). The vLLM engine code and env var stay — VLLM_BASE_URL still configures a vLLM engine for other deployments; only the dev fleet's config moves. AGENTS.md's fleet table says vLLM :8000 for driveripper; that is the one stale fact the final pass fixes. |
| 2 | The per-position spec-acceptance curve is in. | radiance:draft_position_acceptance_ratio{position="0".."6"} renders as a 7-bar hand-rolled SVG on the radiance strip, role="img" + aria-label, pinned in tests/test_api.py beside every other chart. Snapshot-only: the seven per-position ratios do not get history series (a bounded store, rule 9); the overall draft_acceptance_ratio does. |
| 3 | Engine internals the operator cannot act on are out. | link/passes/steps*/ckpt*/hit_cuts/released/kv_stream*/lookup*/linear*/attn_cached/client_disconnect/stream_overflow stay out of the payload (flavour text is not helpful information). What the payload carries: native + measured throughputs, KV usage + max tokens/bytes, queue depth/cap/admission-rejected, preemptions, the prefix hit-rate gauge, overall + per-position spec acceptance, the decode-step gauges, requests[] sessions, per-card VRAM, model/version/uptime_s/startup_s, lifetime tokens_total. |
| 4 | No new thresholds, no new write path. | The only rated radiance cell is KV pressure, via the existing llm.kv_cache_usage_pct row (radiance publishes the same 0-1 ratio the vLLM map already feeds it). Spec acceptance is an efficiency number, not a verdict — uncoloured. No radiance endpoint accepts writes; the app's only upstream write stays POST /api/ups/command (invariant 1 unchanged). No new dependency, no new /api route — the served-route walk and the public-surface pin are untouched. |
Dependencies
23_llm_rate_responsiveness(complete) — the per-cadenceRateEstimatorand the refused-window →n/a+Δ<window>semantics this phase reuses for the measured Δ of radiance's vLLM-shaped counters.13_llm_page_and_decode_rate(complete) — the engine-panel/strip shape, theonly:scoping, the served-byte pins this phase extends.24_dev_mtls_rollout(complete) — the direct-dial fleet; radiance is dialled the same plain way the other engines are (no token, no certificate — the operator's address answers unauthenticated).- Independent of
33_gateway_route_switching(todo, in progress) — orthogonal module; no shared file besidesapi.py's already-present llm routes, which this phase does not touch.
Tasks
01_capture_radiance_ground_truth.md—capture-fixtures.shrecords radiance's/metrics,/statsand/v1/modelsverbatim intotests/fixtures/, and the fixture name-set is pinned hermetically.02_config_and_the_engine_registry.md—RADIANCE_BASE_URL/RADIANCE_API_KEY, onellm_engines()registry replacing the five hardcoded gufo/vllm enumeration sites, the dev config moves to radiance.03_the_radiance_field_map.md—RADIANCE_SERIES/RADIANCE_HISTOGRAMS,parse_radiance_metrics(), the radiance_sessions()arm, the additive history series,fleet_totals' seams copy.04_the_radiance_job.md—fetch_enginelearns the best-effort/statsfetch, thellm:radiancejob.05_the_llm_page_learns_radiance.md— the radiance strip (queue cap, version/uptime, per-card VRAM, the 7-bar spec curve), theonly:scopes,requests[]rows, the empty-state text.06_docs_and_live_verify.md— the live read-only test, the fixture re-capture, README/AGENTS.md pass, the live-data screenshots.
Testing & Quality
- Unit/integration: the radiance parse against the verbatim fixtures (name-set drift pin, rule-2 precedence in both directions, absent →
n/a, the refused-window arm, severity pass-through, the per-position shape, both session arms,fleet_totalswith a radiance payload), the collector's best-effort/stats(a dead/statskeeps the/metricspoll healthy — invariant 4), the registry (one place lists the engines), the API surface (/api/config.llm.radiance, the 404 gate, the history defaults, the summary), and the live read-only test. - Coverage: >90% on new/modified code; the whole suite 100%;
ruff+pyrightclean. - The phase is "Complete" only when the entire project test suite passes 100% (every test in the project, not just this phase's — pre-existing failures included) and achieves >90% code coverage on new/modified code.
- Every UI change is verified in a real browser against live data, screenshot in
data/logs/(AGENTS.md rule 10) — with gufo and radiance both answering, the cross-engine fleet block finally renders on the dev fleet, which is the phase's own proof that the sum is honest.
Documentation & Consistency
- The final pass reviews
README.mdin full against the project as it stands after this phase — fixing every inconsistency found, including pre-existing ones not caused by this phase. ForAGENTS.mdit fixes only stale statements (a dead command, a changed rule, an outdated fact) and never adds or expands its content (a file that states its own update policy, e.g. "updated rarely, if ever", wins). - Tasks update
README.mdimmediately when their own changes are user-visible (setup, commands, configuration, features, conventions), andAGENTS.mdonly when a statement in it became stale.
Completion Criteria
RADIANCE_BASE_URLset andGUFO_BASE_URLset:curl -s http://127.0.0.1:8090/api/llm/snapshot | jq .engines | jq 'map(.engine)'listsgufo,radiance(andvllmonly if configured), andfleet.engines_liveis 2;/api/config.llm.radiance.enabledistrue.RADIANCE_BASE_URLunset:/api/llm/snapshotanswers404 {"configured": false}with no dial (spy-pinned), and nollm:radiancejob exists in the hub.tests/fixtures/metrics_radiance.txtandtests/fixtures/stats_radiance.jsonexist, are verbatim captures, and a hermetic test fails if the fixture'sradiance:*/vllm:*name set drifts fromRADIANCE_SERIES/RADIANCE_HISTOGRAMS.- The radiance panel on
/llmshows the nativeΔ<window>-labelled throughputs when the gauge is absent, the KV bar with its severity colour, the 7-bar spec curve with itsaria-label, therequests[]rows when a request is live and the counts-otherwise arm at rest — screenshot indata/logs/. uv run pytest -m live --liveincludes a radiance test that passes read-only against the running engine.- full test suite 100% passing (every test in the project, not just this phase's), coverage >90%;
ruff+pyrightclean;bash .agents/validate.shgreen. - README.md is accurate and consistent with the whole project; AGENTS.md has no stale statements (verified in the final pass — the
vLLM :8000fleet fact included). - no behaviour change in completed work: the gufo and vLLM payloads, history names, alerts, and served pages are byte-identical where this phase does not touch them (the suite's existing pins untouched).