"""Exact T533 preservation checks; run: agents/sage.sh check-repair-20261027T011353Z.py document-repair-20261027T011353Z.json generate.py skill-repair-20261027T011353Z.json.
The companion generator remains unchanged. This check writes only JSON to stdout.
"""
import json,hashlib,sys,platform
from pathlib import Path
from fractions import Fraction as F
from math import comb,factorial
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.version import version as sage_version
import generate
p=Path(__file__).parent
doc=json.loads((p/'document-repair-20261027T011353Z.json').read_text())
provenance=json.loads((p/'skill-repair-20261027T011353Z.json').read_text())
g=generate.BesselRayleighSums()
rows=[({'nu':nu,'n':str(n)},v) for nu,block in doc['Numbers'].items() for n,v in block.items()]
assert list(g.enumerate())==[r[0] for r in rows]
# Kishore convolution uses a different recurrence from the generator's series quotient.
def sigma(nu,n):
    nu=F(nu); s=[F(0),F(1,4)/(nu+1)]
    for m in range(2,n+1): s.append(sum((s[k]*s[m-k] for k in range(1,m)),F(0))/(nu+m))
    return s[n]
assert sigma('0',1)==F(1,4) and sigma('1/2',1)==F(1,6)
# Bernoulli numbers from the triangular binomial identity.
b=[F(1)]
for m in range(1,25): b.append(-sum((comb(m+1,k)*b[k] for k in range(m)),F(0))/F(m+1))
assert b[2]==F(1,6) and b[4]==F(-1,30)
namespace={}; exec(doc['Programs']['program-python']['code'],namespace)
for params,v in rows:
    value=F(v['number'] if isinstance(v,dict) else str(v)); nu=params['nu']; n=int(params['n'])
    assert value==sigma(nu,n)
    assert QQ(value.numerator)/QQ(value.denominator)==g.value(params,100)
    assert value==namespace['rayleigh'](nu,n)
    if nu=='1/2': assert value==(-1)**(n+1)*2**(2*n-1)*b[2*n]/factorial(2*n)
assert sigma('0',1)!=F(1,4)+F(1,10**100)
print(json.dumps({'table':'T533','skill_provenance':provenance,'document_sha256':hashlib.sha256((p/'document-repair-20261027T011353Z.json').read_bytes()).hexdigest(),'generate.py_sha256':hashlib.sha256((p/'generate.py').read_bytes()).hexdigest(),'entries_checked':len(rows),'generator_default_order_matches':True,'convolution_exact_matches':96,'program_exact_matches':96,'generator_exact_matches':96,'bernoulli_matches':12,'known_controls_passed':True,'perturbation_rejected':True,'new_values':0,'argument_uncertainty':'All orders and moment indices are exact; no rounded arguments or approximate values used.','versions':{'python':platform.python_version(),'sage':sage_version}},indent=2))
