#!/usr/bin/env python3
from __future__ import annotations
import hashlib,json,os,subprocess,sys
from pathlib import Path
ROOT=Path(__file__).resolve().parent
PROJECT=ROOT.parents[3]
def sha(p:Path)->str:return hashlib.sha256(p.read_bytes()).hexdigest()
def main()->int:
 seal=json.loads((ROOT/'SEAL.json').read_text());manifest=json.loads((ROOT/'candidate-manifest.json').read_text());rows=json.loads((ROOT/'PACKAGE-INVENTORY.json').read_text());checks=0
 def need(ok:bool,msg:str)->None:
  nonlocal checks
  if not ok:raise RuntimeError(msg)
  checks+=1
 need(seal['status']=='READY_STRICT_REHEARSAL','status')
 need(seal['full_candidate_digest']==manifest['full_candidate_digest'],'candidate')
 need(sha(ROOT/'PACKAGE-INVENTORY.json')==seal['package_inventory_sha256'],'package inventory')
 expected_paths={row['path'] for row in rows}
 allowed_metadata={'PACKAGE-INVENTORY.json','SEAL.json','PERMISSION-v6.json','launch_controller_v6.py','verify_successor.py'}
 actual_paths={p.relative_to(ROOT).as_posix() for p in ROOT.rglob('*') if p.is_file() and '__pycache__' not in p.parts and '.pytest_cache' not in p.parts}
 need(actual_paths==expected_paths|allowed_metadata,'unindexed package bytes')
 for row in rows:
  p=ROOT/row['path'];need(p.is_file() and p.stat().st_size==row['size'] and sha(p)==row['sha256'],row['path'])
 need(sha(ROOT/'launch_controller_v6.py')==seal['launch_controller_v6_sha256'],'controller')
 need(sha(ROOT/'PERMISSION-v6.json')==seal['launch_permission_sha256'],'permission')
 need(sha(ROOT/'lifecycle_observer_v7.py')==seal['lifecycle_observer_v7_sha256'],'observer')
 need(sha(ROOT/'cleanup_controller_v6.py')==seal['cleanup_controller_v6_sha256'],'cleanup')
 need(sha(PROJECT/'.omo/evidence/task26/task26-strict-final-candidate-st_01a00f35/SEAL.json')==seal['predecessor_seal_sha256'],'predecessor')
 need(sha(PROJECT/'.omo/evidence/task26/task26-strict-launch-controller-v5-st_01a00f53/run-20260817-strict-a-v5/RUN-SEAL-v5.json')==seal['failed_launch_v5_clean_seal_sha256'],'v5 rollback')
 text=(ROOT/'launch_controller_v6.py').read_text();need('load_gateway_preflight_inputs' in text,'new api');need('load_gateway_'+'config' not in text,'old api forbidden')
 for lane in ('objective','security','trainer-free','quality','qa','provenance'):need(json.loads((ROOT/f'review-{lane}.json').read_text())['status']=='READY_STRICT_REHEARSAL',lane)
 show=subprocess.run(['/usr/bin/systemctl','--user','show','hermes-gateway-dualcoachtest.service','-p','ActiveState','-p','SubState','-p','MainPID'],text=True,capture_output=True,check=True).stdout
 state=dict(x.split('=',1) for x in show.splitlines());need(state=={'MainPID':'0','ActiveState':'inactive','SubState':'dead'},'service clean')
 need(not Path('/home/cube/.hermes/profiles/dualcoachtest/customers/registry.json').exists(),'registry clean');need(not Path('/home/cube/.hermes/profiles/dualcoachtest/sessions').exists(),'sessions clean')
 print(json.dumps({'status':'READY_STRICT_REHEARSAL','candidate':seal['full_candidate_digest'],'core':seal['core_candidate_digest'],'inventory':seal['inventory_digest'],'package_inventory':seal['package_inventory_sha256'],'seal_sha256':sha(ROOT/'SEAL.json'),'checks':checks,'clean_state':'PASS'},sort_keys=True));return 0
if __name__=='__main__':
 try:raise SystemExit(main())
 except Exception as e:print('BLOCKED:',e,file=sys.stderr);raise SystemExit(2)
