#!/usr/bin/env python3
"""Strict read comparison, including cold DB proof rather than cache-only evidence."""
import argparse
import importlib.util
import json
from pathlib import Path
import re

p=argparse.ArgumentParser()
p.add_argument('b_runtime');p.add_argument('c_runtime')
args=p.parse_args()
module=Path(__file__).resolve().parents[3]/'work/2026-09-28-smart-canteen-dm8-poc/http-harness/strict_response_compare.py'
spec=importlib.util.spec_from_file_location('strict',module)
strict=importlib.util.module_from_spec(spec);spec.loader.exec_module(strict)
br,b=[strict.load_json(Path(args.b_runtime)/n) for n in ['report.json','responses.json']]
cr,c=[strict.load_json(Path(args.c_runtime)/n) for n in ['report.json','responses.json']]
expected={f'{m}_{a}_{mode}' for m in ['API','STORE','TERMINAL'] for a in ['ALL','TREE'] for mode in ['COLD','WARM']}
expected|={f'{m}_SPEC_{i}' for m in ['TERMINAL','STORE'] for i in ['10001','10003','0','NEG1','MISSING']}
if set(b)!=expected or set(c)!=expected:raise SystemExit('Required 22 scenarios absent')
if br['source_sha256']!=cr['source_sha256']:raise SystemExit('Source drift')
for report in [br,cr]:
    if report['failures'] or not report['natural_unchanged'] or report['non_select_observed'] or not report['token_cleaned'] or not report['region_cache_cleaned']:
        raise SystemExit('Read-only/source/cleanup proof absent')
    for case in report['cases']:
        if not case['source_equal']:raise SystemExit('Independent source mismatch')
        if case.get('cache_mode')=='COLD' and case['region_query_observations']<1:raise SystemExit('Cold cache did not observe business Region SELECT')
        if case.get('cache_mode')=='WARM' and case['region_query_observations']!=0:raise SystemExit('Warm cache unexpectedly queried Region data')
rule={'$["trace_id"]':{'type':'string','pattern':'[0-9a-f]{13}',
    'reason':'Validated distinct per-request framework trace','require_distinct':True}}
cases=[]
for name in sorted(expected):
    bc=next(x for x in br['cases'] if x['scenario']==name);cc=next(x for x in cr['cases'] if x['scenario']==name)
    if any(bc[k]!=cc[k] for k in ['args','path','method','expected_business_status']):raise SystemExit('Inputs or expected status differ')
    for response in [b[name],c[name]]:
        if response['http_status']!=200 or response['body'].get('status')!=bc['expected_business_status']:
            raise SystemExit('Unexpected HTTP/business status: '+name)
        if re.fullmatch('[0-9a-f]{13}',response['body'].get('trace_id','')) is None:raise SystemExit('Trace malformed')
    diffs=strict.compare(b[name]['body'],c[name]['body'],rules=rule)
    cases.append({'scenario':name,'method':bc['method'],'path':bc['path'],'args':bc['args'],
        'expected_business_status':bc['expected_business_status'],'source_rows_B':bc['source_rows'],'source_rows_C':cc['source_rows'],
        'region_data_select_B':bc.get('region_query_observations'),'region_data_select_C':cc.get('region_query_observations'),
        'strict_differences':len(diffs),'type_differences':sum(l!=r for _,l,r,_,_ in diffs),
        'difference_paths_and_types':[{'path':path,'mysql_type':left,'dm_type':right} for path,left,right,_,_ in diffs]})
def runtime(report):
    events=[e for e in report['events'] if e.get('kind')=='query_observed']
    return {'queries':len(events),'fingerprints':len({e['fingerprint'] for e in events}),
        'operations':{op:sum(e['operation']==op for e in events) for op in sorted({e['operation'] for e in events})},
        'classification':{k:sum(e.get(k,0) for e in report['events'] if e.get('kind')=='listener_classification') for k in ['metadata_events','connection_events','unclassified_events']},
        'lexical_warnings':sum(bool(e.get('lexical_warning')) for e in events),
        'callsites':sorted({site for e in events for site in e.get('callsites',[])})}
result={'date':'2026-10-10','baseline':br['baseline'],'exact_get_paths':8,'new_candidate_get_paths':7,
    'store_spec_existing_coverage_enhanced_not_new':True,'scenario_pairs':22,'strict_equal_cases':sum(not x['strict_differences'] for x in cases),
    'region_routes_cold_db_observed':6,'region_warm_cache_cases':6,
    'spec_nonempty_B_cases':4,'spec_nonempty_C_cases':0,'spec_nonempty_both_cases':0,
    'spec_expected_empty_boundary_cases':4,'spec_expected_missing_parameter_errors':2,'cases':cases,
    'source_sha256':br['source_sha256'],'runtime':{'B':runtime(br),'C':runtime(cr)},
    'audit':{lane:{k:r[k] for k in ['before','after','natural_unchanged','non_select_observed','token_cleaned','region_cache_cleaned']} for lane,r in [('B',br),('C',cr)]},
    'normalization':'Validated distinct top-level trace_id only; no ID/value/type or array-order normalization',
    'scope':'Natural Region cold/warm cache and selected goods Spec source/projection; not full interface or system acceptance'}
print(json.dumps(result,indent=2,ensure_ascii=False,default=str))
raise SystemExit(any(x['strict_differences'] for x in cases))
