Audit the WNBA Oracle training corpus and model artifact. Verifies that the backups branch is current, the live model artifact SHA matches STATUS.md, and the game-log corpus covers the expected date range. Use before a training run, before promoting a new model artifact, or after a production incident to verify corpus integrity. Authoritative stores: Postgres (wnba_game_logs), GitHub backups branch, STATUS.md (artifact SHA pin).
Install
npx skillscat add cheeksmagunda/sports/wnba-oracle-corpus-status Install via the SkillsCat registry.
What is the corpus?
The corpus has two separate grains:
- wnba_game_logs (Postgres): per-player per-game ground truth for
minutes, box-score stats, and real_score. Written by dayclose and
backfill. This is the label corpus for training. - player_pool / player_features (Postgres): per-player per-slate
enrichment written by job1/job1-late. This is the feature corpus.
These grains have different identifiers (game_date vs slate_date,
player_id vs nba_api player identity). Do not join them without the
WNBA-owned identity map (ingest/identity.py).
Step 1: Check corpus coverage in Postgres
uv run --frozen --package wnba-oracle python -c "
from wnba_oracle.db.engine import get_engine
from sqlalchemy import text
engine = get_engine()
with engine.connect() as conn:
# Game-log coverage
row = conn.execute(text(
'''SELECT MIN(game_date)::text AS earliest,
MAX(game_date)::text AS latest,
COUNT(DISTINCT game_date) AS n_game_dates,
COUNT(DISTINCT player_id) AS n_players,
COUNT(*) AS n_rows
FROM wnba_game_logs'''
)).fetchone()
print('Game log corpus:')
print(f' Dates: {row.earliest} to {row.latest} ({row.n_game_dates} game dates)')
print(f' Players: {row.n_players}, Rows: {row.n_rows}')
# Slate label coverage
row2 = conn.execute(text(
'''SELECT MIN(slate_date)::text AS earliest,
MAX(slate_date)::text AS latest,
COUNT(DISTINCT slate_date) AS n_slates,
COUNT(CASE WHEN real_score IS NOT NULL THEN 1 END) AS n_labeled
FROM slate_labels'''
)).fetchone()
print('Slate labels:')
print(f' Slates: {row2.earliest} to {row2.latest} ({row2.n_slates} total, {row2.n_labeled} labeled)')
"Step 2: Verify model artifact identity
Compare two artifacts by trained-model content:
# From wnba-oracle/
uv run --frozen --package wnba-oracle python scripts/compare_artifacts.py \
models/<active-artifact>.pkl models/<candidate-artifact>.pklThe script compares the canonical model serialization and baseline parameters.
Verify the active artifact SHA separately against the live deployment and the
current STATUS.md snapshot.
Correct path: track the rotation in an issue and PR, then update STATUS.md
with the new live artifact SHA after deployment verification.
Step 3: Check the GitHub backups branch
The backups branch holds JSON exports of the corpus. This is non-canonical
(Postgres is canonical), but it is the off-site recovery path for training.
# List recent backup objects on the backups branch
git fetch origin backups
git log origin/backups --oneline -10If the last backup is more than 7 days old, the GitHub Actions corpus backup
workflow may have failed. Check the Actions run log for corpus-backup.
To trigger a manual backup:
gh workflow run corpus-backup.yml --ref mainStep 4: Snapshot training inputs for a new model run
Before training, snapshot the feature and label corpus from Postgres:
# From wnba-oracle/
uv run --frozen --package wnba-oracle python scripts/snapshot_training_inputs.py \
--output runs/training-snapshot-$(date +%Y%m%d)/The snapshot writes to runs/ (gitignored). Record the snapshot date and
Postgres row counts in the training PR, not in STATUS.md.
Step 5: Run the training pipeline (offline, not on a game day)
Training uses the snapshotted corpus, not a live Postgres connection:
# From wnba-oracle/ -- only run when no live contest is active
uv run --frozen --package wnba-oracle python -m wnba_oracle.train.cli \
--corpus runs/training-snapshot-<date>/ \
--output models/After training, verify the new artifact with:
uv run --frozen --package wnba-oracle python scripts/validate_minutes_model.py \
--artifact models/<new-artifact>.pklIf validation passes, open a linked PR. Update STATUS.md only when the new
artifact becomes the verified live artifact. The PR must include amake test-contract run from wnba-oracle/.
Constraints
- The model artifact SHA in
STATUS.mdis the canonical identity. TheWNBA_ORACLE_MODEL_ARTIFACT_SHARailway env var must match it on every
production service. wnba_game_logsandplayer_pool/player_featureshave different grains.
Do not join them withoutingest/identity.py.- Training must not run on a game-day job2 Railway service. Use a local or
Codespace environment with a Postgres connection to the production DB (read
operations only during training data export). - Local
models/andruns/are non-canonical. The artifact identity is the
SHA, not the filename.