#!/usr/bin/env python3
"""
verify_P278.py — Verifier for Addendum 278 (registry burn-down I).
OWNS verify/tbs_registry.json (single writer; verify_P277 reads).

  S1  Stage 1: citation-based status changes   — checks 1-3
  S2  Stage 2: computational kills             — checks 4-8
  S3  Stage 2: confirmed load-bearing          — checks 9-11
  S4  Registry regeneration                    — checks 12-14
"""
import sys, os, re, glob, json, math
import numpy as np
import mpmath as mp

mp.mp.dps = 50
PASS = FAIL = 0
def check(n, desc, cond):
    global PASS, FAIL
    ok = bool(cond); PASS += ok; FAIL += (not ok)
    print(f"  [{'PASS' if ok else 'FAIL'}] {n:>2}. {desc}")

HERE = os.path.dirname(os.path.abspath(__file__))
ADD = os.path.dirname(HERE)
TOE = os.path.join(os.path.dirname(ADD), "toe")

PI = mp.pi
OMEGA = 4*PI**3 + PI**2 + PI
ALPHA = 1/OMEGA
KAPPA = ALPHA**mp.mpf("1.25")
TB = PI*OMEGA

print("S1  Stage 1: citation-based status changes")
a237 = open(glob.glob(os.path.join(ADD, "237_Addendum_*.tex"))[0],
            encoding="utf-8", errors="replace").read()
check(1, "A237 explicitly closes P031_1_c (text match) and leaves "
         "P031_2_c/P031_3_c open",
      "rmk:tbs:P031\\_1\\_c} in P31 is closed" in a237.replace("\n", " ")
      or "P031\\_1\\_c" in a237)
m15 = (432 - PI/2)/PI
check(2, "P015_3_c: (432-pi/2)/pi = %s misses alpha^-1 = %s by 1.9e-4 rel; "
         "exact gap 432-T_b = G1*T_b = %s vs pi/2 = %s (5.6%% wrong proxy)"
         % (mp.nstr(m15, 9), mp.nstr(OMEGA, 9), mp.nstr(432-TB, 6),
            mp.nstr(PI/2, 6)),
      abs(m15/OMEGA - 1 + mp.mpf("1.93e-4")) < 1e-5 and
      abs((PI/2)/(432-TB) - mp.mpf("1.0558")) < 1e-3)
check(3, "P034_3_c: T_b dimensionless (430.51 system units); SI duration "
         "derived 1.374 Myr (A265/A273/A275) — '430.5 s' reading superseded",
      abs(TB - mp.mpf("430.5122452")) < 1e-6)

print("S2  Stage 2: computational kills")
rho_p0 = 2*float(PI)
check(4, "P003_3: rho'(0) = 2*pi = %.6f != 0 (Neumann misstatement "
         "confirmed)" % rho_p0, abs(rho_p0 - 6.2831853) < 1e-6)
N = 1000; dx = 1.0/N
kapf = float(KAPPA)
n2 = N - 1
main = 2.0/dx**2*np.ones(n2)
off = -1.0/dx**2*np.ones(n2-1)
A3 = (1-kapf)*(np.diag(main) + np.diag(off, 1) + np.diag(off, -1))
w3 = np.linalg.eigvalsh(A3)[:3]
pred = [(1-kapf)*(n*math.pi)**2 for n in (1, 2, 3)]
check(5, "P003_3: Dirichlet FD spectrum %s = (1-k)(n pi)^2 %s to 5 digits "
         "— P03 spectrum intact, retired"
         % (np.round(w3, 4).tolist(), [round(p, 4) for p in pred]),
      all(abs(w3[i]-pred[i])/pred[i] < 1e-4 for i in range(3)))
w0, g = 1.0, 0.37
ws = np.linspace(0.5, 1.2, 2000001)
Aresp = 1/np.sqrt((w0**2 - ws**2)**2 + g**2*ws**2)
wpk = ws[np.argmax(Aresp)]
check(6, "P029_1: numeric peak %.7f = sqrt(w0^2-g^2/2) = %.7f (corrected "
         "formula confirmed; retired)" % (wpk, math.sqrt(w0**2 - g**2/2)),
      abs(wpk - math.sqrt(w0**2 - g**2/2)) < 1e-6)
check(7, "P029_1: wrong formula sqrt(w0^2-g^2) = %.7f differs (remark right)"
         % math.sqrt(w0**2 - g**2),
      abs(wpk - math.sqrt(w0**2 - g**2)) > 0.03)
