MLB Player Props Data Audit — Council Ruling
Date: 2026-04-01
Process: Full 5-phase council (Advisory → Anonymization → Peer Review → Chairman Synthesis → Boss Ruling)
Advisors: Opus, Sonnet, Gemini 3.1 Pro, Grok 4.20 Reasoning, gpt-oss-120b
Winner: gpt-oss (3 of 5 peer review votes)
Status: PENDING BOSS RULING on open questions
COUNCIL SUMMARY
Where Advisors Agreed
- Game-log data is the #1 missing layer — per-game stats for every pitcher and batter from MLB Stats API
- Statcast data essential — exit velocity, barrel rate, launch angle, sprint speed from Baseball Savant
- EWMA with prop-specific decay rates — different spans for different stat types (K=8 games, HR=20, SB=25)
- 8 separate edge scanners — one per prop type with appropriate distribution
- FanDuel alt lines as sharp anchor for player prop pricing
- Platoon splits (L/R) critical at individual batter level
- Catcher framing and pop time data needed for pitcher K props and SB props
- Park factors at prop level (HR factor hand-specific, K factor by park)
- 3-season backfill recommended for historical data
- Cross-prop correlation tracking needed (K-over + Outs-over = ~0.6 correlation)
Where Advisors Disagreed
- Database engine: gpt-oss recommended PostgreSQL + TimescaleDB, Sonnet specified exact SQLite schemas. Council verdict: SQLite WAL for current scale.
- Strikeouts distribution: Gemini proposed Conway-Maxwell-Poisson, Sonnet used Negative Binomial. Council verdict: NB is sufficient and simpler — COM-Poisson adds complexity without clear benefit.
- Total bases distribution: Gemini used Zero-Inflated NB, Grok used multinomial per-PA outcomes. Council verdict: Multinomial per-PA is more correct (each at-bat produces discrete base outcomes).
- Architecture scope: gpt-oss built full production system (ETL, caching, Celery workers, React dashboard). Others focused on data/modeling only. Council verdict: Hybrid — gpt-oss architecture with Sonnet's distribution choices and EWMA specifics.
Strongest Arguments (from peer review)
gpt-oss wins with the only complete full-stack architecture:
- 13-table relational schema with clear relationships
- Nightly ETL plan with extract/transform/load steps
- 8 independent edge scanner workers
- Dashboard tech stack (FastAPI + React + WebSockets)
- Prop-history calibration loop (feedback between predictions and outcomes)
- Clear mapping of which data lives where and how it's consumed
Sonnet runner-up with deepest analytical specifics:
- Real API endpoints with exact query parameters and JSON field names
- Prop-specific EWMA decay rationale (span 8 for Ks, 20 for HR, 25 for SB)
- Cross-prop correlation table with specific coefficients and sizing adjustments
- Fully populated matchup card templates ready for developer handoff
Biggest Blind Spot
Opus: Response appeared truncated/incomplete in peer review. When complete, focused heavily on matchup card formatting over data architecture and pipeline design.
What Everyone Missed (from peer reviews)
- Player identity mapping system — MLB ID, FanGraphs ID, Savant ID, Kalshi ID, retail betting IDs are all different. Need canonical
player_master table with ID cross-references, alias mapping, and trade/call-up handling.
- Umpire home plate assignment — Strike zone changes every night. Pitcher K prop and BB prop are massively impacted by umpire zone size. Need daily umpire-assignment pipeline.
- Retractable roof status — 6 MLB stadiums have retractable roofs. Open vs closed drastically changes HR/TB probabilities. NWS API won't tell you roof status — need separate data feed.
- Real-time odds ingestion — Polling FanDuel/Kalshi via REST every few minutes is too slow. Need streaming odds architecture for edge detection.
- Manager hook probability — Pitcher outs/K totals depend on when manager pulls the pitcher. Need historical hook-point model per manager.
BUILD PLAN
Phase 1: Player Master & Game Logs
mlb_player_master:
- player_id (canonical), mlb_id, fangraphs_id, savant_id, kalshi_id
- player_name, team, position, bats (L/R/S), throws (L/R)
- active (boolean), roster_status
- trade_history (JSON — team changes with dates)
mlb_pitcher_game_logs:
- pitcher_id, date, game_id, opponent, home_away
- strikeouts, outs_recorded, innings_pitched, pitches_thrown, batters_faced
- k_per_9, k_rate, swinging_strike_rate, called_strike_rate, chase_rate
- pitch_mix_pct (JSON: FB/SL/CH/CB/CUT percentages)
- vs_lhb_k_rate, vs_rhb_k_rate
- hook_inning (inning when pulled), hook_pitch_count
- Source: MLB Stats API + Baseball Savant, 3-season backfill
mlb_batter_game_logs:
- batter_id, date, game_id, opponent_sp_id, opponent_sp_hand
- plate_appearances, at_bats, hits, doubles, triples, home_runs
- rbis, runs, stolen_bases, caught_stealing, walks, strikeouts
- total_bases, batting_order_position
- exit_velocity_avg, max_exit_velocity, barrel_rate, hard_hit_rate, launch_angle_avg
- sprint_speed
- Source: MLB Stats API + Baseball Savant, 3-season backfill
Phase 2: Baselines & EWMA
mlb_pitcher_prop_baselines:
- pitcher_id, date, stat_type (strikeouts/outs_recorded)
- last_3, last_5, last_10, season_avg
- ewma_fast (span=8 for Ks — stabilizes quickly)
- ewma_standard (span=15)
- ewma_slow (span=25)
- vs_lhb_rate, vs_rhb_rate, home_rate, away_rate
- early_season_flag (fewer than 5 starts)
mlb_batter_prop_baselines:
- batter_id, date, stat_type (hits/hr/rbi/runs/tb/sb)
- last_5, last_10, last_20, season_avg
- ewma_fast (HR: span=20, SB: span=25, hits: span=12)
- ewma_standard, ewma_slow
- vs_lhp_rate, vs_rhp_rate
- woba, xwoba, iso_power, barrel_rate_ewma
Phase 3: Matchup Context
mlb_prop_matchup_context:
- player_id, game_id, date, prop_type
- opponent_sp_id, opponent_sp_hand (for batters)
- opp_team_k_rate, opp_team_contact_rate (for pitchers)
- sp_pitch_mix_vs_hand (JSON — for batters)
- park_factor_for_prop (K factor, HR factor by hand, etc.)
- weather_adjustment (wind, temp for HR/TB)
- umpire_id, umpire_k_zone_adj
- roof_status (for retractable roof parks)
- catcher_framing_runs (for pitcher K props)
- catcher_pop_time (for SB props)
- lineup_position, projected_plate_appearances
Phase 4: Distribution Models
| Prop |
Distribution |
EWMA Span |
Key Parameters |
| Pitcher Strikeouts |
Negative Binomial |
8 games |
μ from K/9 × proj_IP × opp_K_rate × ump_zone; k from variance |
| Pitcher Outs |
Truncated Normal |
12 games |
μ from avg outs; σ from variance; hook probability model |
| Batter Hits |
Beta-Binomial |
12 games |
α, β from hit rate history; n from projected PA × platoon |
| Batter HRs |
Zero-Inflated Poisson |
20 games |
λ from HR/PA × PA × park_HR × weather; π from ~85% zero |
| Batter RBIs |
Monte Carlo (10K) |
15 games |
Lineup simulation with baserunner states |
| Batter Total Bases |
Multinomial per PA |
15 games |
P(1B), P(2B), P(3B), P(HR) summed over projected PAs |
| Batter Runs |
Monte Carlo (10K) |
15 games |
Lineup simulation — depends on subsequent batters |
| Stolen Bases |
Bernoulli per opp |
25 games |
P(attempt) × P(success) × opportunities; catcher pop time |
Phase 5: Edge Scanners (8)
Common engine: FanDuel alt lines → de-vig → fit distribution → compare Kalshi → min 4c edge after 7% fee
Cross-prop correlation rules:
- Pitcher K-over + Pitcher Outs-over: ρ ≈ 0.6 → reduce combined position 20%
- Batter Hits-over + TB-over: ρ ≈ 0.7 → reduce combined position 25%
- Batter HR-over + RBI-over: ρ ≈ 0.4 → reduce combined position 15%
- Max exposure per player across all props: 5% of daily bankroll
Phase 6: Dashboard
- Prop board: All today's player props with edge counts per prop type
- Pitcher K center: All SPs with K edges, K trends, umpire zones, catcher framing
- Batter hub: Batter cards with all prop edges, Statcast viz, platoon splits
- Lineup monitor: Confirmed vs projected, batting order changes
- Correlation matrix: Visual showing cross-prop positions and aggregate exposure
- Calibration: Rolling Brier scores per prop type, model drift detection
- P&L: By prop type, by edge bucket, by player
OPEN QUESTIONS FOR BOSS RULING
3-season backfill: Council recommends downloading 3 full seasons of game logs (2023-2025) for every pitcher and batter. This is ~150K pitcher games + ~500K batter games. Confirm?
Statcast data depth: Full pitch-by-pitch data is massive. Should we collect summary Statcast (per-game exit velo, barrel rate) or full pitch-level data?
Player ID mapping: Need canonical player_master table mapping MLB, FanGraphs, Savant, and Kalshi IDs. Build manually or find existing crosswalk?
Umpire data pipeline: Should we build daily umpire assignment scraper now, or defer to later phase?
Manager hook model: Should we build a logistic regression model predicting when managers pull pitchers (affects outs/K totals)? Or use historical averages?
Monte Carlo expense: RBI and Runs props need full game simulation (10K runs per game). Build now or defer?
COUNCIL METADATA
| Detail |
Value |
| Council date |
2026-04-01 |
| Advisory responses |
5 (all completed) |
| Peer reviews |
5 (all completed) |
| Strongest advisor |
gpt-oss (3/5 votes) |
| Runner-up |
Sonnet (2/5 votes) |
| Biggest blind spot |
Opus (truncated response) |
| Full council data |
/home/ubuntu/edgeclaw/data/councils/2026-04-01/mlb-player-props-data-audit/ |
Source: ~/edgeclaw/results/panel-results/mlb-player-props-data-audit-ruling.md