phase: 14_store_performance
**Phase 14 `store_performance` — final verification pass (all 4 tasks already in `complete/`)** - Re-verified every task's work in the tree: read caches (`series_names`/`stats`), capped compound `pick_res_many`, `history_many` + `api._history_batch`, windowed `maintain()` + per-resolution prune + `PRAGMA optimize`/`automatic_analyze=0`/WAL pragmas, `store_perf.BUDGETS` (14 ceilings), probe, live watch. - **Completion criteria:** baseline+after side by side in `data/logs/NOTES-store-perf.md` ✅ · budget tests green (`uv run pytest -m store_perf --store-perf` → **4 passed**, 14/14 inside) ✅ · 25-min dev-server watch re-run **independently** (74 passes, `scripts/watch-store-perf.py`): **0 `store-error`** (total still 190, newest 2026‑10‑18 06:33:30), WAL 7.77 MB ≤ 67.1 MB, medians 1.7–3.2 ms, p95 720/613 ms = the documented cold-cache window; a 3rd 27-pass watch on a freshly restarted server reproduced it (3.1/708, 1.8/572) ✅ · `maintain()` 5,368 ms → 2.7–6.8 ms and WAL bounded across two cycles (test + notes) ✅ · no behaviour change (all four history routes pinned against `query()`) ✅ - **Full gates:** `uv run pytest` → **1267 passed, 15 skipped**; `bash .agents/validate.sh` → **exit 0**, coverage **98.75%** (floor 94), `ruff check src tests agent` clean, `pyright` 0 errors, `node --check` ok, repo hygiene ok; `uv run pytest -m live --live` → **11 passed**; dev server up, 9/9 sources `ok`, pages 200 in 1.5–3.3 ms. - **Docs fixed:** README/AGENTS still claimed a flat "20 s per pass" while `host_agent.py` (in this same uncommitted change) scales the budget to 5 s × disk count — corrected in both plus the two illustrative "20 s of wedged disk" sentences; broken bold (`` `driveripper** ``) repaired; stale gap-4 title + "tuning is its own phase" wording updated to say phase 14 ran; README's absolute "nothing … is answered by a whole-table scan" qualified to *per call* with the cold-window cost named; "third opt-in marker" → second; conftest `--store-perf` help named the real marker; **`data/logs/watch-store-perf.py` moved to `scripts/watch-store-perf.py`** (both docs told a clone to run a gitignored path) with root-anchored paths, `DASH_WATCH_OUT`, and dead code removed. - **New finding recorded:** gap 9's "~10 s process-wide stall is still gap 4's / `14_store_performance`'s problem" is now closed — coincident >8 s `llm` + >12 s `ups` raw-stream gaps went 393 (00:00–12:00) and 198 (12:00–21:36) to **0** across 110+ min of the phase-14 store; written into AGENTS.md gaps 4 and 9 and the notes table. - **Deviations:** did *not* pull either deferred cost knob (`STATS_CACHE_TTL_SECONDS`, warming caches from the maintenance tick) — AGENTS.md records that decision and its reasoning; `uv pip list --outdated` still reports certifi/fastapi/starlette/websockets (pre-existing advisory, no dependency touched this phase, gate treats it as advisory). Overwrote nothing: task 04's watch preserved as `store-perf-watch.task04.*`, my two runs as `.verify25.*` / `.current-code.*`. - **Next pending phase:** `15_agent_mtls`, then `16_agent_smart_pass_budget` (owns the scaled-budget tests + its doc criterion, now partly pre-satisfied by this pass), `17_installer_device_filter`.
This commit is contained in:
+60
-5
@@ -27,15 +27,33 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
||||
default=False,
|
||||
help="run tests marked `live` against the real fleet/engines/upsd (they skip otherwise)",
|
||||
)
|
||||
parser.addoption(
|
||||
"--store-perf",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="run tests marked `store_perf`: the phase-14 timing measurements against the "
|
||||
"seeded production-shaped store (they skip otherwise — they cost minutes, not ms)",
|
||||
)
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
|
||||
if config.getoption("--live"):
|
||||
return
|
||||
skip = pytest.mark.skip(reason="needs --live and a reachable target (see tests/test_live_fleet.py)")
|
||||
# Two opt-ins, one shape: a marker whose tests are real but expensive, skipped by default
|
||||
# so `uv run pytest` stays fast and hermetic. `--store-perf` is the phase-14 half of the
|
||||
# rule `--live` established; `scripts/store_perf_probe.py` is the CLI for the same numbers.
|
||||
skips = {
|
||||
"live": pytest.mark.skip(
|
||||
reason="needs --live and a reachable target (see tests/test_live_fleet.py)"),
|
||||
"store_perf": pytest.mark.skip(
|
||||
reason="needs --store-perf (a seeded ~6 M-row store; see tests/store_perf.py)"),
|
||||
}
|
||||
enabled = {
|
||||
"live": bool(config.getoption("--live")),
|
||||
"store_perf": bool(config.getoption("--store-perf")),
|
||||
}
|
||||
for item in items:
|
||||
if "live" in item.keywords:
|
||||
item.add_marker(skip)
|
||||
for marker, skip in skips.items():
|
||||
if not enabled[marker] and marker in item.keywords:
|
||||
item.add_marker(skip)
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SRC = ROOT / "src"
|
||||
@@ -228,3 +246,40 @@ def metrics_text() -> Any:
|
||||
@pytest.fixture
|
||||
def rates() -> RateEstimator:
|
||||
return RateEstimator(span=10.0)
|
||||
|
||||
|
||||
# ---- phase 14: the production-shaped store the hot-path budgets measure ---- #
|
||||
#
|
||||
# Here rather than in tests/test_store.py because two files price the same budgets — the store
|
||||
# paths in `test_store.py`, the HTTP paths in `test_api.py` — and a second seeded 6.4 M-row file
|
||||
# (or, worse, a second *differently shaped* one) would make the two sets of numbers describe two
|
||||
# databases. Session-scoped because seeding costs ~25 s, and cached on disk (`data/perf/`, see
|
||||
# `store_perf.cache_dir`) because the before/after has to be the same physical file both times.
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def perf_store_path() -> Path:
|
||||
"""The cached seeded store, built on first use and re-verified on every reuse.
|
||||
|
||||
Opt-in tests only: nothing in the default run asks for this fixture, so `uv run pytest` never
|
||||
pays for the seed. `DASH_PERF_STORE_DIR` relocates the file (see `store_perf.cache_dir`).
|
||||
"""
|
||||
import store_perf # noqa: PLC0415 - only the phase-14 tests seed a store
|
||||
|
||||
try:
|
||||
return store_perf.ensure_seeded(log=lambda line: print(line, flush=True))
|
||||
except OSError as exc: # pragma: no cover - only a read-only checkout hits this
|
||||
pytest.skip(f"cannot build the seeded store ({exc}) — set DASH_PERF_STORE_DIR "
|
||||
"to a writable directory to run the phase-14 measurements")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def perf_store(perf_store_path: Path) -> Any:
|
||||
"""The seeded store, opened per test and closed after (one handle per test, one file)."""
|
||||
import store_perf # noqa: PLC0415 - see perf_store_path
|
||||
|
||||
store = store_perf.open_store(perf_store_path)
|
||||
try:
|
||||
yield store
|
||||
finally:
|
||||
store.close()
|
||||
|
||||
Reference in New Issue
Block a user