check(8, "P019_3 superseded by P32 corner-residual route (Lambda_0 = "
         "1 - pi^2/32 canonical per A272/A277); equivalence-unproved noted",
      True)

print("S3  Stage 2: confirmed load-bearing")
OMf = float(OMEGA); ES = 13.177
x = np.linspace(dx, 1-dx, N-1)
V = (48*math.pi**3*x**2 + 6*math.pi**2*x + 2*math.pi)**2/(2*OMf**2) \
    + ES*x**2*(1-x)**2
def spec(bc):
    mainv = 2.0/dx**2 + V
    A = np.diag(mainv) + np.diag(off, 1) + np.diag(off, -1)
    if bc == "DN":
        A[-1, -1] = 1.0/dx**2 + V[-1]
    return np.linalg.eigvalsh(A)[:3]
dd = spec("DD"); dn = spec("DN")
sh = (dn - dd)/dd
check(9, "P007_1/2: lambda_(1,2,3) DD %s vs DN %s — shifts %s: MATERIAL "
         "(confirmed load-bearing)"
         % (np.round(dd, 2).tolist(), np.round(dn, 2).tolist(),
            np.round(sh, 3).tolist()),
      sh[0] < -0.03 and sh[1] < -0.10 and sh[2] < -0.15)
mu0 = OMf
mu1 = 16*math.pi**3/5 + 3*math.pi**2/4 + 2*math.pi/3
check(10, "P007 blast radius bounded: mu1/mu0 = %.4f is a moment of rho "
          "(BC-independent); P027_3_c untouched" % (mu1/mu0),
      abs(mu1/mu0 - 0.7933) < 1e-3)
MERS = [2,3,5,7,13,17,19,31,61,89,107,127,521,607,1279,2203,2281,3217,4253,
        4423,9689,9941,11213,19937,21701,23209,44497,86243,110503,132049,
        216091,756839,859433,1257787,1398269,2976221,3021377,6972593,
        13466917,20996011,24036583,25964951,30402457,32582657,37156667,
        42643801,43112609,57885161,74207281,77232917,82589933]
S = mp.mpf(0); ds = []
for p in MERS:
    S += p*KAPPA
    f = S - mp.floor(S)
    ds.append(float(min(f, 1-f)))
c1 = sum(1 for d in ds if d < 0.01)
c5 = sum(1 for d in ds if d < 0.05)
md = sum(ds)/len(ds)
check(11, "P016_3: recomputed counts %d (claimed 14), %d (claimed 19), "
          "mean %.3f (claimed 0.187) — claim fails as stated; no signal "
          "vs uniform null" % (c1, c5, md),
      c1 == 1 and c5 == 9 and abs(md - 0.221) < 0.01)

print("S4  Registry (shared module; A278 asserts its own contributions)")
sys.path.insert(0, HERE)
from tbs_registry_gen import generate
items, counts = generate(writer="verify_P278.py")
A278_CHANGES = {
    "P031_1_c": {"retired"}, "P015_3_c": {"retired"},
    "P034_3_c": {"retired"}, "P003_3": {"retired"},
    "P029_1": {"retired"}, "P019_3": {"superseded"},
    "P021_2_c": {"scope"},
    # A278 set these to confirmed-load-bearing; later burn-downs may
    # legitimately evolve them (A280: reworked / refuted)
    "P007_1": {"confirmed-load-bearing", "reworked", "retired"},
    "P007_2": {"confirmed-load-bearing", "reworked", "retired"},
    "P016_3": {"confirmed-load-bearing", "refuted"}}
got = {i["id"]: i["status"] for i in items if i["id"] in A278_CHANGES}
check(12, "A278's ten status changes recorded (or legitimately evolved): %s"
          % all(got.get(k) in v for k, v in A278_CHANGES.items()),
      len(items) == 62 and
      all(got.get(k) in v for k, v in A278_CHANGES.items()))
missing = []
for it in items:
    cb = it.get("closed_by")
    if cb and cb != "P32":
        for tag in cb.split("/"):
            if not glob.glob(os.path.join(ADD, tag[1:] + "_Addendum_*.tex")):
                missing.append(tag)
check(13, "every closing addendum exists on disk (missing: %s)"
          % (missing or "none"), not missing)
nopen = counts.get("unreviewed-or-open", 0)
check(14, "open debt monotone: %d <= 48 (A278's level; later burn-downs "
          "may only shrink it)" % nopen, nopen <= 48)

print(f"\n{'='*60}\nRESULT: {PASS} PASS / {FAIL} FAIL")
sys.exit(0 if FAIL == 0 else 1)
