-- pwin-timeforward.sql — calibration refresh on the CURRENT MLB sample (2026-08-01) -- MEASURE-ONLY. Time-forward: earlier games fit/observe, later games prove. -- -- Deliberately RULER-INDEPENDENT, and that is the finding: reliability -- (predicted vs actual hit rate) and resolution (does higher p_win hit more) -- are both p_win-vs-outcome measures. No fair_prob appears anywhere below, -- because none can. This is why the consensus ruler cannot change the -- calibration verdict. -- -- reliability = n-weighted mean |predicted - actual| across deciles. NOTE: -- mean|p - outcome| on 0/1 rows is NOT calibration -- it is noise-dominated -- individual error. Bucket first. -- -- MLB only. WNBA abstains on its own data and is not re-litigated here. with base as ( select sport, game_date, p_win::numeric p, (outcome='hit')::int won, ntile(2) over (order by game_date, id) half from public.ledger_entries where sport='mlb' and user_id is null and outcome in ('hit','miss') and p_win is not null), s as (select *, case when half=1 then 'train' else 'holdout' end split from base), b as (select split, width_bucket(p, 0.0, 1.0, 10) bkt, count(*) n, avg(p) pred, avg(won::numeric) actual from s group by 1,2) select split, sum(n) total_n, count(*) buckets, round(sum(n*abs(pred-actual))/sum(n),4) reliability_mean_abs_dev, round((select corr(p, won::numeric) from s s2 where s2.split=b.split)::numeric,4) resolution_corr, round((select avg(won::numeric) from s s3 where s3.split=b.split)::numeric,4) base_rate, (select min(game_date) from s s4 where s4.split=b.split) first_game, (select max(game_date) from s s5 where s5.split=b.split) last_game from b group by split order by split desc;