"""Independent accounting checks for the delivered tables and frozen pilot."""
import ast
import hashlib
from common import *
d,t=load(); checks={}
def check(name,value):
    checks[name]=bool(value)
    assert value,name
g=pd.read_csv(R/'growth_families.csv')
for year in [2025,2026]:
    x=d[d.paid&d.year.eq(year)&d.month.le(8)]
    row=g[g.year.eq(year)&g.family.eq('all')].iloc[0]
    check(f'growth_{year}_source_counts',row.eligible==len(x) and row.strict==x.strict.sum())
    f=pd.read_csv(R/'growth_fractional_genres.csv').query('year == @year')
    check(f'fractional_{year}_total',abs(f.fractional_games.sum()-x.strict.sum())<1e-8)
    o=pd.read_csv(R/'growth_objects.csv').query('year == @year')
    check(f'objects_{year}_fractional_total',abs(o.fractional_games.sum()-x.strict.sum())<1e-8)
    gp=pd.read_csv(R/'growth_price_text.csv')
    for axis in ['price_bucket','text_bucket']:
        z=gp[gp.year.eq(year)&gp.axis.eq(axis)]
        check(f'{axis}_{year}_accounting',z.eligible.sum()==len(x) and z.builds.sum()==x.strict.sum())
parts=pd.read_csv(R/'growth_decomposition.csv')
check('decomposition_additive',np.allclose(parts.delta,parts.catalog_volume_composition+parts.within_signature_build_share))
check('decomposition_delta',parts.delta.sum()==874)
result=pd.read_csv(R/'reception_groups.csv')
for period in ['2025','2026_H1','2026_JulAug']:
    pool=d[d.build&d.period.eq(period)]
    for label,x in [('all_builds',pool),('deck_strict',pool[pool.deck]),('other_builds',pool[~pool.deck])]:
        row=result[result.period.eq(period)&result.group.eq(label)].iloc[0]
        check(f'{period}_{label}_counts',row.n==len(x) and row.ge100==x.reviews.ge(100).sum() and row.liked100==(x.reviews.ge(100)&x.positive_pct.ge(80)).sum())
        check(f'{period}_{label}_joint_factorization',abs(row.liked100_rate-row.rate100*row.satisfied_among100)<1e-10)
    row=result[result.period.eq(period)&result.group.eq('all_builds')].iloc[0]
    check(f'{period}_standardization_calibrated',all(abs(row[c]-1)<1e-8 for c in ['volume_ratio','joint_ratio','joint_text_ratio']))
th=pd.read_csv(R/'reception_thresholds.csv')
check('threshold_counts_ordered',all(x.qualifying.is_monotonic_decreasing for _,x in th.sort_values('positivity').groupby(['period','group','review_threshold'])))
pilot=json.loads((R/'pilot_blind.json').read_text());labels=json.loads((R/'pilot_labels.json').read_text())
check('pilot_60_unique',len(pilot)==len({r['appid'] for r in pilot})==60)
check('pilot_outcome_columns_hidden',all(not {'reviews','positive_pct','usd_list_price'}.intersection(r) for r in pilot))
check('pilot_strata_balanced',pd.DataFrame(pilot).groupby(['family','period']).size().eq(4).all())
check('pilot_label_alignment',[r['appid'] for r in pilot]==[r['appid'] for r in labels])
frozen=json.loads((R/'pilot_labels_frozen.json').read_text())
check('pilot_labels_unchanged',hashlib.sha256((R/'pilot_labels.json').read_bytes()).hexdigest()==frozen['sha256'])
obs=pd.read_csv(R/'pilot_with_outcomes.csv').set_index('appid')
check('pilot_outcomes_source_match',obs.reviews.eq(d.reviews.reindex(obs.index)).all() and obs.positive_pct.eq(d.positive_pct.reindex(obs.index)).all())
inv=pd.read_parquet(R/'inventory_audit.parquet')
check('inventory_all_cases_accounted',len(inv)==27 and inv.appid.nunique()==27 and inv.spatial_layout_pitch.sum()==7)
check('network_remains_paused',json.loads((ROOT/'network_policy.json').read_text())['network_paused'])
check('no_downloader',not (ROOT/'images.py').exists() and not (ROOT/'2026-09-05/images').exists())
for p in R.glob('*.py'):ast.parse(p.read_text())
check('all_scripts_parse',True)
check('figures_present',all((R/f'{name}.{ext}').stat().st_size>1000 for name in ['growth','deck_reception'] for ext in ['png','svg']))
manifest={}
for rel in ['analysis-2026-09-05/games.parquet','analysis-2026-09-05/tags.parquet','build-expression-2026-09-05/classification.parquet','build-expression-2026-09-05/analysis_membership.parquet','network_policy.json']:
    p=ROOT/rel; h=hashlib.sha256()
    with p.open('rb') as f:
        for chunk in iter(lambda:f.read(1024*1024),b''):h.update(chunk)
    manifest[rel]={'bytes':p.stat().st_size,'sha256':h.hexdigest()}
save_json('source_manifest.json',manifest)
save_json('validation.json',dict(passed=sum(checks.values()),checks=checks,script_hashes={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in R.glob('*.py')}))
print(f'Passed {len(checks)} checks.')
