← All findingssource · memory/project_surprise_wnba.md
The Surprise Desk (players who beat/missed projection by ±σ) now works for WNBA as well as NBA, and the API is hardened. Shipped to nightly-hoops main eafdd44 (2026-06-20, auto-deploys).
Routes: digest /surprise (NBA) + /wnba/surprise; intel /surprise-intel (NBA) + /wnba/surprise-intel. Shared client components src/components/surprise/SurpriseFeed.tsx + src/components/surprise-intel/SurpriseIntelFeed.tsx take a league prop; the four page.tsx are thin wrappers; WNBA routes have their own metadata layout.tsx. Cache keys, API query, and URL base path are all league-scoped.
API: /api/surprise?league=nba|wnba + /api/surprise-intel/explain?league=. League-aware snapshot adapter in route.ts (toBoxscoreGame(snap, league)): NBA reads typed snap.game/snap.live_boxscore; WNBA reads snap.raw_sections.game.game + snap.raw_sections.boxscore.players (stats NESTED under .stats; season-avg keys identical to NBA; team abbrev taken straight from ...home_team.abbrev). Verified WNBA 2026-06-17 → 6 games / 98 players / 10 notable; intel SSE streams.
Lessons (reusable):
- The bulk
/{league}/snapshot/date/{date}endpoint is SLOW (~30-40s — assembles every game serially upstream). Do NOT use it for a synchronous route; use per-game parallel/{league}/snapshot/{id}fetches (warm ~1-2s, cold ~8s each) with a per-game timeout + graceful partials. This was the actual "hardening." - [internal detail removed]
- WNBA boxscore
stats.minutesis a float (no MM:SS parsing). Reach WNBA snapshots via/api/v1/wnba/snapshot/{id}— the bare/api/v1/snapshot/{id}is NBA-default (games-service 404 for WNBA) — see project_data_hydrator_deploy_stale.
Polish DONE (nightly-hoops 44d03bf, 2026-06-20): WNBA team colors — scoped .league-wnba .team-* accents in globals.css (the feeds set league-wnba on their root div; NBA pages unaffected). σ recalibrated — SURPRISE_SIGMA per league (nba=6, wnba=5.5), measured from real data (N≈258 WNBA player-games, std≈5.5, mean≈0); baselines stay shared. Also fixed /wnba/picks bare-route 404 (added index redirect, 85418c3).
Stale-snapshot self-heal (ce3ca03): data-hydrator caches snapshots and serves them STALE after a game finishes if they were assembled while it was scheduled/live (no final box score) — that's why WNBA 6/19 + 6/20 rendered empty despite final games (their snapshots were cached during the projections debugging). The surprise route now detects a final game with an empty box score and forces one ?refresh=true reassembly (self-heals; one-time per stale game). One-off heal = curl '<DH>/wnba/snapshot/{id}?refresh=true'. Also fixed a /nba/results prerender crash (getBestBets can return null top_hits/closest_misses → normalize to []).
Still out of scope: surprise-intel deep-dive stays NBA-only (hits stats.nba.com + deprecated stats/matchup/lineup services); the patterns route (deprecated stats-service). Both degrade gracefully for WNBA.