Files
6krrt/tests/test_router_wall_clock.py
adlee-was-taken 0111da9bbf feat(telemetry): router-observed wall-clock and TTFT columns, with plan docs
Adds router_wall_seconds and router_ttft_seconds to energy_observations:

- router_wall_seconds: time.monotonic() from just before the accepted
  candidate's POST/connection-open to the complete response body (buffered)
  or the last byte forwarded (streaming). Re-marked per candidate so
  failover time is excluded — a dead model's 30s stall is not charged to
  the healthy one that replaced it.
- router_ttft_seconds: streaming-only. First delta carrying non-empty
  content or a tool_calls fragment, excluding the role-only opening delta.
  NULL on buffered rows (not applicable) and on streams that produced no
  output token (a broken upstream — not the same as a literal 0).

Separate from duration_seconds (provider's reported serving time) on
purpose: OpenRouter reports duration_seconds on 0 of 3,850 rows, while
the router can always measure its own clock. The two quantities are stored
independently and never written into each other.

log_observation() defaults both new params to None so seed_energy.py and
eval_proficiency.py pass unchanged — a reprise of 6e729ad's bug where new
keyword-only arguments killed the seed timer.

Also:
- docs/data-model.md: document the new columns, span definitions, and
  the distinction from duration_seconds
- config/schema.sql: full CREATE TABLE declaration
- plans/token-waste-waves.md: status update for Wave 1
- plans/ten-thousand-foot-review.md: companion diagnosis
2026-09-13 12:25:39 -04:00

19 KiB