import base64,hashlib,importlib.util,json,re
from pathlib import Path
HERE=Path(__file__).resolve().parent;spec=importlib.util.spec_from_file_location('source_oracle',HERE/'oracle.py');source_oracle=importlib.util.module_from_spec(spec);spec.loader.exec_module(source_oracle)
COUNT=0
def check(ok,why):
    global COUNT
    COUNT+=1
    if not ok:raise AssertionError(why)
def exact(a,b,where=''):
    check(type(a) is type(b),where+' type')
    if isinstance(b,dict):
        check(list(a)==list(b),where+' keys/order')
        for k,v in b.items():exact(a[k],v,where+'/'+k)
    elif isinstance(b,list):
        check(len(a)==len(b),where+' length')
        for i,v in enumerate(b):exact(a[i],v,where+'/'+str(i))
    else:check(a==b,where+' value')
def load(lane,name):return json.loads((HERE/'private'/lane/name).read_text())
def run():
    report={'HTTP':0,'DML':0,'DDL':0,'logs':0,'full_original_DTO':{},'compatibility_differences':{},'negative_cases':0};bodies={}
    for lane in ['B','C']:
        before=load(lane,'before.json');expected=source_oracle.oracle(before,lane);exact(expected,load(lane,'expected-before-http.json'),'preHTTP expected immutable')
        attempts=load(lane,'http-attempts-root959.json');check(len(attempts)==2,'actual2 HTTP per lane');report['HTTP']+=len(attempts);bodies[lane]={}
        for a in attempts:
            w=load(lane,'wire-'+a['label']+'.json');check(a['complete'] and base64.b64decode(a['body_base64']).decode()==w['body'],'actual client/wire raw bytes');check(hashlib.sha256(w['body'].encode()).hexdigest()==w['body_sha256'],'raw SHA');check(w['status']==200 and w['last_error'] is None,'original200/no runtime error');dto=json.loads(w['body']);exact(dto,expected,lane+'/'+a['label']+' full DTO');bodies[lane][a['label'][0]]=dto
            for s in [w['source_before'],w['source_after']]:
                x=dict(s);y=dict(before);x.pop('active_count');y.pop('active_count');exact(x,y,'own product/Set/Category/Time/actor/config/native preserved')
            check(w['own_source_unchanged'] and w['source_before']['active_count']==w['source_after']['active_count']==before['active_count'],'own invariant plus separately observed stable per-lane natural count')
            counts=[];business_rows=[];config_fetch=0
            for e in w['native']:
                sql=e['queryString'];check(not re.match(r'^\s*(INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|MERGE|TRUNCATE)\b',sql,re.I),'0 native DMLDDL')
                if e['layer']=='actual PDOStatement.execute':
                    check(e['success'] and e['errorInfo'][0]=='00000','actual native execute success')
                    if 'COUNT(' in sql.upper() and 'ydy_nutrition' in sql:counts.append((sql,e['bound']))
                    if sql.startswith('CALL '):check(sql=='CALL SP_TABLEDEF(?, ?)' and e['bound']['1']['value']=='ZHCT_APP' and e['bound']['2']['value'].lower() in ['ydy_nutrition','ydy_nutrition_set','ydy_nutrition_category','ydy_nutrition_time','ydy_user','ydy_config'],'exact metadata CALL boundary')
                if e['layer']=='actual PDOStatement.fetchAll':
                    if sql.startswith('SELECT ') and 'FROM `ydy_config`' in sql:check('rows' not in e and e['config_values_recorded'] is False and e['rows_count']==6 and len(e['rows_sha256'])==64,'bootstrap clock values count/SHA only');config_fetch+=1
                    elif 'a.*' in sql.replace('`','') and 'ydy_nutrition' in sql:business_rows+=e['rows']
            check(config_fetch==1 and len(counts)==2 and len(business_rows)==1,'exact bootstrap/twoCOUNT/one business row')
            total_binds=next(v for s,v in counts if 'LIKE' in s);global_binds=next(v for s,v in counts if 'LIKE' not in s);check(total_binds[':where__name']['value']==total_binds[':where__synopsis']['value']=='%CDXNF11F5-candidate-product%' and global_binds=={':where_AND_is_del':{'value':1,'type':1,'php_type':'integer','ok':True}},'native exact COUNT SQL/binds; values independently frozen before/after')
            raw=business_rows[0];check(raw['uuid']==before['nutrition'][0]['uuid'],'native single owned row');check(raw['fat']==before['nutrition'][0]['fat'] and raw['use_weight']==before['nutrition'][0]['use_weight'],'actual direct FLOAT M,D and plain native values retained')
            logic='app\\'+a['label'][0]+'\\logic\\Nutrition';sha='12c4f19da6bd3899de2cffc76e38650bdaf69f8f53e26f08dbf31a6dcf1f4e44' if a['label'][0]=='p' else '85c978ac82a22c101798f2af9da0976840e25749b17edd5e820db7b54689a712';check(w['reflection'][logic]['sha256']==sha and w['reflection'][logic]['file'] in w['included_files'],'actual Root logic SHA/included')
            for helper in ['NutritionFloat82Write.php','NutritionPlainFloatWeight.php']:check('/tmp/cdx-nutrition-lists-root959-20261011/source/application/common/service/'+helper in w['included_files'],'actual Root helper loaded')
            if lane=='B':
                old=json.loads((HERE.parent/'retry1/private/B'/('wire-'+a['label'][0]+'-lists-retry1.json')).read_text());check(w['body']==old['body'],'MySQL exact original/new raw body unchanged, no normalization')
        exact(load(lane,'final.json'),{'own_source_unchanged':True,'HTTP':2,'DML':0,'DDL':0,'logs':0},'final readonly result')
        resource=load(lane,'resource-check.json');check(all(resource[k] for k in ['own_worker_absent','own_port_closed','original_parent_present','request_absent','cache_absent']) and resource['AppleDouble']==[],'precise own cleanup')
        provenance=load(lane,'source-provenance.json');check(provenance['source_php_files']==959 and provenance['source_lock_sha256']=='49b1a564de5a93dcd0385659a3d79f2e92256970b7fd7cc0a1adb8d482ccdd57','actual Root runtime959 pin')
        report['full_original_DTO'][lane]={'methods':2,'own_single_row':True,'nutrition_sum_independent':before['active_count'][0]['n']}
    for method in ['p','m']:
        b=bodies['B'][method];c=bodies['C'][method];rowb=b['data']['rows'][0];rowc=c['data']['rows'][0];diff=[]
        for k in rowb:
            if type(rowb[k]) is not type(rowc[k]) or rowb[k]!=rowc[k]:diff.append({'field':k,'B':rowb[k],'C':rowc[k],'kind':'FLOAT(M,D) direct getter mismatch' if k in ['power','carbohydrate','protein','fat','sodium'] else 'plain FLOAT getter/physical mismatch' if k=='use_weight' else 'independently evidenced own identity/time data'})
        check(rowb['fat']==12.35 and rowc['fat']==12.35 and rowb['use_weight']==123.457 and rowc['use_weight']==123.457,'both original numeric defects now match source getters')
        report['compatibility_differences'][method]={'body_equal':b==c,'row_differences':diff,'nutrition_sum':{'B':b['data']['nutrition_sum'],'C':c['data']['nutrition_sum'],'kind':'independent natural data difference, not formatter bug'}};check(b['data']['nutrition_sum']==150 and c['data']['nutrition_sum']==3,'natural per-lane counts explicitly retained')
    dto=bodies['B']['p']
    for bad in [None,{},[],{**dto,'code':'0'},{**dto,'data':{**dto['data'],'nutrition_sum':3}},{**dto,'data':{**dto['data'],'rows':[]}}]:
        try:exact(bad,dto,'counterexample')
        except AssertionError:report['negative_cases']+=1
        else:raise AssertionError('Verifier accepted mutation')
    report['assertions']=COUNT;report['status']='Root959 candidate four full DTO pass; both numeric defects resolved for fixed lists; natural count/own identity differences retained'
    (HERE/'verification.json').write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');print(json.dumps(report,ensure_ascii=False))
if __name__=='__main__':run()
