"""Independent standard-library implementation of the fixed synthetic process replay.
No training, downloads, model SDK, execution authority or network requests.
New wrapper: MIT. Original artifacts retain their own MIT LICENSE/NOTICE files.
"""
from pathlib import Path
import copy,csv,hashlib,json,math,platform,time
VARIANTS=('original_float64','weight_float32','weight_int8','weight_int4','refitted_head','shuffled_head_control')
TOLERANCE=1e-12
MANIFEST_SHA256='9ad0d91f9f6a80e89252c897b20dc689b4e6cba0a73babc0a5967c41289b58b2'

def reject(code):raise ValueError(code)
def unique_pairs(pairs):
    d={}
    for k,v in pairs:
        if k in d:reject('DUPLICATE_JSON_KEY')
        d[k]=v
    return d

def decode(raw):
    if not isinstance(raw,bytes)or len(raw)>2000000:reject('INPUT_SIZE')
    return json.loads(raw.decode('utf-8'),object_pairs_hook=unique_pairs,parse_constant=lambda x:reject('NONFINITE_JSON'))

def finite(x):return type(x)in(int,float)and math.isfinite(x)
def validate_features(x):
    if not isinstance(x,list)or len(x)!=11 or not all(finite(v)for v in x):reject('FEATURE_SHAPE_OR_TYPE')
    if any(v<0 or v>1 for v in x[:7])or abs(sum(x[:4])-1)>1e-8 or abs(sum(x[4:7])-1)>1e-8:reject('FEATURE_PROPORTIONS')
    if x[7]not in(0,1)or x[9]not in(0,1)or not -.875<=x[8]<=1.125 or not 0<=x[10]<=.875:reject('FEATURE_DOMAIN')

def validate_model(m):
    if m.get('format')!='meok.experimental-process-predictor/1' or m.get('hidden_activation')!='relu' or m.get('output_activation')!='identity':reject('MODEL_FORMAT')
    means,scales=m['scaler_mean'],m['scaler_scale']
    if len(means)!=11 or len(scales)!=11 or not all(finite(v)for v in means)or not all(finite(v)and v>0 for v in scales):reject('SCALER')
    width=11
    if not 1<=len(m['coefs'])<=5 or len(m['coefs'])!=len(m['intercepts']):reject('LAYERS')
    for matrix,bias in zip(m['coefs'],m['intercepts']):
        if not 1<=len(bias)<=1024 or len(matrix)!=width or not all(finite(v)for v in bias):reject('TENSOR_SHAPE')
        if any(len(row)!=len(bias)or not all(finite(v)for v in row)for row in matrix):reject('TENSOR_SHAPE')
        width=len(bias)
    if width!=4:reject('OUTPUT_WIDTH')

def predict(m,x):
    validate_features(x)
    state=[(v-m['scaler_mean'][i])/m['scaler_scale'][i] for i,v in enumerate(x)]
    for layer,(matrix,bias)in enumerate(zip(m['coefs'],m['intercepts'])):
        nxt=[]
        for column,b in enumerate(bias):
            value=0.0
            for row,v in enumerate(state):value+=v*matrix[row][column]
            value+=b
            nxt.append(max(0.0,value)if layer+1<len(m['coefs'])else value)
        state=nxt
    if not all(finite(v)for v in state):reject('NONFINITE_PREDICTION')
    clipped=[min(1.0,max(0.0,v))for v in state];total=sum(clipped)
    answer=[v/total for v in clipped]if total else x[:4]
    if x[8]<=0:answer=x[:4]
    return answer

def argmax(x):return max(range(len(x)),key=lambda i:x[i])
def compare_metrics(actual,expected):
    delta=0.0
    for field in ('mae','max_abs_error'):
        a,b=actual[field],expected[field]
        if not finite(a)or not finite(b):reject('NONFINITE_METRIC')
        d=abs(a-b);delta=max(delta,d)
        if d>TOLERANCE:reject('METRIC_MISMATCH:'+field)
    return delta

def replay(models,rows,expected_count):
    if len(rows)!=expected_count:reject('BANK_SIZE')
    predictions={};metrics={}
    for name in VARIANTS:
        m=models[name];validate_model(m);answers=[];total=0.0;worst=0.0
        for r in rows:
            target=r['target']
            if len(target)!=4 or not all(finite(v)and 0<=v<=1 for v in target)or abs(sum(target)-1)>1e-8:reject('TARGET_DOMAIN')
            answer=predict(m,r['features']);answers.append(answer)
            for a,b in zip(answer,target):
                e=abs(a-b);total+=e;worst=max(worst,e)
        predictions[name]=answers
        metrics[name]={'mae':total/(len(rows)*4),'max_abs_error':worst,'argmax_changes_from_base':sum(argmax(a)!=argmax(b)for a,b in zip(answers,predictions['original_float64']))}
    return predictions,metrics

def load_locked(root):
    root=Path(root);raw=(root/'manifest.json').read_bytes()
    if hashlib.sha256(raw).hexdigest()!=MANIFEST_SHA256:reject('MANIFEST_PIN_MISMATCH')
    manifest=decode(raw);assets={}
    for name,pin in manifest['files'].items():
        flat=pin['flat_name']
        if Path(flat).name!=flat or flat in('.','..'):reject('UNSAFE_ASSET_PATH')
        file=root/flat
        if file.is_symlink()or not file.is_file()or file.stat().st_size!=pin['bytes']:reject('ASSET_SIZE_OR_TYPE:'+name)
        content=file.read_bytes()
        if hashlib.sha256(content).hexdigest()!=pin['sha256']:reject('ASSET_DIGEST:'+name)
        assets[name]=content
    return manifest,assets

