60 Commits

Author SHA1 Message Date
AmanTahiliani
b884ba8885 fix(#98): preserve bare race hub handoff 2026-07-29 03:46:57 -04:00
AmanTahiliani
56ea860101 feat(#98): Keep completed analysis as the Race Hub default until the next Grand Prix is imminent
Implemented by opencode via .agents/dev dispatch.
2026-07-29 03:28:42 -04:00
Aman Tahiliani
7c7886e6c6 Merge pull request #95 from AmanTahiliani/fix/live-stint-history-merge
fix(live): merge stint deltas instead of replacing stint history
2026-07-29 01:25:12 -04:00
AmanTahiliani
255b296ecc fix(live): merge stint deltas instead of replacing stint history
The F1 feed sends TimingAppData stints as sparse deltas keyed by stint
index — a mid-stint update is just {"1": {"TotalLaps": 14}}. The parser
replaced the whole stint slice with whatever a delta carried, so pit
history collapsed to a single entry and tyre age was pinned near zero for
the entire race. A partial delta was also dropped outright, because the
parser required a Compound field that mid-stint updates do not send.

Observed live at lap 49 of the 70-lap 2026 Hungarian GP: all 22 drivers
reported exactly one stint with age 0 or 3, after most had pitted twice.
With the fix, the same feed at lap 51 yields 3 stints for 15 drivers and
2 for 6, ages spread 1-30 — e.g. car 1 as MEDIUM 17 / HARD 22 / HARD 11.

Stints now merge by index, and Compound, New and TotalLaps each apply only
when the delta actually carries them.

Also stop folding non-numeric keys into index 0 in indexedRawValues. The
feed's "_kf" key-frame marker parsed as 0 and overwrote the first entry;
only the CurrentTyres path guarded against it, leaving the other five
callers exposed.

This feeds the tyre column, the deg model, stint history and the pit
window, all of which were reading near-zero tyre age all race.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 10:16:38 -04:00
AmanTahiliani
77a6b0f2dd feat(#76): harvest request-scoped availability and freshness truth
Backend-only re-cut of the #76 availability work onto main, stacked on the
canonical Weekend Context API. Adds request-scoped freshness reporting so
aggregate responses cannot report fresh when a component is stale, plus
local-first driver summary resolution and cache/pacing truth.

The frontend half of #76 is deliberately excluded: it is built on the
Weekend shell that failed owner review, including the full-width Partial
banner treatment. Availability presentation is re-cut with the shell in #89.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:14:37 -04:00
AmanTahiliani
d03e480e03 test(#90): regress analysis selection against later unrun race
Reproduces the production shape from the v0.4.0 release blocker: a run
British race and an unrun Belgian race two weekends apart, both carrying
result rows. Analysis must resolve to the race that actually happened.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:11:03 -04:00
AmanTahiliani
0b9c3fff0a fix: make weekend context transitions truthful 2026-07-26 09:08:38 -04:00
AmanTahiliani
adfa934f9d feat: add canonical weekend context API 2026-07-26 09:08:38 -04:00
AmanTahiliani
5a6323d3b4 fix(live): keep red-flagged sessions active 2026-07-17 12:04:13 -04:00
Aman Tahiliani
79acf0579a Merge pull request #66 from AmanTahiliani/feat/issue-24-rivalry-compare-view
Rivalry compare view (#24)
2026-07-12 12:38:00 -04:00
AmanTahiliani
82abbd6b35 feat(#24): Rivalry compare view
Implemented by claude via .agents/dev dispatch.
2026-07-11 18:29:52 -04:00
AmanTahiliani
5b112fb012 feat: add narrative chapter headlines and race-hub chapter strip (#21)
Generate deterministic template headlines server-side for each replay chapter
kind, expose Chapter.headline in the race-hub payload, and render a horizontal
chapter strip on the story view with active-chapter highlighting, click-to-jump,
and a 90-second tour mode built on the existing scrubber playback.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 18:23:11 -04:00
Aman Tahiliani
96d741424c Merge pull request #63 from AmanTahiliani/feat/issue-20-combined-position-graph-track-map-scrubb
Combined position-graph + track-map scrubber (#20)
2026-07-11 18:20:04 -04:00
AmanTahiliani
c2617d39bb feat: add replay track map scrubber
Spike: replay location fan-out is bounded with a semaphore at 4 concurrent GetLocation calls, covered by TestAssembleReplayFramesBoundsLocationFanOut.

Adds /api/v1/replay/frames with 5s interval floor, 3000-frame cap, nearest-sample snapping, and empty-driver omission. Wires RaceStoryCanvas to lazy-load replay frames plus cached track outlines when the map panel opens, sharing the existing scrubber/playback state across chart and map.

Tests: HOME=/private/tmp/box-box-home GOCACHE=/private/tmp/box-box-go-cache GOMODCACHE=/Users/aman/go/pkg/mod go test ./internal/web; go build ./... (same env, passed with read-only module stat-cache warning); npm run test; npx tsc --noEmit. Full go test ./... is blocked in this sandbox by existing network/listener-dependent internal/api and internal/news tests.
2026-07-11 18:17:15 -04:00
AmanTahiliani
f8bd183c26 merge phase-2 (preview page, chapters) — resolve additive import conflicts 2026-07-11 18:13:41 -04:00
AmanTahiliani
01ec1f24e7 feat(#22): Driver profile page
Implemented by claude via .agents/dev dispatch.
2026-07-11 18:12:00 -04:00
AmanTahiliani
7212eb9b44 feat: detect race replay chapters
Add deterministic server-side chapter detection for starts, flag periods, pit phases, decisive top-five swings, and finishes, then expose chapters on the race-hub payload.

Spike result: race-hub already loads race control, positions, and laps in one read model. The requested Detect signature does not include pit stops, so pit phases use IsPitOutLap clusters as the local deterministic pit-stop proxy.
2026-07-11 18:04:44 -04:00
Aman Tahiliani
71523641ad chore: clean up verification artifacts for repo hygiene
Removes temporary verification screenshots, docker files and verify.html
introduced for PR #58 validation.

- Before/after images and real-app screenshots remain accessible in history
  at e51cabb for PR review but are not needed in main
- Keeps only the actual fix: internal/query/championship.go + test
- Maintains docs/ structure without binary clutter (PRODUCT_ROADMAP, assets, etc.)

Fixes #57 remains: Sprint points now included (ANT 158->179)
2026-07-10 23:53:11 -04:00
Aman Tahiliani
e51cabba62 docs(verify): add real app screenshots with sprint fix - ANT 179, RUS 154, HAM 147
- Running /tmp/boxbox-server --db /tmp/boxbox-verify.db (localChampionshipHub)
- /verify.html shows championship hub table with fixed points
- /api/v1/championship/hub?year=2026&source=local returns 179/154/147
- Captured via google-chrome --headless --screenshot
- Add Dockerfile + docker-compose.yml for future prod-parity verification
2026-07-10 23:50:05 -04:00
Aman Tahiliani
16d82afad5 fix(championship): include Sprint points in standings
- GetChampionshipInputs now sums Race + Sprint sessions per meeting
- Bahrain 1282 / Saudi 1283 cancelled (Force Majeure) - intentional Round 9/24
- 2026 sprints up to British GP: 11240 Chinese, 11275 Miami, 11286 Canadian, 11321 British
  Totals ANT +21, RUS +26, HAM +18 etc.
- Adds regression test TestGetChampionshipInputsIncludesSprintPoints (25+8=33)
- Fixes #57
2026-07-10 23:32:12 -04:00
AmanTahiliani
a1d71900d1 fix: separate live archive snapshots
Parse and expose SessionStatus from the official live feed, treating Started/Resumed as active and terminal or missing statuses as inactive archive candidates.

Keep /api/v1/live/state and SSE snapshot data reserved for active sessions while exposing memory-only last_snapshot, last_positions, and last_snapshot_at for the explicit Live tab archive view.
2026-07-04 01:40:58 -04:00
AmanTahiliani
b0fd252096 feat(cli): add track outline cache warmer
Spike: existing TUI prefetch stored outlines under time.Now().Year(), so the CLI uses a new explicit year-aware prefetch path and the TUI wrapper now derives the year from meetings when available.
2026-07-04 01:06:19 -04:00
AmanTahiliani
6c72c12821 feat(live): add team radio ticker
Subscribe to TeamRadio on the F1 live feed, parse defensive capture snapshots and patches, and relay capped captures through live snapshots with the SessionInfo static path. Add the frontend CDN URL helper and ticker using one shared audio element.
2026-07-03 23:56:19 -04:00
Aman Tahiliani
7263949260 feat(live): add web track map (#32)
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.
2026-07-03 19:34:09 -04:00
AmanTahiliani
c973c03689 Show cancelled schedule status 2026-07-03 02:57:18 -04:00
AmanTahiliani
127628e4dd Speed up championship hub loading 2026-07-03 01:11:31 -04:00
AmanTahiliani
7f0c338a57 Add OpenF1 request pacing, 429 retry, and hub completeness guard
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>
2026-07-03 00:47:52 -04:00
AmanTahiliani
282b5a8c24 Parallelize championship hub fetches and cache aggregated response
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>
2026-07-03 00:14:07 -04:00
AmanTahiliani
2220d5d30a Add championship hub with derived stats and progression views
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>
2026-07-03 00:09:47 -04:00
AmanTahiliani
91e2d13ab7 Implement SignalR Core support and add session fetching for live timing 2026-06-21 19:53:42 -07:00
AmanTahiliani
a2aa772838 Add race control visuals and driver names in laps view 2026-05-25 15:55:36 -04:00
AmanTahiliani
3eb74a9083 Paginate briefing cards and add video previews 2026-05-25 15:27:34 -04:00
AmanTahiliani
e3453de788 feat(paddock): initial paddock briefing pages and store changes 2026-05-25 15:16:00 -04:00
AmanTahiliani
e060bcba24 fix(web): resolve practice/qualifying partial session bug by flagging starting_grid as N/A 2026-05-25 14:33:14 -04:00
AmanTahiliani
937674f808 feat(backend): implement session coverage, resumable ingestion, deep year backfill, backoff rate-limit, and dynamic cache TTLs 2026-05-25 13:52:43 -04:00
AmanTahiliani
ee88a07aa1 Add paddock briefing feed ingestion 2026-05-25 12:30:21 -04:00
AmanTahiliani
84a8827244 Add paddock briefing RSS backend spike 2026-05-25 12:02:18 -04:00
AmanTahiliani
17c94d83ad Tighten race result ingestion ordering 2026-05-25 10:03:57 -04:00
AmanTahiliani
5eb0983ffb Preserve optional analytics partial ingestion 2026-05-25 02:51:50 -04:00
AmanTahiliani
95060b07a5 Serve built React app from web mode 2026-05-25 02:49:31 -04:00
AmanTahiliani
f2339a00a9 Add weekend ingestion orchestration 2026-05-25 02:38:27 -04:00
AmanTahiliani
1661f8dec3 Add local navigation API 2026-05-25 02:25:06 -04:00
AmanTahiliani
c7438f0ed8 Add analytics data foundation 2026-05-25 02:04:16 -04:00
AmanTahiliani
e08255db70 Add local-first race hub API 2026-05-25 00:49:13 -04:00
AmanTahiliani
517c6b987b Add local-first refactor foundation 2026-05-25 00:45:46 -04:00
AmanTahiliani
161e871c53 UI Updates and Web App 2026-05-24 20:56:00 -04:00
AmanTahiliani
ce2bc41a7f UI Updates 2026-03-27 21:02:16 -04:00
AmanTahiliani
7d46b94c42 Updated Web UI 2026-03-27 20:53:06 -04:00
AmanTahiliani
1027dd6f8e Updated UI default next session detail 2026-03-27 20:30:07 -04:00
AmanTahiliani
15faf07691 Initial UI 2026-03-27 20:12:57 -04:00