← All findingssource · memory/project_wnba_projections_playbook.md
STATUS 2026-05-31 — ESSENTIALLY DONE (this playbook's estimate was wrong)
The ONLY real gap: data-hydrator never called attachProjections on the WNBA path. assembleMultiSport did hydrateMultiSportPlayerBundles → attachDiagnostic but skipped projections (it was NBA-only at assembleNBA:602), so WNBA snapshots had Projection=nil → diagnostic degraded to L10 recency. THE WHOLE reason WNBA props were "recency-only, 1 lean."
FIX (branch wnba-attach-projections, data-hydrator, UNCOMMITTED, builds/tests pass, NOT deployed): (1) added a.attachProjections(ctx, snap, ref, addError) in assembleMultiSport before attachDiagnostic; (2) added snap.Lineups team-id fallback in attachProjections (snap.Game is nil on multi-sport path). Verified the join keys align: slate team_ids == snapshot lineup team_ids (slug resolves), 17/21 slate players overlap the snapshot incl. all 8 key market players. Once deployed, WNBA snapshots carry proj_q and the diagnostic uses the q50 baseline. Cold-start (Bayesian/NumPyro) was CUT from v1 and is NOT needed to ship — it degrades gracefully (no projection → recency, same as before). Empirical-Bayes ridge shrinkage is the v2 quality step, gated on CLV measurement. REMAINING: commit + deploy data-hydrator; optionally backfill WNBA beneficiaries.parquet; fix odds-service WNBA player_id (name-matcher ~95%).
What this would buy
Today data-hydrator's WNBA snapshot has baseline_q50 = 0 for every
WNBA player because projections-engine is NBA-only. Line_edges still
compute from L10 recency (graceful degradation), so picks ARE
actionable — but the model's posterior-adjusted projection field
stays empty, missing the matchup + market layer projections-engine
adds on top of raw recency.
The upside is marginal but real: tighter quantile bands + a model baseline that incorporates pace + opponent-defense + market signals.
Why this isn't a tonight ship
- Phase 9 reference: "WNBA gets ported as Phase 9 once NBA is shipped and proven."
- Phase 11: "Add NumPyro Bayesian cold-start (most WNBA players have < 50 games)" — DIFFERENT MODEL ARCHITECTURE from NBA's pure quantile-regression approach. WNBA needs Bayesian shrinkage because the sample size per player is small.
Multi-day work, not a clean one-shot.
What's already in place that helps
projections/orchestrate/daily.pyacceptsleague=param throughout the run() flow.projections/ingest/players.pyfetch_all_rosters/ingest_all_rostersacceptleague="nba"parameter; passing "wnba" would route to the same SDS endpoint with the wnba prefix.projections/sports/directory hasnba/subdir already, implyingsports/wnba/would slot in cleanly.- SDS WNBA player_stats endpoint is verified live (b2dba69 unblocks reachability; player 204319 returns 3 real 2025 games). The data source is ready.
- data-hydrator's WNBA snapshot path (f114e9b + 87befcc) populates snap.Players from SDS — the projections would be consumed alongside.
Concrete work breakdown (sequenced)
Step 1 — verify ingest reaches WNBA games (~2 hrs)
- Run
python -m projections.ingest.games --league wnba --date 2026-05-21(or equivalent). Inspect whether games + boxscores + rosters land. - Files to verify:
projections/ingest/{games,boxscores,players}.pyfor WNBA-specific quirks (different game_id format, fewer teams).
Step 2 — feature engineering for WNBA (~1 day)
projections/features/— feature builders are stat-name-based; basketball stats map 1:1 between NBA and WNBA. Should mostly work unchanged. Verify season_segment + role_anchor features handle the sparser WNBA history (4 months vs 6).
Step 3 — model choice (~1-2 days)
- Per PLAN.md Phase 11: WNBA needs Bayesian cold-start because most WNBA players have <50 games of history (the same window NBA models rely on for stable quantile estimation).
- Options: (a) Train NBA models on WNBA data (might overfit / underperform). (b) Bayesian shrinkage toward league averages until N>=K (PLAN.md's recommended approach). (c) Finetune NBA models on WNBA data + position-aware prior.
- Recommend (b) — aligns with PLAN.md's explicit guidance.
Step 4 — slate orchestration (~half day)
-
projections/orchestrate/daily.py— addleague="wnba"invocation path. Mostly parameter-threading since daily.run already accepts league. Cron schedule needs WNBA day (different timezone for the season-active months). -
projections/serve/slate_store.py— verify slates land underslates/{date}/{slug}/with WNBA-shaped slugs. Probably no change.
Step 6 — data-hydrator integration (~half day)
- [internal detail removed]
Step 7 — backtest + ship (~1 day)
- Compare WNBA model predictions vs actual outcomes for the 2025 season. Hit-rate threshold like NBA had.
- [internal detail removed]
Total estimate: 4-6 focused days, single owner.
What's blocking right now (none)
After tonight's work, the WNBA reachability + bundle wiring is complete. The projections port is a clean self-contained workstream in projections-engine that doesn't depend on further data-hydrator or sport-agents changes.
See also
- project_wnba_lockdown_live (data-layer end-to-end)
- project_wnba_sport_agents_playbook (picker side — closed)
- project_methodology_lockdown (the methodology being projected)
- projections-engine/PLAN.md (the authoritative repo roadmap)