← All findingssource · memory/project_sds_is_the_data_layer.md
Verified 2026-05-21 after the user (again, rightly) snapped: "so why the fuck do u keep mentioning other services, SDS should be our go to."
The actual service topology
SDS is the SoT for everything in the "data" domain:
| Domain | Owned by | SDS routes |
|---|---|---|
| Player stats (season/rolling/recent) | SDS | /{league}/stats/player/:id, /{league}/stats/player/:id/games |
| Team stats | SDS | /{league}/stats/team/:id, /{league}/advanced/team/:id, /{league}/defense/team/:id |
| Player metadata (id/name/team/position) | SDS | /{league}/player/:id, /{league}/players/team/:id, /{league}/players/search, /{league}/players/batch, /{league}/players/all |
| Schedule | SDS | /{league}/games/date/:date, /{league}/games/:id, /{league}/schedule/{team,season,live,upcoming} |
| Lineups | SDS | /{league}/lineups/:game_id, /{league}/lineups/date/:date, /{league}/lineups/player/:id/status |
| Injuries | SDS | /{league}/injuries/date/:date, /{league}/injuries/game/:id, /{league}/injuries/player/:id/history |
| Boxscore (final) | SDS | /{league}/games/:id/boxscore |
| History (player career, vs-opponent, series) | SDS | /{league}/history/player/:id/{career,vs/:opp,series_history}, /{league}/history/team/:id/vs/:opp |
| Standings + rest profile | SDS | /{league}/standings, /{league}/standings/team/:id, /{league}/rest/team/:id |
| Scout data (Synergy play-types, shot zones) | SDS | /{league}/scout/player/:id/{synergy,shotzones} |
| Prop hitrates / metrics | SDS | /{league}/props/player/:id/{hitrate,metrics} |
Legitimately NOT SDS (different domain, won't be consolidated):
| Domain | Service |
|---|---|
| In-game live state (clock/score/period) | live-service |
| Play-by-play events | pbp-service |
| Market data (sportsbook prices) | odds-service |
| Model outputs (slate projections q10-q90) | projections-engine |
| ML model predictions | ml-scout-service |
| External intel feed | xintel |
What's still legacy in data-hydrator
Per call audit on 2026-05-21, data-hydrator's internal/fetcher/client.go
defines clients for: SportData, Games, Projections, MLScout, Players, Live, PBP, Odds, Matchup, Lineup, XIntel, Injury. Five of those (Games, Players, Lineup, Matchup, Injury) are LEGACY paths — SDS has destination routes for
each, but ~18 call sites in internal/fetcher/assembler.go and
internal/handlers/scout.go haven't been cut over.
Concrete migration backlog (18 calls):
Games(9 calls) → SDS/{league}/games,/standings,/schedule,/restPlayers(4 calls) → see project_players_service_migrationLineup(2 calls) → SDS/{league}/lineups/:game_idMatchup(2 calls) → SDS/{league}/history/player/:id/vs/:oppInjury(1 call) → SDS/{league}/injuries/{date,game}
After all 18 cut over, the 5 legacy services can be decommissioned. data-hydrator ends up with: SDS (everything stat/metadata), Live, PBP, Odds, Projections, MLScout, XIntel. Seven clients, not twelve.
How to talk about this in future sessions
When asked "what owns X data" or "where does X come from":
- If X is stats / metadata / schedule / lineups / injuries / history / scout-data → answer SDS. Don't say "players-service has it" or "lineup-service does that." Those are un-decommissioned code paths, not independent authorities.
- If X is live state / pbp / odds / model outputs → name the specific service (live, pbp, odds, projections-engine, ml-scout).
- If data-hydrator's code still calls a legacy service for something SDS owns, that's a known migration backlog, not "two services own this." Call it out as a backlog item, don't muddy the architecture.
See also: project_hydrator_stats_to_sds (the migration that DID finish for stats), project_players_service_migration (in-progress for metadata), project_wnba_sds_empty (the gap that started this whole thread), feedback_verify_before_extend (the discipline that should have caught this from the first answer).