Session 25: Fix all data rendering — proxy routes, Tank01 normalizer, box-score bridge, inline streaks (1579 tests)

This commit is contained in:
Kev
2026-06-12 17:58:55 -04:00
parent 433e827103
commit 956cdb863a
15 changed files with 602 additions and 39 deletions
+71
View File
@@ -4,6 +4,77 @@
2026-06-12
## Current Phase
SHIP BUILD v25.0 — Fix every data-rendering bug: the frontend now actually SHOWS the backend's data (Session 25)
## Session 25 (2026-06-12) — SHIPPED
Traced data from API response → normalizer → cache → frontend fetch →
render and fixed every break. The backend was serving real data; the
frontend showed "NO SLATE." Root causes found and fixed.
Backend 1571 → **1579 tests** (+8), 125 suites, zero regressions.
Web build clean.
### PHASE 1 — Tank01 game-lines normalizer (traced + fixed)
- TRACE: the real Tank01 betting-odds shape puts each sportsbook as a
TOP-LEVEL key on the game object (`{ awayTeam, homeTeam, bet365:{...},
betmgm:{...} }`), NOT inside a `sportsBooks` array. The old normalizer
looked for the array → `books: {}` every time.
- FIX: `extractBooks()` filters out NON_BOOK_KEYS and treats remaining
object values as books (counted only if they yield a real odds field).
`normalizeBook` now reads `homeTeamML`/`totalOver`/`homeTeamRunLine`
(MLB) alongside the older spellings. Legacy array shape still handled.
### PHASE 2 — Slate schedule rendering (THE root cause)
- TRACE: the all-day endpoints (`/api/schedule`, `/api/gamelines`,
`/api/streaks`, `/api/hotlist`) existed on Express but had NO Next.js
proxy route — so the browser's `fetch('/api/schedule/mlb')` 404'd on the
Next origin and the slate was always empty.
- FIX: created 4 Next.js proxy route handlers (mirroring `/api/odds/*`).
- Sport tabs now show merged counts ("MLB (8)") from schedule+odds.
- Games already rendered with 0 props (Session 24 merge); now they get data.
### PHASE 3 — Dashboard
- The Session 24 schedule fallback was 404ing for the same proxy reason;
the Phase 2 proxy unblocks it. Dashboard now shows ESPN schedule games.
### PHASE 4 — Hero prop
- The static Jokic fallback card is now labelled "EXAMPLE" so its fixed
stats don't read as stale live data when no live hero-prop is flowing.
### PHASE 5 — Per-game inline streaks
- `GameCard` renders a 🔥 STREAKS section inline (below props/lines),
matched to the game by team abbreviation in the Slate. Renders only when
streaks exist for that game's teams. Sport-wide panels kept as the board.
### PHASE 6 — Game-log cache key alignment (traced + bridged)
- TRACE: prefetch writes `tank01:{sport}:boxscore:{gameId}`; rosterLogs
read `gamelogs:{sport}:*` / `rosterlogs:{sport}`. NBA/WNBA are fed by
gameLogService (Python) during grading — ALIGNED. MLB had NO writer for
the keys rosterLogs read — MISALIGNED, so MLB streaks were always empty.
- FIX: `rosterLogs` now falls back to aggregating the cached Tank01 box
scores (`tank01:{sport}:boxscore:*`) into per-player multi-game logs,
flattening MLB `_raw` and ordering games most-recent-first by the date
in the gameID. Honest limitation: streaks need 2+ cached games to
surface, so coverage grows as box scores accumulate across prefetch runs.
### Files created
- `web/src/app/api/schedule/[sport]/route.ts`
- `web/src/app/api/gamelines/[sport]/route.ts`
- `web/src/app/api/streaks/[sport]/route.ts`
- `web/src/app/api/hotlist/[sport]/route.ts`
### Files modified
- `src/routes/gameLines.js` (normalizer rewrite + extractBooks)
- `src/services/rosterLogs.js` (box-score aggregation bridge)
- `web/src/components/Slate.tsx` (streaks fetch+match, tab counts)
- `web/src/components/GameCard.tsx` (inline streaks section)
- `web/src/components/LiveHeroProp.tsx` (EXAMPLE label)
- `tests/integration/gameLinesRoute.test.js`, `tests/unit/rosterLogs.test.js`
---
## Previous Phase
SHIP BUILD v24.0 — Connect Everything: wired the all-day intelligence layer into the live UI + killed stale copy (Session 24)
## Session 24 (2026-06-12) — SHIPPED