from pathlib import Path
import pandas as pd,numpy as np,json,hashlib
R=Path(__file__).resolve().parent
g=pd.read_parquet(R.parent/'fable-verification-2026-09-06/games.parquet')
allp=g[g.valid&~g.free&~g.explicit&g.year.between(2016,2024)].copy();p=allp[allp.reviews.lt(10000)].copy()
p['period']=pd.cut(p.year,[2015,2018,2021,2024],labels=['2016-18','2019-21','2022-24']).astype(str)
p['review_band']=pd.cut(p.reviews,[-1,49,199,999,9999],labels=['0-49','50-199','200-999','1000-9999']).astype(str)
p['stratum']=p.period+' / '+p.review_band;parts=[]
for i,(label,a) in enumerate(p.groupby('stratum',sort=True)):
    x=a.sort_values('appid').sample(5,random_state=77007+i).copy();x['draw']=np.arange(5);x['population_n']=len(a);x['weight']=len(a)/5;parts.append(x)
s=pd.concat(parts).sort_values(['draw','stratum']).reset_index(drop=True);s['order']=np.arange(len(s))
s.to_parquet(R/'sample.parquet',index=False);s.drop(columns=['desc']).to_csv(R/'sample.csv',index=False)
p[['appid','stratum']].to_parquet(R/'population.parquet',index=False)
spec={'population':len(p),'all_paid_nonexplicit_2016_24':len(allp),'excluded_10000plus':len(allp)-len(p),'sample_n':len(s),'seed':77007,'strata':'three release periods x four current review-count bands; five random games per cell','estimated_reviews':int(s.reviews.sum()),'estimated_requests':int(sum(np.ceil(s.reviews/100)+2)),'sample_sha256':hashlib.sha256((R/'sample.csv').read_bytes()).hexdigest(),'source':'../2026-09-05 catalog via independently normalized fable-verification games.parquet','observation':'Currently returned Steam-purchase reviews, all languages, off-topic filtering on. Creation timestamps of surviving reviews; not original complete history or historical sentiment.','analysis':'first30/90/365/730; first-review clock sensitivity; last twelve complete calendar months; bounded late-burst screen; no causal update attribution','review_text_and_accounts':'Not collected'}
(R/'study_spec.json').write_text(json.dumps(spec,indent=2));print(json.dumps(spec,indent=2))