def run(root,out):
    begin=time.perf_counter();manifest,assets=load_locked(root);out=Path(out);out.mkdir(parents=True,exist_ok=True)
    models={n:decode(assets['research-v03/models/'+n+'.json'])for n in VARIANTS}
    old=decode(assets['research-v03/prediction-cases.json']);fresh=decode(assets['research-v03/fresh-stress-rows.json'])
    expected_old=decode(assets['research-v03/results.json'])['results'];expected_new=decode(assets['research-v03/fresh-stress-results.json'])['metrics']
    old_pred,old_metrics=replay(models,old,560);new_pred,new_metrics=replay(models,fresh,640)
    metric_delta=0.;row_delta=0.
    for n in VARIANTS:
        metric_delta=max(metric_delta,compare_metrics(old_metrics[n],expected_old[n]['constrained']),compare_metrics(new_metrics[n],expected_new[n]))
        if old_metrics[n]['argmax_changes_from_base']!=expected_old[n]['constrained']['argmax_changed_from_base']:reject('OLD_ARGMAX_MISMATCH')
        if new_metrics[n]['argmax_changes_from_base']!=expected_new[n]['argmax_changes_from_base']:reject('NEW_ARGMAX_MISMATCH')
        for r,y in zip(old,old_pred[n]):
            for a,b in zip(y,r['outputs'][n]):row_delta=max(row_delta,abs(a-b))
    if row_delta>TOLERANCE:reject('PER_ROW_PARITY')
    controls=[]
    def negative(name,fn):
        try:fn()
        except (ValueError,TypeError,KeyError):controls.append({'name':name,'status':'REFUSED_AS_EXPECTED'});return
        reject('NEGATIVE_CONTROL_ACCEPTED:'+name)
    x=old[0]['features']
    negative('boolean_feature',lambda:validate_features([True]+x[1:]))
    negative('nonfinite_feature',lambda:validate_features([float('nan')]+x[1:]))
    negative('missing_feature',lambda:validate_features(x[:-1]))
    negative('invalid_proportions',lambda:validate_features([1,1,1,1]+x[4:]))
    negative('duplicate_json_key',lambda:decode(b'{"a":1,"a":2}'))
    negative('nonfinite_json_constant',lambda:decode(b'{"a":NaN}'))
    negative('wrong_bank_size',lambda:replay(models,old[:-1],560))
    bogus=copy.deepcopy(old_metrics['refitted_head']);bogus['mae']=0
    negative('false_zero_error_claim',lambda:compare_metrics(bogus,expected_old['refitted_head']['constrained']))
    bogus=copy.deepcopy(old_metrics['refitted_head']);bogus['max_abs_error']=0
    negative('hidden_tail_failure',lambda:compare_metrics(bogus,expected_old['refitted_head']['constrained']))
    bad=copy.deepcopy(models['original_float64']);bad['scaler_scale'][0]=0
    negative('zero_scaler',lambda:validate_model(bad))
    bad=copy.deepcopy(models['original_float64']);bad['coefs'][0][0].pop()
    negative('damaged_weight_shape',lambda:validate_model(bad))
    # Check the byte rule with altered content, without modifying the source dataset.
    original=assets['research-v03/models/original_float64.json'];pin=manifest['files']['research-v03/models/original_float64.json']['sha256']
    negative('changed_weight_bytes',lambda:None if hashlib.sha256(original+b' ').hexdigest()==pin else reject('ASSET_DIGEST'))
    report={'schema':'csoai.meok.python-port-replay/1','status':'PASS','source_revision':manifest['source_revision'],'manifest_sha256':MANIFEST_SHA256,'source_files_checked':len(assets),'old_rows':len(old),'fresh_rows':len(fresh),'model_variants':6,'inference_evaluations':7200,'metrics':{'old_bank':old_metrics,'fresh_bank':new_metrics},'max_metric_delta_vs_retained_js_numpy':metric_delta,'max_old_bank_output_delta':row_delta,'negative_controls':controls,'negative_control_count':len(controls),'absolute_tolerance':TOLERANCE,'python':platform.python_version(),'machine':platform.machine(),'system':platform.system(),'elapsed_seconds_diagnostic':time.perf_counter()-begin,'new_training':False,'gpu_requested':False,'network_requests_in_replay':0,'execution_authority':False,'gspc_admitted':False,'independent_organisation':False,'limits':['New standard-library Python implementation checked against the existing synthetic research outputs; same author/owner.','Already-public same-generator banks, not new independent real-world benchmarks.','Matching arithmetic does not authenticate source truth, human authority or producer identity.','Timing is a single diagnostic, not a platform performance comparison.']}
    (out/'cross-platform-results.json').write_text(json.dumps(report,indent=2,sort_keys=True,allow_nan=False)+'\n')
    with(out/'metrics.csv').open('w',newline='')as f:
        writer=csv.writer(f);writer.writerow(['bank','variant','mean_absolute_error_fraction','worst_error_fraction','argmax_changes'])
        for bank,values in report['metrics'].items():
            for name,m in values.items():writer.writerow([bank,name,m['mae'],m['max_abs_error'],m['argmax_changes_from_base']])
    print(json.dumps({k:v for k,v in report.items()if k not in('metrics','negative_controls','limits')},indent=2),flush=True)
    return report

if __name__=='__main__':
    import argparse
    parser=argparse.ArgumentParser();parser.add_argument('--data',required=True);parser.add_argument('--out',required=True);args=parser.parse_args();run(args.data,args.out)
