#!/usr/bin/env python3
import collections,hashlib,json,pathlib,subprocess
import verify_catalog as verify
here=pathlib.Path(__file__).resolve().parent;b=here/'private-evidence/B';c=here/'private-evidence/C'
result=verify.verify(b,c)
mutation=subprocess.run(['python3',str(here/'test_verify_catalog.py'),str(b),str(c)],capture_output=True,text=True,check=True)
mutation=json.loads(mutation.stdout)
def read(root,name):return json.loads((root/name).read_bytes())
lanes={}
for lane,root in [('B',b),('C',c)]:
    stages={}
    for prefix in ['', 'card-', 'green-']:
        file=root/(prefix+'report-private.json')
        if not file.exists():continue
        r=json.loads(file.read_bytes());stages[prefix or 'original']={'source_sha256':r['source_sha256'],'cases':r['cases'],'http_dml':r['http_dml'],'new_fixture_dml':r['new_fixture_dml'],'ddl':r['ddl'],'actor_unchanged':r['actor_unchanged']}
    events=[json.loads(s) for s in (root/'queries.jsonl').read_text().splitlines()]
    operations=collections.Counter(e['operation'] for e in events if e['kind']=='query_observed')
    warnings=[e for e in events if e['kind']=='query_observed' and e.get('fingerprint_lexical_warning')]
    lanes[lane]={'stages':stages,'native_cli':read(root,'native-stats-private.json'),'cleanup':read(root,'cleanup-private.json'),
        'sql_observer':{'all_observed_query_operations_including_metadata':dict(operations),'lexical_warning_count':len(warnings),'lexical_warning_fingerprints':sorted(set(e['fingerprint'] for e in warnings)),'metadata_not_claimed_as_business_queries':True,'sql_fingerprint_gate_closed':False},
        'private_evidence_manifest_sha256':hashlib.sha256((root/'EVIDENCE_MANIFEST.json').read_bytes()).hexdigest(),'private_file_count':len(read(root,'EVIDENCE_MANIFEST.json'))}
methods=[]
for kind,(method,path) in verify.ROUTES.items():
    methods.append({'method':method,'path':path,'status':'limited' if kind=='rotation' else 'partial','nonempty_B':True,'nonempty_C':kind!='rotation','reason':'C自然无station，只missing分支；未造设备' if kind=='rotation' else '双侧真实HTTP非空、完整DTO→本侧原表来源、窗口稳定；自然快照不声称全文等值'})
result.update({'methods':methods,'lanes':lanes,'mutation_test':mutation,'business_tdd':verify.CANDIDATE['tests'],'private_raw_wire_reencoded':False,'business_main_writer':'root only','credentials_or_natural_pii_in_public_results':False})
(here/'results.json').write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n')
manifest={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(here.iterdir()) if p.is_file() and p.name not in ['MANIFEST.json'] and p.suffix in ['.py','.php','.md','.json','.txt','.patch']}
(here/'MANIFEST.json').write_text(json.dumps(manifest,indent=2)+'\n')
print(json.dumps({'status':result['status'],'positive_partial':5,'limited':1,'mutation_tests':mutation['tests'],'DML_DDL':0,'private_manifests':{k:x['private_evidence_manifest_sha256'] for k,x in lanes.items()}},ensure_ascii=False))
