Tighten provider normalization contract and fallback semantics

This commit is contained in:
Alfredo Di Stasio
2026-03-10 16:47:39 +01:00
parent 2252821daf
commit e0e75cfb0c
11 changed files with 340 additions and 59 deletions

View File

@ -0,0 +1,36 @@
# Provider Normalization Contract
HoopScout ingestion consumes provider data through a normalized, provider-agnostic contract defined in:
- `apps/providers/contracts.py`
- `apps/providers/interfaces.py`
## Contract scope
Adapters must return only normalized entities used by ingestion:
- `players`
- `competitions`
- `teams`
- `seasons`
- `player_stats`
- `player_careers`
- optional `cursor`
Raw provider response structures must remain inside `apps/providers` (client/adapter/mapping code).
`ExternalMapping.raw_payload` is used only for diagnostics and troubleshooting.
## Current balldontlie assumptions (MVP)
- Source scope is NBA-centric.
- Competition is normalized as a single NBA competition (`competition-nba`).
- Team country is not reliably available in source payloads and is normalized to `null`.
- Player nationality/birth/physical details are not available in player list payloads and are normalized to `null` (except fields explicitly present).
- Configured seasons are normalized from `PROVIDER_BALLDONTLIE_SEASONS`; the highest configured season is marked `is_current=true`.
- Advanced metrics (`usage_rate`, `true_shooting_pct`, `player_efficiency_rating`) are currently unavailable from this source path and normalized to `null`.
## Domain rules vs provider assumptions
- Domain rules live in ingestion/domain services and models.
- Provider assumptions live only in adapter/mapping modules.
- New providers must map to the same normalized contract and should not require ingestion logic changes.