phase: 34_radiance_llm_engine
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/`.
This commit is contained in:
+303
-12
@@ -45,7 +45,9 @@ from dashboards.sources.disks import SMART_SERIES, DisksCollector, parse_disks_s
|
||||
from dashboards.sources.host import HostCollector, parse_host_snapshot
|
||||
from dashboards.sources.llm import (
|
||||
HISTORY_METRICS,
|
||||
engine_result,
|
||||
parse_gufo_metrics,
|
||||
parse_radiance_metrics,
|
||||
parse_vllm_metrics,
|
||||
)
|
||||
from dashboards.store import RES_RAW, Event, Sample, SampleStore
|
||||
@@ -937,6 +939,152 @@ def test_config_reports_the_window_the_llm_rates_are_actually_measured_over(
|
||||
assert llm["rate_window_seconds"] == llm["interval_seconds"] == 2.0
|
||||
|
||||
|
||||
# ---- the llm engine registry (phase 34 task 02) --------------------------- #
|
||||
|
||||
def test_config_serves_radiance_additively_beside_byte_identical_gufo_and_vllm(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""The additive pin: `radiance` joins the llm block as a third key, and nothing about
|
||||
`gufo`/`vllm` moves — same keys, same shape, same order — while an unset radiance is
|
||||
present as `enabled: false` (a key that appeared only when configured would be the
|
||||
two-engine world leaking back into the API). The redaction is the one rule:
|
||||
`RADIANCE_API_KEY` is the documented way to authenticate, and a token written into
|
||||
the URL instead is stripped before it is served (invariant 6), like the other two.
|
||||
"""
|
||||
with build_client(tmp_path, monkeypatch) as plain:
|
||||
before = plain.get("/api/config").json()["llm"]
|
||||
with build_client(tmp_path, monkeypatch,
|
||||
radiance_url="http://SEKRIT-RADIANCE-TOKEN@driveripper:8000",
|
||||
radiance_api_key="radiance-key") as with_radiance:
|
||||
after = with_radiance.get("/api/config").json()["llm"]
|
||||
assert before["gufo"] == after["gufo"]
|
||||
assert before["vllm"] == after["vllm"]
|
||||
assert before["radiance"] == {"enabled": False, "base_url": "", "auth": False}
|
||||
assert after["radiance"] == {"enabled": True, "base_url": "http://driveripper:8000",
|
||||
"auth": True}
|
||||
assert "SEKRIT-RADIANCE-TOKEN" not in json.dumps(after), "the URL token must not be served"
|
||||
assert list(after) == ["gufo", "vllm", "radiance", "interval_seconds", "poll_ms",
|
||||
"rate_window_seconds"], "the registry's stable order is the byte order"
|
||||
|
||||
|
||||
def test_the_llm_404_gate_answers_from_the_registry_in_all_configurations(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""One engine configured — whichever of the three — is a configured source, and the
|
||||
404 detail names all three variable names so the not-configured arm says the fix
|
||||
for the whole world, not just the two it used to know."""
|
||||
single: list[dict[str, Any]] = [{"gufo_url": "http://deskwork:8731"},
|
||||
{"vllm_url": "http://vllm-box:8000"},
|
||||
{"radiance_url": "http://driveripper:8000"}]
|
||||
for overrides in single:
|
||||
with build_client(tmp_path, monkeypatch, **overrides) as test_client:
|
||||
response = test_client.get("/api/llm/snapshot")
|
||||
assert response.status_code == 200, f"only {next(iter(overrides))} configured must not 404"
|
||||
with build_client(tmp_path, monkeypatch) as test_client:
|
||||
response = test_client.get("/api/llm/snapshot")
|
||||
assert response.status_code == 404
|
||||
body = response.json()
|
||||
assert body["configured"] is False
|
||||
for name in ("GUFO_BASE_URL", "VLLM_BASE_URL", "RADIANCE_BASE_URL"):
|
||||
assert name in body["detail"], f"the not-configured arm must name {name}"
|
||||
|
||||
|
||||
def test_llm_history_defaults_list_the_configured_engines_from_the_registry(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""The defaults are the registry's configured `key`s in registry order — `key` is the
|
||||
history DB's host key samples are written under, not the display name — and an
|
||||
unconfigured engine is not among them, so it is never requested and never dialled.
|
||||
"""
|
||||
with build_client(tmp_path, monkeypatch,
|
||||
gufo_url="http://deskwork:8731",
|
||||
radiance_url="http://driveripper:8000") as test_client:
|
||||
body = test_client.get("/api/llm/history").json()
|
||||
assert body["engines"] == ["gufo", "radiance"], "the vLLM entry is unconfigured and absent"
|
||||
with build_client(tmp_path, monkeypatch) as test_client:
|
||||
body = test_client.get("/api/llm/history").json()
|
||||
assert body["engines"] == []
|
||||
|
||||
|
||||
def test_summary_llm_enabled_follows_the_registry(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
with build_client(tmp_path, monkeypatch,
|
||||
radiance_url="http://driveripper:8000") as test_client:
|
||||
assert test_client.get("/api/summary").json()["llm"]["enabled"] is True
|
||||
|
||||
|
||||
def test_an_unconfigured_radiance_never_becomes_a_job_that_could_look_broken(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Invariant 3's shape, the `disks` precedent: no configured URL, no `llm:radiance`
|
||||
job at all — so nothing dials a hostname the operator never installed, and no health
|
||||
record exists to turn red. The job appears exactly when the URL does.
|
||||
"""
|
||||
with build_client(tmp_path, monkeypatch) as test_client:
|
||||
keys = {row["key"] for row in test_client.get("/api/health").json()["sources"]}
|
||||
assert not any(key.startswith("llm:") for key in keys)
|
||||
with build_client(tmp_path, monkeypatch,
|
||||
radiance_url="http://driveripper:8000") as test_client:
|
||||
keys = {row["key"] for row in test_client.get("/api/health").json()["sources"]}
|
||||
assert "llm:radiance" in keys
|
||||
|
||||
|
||||
def _radiance_stats_doc() -> dict[str, Any]:
|
||||
"""The verbatim /stats capture, its `#` header comment lines stripped."""
|
||||
path = Path(__file__).resolve().parents[1] / "tests" / "fixtures" / "stats_radiance.json"
|
||||
if not path.exists():
|
||||
pytest.skip(f"missing fixture {path.name} — run scripts/capture-fixtures.sh --with-llm")
|
||||
body = "\n".join(line for line in path.read_text().splitlines() if not line.startswith("#"))
|
||||
return json.loads(body)
|
||||
|
||||
|
||||
def test_radiance_payload_reaches_the_page_rows_and_rest(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, metrics_text) -> None:
|
||||
"""The render path's input as the browser would receive it: the fixture /stats, through
|
||||
the real `engine_result`, into the `llm:radiance` job — and `/api/llm/snapshot` hands
|
||||
it to the page. At rest (the capture's own empty `requests[]`): the counts-otherwise
|
||||
sentence, the whitelisted stats block, and `queue_cap` from the sidecar. A request in
|
||||
flight: the rows verbatim under `sessions.list`. A dead sidecar: the metrics gauges
|
||||
with their provenance said, and the cap `null`, never `0` (rule 2)."""
|
||||
stats = _radiance_stats_doc()
|
||||
rows = [{"id": 42, "model": "juggernaut", "state": "running",
|
||||
"prompt_tokens": 1_200, "completed_tokens": 250}]
|
||||
with build_client(tmp_path, monkeypatch, radiance_url=DEAD_URL) as test_client:
|
||||
hub = test_client.app.state.ctx.hub # type: ignore[attr-defined]
|
||||
job = hub.jobs["llm:radiance"]
|
||||
|
||||
job.state.payload = engine_result("radiance", "http://r:8000",
|
||||
metrics_text("radiance"), RateEstimator(),
|
||||
stats=stats, now=1.0).payload
|
||||
rest = next(p for p in test_client.get("/api/llm/snapshot").json()["engines"]
|
||||
if p["engine"] == "radiance")
|
||||
assert rest["sessions"]["list"] == stats["requests"]
|
||||
if not stats["requests"]:
|
||||
assert "counts, not sessions" in rest["sessions"]["detail"]
|
||||
assert rest["stats"]["version"] == "1.15.1"
|
||||
assert isinstance(rest["stats"]["uptime_s"], int) and rest["stats"]["uptime_s"] >= 0, \
|
||||
"uptime is the engine's own seconds — volatile between captures"
|
||||
assert rest["stats"]["cards"][0]["vram_used"] == stats["cards"][0]["vram_used"]
|
||||
assert rest["metrics"]["queue_cap"]["value"] == stats["queue_cap"]
|
||||
assert len(rest["metrics"]["spec_positions"]) == 7
|
||||
|
||||
busy = {**stats, "requests": rows, "running": 1}
|
||||
job.state.payload = engine_result("radiance", "http://r:8000",
|
||||
metrics_text("radiance"), RateEstimator(),
|
||||
stats=busy, now=1.0).payload
|
||||
again = next(p for p in test_client.get("/api/llm/snapshot").json()["engines"]
|
||||
if p["engine"] == "radiance")
|
||||
assert again["sessions"]["list"] == rows, "the rows are not the verbatim passthrough"
|
||||
assert again["sessions"]["source"] == "radiance /stats"
|
||||
assert again["sessions"]["detail"] is None
|
||||
|
||||
job.state.payload = engine_result("radiance", "http://r:8000",
|
||||
metrics_text("radiance"), RateEstimator(),
|
||||
now=1.0).payload # stats=None: dead sidecar
|
||||
dead = next(p for p in test_client.get("/api/llm/snapshot").json()["engines"]
|
||||
if p["engine"] == "radiance")
|
||||
assert dead["sessions"]["queue_cap"] is None, "null, not 0 — rule 2"
|
||||
assert "gauges" in dead["sessions"]["detail"]
|
||||
assert "stats" not in dead, "no stats block when the sidecar never answered"
|
||||
assert dead["metrics"]["queue_cap"]["value"] is None
|
||||
|
||||
|
||||
def wait_for_state(client: TestClient, path: str, *, timeout: float = 5.0) -> dict[str, Any]:
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
@@ -2995,8 +3143,11 @@ def test_every_llm_cell_carries_a_window_sparkline_with_percentile_feet(client)
|
||||
assert name in js, f"{name} no longer feeds a foot line"
|
||||
assert "p95 n/a" in js
|
||||
assert 'data-foot' in js
|
||||
# engine-scoped rows: gufo never grows a TTFT row, vLLM never a spec-accept row
|
||||
assert "only: ['vllm']" in js and "only: ['gufo']" in js
|
||||
# engine-scoped rows: gufo never grows a TTFT row, radiance joins the vLLM latency
|
||||
# scope (the vLLM-shaped histograms this build carries, task 03) and spec acceptance
|
||||
# (the gauge reuses gufo's key, the same 0-1 scale)
|
||||
assert "only: ['vllm', 'radiance']" in js and "only: ['gufo', 'radiance']" in js
|
||||
assert "only: ['gufo']" in js, "slots busy left its gufo scope"
|
||||
scoped = js[js.index("function sparkCellsFor("):js.index("function enginePanel(")]
|
||||
assert "cell.only" in scoped
|
||||
assert "minSpan: cell.minSpan" in sparks, "cell minSpan never reaches the sparkline"
|
||||
@@ -3061,7 +3212,8 @@ def test_llm_alarm_cells_exist_only_while_there_is_an_incident(client) -> None:
|
||||
# publishes, and no row is printed in the strip *and* in the panel under it.
|
||||
|
||||
#: row key -> the cells `cellValue()` resolves it from (`sessions.*` is the gufo slot count,
|
||||
#: which is not a metrics cell). The served `STRIP_ROWS` table must match these keys exactly.
|
||||
#: `stats.*` radiance's /stats subset — neither is a metrics cell). The served `STRIP_ROWS`
|
||||
#: table must match these keys exactly.
|
||||
STRIP_ROW_PATHS: dict[str, tuple[str, ...]] = {
|
||||
"prompt": ("prompt_tokens_per_second",),
|
||||
"decode": ("decode_tokens_per_second",),
|
||||
@@ -3072,6 +3224,10 @@ STRIP_ROW_PATHS: dict[str, tuple[str, ...]] = {
|
||||
"cache_hit": ("prefix_cache_hit_ratio", "prompt_cache_hit_ratio"),
|
||||
"spec_accept": ("spec_accept_rate",),
|
||||
"queue_mean": ("request_queue_time_seconds__mean",),
|
||||
"cap": ("queue_cap",),
|
||||
"build": ("stats.version",),
|
||||
"uptime": ("stats.uptime_s",),
|
||||
"vram": ("stats.cards",),
|
||||
"preemptions": ("num_preemptions_total",),
|
||||
"device_lost": ("device_lost_total",),
|
||||
}
|
||||
@@ -3079,6 +3235,13 @@ STRIP_ROW_PATHS: dict[str, tuple[str, ...]] = {
|
||||
#: rows that are incidents, not stats: absent where the engine does not count them.
|
||||
ALARM_ROW_KEYS = ("preemptions", "device_lost")
|
||||
|
||||
#: (row key, engine) pairs the scope keeps even though **this capture** does not publish
|
||||
#: the cell: the series is standard for the engine family, so another build fills it.
|
||||
#: `queue_mean` on radiance — this build publishes no `request_queue_time_seconds` (the
|
||||
#: vLLM-compat family is pinned in RADIANCE_OPTIONAL), so the row prints `n/a` by
|
||||
#: absence, never back-filled. A row the engine could *never* fill is not shown at all.
|
||||
DOCUMENTED_ABSENCE = {("queue_mean", "radiance")}
|
||||
|
||||
|
||||
def _strip_rows(js: str) -> dict[str, str | None]:
|
||||
"""The served `STRIP_ROWS` table: row key -> its `only` scope (`None` = every engine)."""
|
||||
@@ -3150,10 +3313,13 @@ def test_llm_strip_card_is_one_card_per_engine_of_shared_vocabulary(client) -> N
|
||||
|
||||
|
||||
def test_llm_strip_scopes_its_rows_to_the_engines_that_publish_them(client) -> None:
|
||||
"""gufo gets slots and speculative decoding; vLLM gets running and queue time."""
|
||||
"""gufo gets slots; vLLM and radiance get running and queue time; the radiance
|
||||
strip's four own cells (cap / build / uptime / VRAM) are radiance's alone."""
|
||||
rows = _strip_rows(client.get("/static/page-llm.js").text)
|
||||
assert rows["slots_busy"] == "'gufo'" and rows["spec_accept"] == "'gufo'"
|
||||
assert rows["running"] == "'vllm'" and rows["queue_mean"] == "'vllm'"
|
||||
assert rows["slots_busy"] == "'gufo'" and rows["spec_accept"] == "'gufo', 'radiance'"
|
||||
assert rows["running"] == "'vllm', 'radiance'" and rows["queue_mean"] == "'vllm', 'radiance'"
|
||||
for key in ("cap", "build", "uptime", "vram"):
|
||||
assert rows[key] == "'radiance'", f"the {key} row left its radiance scope"
|
||||
assert rows["waiting"] is None and rows["cache_hit"] is None and rows["tokens_total"] is None
|
||||
js = client.get("/static/page-llm.js").text
|
||||
scoped = js[js.index("function stripRowsFor("):js.index("function stripCard(")]
|
||||
@@ -3166,19 +3332,24 @@ def test_llm_strip_rows_name_cells_the_engines_publish(client, metrics_text) ->
|
||||
`STRIP_ROW_PATHS` mirrors the JS table; every metric cell is checked against the
|
||||
capture-parsed metrics of each engine that would render that row, so a rename in
|
||||
`sources/llm.py` fails here instead of printing a permanent `n/a` in the browser, and a
|
||||
row scoped to one engine cannot leak into the other's card.
|
||||
row scoped to one engine cannot leak into the other's card. `DOCUMENTED_ABSENCE` is the
|
||||
one exemption: a series standard for the engine family that this build's capture does
|
||||
not publish (the row prints `n/a` by absence, never back-filled — the scope stays for
|
||||
the builds that do).
|
||||
"""
|
||||
rows = _strip_rows(client.get("/static/page-llm.js").text)
|
||||
assert set(rows) == set(STRIP_ROW_PATHS), \
|
||||
f"the served strip rows drifted: {set(rows) ^ set(STRIP_ROW_PATHS)}"
|
||||
parsed = {"gufo": parse_gufo_metrics(metrics_text("gufo")),
|
||||
"vllm": parse_vllm_metrics(metrics_text("vllm"))}
|
||||
"vllm": parse_vllm_metrics(metrics_text("vllm")),
|
||||
"radiance": parse_radiance_metrics(metrics_text("radiance"))}
|
||||
for key, only in rows.items():
|
||||
paths = STRIP_ROW_PATHS[key]
|
||||
if paths[0].startswith("sessions."):
|
||||
if paths[0].startswith("sessions.") or paths[0].startswith("stats."):
|
||||
continue # its own payload object; pinned on the JS below
|
||||
shown = {engine: metrics for engine, metrics in parsed.items()
|
||||
if not only or engine in only}
|
||||
if (not only or engine in only)
|
||||
and (key, engine) not in DOCUMENTED_ABSENCE}
|
||||
present = [engine for engine in shown if any(path in shown[engine] for path in paths)]
|
||||
if key in ALARM_ROW_KEYS:
|
||||
# an alarm the engine does not count simply is not there: the chip renders only
|
||||
@@ -3743,14 +3914,19 @@ def test_llm_vllm_panel_says_there_is_no_per_slot_json(client) -> None:
|
||||
`sources/llm.py`'s `_sessions()` publishes counts for vLLM and says so in `detail`; the
|
||||
panel turns that into the `llm_monitor` line, with the API's sentence as the tooltip. The
|
||||
gate is the engine's name (`SLOT_ENGINES`), not `sessions.list.length`, so an engine that
|
||||
has not answered yet still shows its label and the honest empty sentence.
|
||||
has not answered yet still shows its label and the honest empty sentence. And the line
|
||||
stays vLLM's: radiance's panel slot section is empty (its per-request rows live in the
|
||||
strip), so a sentence naming vLLM on the radiance card is a line the engine never said.
|
||||
"""
|
||||
js = client.get("/static/page-llm.js").text
|
||||
markup = _slot_markup(js)
|
||||
branch = markup.split("if (SLOT_ENGINES.indexOf(engine) < 0) {")[1].split("}")[0]
|
||||
branch = markup.split("if (engine === 'vllm') {")[1].split("}")[0]
|
||||
assert 'class="slots-note" data-slots-note' in branch, "the vLLM line lost its element"
|
||||
assert "NO_SLOT_JSON" in branch and "vLLM exposes no per-slot JSON" in js
|
||||
assert '<div class="slots"' not in branch, "the vLLM panel grew a grid it cannot fill"
|
||||
radiance_branch = markup.split("if (SLOT_ENGINES.indexOf(engine) < 0) {")[1].split("}")[0]
|
||||
assert "return ''" in radiance_branch, "the radiance panel re-grew a slot section"
|
||||
assert "NO_SLOT_JSON" not in radiance_branch, "the vLLM sentence leaked onto the radiance panel"
|
||||
body = _slot_js(js)
|
||||
assert body.startswith("function slotValue("), "the grid's code path moved"
|
||||
assert "if (!grid) {" in body, "renderSlotGrid no longer leaves a panel with no grid alone"
|
||||
@@ -3815,6 +3991,80 @@ def test_llm_charts_are_secondary_and_named(client) -> None:
|
||||
assert "height: 110" in js and "height: 165" not in js
|
||||
charts = js[js.index("function makeCharts("):js.index("function pointsFor(")]
|
||||
assert charts.count("ariaLabel:") == 4, "an /llm chart lost its accessible name"
|
||||
# the radiance strip's 7-bar spec curve (phase 34) joins the named list: `role="img"`
|
||||
# and an `aria-label` computed from the payload's `spec_positions` — a label that
|
||||
# cannot say which ratios it plots is not an accessible name, and an absent label
|
||||
# fails here
|
||||
curve = _code(client.get("/static/page-llm.js").text)
|
||||
curve = curve[curve.index("function renderSpecCurve("):curve.index("function reqCellText(")]
|
||||
assert 'role="img"' in curve, "the spec curve is an unlabelled plot"
|
||||
assert 'aria-label="' in curve and "escapeHtml(label)" in curve, \
|
||||
"the spec curve's label is not the computed one"
|
||||
|
||||
|
||||
def test_the_radiance_spec_curve_is_neutral_and_built_from_the_payload(client) -> None:
|
||||
"""Decision 4, pinned both ways: the 7-bar curve draws in the page's neutral ink,
|
||||
reaches for no verdict token, and its label is computed from the payload — the
|
||||
connector word turns on the first/last published ratio's order, and an absent
|
||||
position stays absent rather than becoming a zero bar (rule 2)."""
|
||||
js = _code(client.get("/static/page-llm.js").text)
|
||||
curve = js[js.index("function renderSpecCurve("):js.index("function reqCellText(")]
|
||||
assert "spec_positions" in curve, "the curve stopped reading the payload's positions"
|
||||
assert "cssVar('--text-faint')" in curve, "the curve left the neutral ink"
|
||||
assert "Math.min(1, row.ratio)" in curve, "a ratio above 1 would stretch a bar"
|
||||
for token in ("--ok", "--warn", "--fail", "severity"):
|
||||
assert token not in curve, f"the spec curve grew a verdict: {token}"
|
||||
assert "falling to" in curve and "rising to" in curve and "holding at" in curve, \
|
||||
"the connector word is not computed from the payload's order"
|
||||
assert "Number.isFinite(row.ratio)" in curve, \
|
||||
"a missing position must stay absent, not zeroed"
|
||||
|
||||
|
||||
def test_radiance_strip_cells_print_na_never_zero_when_stats_never_answered(client) -> None:
|
||||
"""A radiance payload without the /stats block: cap / build / uptime / vram print
|
||||
`n/a`, never `0` — the null guards on the served path (a missing sidecar is an
|
||||
absent number, rule 2), and the number formatter never sees a string value."""
|
||||
js = _code(client.get("/static/page-llm.js").text)
|
||||
value = js[js.index("function cellValue("):js.index("function p95Value(")]
|
||||
assert "case 'cap':" in value and "get('queue_cap')" in value, \
|
||||
"cap stopped reading the /stats passthrough the server degrades to null"
|
||||
assert "stats && typeof stats.version === 'string'" in value, \
|
||||
"build must be the engine's own string or null"
|
||||
assert "Number.isFinite(stats.uptime_s)" in value and "duration(stats.uptime_s)" in value
|
||||
assert "cards.find((c) => c && c.index === 0)" in value, "vram reads the wrong card"
|
||||
assert "(used / GIB).toFixed(1)" in value and "2 ** 30" in js, \
|
||||
"the one conversion is GiB = 2³⁰, labelled in the tip"
|
||||
body = _strip_render_path(js)
|
||||
assert "cellValue(engine, metrics, sessions, row.key, stats)" in body, \
|
||||
"the radiance cells lost the payload's stats block"
|
||||
assert "typeof value.value === 'string' ? value.value" in body, \
|
||||
"a string value hits the number formatter"
|
||||
|
||||
|
||||
def test_radiance_request_rows_render_as_is_and_the_rest_state_says_so(client) -> None:
|
||||
"""The rows are the engine's own fields, as-is: the columns are the union of the
|
||||
keys the rows publish (no invented key), a number prints only when it is a number,
|
||||
anything else its string verbatim — and an empty list hides the table and puts the
|
||||
API's own count-otherwise sentence in the note slot."""
|
||||
js = _code(client.get("/static/page-llm.js").text)
|
||||
card = js[js.index("function stripCard("):js.index("function renderStripCard(")]
|
||||
assert 'data-spec-curve' in card and 'data-reqs' in card and 'data-reqs-note' in card, \
|
||||
"the radiance card lost its curve / rows / note homes"
|
||||
cell = js[js.index("function reqCellText("):js.index("function renderReqs(")]
|
||||
assert "typeof value === 'number' && isFinite(value)" in cell, \
|
||||
"a number prints only when it is a number"
|
||||
assert "typeof value === 'string') return value" in cell, \
|
||||
"anything else prints its string verbatim"
|
||||
reqs = js[js.index("function renderReqs("):js.index("function makeCharts(")]
|
||||
assert "sessions.list" in reqs and "Object.keys(row)" in reqs, \
|
||||
"the columns are a hardcoded list again"
|
||||
assert "indexOf(key) < 0" in reqs, "first-seen order must keep the rows as published"
|
||||
assert "note.hidden = !sessions.detail" in reqs, \
|
||||
"the rest state lost the API's own sentence"
|
||||
assert "note.hidden = true" in reqs, "rows visible: the sentence must leave"
|
||||
assert "table.title = sessions.source" in reqs, "the table's source left its tooltip"
|
||||
# the gufo gate is untouched: the slot grid is gufo's, the radiance rows live in the strip
|
||||
assert "SLOT_ENGINES = ['gufo']" in js
|
||||
|
||||
|
||||
def test_llm_engine_panels_are_not_stretched_to_their_tallest_sibling(client) -> None:
|
||||
@@ -4006,6 +4256,9 @@ def test_the_copy_the_operator_acts_on_survives_the_audit(client) -> None:
|
||||
assert "smartmontools" in pages["/disks"] + scripts["page-disks.js"]
|
||||
assert "disk group" in scripts["page-disks.js"]
|
||||
assert "No engines configured" in pages["/llm"]
|
||||
# the not-configured arm is actionable only if it names the variable for every engine
|
||||
for name in ("GUFO_BASE_URL", "VLLM_BASE_URL", "RADIANCE_BASE_URL"):
|
||||
assert name in pages["/llm"], f"/llm's empty state stopped naming {name}"
|
||||
assert "No UPS reporting" in pages["/ups"]
|
||||
assert "instcmds" in pages["/ups"], "the UPS setup note stopped naming the grant that matters"
|
||||
assert "3493" in pages["/ups"], "the page stopped warning that upsd's port is not always 3493"
|
||||
@@ -10087,6 +10340,44 @@ def test_a_card_disclosure_scrolls_what_it_reveals_at_every_width(client) -> Non
|
||||
"at 1280 px, where it would then do nothing")
|
||||
|
||||
|
||||
def test_the_radiance_reqs_table_scrolls_instead_of_stretching_its_card(client) -> None:
|
||||
"""The radiance strip's request table must not grow the card to its min-content.
|
||||
|
||||
Measured on the live fleet (1280 px, two strip cards across, each 613 px): with a
|
||||
request in flight the `.reqs` table — the union of the row's ten published keys —
|
||||
sat at ~950 px of min-content, and because the strip body is a one-column grid
|
||||
(`.strip > .card > .body`) with an implicit auto column, a grid item's automatic
|
||||
minimum size is its content's min-content width, so the *column* grew to ~946 px.
|
||||
Every row of the card laid out at 946 px inside a 613 px card: the value column of
|
||||
each `dl.kv` row resolved to ~857 px, the right-aligned value span painted at
|
||||
x≈1582 against a card edge at 1260, and `.card { overflow: hidden }` ate it — the
|
||||
strip printed its labels with no values while the request row and the spec curve
|
||||
(their own boxes) painted fine. `min-width: 0` is the first half: without it the
|
||||
table's min-content still sets the column and nothing below can overflow. `overflow-x:
|
||||
auto` is the second: the table reaches its last column by scrolling inside the card,
|
||||
only where it is wider than the card (a table that fits paints no scrollbar —
|
||||
horizontal only, no height cap, no vertical scrollport).
|
||||
"""
|
||||
reqs = _declarations(_css_section(_css(client), "engine slot grid"), ".reqs")
|
||||
assert reqs.get("min-width") == "0", (
|
||||
"the `.reqs` item may not be narrower than its table: without this the ten-column "
|
||||
"request table's min-content grows the strip body's grid column and every value "
|
||||
"cell of the card paints past the card, clipped by `.card { overflow: hidden }`")
|
||||
assert reqs.get("overflow-x") == "auto", (
|
||||
"the request table lost its sideways scroll inside the card — the columns beyond "
|
||||
"the card edge are unreachable again")
|
||||
for forbidden in ("max-height", "overflow-y", "overflow"):
|
||||
assert forbidden not in reqs, (
|
||||
f"the `.reqs` rule declares `{forbidden}`: this is a sideways scroll only — a "
|
||||
"height cap or vertical scrollport here would hide rows the operator has not "
|
||||
"chosen to hide")
|
||||
# the strip body is the grid the item sits in: a one-column body is what the
|
||||
# min-content growth acts on, so the fix is inert if the body stops being a grid
|
||||
body = _declarations(_css_section(_css(client), "engine stats strip"), ".strip > .card > .body")
|
||||
assert body.get("display") == "grid", (
|
||||
"the strip body is not a one-column grid anymore — re-measure before touching `.reqs`")
|
||||
|
||||
|
||||
def test_every_table_on_every_page_carries_the_class_the_rule_targets(client) -> None:
|
||||
"""The mobile rule is class-level, so a `<table>` without `data` would silently not scroll.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user