Subscribe to SignalR Position.z and CarData.z, decode DEFLATE payloads, stream throttled positions over SSE, and render live car dots against cached track outline bounds with tap telemetry.
Alignment spike: no checked-in or locally cached real Position.z samples were available in this isolated worktree; verified both streams expose the official raw F1 X/Y/Z coordinate contract and implemented shared-bounds normalization against prefetched OpenF1 outlines. Fallback build-outline-from-stream was not taken.
Playwright remains out of scope for live rendering because BOXBOX_DISABLE_LIVE is used there; coverage is via parser, web handler/SSE, pure transform, and seeded component tests.
Six suite failures had rotted in: three race-hub specs targeted the
sub-tabbed Race Story UI deleted in the Phase 22 redesign, and the
command-center specs depended on the real OpenF1 calendar, whose focus
weekend drifted away from the seeded Monaco session as time passed.
The e2e/visual configs now point BOXBOX_OPENF1_BASE_URL (new override)
at an unreachable address so runs are hermetic and date-stable; the
race-hub specs were rewritten against the current RaceStoryCanvas UI,
and the one drifted mobile snapshot regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Concurrent fan-outs could burst past the free-tier rate limit; callers
swallowed the 429s as missing data, and the championship hub cached the
resulting partial season for its full TTL (observed live: 8 of 22
rounds, zero wins/podiums/form).
- requestPacer spaces live requests (350ms anonymous, 100ms with key);
cache hits never wait
- get() retries 429s up to 3 times honouring Retry-After (capped 10s)
- hub tracks per-meeting fetch failures and caches incomplete
aggregates for only 2 minutes instead of 15min/24h
Verified against the live API: 2026 hub now reports all 22 rounds with
wins/podiums/form populated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fourth view on the championship page: assign P1-P10 per remaining
round and see projected standings update live, with position deltas
and mathematically alive/eliminated title states. Pure projection
logic in lib/simulator.ts (2025 points system, standard GPs only);
scenarios persist to localStorage per season. 169 frontend tests
passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mocks /api/v1/live/state with a race snapshot to exercise the tower,
flag banner, weather strip, battle detection, stint history, and
driver pinning; also covers the no-session empty state.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Track status flag banner (green/yellow/SC/VSC/red, defensive mapping)
- Weather strip: air/track temp, humidity, wind with compass, rain badge
- Gap trend sparklines from a per-driver interval ring buffer
- Battle detection: consecutive cars within 1.0s chained and highlighted
- Stint history column with compound sequence per driver
- Pinnable drivers (max 3) with focus cards, persisted to localStorage
Pure logic lives in lib/gapHistory.ts and lib/battles.ts with unit
tests; 137 frontend tests passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CLAUDE.md previously described only the TUI; it now covers the web
server (internal/web), React frontend, ingestion CLI, and the vitest/
playwright test commands. plan.md Phase 3 framing updated and the
championship hub recorded.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cold-cache hub loads previously issued ~70 sequential OpenF1 calls.
Per-meeting fetches now fan out 5-wide (order preserved), and the
aggregated response is cached in memory: 15min TTL for the current
season, 24h for past seasons.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New /api/v1/championship/hub endpoint aggregates official standings with
wins, podiums, poles, recent form, teammate head-to-head, and per-round
cumulative points. ChampionshipPage renders drivers, constructors, and
progression views.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>