WHAT'S NEW
Still being built.
Every release that changed what you see or how a number is produced, newest first. The betting record itself is never rewritten by any of them — a play locks at its posted price when it fires and only the grader touches it again.
Currently on v2.7.0
- v2.7.0
Founding members: the first 25 accounts get 50% off any plan at launch
- The first 25 free accounts are founding members. When paid plans launch, each gets 50% off any plan for as long as that subscription stays active
- Nothing to redeem: the discount is applied automatically at checkout, and your account page shows your founding-member number
- The graded track record is not part of any paid plan. Every staked play stays on the free public ledger, win or lose
- About, the Terms, the account page and sign-in now say the same thing about what becomes paid, and no sport is promised first
- The legal pages use the same header as the rest of the site, and the About page reads each sport's status from the ledger
- v2.6.0
New MLB hitter and strikeout projections, and a rebuilt Matchup Score
- Starting pitchers' projected strikeouts and batters faced now come from our strikeout model, which has been more accurate than the old projections on this season's starts. Innings and pitch counts are unchanged
- Batter strikeout props are on the Props board (new Strikeouts tab), and home-run props now show every book posting an Over
- Every hitter projection on the Leaderboard, Props and Matchups tabs now comes from our new hitter model: plate appearances, hits, total bases, home runs, runs, RBI and strikeouts
- The Matchup Score is rebuilt on it: where tonight's projected total bases rank against every start this season, 0-100. Click a pill for hits, power, runs, RBI and strikeout risk
- On this season's games the new score separates hitters who go on to get a hit, two-plus total bases or a home run more cleanly than the old one
- Projections are built each morning on the likely lineups and rebuilt once the real lineups post. The separate Score column is gone; Matchup and LII sit side by side
- v2.5.0
Accounts are open — free, and here is the plan for what becomes paid
- Sign in with a one-time email link. No password to set, forget or leak; creating an account is free and takes one click from the email
- Everything on the site stays readable today. Paid plans will follow for the tools; the graded track record stays free (wording updated 2026-09-25, see 2.7.0)
- You will be told before anything you read becomes paid, and before any charge: the price, the billing period, how it renews and how to cancel are all shown first
- Your account holds your email address (plus the name and picture link Google shares, if you sign in with Google) and nothing else. Delete it from the account page at any time and it is gone, not flagged
- v2.4.0
Props boards show where a line OPENED, and the NFL card is one day at a time
- New Open column on the MLB and NFL props boards, beside the line (now labelled Current) — the number a market was first seen at, with a signed delta so you can see which way it has moved and by how much
- An open is only shown when one was actually observed: markets already posted before this shipped read "—", which means no open on record, NOT that the line has not moved
- NFL Best Bets is now a single day rather than a Tuesday-to-Monday week, so the graded Thursday-night plays no longer sit on the same card as the open Sunday ones — the multi-day view lives on History
- Hand-entered plays now always appear on the MLB card; home-run bets were being written, graded and counted in the ledger while staying invisible on the board
- v2.3.0
Locked-In Index rebalanced to v3 — the breakdown describes the score again
- Same inputs as v2, reweighted .65/.08/.27 → .45/.20/.35 so Contact Quality and Plate Discipline visibly move the number instead of riding along
- Power now drives 58% of the headline instead of 84% — click-to-explain finally matches the score above it, and LII behaves like a form metric again rather than a talent board
- The percentages shown in the popover and on the methodology page are MEASURED variance shares (58/23/19), not the formula weights — so the parts add up to what they claim
- Held out on 2026, a season no fit or test cohort saw: the weights sit on a broad plateau, so the legibility gain cost 0.0055 Spearman and nothing detectable at the top of the board
- v2.2.0
New Props tab — every hitter prop line on the slate, ranked by real edge
- Per-market board for Hits, Total Bases, Runs, RBI, and Home Runs: the posted line, the book it came from (Pinnacle first where it posts), the bbsim projection, and model P(over) at that exact line
- Ranked by juice-aware edge — model probability minus the book's vig-inclusive implied probability, the same math Best Bets uses, capped at 15pp
- Suspicious edges above the cap are flagged "alt-line?" instead of shown — a giant edge usually means an alternate or stale line, not free money
- Hits shows both O/U prices; sort by edge, P(over), projection, or line; summary chips count posted lines and +EV spots per market
- v2.1.0
Locked-In Index upgraded to v2 — the "seeing the ball" model
- LII now leads with Power (peak & average exit velocity, barrel%, hard-hit%) — peak exit velocity is the single strongest forward predictor of production and was absent from v1
- Three components on one 0-100 scale: Power (65%), Contact Quality (xwOBA/xBA, 8%), Plate Discipline (chase / whiff / zone-contact / K%, 27%)
- Held-out validated: forward-wOBA rank correlation improves from 0.149 (v1) to 0.171 (v2) on seasons the weights never saw
- Click any LII number for the v2 component breakdown; the column tooltip and methodology page now describe v2
- v2.0.0
The Sport Stack goes live — automated bet selectors, hardened data pipeline, board upgrades
- Best Bets now fire on their own: live pitcher-strikeout and game-totals selectors run on a cron, lock in at the price they fired at, and push a Discord + phone alert the moment a new bet lands
- New live totals board — a monitoring tab that snapshots line movement through the day and surfaces the best available number across books
- Two-way juice on the Open and Pinnacle board columns, plus the best-available line shown even on no-edge games with the opening line timestamped
- Data-integrity sweep: stale rolling-window rows (the impossible L14 > L30 case) are now pruned every run, and every lineup resolves through one canonical resolver so Matchup Score never silently goes missing
- Reliable Statcast: historical-season backfill fixed (2025 pitcher cards filled in), daily Statcast columns no longer wiped mid-run, and a new column-coverage freshness check catches silent NULL regressions
- Pipeline hardening: daily runs serialized to stop overlapping-run data races, the live-projection cache refresh re-enabled hourly, and a grace period on date SLAs ends the false-alarm freshness banners every morning
- Matchup card rebuilt into refined visual cards (win-probability bar, run-range bands, total-runs histogram); pitcher queries batched and the matchup prefetched on hover for near-instant tab loads
- LII headline now equals the weighted average of its component subscores — the parts finally sum to the whole
- Methodology page reworked: clearer on what we show (data provenance, out-of-sample accuracy, audited live results) and deliberate about what stays proprietary (the exact bet-selection rules)
- v1.5.3
Matchup Score back on the Matchups tab; SSR + response cache for sub-100ms tab clicks
- Matchup Score column restored on the Matchups tab (HitterTableV3 MS pill + breakdown tooltip showing batter / pitcher / park / weather contributions in wOBA points). Backed by the existing bbsim/matchup compute stack and the matchup_scores Supabase table
- Migration 021 recreates the matchup_scores table dropped in 019
- Migration 020 drops the unused LII v2 columns from lii_scores added in 014 (xwoba_vs_hand, weighted_z, season_lii, etc.) — slim the schema
- In-process response cache on /api/leaderboard/hitters, /api/leaderboard/pitchers, /api/matchup/[gamePk] with 30s TTL. Repeat tab clicks on a warm instance: 12-20ms vs 6-7s cold
- SSR prefetch (lib/mlb/prefetch.ts) was forcing every page-load to bypass cache via cache: 'no-store'. Switched to next: { revalidate: 30 } so SSR re-uses recent compute and Vercel's edge cache. Combined with the response cache, repeat tab clicks land sub-100ms
- CI freshness fix landed: pipeline/supabase_client.py imports httpx but daily-pipeline.yml never installed it — silently broke fetch_lineups + fetch_daily_statcast for ~4 weeks. Backfilled daily_statcast through 2026-04-27, refreshed events_2026.parquet
- fetch_lineups.py hydrates `team` in the schedule API call so daily_lineups.team_abbr is correct (was writing "??", breaking team filters and Matchup tab data flow for every team)
- pipeline/init_local_db.py now creates batter_projection_snapshots / pitcher_projection_snapshots so fresh-environment runs of fetch_game_actuals don't crash
- v1.5.1
LII reverted to v1 (3-component model + click-to-explain popover)
- LII tab is back to the v1 layout — 3 components (contact quality, plate vision, expected production), EV / HH% / Brl% / Chase% / Whiff% / xwOBA / xBA columns, click any LII number for the calculation breakdown popover
- Reads from the daily-refreshed daily_statcast Supabase table — fresh through yesterday's games, not the stale events parquet that was capping LII PA counts
- v2 model (5-input weighted z, hand-filtered, Marcel-regressed) parked: the heavy shrinkage was hiding hot streaks behind season baselines and the tab capped at LII ~58 in early April when most batters had < 30 PA in 14 days vs a single hand
- Matchup Score backend (Supabase matchup_scores table + API) preserved — no UI surfaces it currently but the data layer is intact for future use
- Migration 018 restores the regression_alert / cooloff_alert columns dropped in migration 017
- v1.5.0
LII v2 + Matchup Score — formal definitions, hand-filtered, percentile-anchored
- Locked-In Index reformulated: 5-input weighted z (xwOBA · K% · BB% · ISO · HardHit%), hand-filtered to tonight's SP, Marcel-regressed toward season baseline
- New "Δ vs season" column on the LII tab — LII percentile minus the player's season-baseline percentile (hotter or colder than usual)
- Matchup Score: 0-100 percentile of expected per-PA wOBA, ranked against the 2023-2025 distribution of all batter × pitcher × park × weather combos
- Park factors recomputed wOBA-direct + hand-split from 2023-2025 events (no more HR-multiplier-to-wOBA translation fudge)
- Weather coefficients fit empirically (temp +0.30 wOBA pts/°F, wind-to-CF +0.72 pts/mph) — replace the prior "sane prior" estimates
- Lineup-confirmed freeze rule: skill + park lock when daily_lineups flips to confirmed; weather keeps refreshing
- Dropped LII regression / cool-off alerts — short-term metric should be read as form, not a buy/fade signal
- v1.4.0
Real tab routes, TheOddsAPI sole odds source, feed-health banner
- Each tab is now a real /mlb/[tab] route — back-button works, deep links share, reload stays put
- Methodology live track record paginated through the full 2025 season (was truncated at 1,000 rows)
- Per-season breakdown table + early-season-skip footnote on the live track record panel
- ESPN odds scrape retired — TheOddsAPI is now the sole game-level + team-total feed
- Odds feed-health banner appears when TheOddsAPI hasn’t refreshed in > 30 min
- v1.3.0
P3: docs + calibration
- New /methodology page documenting data sources, model, stabilization thresholds, calibration
- Richer footer attribution — bbsim v1.0, FanGraphs park factors, ESPN odds, Open-Meteo weather
- Version chip in the header opens a changelog drawer (you are here)
- Calibration report wired up — backtest MAE + Brier on recent seasons
- v1.2.0
P2 UX sweep
- Game times render as "3:10 PM ET" consistently across Slate / Matchup / Weather
- "Updated HH:MM ET · refreshes every Nm" stamp on Slate / Leaderboard / LII / Weather
- Color-legend footer under heatmap tables (5-tier scale + ★ small-sample marker)
- Wind-arrow legend (↑OUT / ↓IN / ↔ cross) under Weather summary table
- Matchups tab auto-selects today's highest-composite game when no game is picked
- Metrics dictionary (lib/metrics/dictionary.ts) centralizes stat tooltips
- Weather condition labels no longer UPPERCASE "OVER/PARTLY/MOSTLY"
- "Top Hitter" column clarifies the pill number is the 0-100 Composite score
- v1.1.0
Projection correctness pass (QA Sprint C + D)
- bbsim Monte Carlo bumped 500 → 5,000 sims; projections now surface p10/p50/p90 bands
- ESPN scoreboard odds ingest replaces the dead TheOddsAPI key — ML / Team Tot / Edge / O/U flow again
- Pitcher rate stats (K%, BB%, xwOBA, FIP) Marcel-regressed toward league mean before engines read them
- Sasaki-style 13-IP samples no longer project 7+ BB/9 — regression matches display
- Leaderboard LII min-PA floor drops single-digit-PA noise rows from the ranking
- Pitcher oppDifficulty bucket now includes park + weather (Coors pitchers no longer "Easy")
- v1.0.0
Sprint A: data foundation
- Park factors: killed runtime override, FanGraphs-sourced per-side values flow authoritatively
- Weather model: humidity / wind clips, SF Oracle CF bearing 90° → 45° fix
- Matchup card pitcher/lineup/bullpen pairing reversed to match team abbreviations
- Heatmap coloring is deterministic on displayed value + context-aware for pitchers
- v0.9.0
V2 UI shell
- Matchup / Slate / LII / Leaderboard / Weather rebuilt on shadcn/ui
- Dark-mode default, tabular-nums + heatmap conventions
- v2 components live under components/mlb/v2/; page.tsx shell still Ant Design
Something look wrong, or a number you cannot reconcile? How this works · The full ledger