"""Check the stored T680 claims, normalization identity and period companion.

Run with plain Python and the numberdb client on PYTHONPATH:
    python readback_checks.py
The NumberDB key is read from NUMBERDB_KEY_FILE without being printed.
Download checks.jsonl and prepared-entries.json beside this script.
This checks written intervals against the independent computations, not just
against the generator's cache. Exact Decimal arithmetic is used for the bounds.
"""
import json,os,sys
from decimal import Decimal,localcontext
from pathlib import Path
import numberdb
from numberdb._compare import _claim,_complex_parts,digits_of

W=Path(__file__).resolve().parent

def number(row):return row['number'] if isinstance(row,dict) else row

def parts(text):
    out=_complex_parts(text)
    if out is None:out=(text,'0')
    result=[]
    for p in out:
        if p.startswith('[') and p.endswith(']'):
            lo,hi=(Decimal(x.strip()) for x in p[1:-1].split(','))
            c,r=(lo+hi)/2,(hi-lo)/2
        else:c,r=_claim(p)
        assert c.is_finite() and r.is_finite()
        result.append((c,r))
    return result


def within(text,reference):
    worst=Decimal(0)
    for (c,r),v in zip(parts(text),reference):
        v=Decimal(v)
        if r==0:assert c==v
        else:
            distance=abs(c-v)/r
            assert distance<=1,(text,str(distance))
            worst=max(worst,distance)
    return worst


def main():
    key=Path(os.environ['NUMBERDB_KEY_FILE']).read_text().strip()
    numberdb.configure(api_key=key)
    doc=numberdb.table('T680');period=numberdb.table('T679')
    (W/'T680-readback.json').write_text(json.dumps(doc,indent=2))
    # The readback is nested in declared parameter order.
    records=[]
    for template,zs in doc['Numbers'].items():
        for z,norms in zs.items():
            for normalization,row in norms.items():
                records.append({'params':{'template':template,'z':z,'normalization':normalization},'number':number(row)})
    expected=json.loads((W/'prepared-entries.json').read_text())
    assert [r['params'] for r in records]==[r['params'] for r in expected]
    assert len(records)==112
    checks={}
    for line in (W/'checks.jsonl').read_text().splitlines():
        r=json.loads(line)
        if 'template' in r:checks[(r['template'],r['z'])]=r
    worst=Decimal(0);period_worst=Decimal(0);scaling_worst=Decimal(0)
    with localcontext() as ctx:
        ctx.prec=230
        # Nonzero control and deliberately incorrect value rejection.
        assert within('1.234',[Decimal('1.2345'),0])==Decimal('0.5')
        try:within('1.234',[Decimal('1.24'),0])
        except AssertionError:pass
        else:raise AssertionError('Interval checker accepted a false control')
        for row in records:
            p=row['params'];r=checks[(p['template'],p['z'])];C=Decimal(r['scale'])
            re,im=Decimal(r['independent_re']),Decimal(r['independent_im'])
            if p['normalization']=='integral':re/=C;im/=C
            worst=max(worst,within(row['number'],[re,im]))
            for text_part,(_,radius) in zip(_complex_parts(row['number']),parts(row['number'])):
                if radius:assert digits_of(text_part)>=100
        for (template,z),r in checks.items():
            period_worst=max(period_worst,within(number(period['Numbers'][template][z]),[r['F_re'],r['F_im']]))
            group=doc['Numbers'][template][z];C=Decimal(r['scale'])
            for (u,ur),(q,qr) in zip(parts(number(group['unit'])),parts(number(group['integral']))):
                assert abs(u-C*q)<=ur+C*qr
                if ur+C*qr:scaling_worst=max(scaling_worst,abs(u-C*q)/(ur+C*qr))
            if z!='2':
                assert parts(number(group['unit']))[1]==(0,0)
                assert parts(number(group['integral']))[1]==(0,0)
            # Explicit definition: the stored value must enclose independently
            # computed z exp(G/F), already evaluated without generator code.
        result={'passed':True,'entries_checked':112,'period_companions_checked':56,
          'scaling_identities_checked':56,'max_independent_error_in_stored_ulp':str(worst),
          'max_companion_error_in_stored_ulp':str(period_worst),
          'max_scaling_discrepancy_over_sum_of_radii':str(scaling_worst),
          'real_fiber_imaginary_parts_exact_zero':True,
          'skill_manifest':'agents/runs/20261102T145807Z-build-skills/manifest.json'}
    (W/'readback-results.json').write_text(json.dumps(result,indent=2)+'\n')
    print(json.dumps(result,indent=2))

if __name__=='__main__':main()
