Sports Provider
- Canonical MLB schedule, scores, participants, moneyline and totals markets, and latest prices.
- Primary live source for dashboard links and recommendation artifacts.
Baseball
The Baseball app is a model-ops dashboard over canonical MLB facts, sportsbook prices, Retrosheet/FanGraphs feature artifacts, and a Python predictor. This page answers the concrete questions behind a pick: what data was loaded, which features matter, what the latest evaluation has taught us, and what proves the pipeline is healthy.
Sources
Baseball uses live canonical facts for today and offline artifacts for historical context. The model should only be trusted when the source and artifact coverage are visible.
Pipeline
Each run moves through the same steps, whether it is triggered by cron, a local smoke command, or a manual production refresh.
Sports Provider is the preferred live feed. It normalizes MLB Stats schedule data and source-labeled sportsbook, Kalshi, and Polymarket prices into canonical games, participants, markets, and price snapshots. Projections prefer a fresh sportsbook quote, then use a fresh executable Kalshi or Polymarket ask when necessary; MLB Stats remains the schedule fallback.
The runner asks for a date window, keeps scheduled games with usable h2h prices, maps MLB teams to Retrosheet team codes, and carries probable pitcher MLBAM IDs into the Retrosheet/Chadwick/FanGraphs identity join.
The offline pipeline exports Retrosheet play-by-play into `plays.jsonl`, rolls it into `games_final.parquet` and `player_stats.parquet`, then enriches with lineups, starters, bullpen usage, Statcast, park, pitch-mix, and odds artifacts.
Hosted runs sync the required model bundle from S3 under `baseball/model-artifacts/current`: the pickled game model, `games_final.parquet`, and `player_stats.parquet`. Optional artifacts are counted separately.
The Python predictor returns home/away win probability, projected runs, calibration method, and defaulting flags. Moneylines use the calibrated win probability with the normal Kelly policy. Totals use a Poisson distribution centered on projected runs to emit over/under/push probabilities. Qualifying moneylines and totals persist capped hypothetical Kelly stakes in one paper ledger for outcome, ROI, and CLV tracking.
The run writes a normalized projection artifact to `baseball/projections/latest.json` with moneyline and totals projections, tracking decisions, canonical event/market links, model metadata, feature snapshot refs, and a quality gate summary.
Features
The model is a Retrosheet LightGBM/Poisson blend. Its best signals come from team form, starter quality, lineup strength, bullpen fatigue, park context, and Statcast/pitch-type deltas.
Rolling runs scored/allowed, win rate, streaks, rest days, pythagorean luck, park run factor, elevation, roof/dome flags, and weather when available.
Starter ERA/WHIP/K9/BB9/HR9, recent form, batters faced, fastball velocity, whiff/chase rates, pitch-mix usage, and pitch-type value features.
Lineup BA/OBP/SLG/K%, platoon aggregates, bench usage, and Statcast hitting deltas such as exit velocity, hard-hit rate, barrel rate, and xwOBA.
Three-day workload, seven-day run prevention, closer/setup/bulk/long-relief usage, appearance counts, and recent rest proxies.
Live American odds are converted to no-vig probabilities. They do not make a pick by themselves; they define edge, expected value per dollar, and stake size.
Starter-ID coverage, optional artifact coverage, calibration fallback, clipped probabilities, and defaulted feature pressure are first-class serving fields.
Learnings
The parser and feature pipeline are useful, but the betting question is still model-vs-market. These are the concrete results worth carrying forward.
The imported Retrosheet parser reports 100% parse success on 2.69M plays across 390 event files. Score validation covers 30,054 games at 97.0%; the documented misses are missing expected game-log entries, not score mismatches.
The imported model-run manifest records AUC 0.642, Brier 0.2308, and market correlation 0.494. Older clean 2022 holdout notes show AUC about 0.599 and Brier about 0.241, so fresh evaluation matters after each feature-schema change.
Project notes repeatedly call out lineup exit-velocity gaps plus starter fastball velocity, whiff rate, and chase rate as top feature-importance signals once Statcast and pitch-type features are joined.
A 2022 overlapping-sample snapshot improved AUC from 0.598 to 0.615 and Brier from 0.2417 to 0.2383 after pitch-type matchup features were added.
The first rolling-origin totals benchmark produced positive threshold ROI over 13,859 games from 2015–2021, but the model trailed the closing market on Brier score and log loss. True opener ingestion, strict nested early stopping, and live CLV remain required before real-money promotion.
The pipeline now treats recent relief workload and role-based bullpen usage as material features, but the docs still flag better days-rest and workload validation as high priority.
Health
A healthy run is traceable from source facts to feature artifacts, model output, policy decisions, and dashboard status.
`pnpm --filter baseball retrosheet:pipeline:dry-run` verifies the offline Retrosheet stage graph before running expensive parser/model work.
The app exposes root pnpm wrappers for Rust fmt, clippy, workspace tests, Python tests, dry-run pipeline checks, and Sports Provider game-fact exports.
Declared early projections warn instead of failing and remain information-only. During schedule gaps they may use critical form snapshots up to seven days old; missing or older critical inputs, unexplained starter gaps, thin artifact coverage, saturation, and collapsed forecasts still fail publication.
`pnpm --filter baseball model-vs-market:gate` compares offline model probabilities against Sports Provider closing no-vig price history and refuses to run when required artifacts are missing.
The current local feature/model manifests record source environment, feature schema, row count, source versions, model version, metrics, canonical game coverage, and canonical market coverage.
The dashboard and recommendations API read normalized projection artifacts. Page load does not rebuild Python predictions, which keeps UI behavior traceable to one generated run.
Sanity
These checks are designed to make weak data visible before it becomes a confident-looking recommendation.
Probable pitcher MLBAM IDs are resolved to Retrosheet IDs before feature lookup. Before starters are named, the board publishes an explicitly labeled schedule-only projection with default starter features and disables staking; unexplained identity gaps still fail the quality gate.
Every game identifies whether it uses schedule-only inputs, probable starters with neutral lineup features, or both confirmed lineups. Projected rosters can still be shown for context, but the model does not treat them as confirmed inputs. Early stages are useful for watching the forecast evolve, but only the confirmed-lineup stage can produce a stake.
The run reports how many optional artifacts are available. Missing park, weather, pitch-mix, or lineup-state artifacts do not crash the run, but they reduce confidence and show up in the UI.
If isotonic calibration returns a saturated 0% or 100% probability, the predictor falls back to Platt calibration or the raw model probability before serving a result.
Served live probabilities are clipped to configurable bounds, defaulting to 2% and 98%, so recommendations never display artificial certainty.
The dashboard degrades when the projection artifact is older than 36 hours, when Sports Provider falls back, or when the model-quality gate fails.
The board is intentionally model-vs-market. A pick appears because model probability clears the no-vig market by policy, not because the model probability looks high by itself.