Backfill Historical Seasons
The historical runner composes the existing season operations into one checkpointed, regular-season-only pipeline. Its default range is 2019-20 through 2024-25; 2025-26 remains the current-season build.
Stages
Each season advances through these stages in order:
| Stage | Operation | Durable output |
|---|---|---|
discover |
Fetch and normalize the season schedule | data/catalog/games.parquet |
bios |
Collect player identity, bio, and draft fields | data/catalog/players.parquet, data/curated/player_seasons/ |
fetch |
Fetch final regular-season game feeds | data/raw/, data/manifests/fetches.parquet |
process |
Reconstruct and validate each game | data/processed/, data/quality/ |
compact |
Publish season Parquet partitions | data/curated/ |
rapm |
Train the canonical one-season baselines | data/analytical/, artifacts/models/rapm/ |
Seasons and stages run serially. Individual game work inside the fetch and process stages uses bounded Prefect thread pools.
Run the backfill
Supply a stable run ID so an interrupted invocation can resume the same plan:
uv run nba-backfill-history \
--run-id history-2019-2024 \
--max-workers 2 \
--min-request-interval 1.0 \
--request-interval-jitter 0.25
The minimum request interval is process-wide, including concurrent workers. The defaults use at least one second between requests plus up to 0.25 seconds of jitter. Cached documents are validated and skipped without consuming this interval.
To run a smaller range, repeat --season:
uv run nba-backfill-history \
--season 2019-20 \
--season 2020-21 \
--run-id history-pilot
Resume
The parent manifest is written after every terminal stage:
data/manifests/history_backfill/{run_id}.json
Rerun the exact command with the same --run-id. Completed stages are skipped,
and a failed stage is replaced only after its retry completes. The underlying
fetch, processing, and compaction operations also resume from validated
game-level artifacts.
A run ID is tied to one immutable season and stage plan. Changing that plan requires a new run ID.
Select a stage range
The endpoints are inclusive:
uv run nba-backfill-history \
--season 2019-20 \
--from-stage fetch \
--through-stage compact \
--run-id history-2019-data
Use stage ranges only when all prerequisite outputs already exist. --refresh
forces source refreshes; --force rebuilds processed and curated outputs.
For the historical RAPM panel, where some game reconstructions are
intentionally excluded by quality gates, add --quality-eligible-only while
running the compact through rapm stages. The compaction manifest records
the subset policy and counts; incomplete catalog games are not silently
promoted.
Failure policy
The default runner never promotes a partial season. A fetch stage fails when any final
regular-season game remains unavailable after retries, processing fails when
any game build fails, and compaction requires every selected game to pass its
quality gate. --quality-eligible-only is the sole documented exception: it
publishes only the successful pass/warning subset for historical modeling and
records the exclusion count in its compaction manifest.
Network failures, NBA CDN 408, 425, and server errors receive bounded
retries. A CDN 403 or 429 instead opens the request circuit for at least 15
minutes and prevents queued work from making more requests. Stop the run, allow
the cooldown, perform the one-game smoke test in
Fetch a Season, and rerun the
same run ID. Existing raw files remain valid and are not downloaded again.