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/`.
134 lines
5.6 KiB
Python
134 lines
5.6 KiB
Python
"""The hand-rolled Prometheus parser, tested against real engine expositions.
|
|
|
|
This parser exists so the app has no Prometheus dependency for the two upstreams that
|
|
already speak the format. That makes it load-bearing on text we do not control: llama.cpp
|
|
emits names with colons, vLLM emits label sets and histograms, and both are free to change
|
|
them. Fixtures are captured verbatim (scripts/capture-fixtures.sh --with-llm).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
from dashboards.prom import Prom
|
|
|
|
|
|
def test_parses_counters_and_gauges_from_a_real_capture(metrics_text) -> None:
|
|
prom = Prom(metrics_text("gufo"))
|
|
# the capture's counters and gauges are live numbers (volatile between
|
|
# re-captures): the pin is that they parse at all, in a sane range
|
|
generated = prom.scalar(["llamacpp:tokens_predicted_total"])
|
|
assert generated is not None and generated >= 0
|
|
usage = prom.scalar(["llamacpp:kv_cache_usage_ratio"])
|
|
assert usage is not None and 0.0 <= usage <= 1.0
|
|
assert prom.parse_errors == 0
|
|
|
|
|
|
def test_help_and_type_comments_are_not_samples(metrics_text) -> None:
|
|
prom = Prom(metrics_text("gufo"))
|
|
assert not any(name.startswith("#") for name in prom.series)
|
|
assert "# HELP llamacpp:prompt_tokens_total" not in prom.series
|
|
|
|
|
|
def test_labels_are_parsed_and_filterable(metrics_text) -> None:
|
|
prom = Prom(metrics_text("vllm"))
|
|
running = prom.values(["vllm:num_requests_running"])
|
|
assert running, "vLLM exposes num_requests_running"
|
|
by_model = prom.by_label(["vllm:generation_tokens_total"], "model_name")
|
|
assert by_model and all(model for model in by_model)
|
|
|
|
|
|
def test_values_by_series_keeps_the_label_sets_apart() -> None:
|
|
"""Counter deltas diff per label set; the summed view would let a joining series
|
|
lend its carried value to one interval (phase 13). This is the accessor that view."""
|
|
prom = Prom('x{a="1"} 5.0\nx{a="2"} 7.0\ny 1.0\n')
|
|
assert prom.values_by_series(["x"]) == [({"a": "1"}, 5.0), ({"a": "2"}, 7.0)]
|
|
assert prom.values_by_series(["y"]) == [({}, 1.0)]
|
|
assert prom.values_by_series(["x"], {"a": "2"}) == [({"a": "2"}, 7.0)]
|
|
assert prom.values_by_series(["nope"]) == []
|
|
|
|
|
|
def test_values_by_series_on_a_real_labelled_capture(metrics_text) -> None:
|
|
prom = Prom(metrics_text("vllm"))
|
|
series = prom.values_by_series(["vllm:generation_tokens_total"])
|
|
assert series, "vLLM exposes generation_tokens_total"
|
|
assert all(labels.get("model_name") for labels, _v in series), "the capture lost its labels"
|
|
|
|
|
|
def test_aggregations(metrics_text) -> None:
|
|
prom = Prom(metrics_text("vllm"))
|
|
total = prom.scalar(["vllm:prompt_tokens_total"], agg="sum")
|
|
assert total is not None and total > 1e6
|
|
# ratios must never be summed across label sets — a 3-way sum would read as 300% used
|
|
usage = prom.scalar(["vllm:kv_cache_usage_perc"], agg="max")
|
|
assert usage is not None and 0.0 <= usage <= 1.0
|
|
|
|
|
|
def test_missing_series_is_none_not_zero(metrics_text) -> None:
|
|
prom = Prom(metrics_text("gufo"))
|
|
assert prom.scalar(["vllm:does_not_exist"]) is None
|
|
assert prom.values(["vllm:does_not_exist"]) == []
|
|
assert prom.by_label(["nope"], "model_name") == {}
|
|
|
|
|
|
def test_histogram_mean_and_p95(metrics_text) -> None:
|
|
hist = Prom(metrics_text("vllm")).histogram(["vllm:time_to_first_token_seconds"])
|
|
assert hist is not None
|
|
assert hist["count"] and hist["count"] > 0
|
|
assert hist["mean"] and hist["mean"] > 0
|
|
assert hist["p95"] is not None
|
|
assert hist["p95"] >= hist["mean"], "p95 below the mean means the interpolation is wrong"
|
|
assert math.isfinite(hist["p95"])
|
|
|
|
|
|
def test_histogram_resolves_through_suffixes(metrics_text) -> None:
|
|
prom = Prom(metrics_text("vllm"))
|
|
# the bare name never appears in the exposition; only _bucket/_sum/_count do
|
|
assert "vllm:time_to_first_token_seconds" not in prom.series
|
|
assert prom.resolve_hist(["vllm:time_to_first_token_seconds"]) == "vllm:time_to_first_token_seconds"
|
|
assert prom.resolve(["vllm:time_to_first_token_seconds"]) is None
|
|
|
|
|
|
def test_resolve_returns_the_first_present_name() -> None:
|
|
prom = Prom('a_total 5\nb_total 7\n')
|
|
assert prom.resolve(["missing_total", "b_total", "a_total"]) == "b_total"
|
|
assert prom.resolve(["nope"]) is None
|
|
|
|
|
|
def test_label_match_narrows_the_series() -> None:
|
|
prom = Prom('x{engine="0"} 1\nx{engine="1"} 2\n')
|
|
assert prom.scalar(["x"], agg="sum") == 3
|
|
assert prom.scalar(["x"], label_match={"engine": "1"}) == 2
|
|
assert prom.scalar(["x"], label_match={"engine": "9"}) is None
|
|
|
|
|
|
def test_malformed_lines_are_counted_not_fatal() -> None:
|
|
prom = Prom("good_metric 1\nthis is not prometheus\nalso_bad{unclosed 2\n")
|
|
assert prom.scalar(["good_metric"]) == 1.0
|
|
assert prom.parse_errors >= 1
|
|
|
|
|
|
def test_empty_exposition_is_harmless() -> None:
|
|
prom = Prom("")
|
|
assert prom.series == {}
|
|
assert prom.scalar(["anything"]) is None
|
|
assert prom.histogram(["anything"]) is None
|
|
|
|
|
|
def test_quantile_ignores_non_finite_values() -> None:
|
|
prom = Prom('m_sum 10\ncount 2\nm{le="1"} NaN\n')
|
|
assert prom.scalar(["m"], label_match={"le": "1"}) is None
|
|
|
|
|
|
def test_multiple_histogram_label_sets_do_not_invent_a_p95(metrics_text) -> None:
|
|
"""Mixing per-DP-rank buckets into one cumulative curve would fabricate a percentile."""
|
|
two = (
|
|
'h_sum{dp="0"} 10\nh_sum{dp="1"} 10\n'
|
|
'h_count{dp="0"} 2\nh_count{dp="1"} 2\n'
|
|
'h_bucket{dp="0",le="1"} 1\nh_bucket{dp="0",le="+Inf"} 2\n'
|
|
'h_bucket{dp="1",le="1"} 1\nh_bucket{dp="1",le="+Inf"} 2\n'
|
|
)
|
|
hist = Prom(two).histogram(["h"])
|
|
assert hist is not None
|
|
assert hist["mean"] == 5.0
|
|
assert hist["p95"] is None, "p95 across mixed label sets is a made-up number"
|