Skip to content

feat(observability): Prometheus /metrics and ws.session wide event (Phase 13) - #23

Merged
withrvr merged 2 commits into
masterfrom
phase-13-observability
Sep 14, 2026
Merged

withrvr merged 2 commits into
masterfrom
phase-13-observability

Conversation

@withrvr

@withrvr withrvr commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • DECISIONS.md §14: Prometheus /metrics, unauthenticated (matches /health), dedicated CollectorRegistry.
  • Metrics: botpit_active_games/botpit_active_ws_connections (gauges), botpit_agent_turn_latency_seconds/_errors_total per model, botpit_agent_turn_timeouts_total (real agent seats only), botpit_moves_total, botpit_model_swaps_total per base_url.
  • All hooked into the existing single centralizing spot for each signal (AgentController._metrics, Referee._commit/_take_turn, RoomService.start/_finish_room) rather than new call sites.
  • Wires the ws.session wide event (docs/admin-and-observability.md has listed this kind since Phase 1; nothing ever built it) plus the connection gauge, in the websocket route.
  • Model-swap counting is in scope; the model-swap-aware scheduler DECISIONS §13 also describes (grouping concurrent AI turns by model to minimize swaps) is explicitly out of scope -- this phase is Observability, not scheduling.
  • Found and fixed in passing: docs/development/setup.md's documented uv sync command silently drops the workspace-root dev/github-actions dependency groups (prek/zizmor/smokeshow) from the shared venv -- discovered when adding this phase's one new dependency (prometheus-client). Fixed to uv sync --all-groups.
  • Also corrected a stale doc claim (agent.turn → the real game.turn event kind).

Test plan

  • Backend suite: 787 tests green
  • prek run --all-files clean (ruff, mypy, ty, biome)
  • Verified /metrics against the real built Docker image (not just TestClient)
  • Full Playwright suite: 59 tests green (unchanged -- no frontend changes this phase)
  • New tests: metrics route shape, swap-counting logic, agent-turn latency/error via a real decide() call, a real Referee.run() agent-seat timeout, ACTIVE_GAMES/MOVES_TOTAL over a real start/finish/move cycle, ws.session wide event + connection gauge over a real websocket connection

Claude-Session: https://claude.ai/code/session_01UbiPa1rKCyqhqufgwJWkeW

…ide event (Phase 13)

Active games/connections, agent turn latency/error/timeout counters per
model, moves, and model-swap counts (DECISIONS.md §14) -- hooked into the
existing single centralizing spot for each (AgentController._metrics,
Referee._commit/_take_turn, RoomService.start/_finish_room), not new call
sites. Also wires the ws.session wide event that docs/admin-and-
observability.md has listed since Phase 1 but nothing ever built.

The model-swap-aware turn *scheduler* DECISIONS §13 also describes
remains explicitly out of scope: this only counts swaps, it doesn't yet
try to minimise them.

Also fixes a real onboarding bug found while adding this phase's one new
dependency: docs/development/setup.md's documented `uv sync` silently
drops the workspace-root dev tooling group (prek/zizmor/smokeshow) from
the shared venv.

Claude-Session: https://claude.ai/code/session_01UbiPa1rKCyqhqufgwJWkeW
- metrics.py: set explicit histogram buckets covering realistic LLM
  latency (default buckets topped out at 10s, LLM_TIMEOUT_SECONDS
  defaults to 120s)
- controller.py: record real elapsed time on a hard LLM failure instead
  of hardcoding latency_ms=0
- fake.py: note why FakeLLMClient.base_url is a shared constant, so a
  future test doesn't assert an absolute swap-count value against it

Claude-Session: https://claude.ai/code/session_01UbiPa1rKCyqhqufgwJWkeW
@withrvr
withrvr merged commit d2f8bb1 into master Sep 14, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant