phase: 23_llm_rate_responsiveness

Phase 23 final verification complete — all green.

```
VERIFIED (criteria)
1  /api/llm/snapshot windows ≈2 s live (1.98–2.00), /api/system window_seconds ≈10 s (9.996–10.005);
   /api/config llm.rate_window_seconds=2=LLM_INTERVAL_SECONDS; browser re-check ALL CHECKS PASSED
   (data/logs/23-window-{llm,system}.png — /llm prints Δ2.0s, /system footnote Δ10.0s)
2  Phase-13 pins unchanged: floor, 2×span ceiling, 8× jump gate + independent anchor — all pass
   (only import/span-line diffs in tests/; git diff confirms no assertion rewritten)
3  Live proof re-derived from artifacts: 780 rows, 0 unlabelled, windows 0.61–3.38 s, 5 starts +
   5 ends settled by poll 2 (0 unsettled), 1 m rollups max 42.3 vs raw 201.6, 0 over 300 tok/s;
   counterfactual 10 s window: median settle poll 3, |ln| 0.924 vs 0.037
4  uv run pytest: 1494 passed / 15 skipped · coverage 98.94% (floor 94) · ruff clean · pyright 0
   errors · node --check clean · bash .agents/validate.sh exit 0 · live 11 passed · store_perf 4 passed
   Dev server up, all nine sources ok. No git add/commit run; everything left in the working tree.

DOCS PASS — 4 inconsistencies fixed in AGENTS.md (last two runs above include them)
- UI conventions hero example still said the `.sub` footnote reads `Δ10.0s`; the only hero that
  prints a Δ is /llm's → now `Δ2.0s` on /llm, "at the current load" on /ups
- gap 9: "found 10 busy-edges" contradicted its own artifact (17 edges, 10 judged, 7 reported-not-
  judged) → 17; and the poll-2 ratios were a 3-of-5 cherry-pick → full five values both windows
- gap 12: the responsive-table fix is now scheduled — names 27_mobile_tables_and_audit
README, config table, .env.example, rates/prom docstrings, app/api bullets and the testing-policy
pins all re-checked against code and found consistent (store pragmas, budgets, throttle, fleet).

NOTES
- Advisory only, not phase 23: fastapi 0.153.0 → 0.156.8 available; dependencies untouched here,
  so rule 8's "update on purpose" is left to the operator.
- NOTES.md is empty in the working tree (its items became phases 24–27); left as-is, untracked-file
  rules forbid me removing it.
- Next phase: 24_dev_mtls_rollout (25–27 follow).
```
This commit is contained in:
2026-10-21 08:04:21 -04:00
parent 895f309f8e
commit 5f3ed9bcd4
37 changed files with 1694 additions and 31 deletions
+36
View File
@@ -15,6 +15,7 @@ import pytest
from dashboards.rates import RateEstimator
from dashboards.severity import classify
from dashboards.sources.host import HostCollector, fleet_summary, parse_host_snapshot
from rate_window_contract import HOST_WINDOW, LLM_WINDOW, assert_window, delta_label
TICKS_PER_SECOND = 100.0
@@ -80,6 +81,41 @@ def test_second_scrape_measures_the_window_it_claims(agent_snapshot) -> None:
assert usage == 10.0
def test_the_host_rates_keep_their_own_cadence_s_window(agent_snapshot) -> None:
"""Phase 23's other direction: a host cell labels ~10 s, the LLM cell's 2 s is not its shape.
`app.build_hub` gives the `host` jobs `RateEstimator(span=RATE_WINDOW_SECONDS)` and the `llm`
jobs one spanned by `LLM_INTERVAL_SECONDS`; the payload shape is identical and only the number
differs, so a pin naming one of them is how the smaller window could quietly reach both
sources. `tests/test_llm_source.py` pins the 2 s side; this pins the 10 s side on the same
scrape-the-agent-twice shape the page reads (`window_seconds` is what `/system`'s footnote
prints).
The second half is the reason one estimator cannot serve both cadences: hand the host's own
10 s poll the LLM's 2 s span and there is nothing inside the window to diff, so every rate
answers `n/a` — the designed refusal, and the reason the host keeps `RATE_WINDOW_SECONDS`.
"""
second = advance(agent_snapshot, 10.0, rx_bytes=100_000, tx_bytes=50_000)
collector = HostCollector(RateEstimator(span=HOST_WINDOW))
parse_host_snapshot("deskwork", agent_snapshot, collector, now=1_000.0)
payload = parse_host_snapshot("deskwork", second, collector, now=1_010.0).payload
assert_window(payload["window_seconds"], HOST_WINDOW,
where="the host payload's window_seconds")
assert delta_label(payload["window_seconds"]) == "Δ10.0s", \
"the /system footnote prints this, and it is not the LLM page's Δ"
assert payload["cpu"]["usage_pct"] is not None
assert payload["network"]["rx_bytes_per_s"] is not None
starved = HostCollector(RateEstimator(span=LLM_WINDOW))
parse_host_snapshot("deskwork", agent_snapshot, starved, now=1_000.0)
narrow = parse_host_snapshot("deskwork", second, starved, now=1_010.0).payload
assert narrow["window_seconds"] is None, \
"a 2 s window over a 10 s poll has nothing to diff: n/a, never a rate"
assert narrow["cpu"]["usage_pct"] is None
assert narrow["network"]["rx_bytes_per_s"] is None
def test_iowait_counts_as_idle_but_is_still_reported(agent_snapshot) -> None:
_first, payload = parse_twice(agent_snapshot)
modes = payload["cpu"]["modes_pct"]