import json,hashlib,subprocess,os,glob,numpy as np,pandas as pd h0=hashlib.sha256(open('out/results.json','rb').read()).hexdigest() for f in ['results.json','forecasts.csv','table1.csv','figure1.png']: os.remove('out/'+f) subprocess.run(['/Users/simon-pierreboucher/wp29/venv/bin/python','out/analysis.py'],check=True,capture_output=True) h1=hashlib.sha256(open('out/results.json','rb').read()).hexdigest() print('C1 clean rerun identical results.json:',h0==h1) r=json.load(open('out/results.json')); fc=pd.read_csv('out/forecasts.csv'); fr=pd.read_csv('data/first_release.csv') print('C2 rows',len(fc),'unique keys',len(fc.drop_duplicates(['origin_date','horizon','model']))) print('C3 vintage_used==origin all:',(fc.vintage_used==fc.origin_date).all()) # C4 first release consistency with shipped vintages ok=True for _,x in fr.iterrows(): p=f"data/vintages/RSAFS_vintage_{x.first_release_vintage}.csv" if os.path.exists(p): v=pd.read_csv(p,index_col=0).iloc[:,0] ok&= v[x.target_month]==x.level_first_release and v.index[-1]>=x.target_month t12=str(pd.Period(x.target_month[:7],'M')-12)+'-01'; ok&= v[t12]==x.level_prev_year_same_vintage ok&= abs(100*np.log(x.level_first_release/x.level_prev_year_same_vintage)-x.yoy_first_release)<1e-5 print('C4 first_release consistent with shipped vintages & formula:',ok) # C5 independent recompute of RMSE/MAE and DM e=fc.forecast-fc.actual_first_release; fc['e']=e bad=0 for (m,h),g in fc.groupby(['model','horizon']): bad+=abs(np.sqrt((g.e**2).mean())-r[f'rmse_{m}_h{h}'])>1e-12 print('C5 RMSE recompute mismatches:',bad) for h in [1,3]: d=(fc[(fc.model=='naive')&(fc.horizon==h)].e.values**2-fc[(fc.model=='model')&(fc.horizon==h)].e.values**2) n=len(d);dc=d-d.mean();g=[np.dot(dc[k:],dc[:n-k])/n for k in range(3)] lrv=g[0] if h==1 else g[0]+2*(2/3*g[1]+1/3*g[2]) print(f'C6 DM h{h} indep',d.mean()/np.sqrt(lrv/n),'stored',r[f'dm_stat_h{h}'],'lrv>0',lrv>0) # C7 naive = last yoy of vintage, model base month check o='2026-04-30';v=pd.read_csv(f'data/vintages/RSAFS_vintage_{o}.csv',index_col=0).iloc[:,0] print('C7 naive check',fc[(fc.origin_date==o)&(fc.model=='naive')].forecast.values, 100*np.log(v.iloc[-1]/v.iloc[-13])) print('C8 rel impr', r['rel_improvement_rmse_h1'],1-r['rmse_model_h1']/r['rmse_naive_h1']) print('C9 MAE<=RMSE all', all(r[f'mae_{m}_h{h}']<=r[f'rmse_{m}_h{h}'] for m in ['naive','snaive','ar1','model'] for h in [1,3])) print('C10 targets all > last(V):', all(pd.Period(t[:7],'M')>pd.Period(x['last_month'],'M') for x in r['real_time_design'] for t in fc[fc.origin_date==x['origin']].target_date)) cur=pd.read_csv('data/RSAFS_current.csv',index_col=0).iloc[:,0] t='2026-01-01';tp='2025-01-01';print('C11 revision check 2026-01',abs(100*np.log(cur[t]/cur[tp])-fr.set_index('target_month').yoy_first_release[t]), r['abs_revision_h1_by_target']['2026-01'])