Document
Seasonal refresh cadence
Reference runbook for keeping the GLAX pipeline, schedule clusters, shift watchlist, and website in sync across the school year.
Orchestrator: scripts/run_seasonal_refresh.py
Related: SCHEDULE_VALIDATION_PLAN.md, SCHEDULE_AD_CHEATSHEET.md, VALIDATION.md
Profiles
| Profile | When to use | Typical runtime |
|---|---|---|
| quick | After roster/stats scrape mid-season; refresh forward 2027 outlook only | ~2–5 min |
| standard | Monthly during season; after major data updates | ~5–15 min |
| full | End of season; before schedule meetings; after adding tier-A finish file | ~30–90 min |
cd glax-pipeline
# Default — pipeline + audits + walk-forward + targeted Neon import
python3 scripts/run_seasonal_refresh.py
# Mid-season forward refresh only
python3 scripts/run_seasonal_refresh.py --profile quick
# End-of-year deep refresh (all seasons + tune + full import)
python3 scripts/run_seasonal_refresh.py --profile full --with-tests
# Preview commands without running
python3 scripts/run_seasonal_refresh.py --profile full --dry-run
Each run writes output/seasonal_refresh_report.json (step pass/fail, timestamps).
Calendar cadence
During season (monthly or after scrape)
- Ensure scraped stats/rosters are current under
stats/androsters/. - Run standard refresh (or quick if only forward ranks changed).
- Review on website:
-
/ranking/2027— board line -/schedule-risk?year=2027— clusters + shift watchlist -/strength/2027— margin diagnostics - Check
output/sanity_report_2025_26.mdfor large anchor vs composite splits.
End of season (May–June)
- Add hand-curated
finish_YYYY.tsv(tier A) for the completed year. - Update
docs/finish_ground_truth_manifest.jsonif ground-truth tier changes. - Promote next season in
seasons_registry.jsonwhen data is ready. - Run full refresh:
bash python3 scripts/run_seasonal_refresh.py --profile full --with-tests - Re-tune shift thresholds if tier-A recall dropped:
bash python3 scripts/tune_shift_detection.py python3 scripts/audit_shift_detection.py --forward - Import to Neon (included in full profile, or manually):
bash cd ../website uv run python scripts/import_data.py --skip-migrations
Before AD schedule meetings (June–July)
- Export and share (already in
output/): -schedule_clusters_2027.csv-schedule_shift_watchlist_2027.csv-schedule_risk_matrix_2026_27.csv - Walk ADs through
/schedule-guideon the live site. - Confirm cluster validation passed:
bash python3 scripts/validate_schedule_clusters.py --forwardTarget: 5 tiers, median size ~8, blowout rate within tiers ≈ 0%.
Annually (off-season)
| Task | Script | Gate |
|---|---|---|
| Walk-forward evidence | run_walk_forward_backtest.py |
Grid CSV updated |
| Feature signal screen | audit_feature_signal.py --subset large |
Spearman signs stable |
| Shift threshold tune | tune_shift_detection.py |
Tier-A recall ≥ 0.7 |
| Cluster method check | validate_schedule_clusters.py |
fixed8 still passes |
| Unit tests | python3 -m unittest discover -s tests |
All green |
What each step does
| Step | Command | Outputs |
|---|---|---|
| pipeline | run_glax_analysis.py --season 2025-26 |
team_strength_*, projected_power_*, schedule_clusters_*, watchlist, risk matrix, run_meta.json |
| batch_pipeline | batch_run_glax_pipeline.py --skip 2025-26 |
All output/backtest_* dirs |
| validate_forward | audit_shift_detection.py --forward |
Refreshed schedule_shift_watchlist_2027.csv |
| walk_forward | run_walk_forward_backtest.py |
backtest_grid_summary.csv, per-fold reports |
| validate_clusters | validate_schedule_clusters.py --forward |
cluster_validation_report.md |
| shift_audit | audit_shift_detection.py --min-tier full |
shift_detection_report.md |
| feature_signal | audit_feature_signal.py |
feature_signal_report.md |
| tune_shifts | tune_shift_detection.py |
Updates shift_detection_config.json |
| import | website/scripts/import_data.py --only … |
Neon tables for live site |
| tests | unittest discover -s tests |
Regression guard |
Website import scope
Quick profile imports: team power/strength, projections, rankings, schedule risk, clusters/watchlist, run_meta.
Standard profile adds: backtest grid, holdout errors, benchmark tiers, markdown docs (cheat sheet), graduation/margin stats.
Full profile runs complete import_data.py (all tables except board edits).
Always set in website/.env:
DATABASE_URL=postgresql://...
SOURCE_DIR=../glax-pipeline
Repeat imports are safe (--skip-migrations after first deploy).
Pre-flight checklist
- [ ]
python3 scripts/glax_season_status.py— current season showsYfor results, rosters, finish - [ ]
finish_2026.tsv(forward anchor) exists and has ~36 MO teams - [ ] Awards CSV refreshed if using award signals:
python3 fetch_awards.py 2026 - [ ]
.env/DATABASE_URLpoints at correct Neon branch - [ ] Board overrides on website preserved (import does not truncate overrides)
Post-flight verification
- [ ]
output/seasonal_refresh_report.json— all steps"ok": true - [ ]
/schedule-risk?year=2027— 5 colored tiers, watchlist populated - [ ]
/backtest— walk-forward grid shows 24 folds; 2024-25 row highlighted - [ ]
/ranking/2027— ranks load without import errors - [ ] Spot-check 2–3 ★ watchlist teams — slot_rank matches CSV
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Single cluster (36 teams) | Old gap=4.5 export | Re-run pipeline; confirm run_meta.cluster_method = fixed8 |
| Empty watchlist | Stale projected_power | Re-run pipeline + audit_shift_detection.py --forward |
Import fails on backtest_grid_folds |
Migration 018 not applied | Run import without --skip-migrations once |
| Walk-forward fold missing | No finish file for next year | Add finish TSV or exclude season in registry |
| Shift recall dropped | New season data pattern | Run tune_shift_detection.py; review tier-A folds only |
Manual one-offs
# Holdout only (2024-25 → 2026)
python3 run_glax_analysis.py --season both
# Single backtest season
python3 scripts/batch_run_glax_pipeline.py --season 2023-24
# Import only schedule artifacts
cd ../website && uv run python scripts/import_data.py \
--only schedule_shift_watchlist backtest_grid --skip-migrations
Revision log
| Date | Notes |
|---|---|
| 2026-06-07 | Initial runbook + run_seasonal_refresh.py orchestrator |