from pathlib import Path
import subprocess,sys,json,os,re,importlib.util
R=Path(__file__).resolve().parents[1]
cp=subprocess.run([sys.executable,str(R/'src/static_preflight_q1.py')],cwd=R,text=True,capture_output=True,env={**os.environ,'PYTHONDONTWRITEBYTECODE':'1'}); print(cp.stdout,end='')
m=re.findall(r'(\d+)/(\d+) PASS',cp.stdout); bp,bt=(map(int,m[-1]) if m else (0,1)); checks=[]
def ck(n,v): checks.append((n,bool(v)))
base=json.loads((R/'fixture/baseline-state.json').read_text()); pol=json.loads((R/'fixture/golden-policy.json').read_text())
expected=[
 {'from':'DRAFT','trigger':'submit','to':'SUBMITTED','guard':'has_required_fields'},
 {'from':'SUBMITTED','trigger':'hold','to':'ON_HOLD','guard':'needs_more_info'},
 {'from':'ON_HOLD','trigger':'resume','to':'SUBMITTED','guard':'resume_ready'},
 {'from':'SUBMITTED','trigger':'approve','to':'APPROVED','guard':'approver_authorized'},
 {'from':'SUBMITTED','trigger':'reject','to':'REJECTED','guard':'approver_authorized'},
]
fields=['Current State','Trigger','Guard','Next State','Hold or Terminal','Side Effect','Invalid Alternative','Evidence','Recovery or Resume Rule']
ck('exact transition matrix',base['transitions']==expected)
ck('all endpoints declared',all(e['from'] in base['states'] and e['to'] in base['states'] for e in base['transitions']))
ck('transition keys unique',len({(e['from'],e['trigger']) for e in base['transitions']})==5)
ck('record schema exact',base['record_fields']==fields)
ck('policy record schema exact',pol['required_record_fields']==fields)
ck('terminal policy parity',pol['terminal_states']==base['terminal_states'])
ck('hold policy parity',pol['resumable_holds']==['ON_HOLD'])
sp=importlib.util.spec_from_file_location('sm',R/'src/state_machine_fixture.py'); sm=importlib.util.module_from_spec(sp); sp.loader.exec_module(sm)
machine=sm.ReviewMachine()
ck('runtime terminal parity',machine.terminal==set(base['terminal_states']))
ck('baseline graph valid',machine.graph_contract()['valid'] is True and machine.graph_contract()['terminal_outgoing_violations']==[])
ck('runtime states parity',machine.states==base['states'])
for n,v in checks: print(('PASS' if v else 'FAIL'),n)
p=bp+sum(v for _,v in checks); t=bt+len(checks); print(f'{p}/{t} PASS'); sys.exit(0 if p==t else 1)
