from pathlib import Path
import json, csv
P=Path(__file__).resolve().parent
E=json.loads((P/'events.json').read_text()); expected=json.loads((P/'expected.json').read_text()); C=json.loads((P/'contract.json').read_text())
seen=set();versions={};orders={};stock=0

def apply(e):
 global stock
 key=('stock' if e['kind']=='stock' else 'order',e['key'])
 if e['id'] in seen: reason='duplicate_id'
 elif e['version']<=versions.get(key,-1): reason='old_version';seen.add(e['id'])
 else:
  reason='apply';seen.add(e['id']);versions[key]=e['version']
  if e['kind']=='stock':stock=e['qty']
  else:orders[e['key']]=e['qty'] if e['kind']=='order' else 0
 return stock-sum(orders.values()),reason

rows=[]
for e,x in zip(E,expected,strict=True):
 available,reason=apply(e);lag=e['visible']-e['occurred']
 actual=[e['id'],reason,available,lag];assert actual==x,(actual,x)
 rows.append(actual+[lag>C['freshness_budget_s']])
state=(stock,dict(orders),dict(versions))
for e in E:apply(e)
assert state==(stock,orders,versions),'replay changed state'
with (P/'actual.csv').open('w',newline='') as f:
 w=csv.writer(f);w.writerow(['event_id','decision','available','lag_s','over_budget']);w.writerows(rows)
summary={'checked_events':len(rows),'matched_expected':len(rows),'final_available':stock-sum(orders.values()),'replay_state_unchanged':True,'budget_breaches':sum(r[-1] for r in rows),'scope':'local contract exercise, not Flow or a production stock system'}
(P/'summary.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(summary,ensure_ascii=False))
