#!/usr/bin/env python3
from __future__ import annotations
import hashlib,importlib.util,json,os,re,subprocess,sys
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
def can(x):return json.dumps(x,ensure_ascii=False,sort_keys=True,separators=(',',':')).encode()
def sha(p):return hashlib.sha256(p.read_bytes()).hexdigest()
def fail(x):raise SystemExit(x)
manifest=json.loads((ROOT/'candidate.json').read_text());unsigned={k:v for k,v in manifest.items() if k!='candidate_digest'}
if hashlib.sha256(can(unsigned)).hexdigest()!=manifest['candidate_digest']:fail('candidate digest mismatch')
excluded={'candidate.json','seal.sha256','receipts/independent-verification.json','receipts/final-immutability.json'};actual=[]
for p in sorted(x for x in ROOT.rglob('*') if x.is_file() and x.relative_to(ROOT).as_posix() not in excluded):
 rel=p.relative_to(ROOT).as_posix();actual.append({'path':rel,'sha256':sha(p),'size':p.stat().st_size})
if actual!=manifest['evidence_inventory']:fail('evidence inventory mismatch')
verifier=ROOT/'tools/verify_source_golden_path.py'
def fresh_verify(bundle, *, source_mode=False):
 env=os.environ.copy();env['PYTHONDONTWRITEBYTECODE']='1'
 if source_mode:env['PYTHONPATH']=os.pathsep.join(manifest['source_roots'])
 else:env.pop('PYTHONPATH',None)
 run=subprocess.run([sys.executable,str(verifier),str(bundle)],cwd=ROOT,text=True,capture_output=True,env=env)
 if run.returncode:fail(f'fresh verifier failed: {run.stderr.strip()}')
 return json.loads(run.stdout)
installed=fresh_verify(ROOT/'installed-golden-bundle');source=fresh_verify(ROOT/'source-golden-bundle',source_mode=True)
if source['status']!='ACTUAL_SOURCE_GOLDEN_PATH_PASS' or installed['status']!='ACTUAL_INSTALLED_GOLDEN_PATH_PASS':fail('Golden status mismatch')
spec=importlib.util.spec_from_file_location('candidate_verifier',verifier);v=importlib.util.module_from_spec(spec);spec.loader.exec_module(v)
if source['task26_contract']['clause_count']!=7 or installed['task26_contract']['clause_count']!=7:fail('clause count mismatch')
expected=[('missing','inventory'),('summary','incomplete'),('forged','miscanonicalized')];attacks=[]
for name,needle in expected:
 try:v.verify_task26_contract(ROOT/f'adversarial-fixtures/{name}')
 except ValueError as e:
  if needle not in str(e):fail(f'wrong {name} rejection: {e}')
  attacks.append({'attack':name,'reason':str(e),'rejected':True})
 else:fail(f'{name} accepted')
parity=json.loads((ROOT/'seals/source-wheel-installed-product-parity.json').read_text());
if parity['status']!='PASS':fail('product parity failure')
checks={'profile':(ROOT/'receipts/profile-full.log',r'749 passed'), 'contract_source':(ROOT/'receipts/contract-focused-source.log',r'51 passed'), 'contract_installed':(ROOT/'receipts/contract-focused-installed.log',r'51 passed'), 'focused_source':(ROOT/'receipts/focused-source.log',r'106 passed'), 'focused_installed':(ROOT/'receipts/focused-installed.log',r'106 passed'), 'related_installed':(ROOT/'receipts/related-installed.log',r'76 passed'), 'gateway':(ROOT/'receipts/full-gateway.log',r'8288 tests passed, 0 failed')}
for name,(path,pattern) in checks.items():
 text=path.read_text(errors='replace')
 if not re.search(pattern,text) or 'EXIT=0' not in text:fail(f'{name} result mismatch')
if (ROOT/'receipts/static.log').read_text().strip().splitlines()[-1]!='EXIT=0':fail('static failed')
if (ROOT/'receipts/pip-check.log').read_text().strip().splitlines()[-1]!='EXIT=0':fail('pip check failed')
result={'schema':'task26-independent-verification-v1','status':'PASS','candidate_digest':manifest['candidate_digest'],'source_candidate_digest':source['candidate_digest'],'installed_candidate_digest':installed['candidate_digest'],'source_contract':source['task26_contract'],'installed_contract':installed['task26_contract'],'terminal_inventory':installed['terminal_inventory'],'adversarial_attacks':attacks,'verified_inventory_count':len(actual),'python':sys.executable}
print(json.dumps(result,ensure_ascii=False,sort_keys=True,separators=(',',':')))
