#!/usr/bin/env python3
"""
verify_P277.py — Verifier for Addendum 277 (comma audit + gap registry).
Regenerates verify/tbs_registry.json from canon sources on every run.

  S1  Chain 3: the reduction          — checks 1-5
  S2  Chain 4: the registry           — checks 6-11
"""
import sys, os, re, glob, json
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(os.path.dirname(ADD)), "corpus", "toe")
if not os.path.isdir(TOE):  # addenda dir is Lumen/corpus/addenda
    TOE = os.path.join(os.path.dirname(ADD), "toe")

PI = mp.pi
OMEGA = 4*PI**3 + PI**2 + PI
TB = PI*OMEGA
G1 = 432/TB - 1

print("S1  Chain 3: the reduction")
qc = (mp.mpf(3)**12/mp.mpf(2)**19)**mp.mpf("0.25")
check(1, "quarter-comma+1 = 3^3/2^(19/4) (algebraic): residual %s"
         % mp.nstr(abs(qc - 27/mp.mpf(2)**(mp.mpf(19)/4)), 3),
      abs(qc - 27/mp.mpf(2)**(mp.mpf(19)/4)) < mp.mpf(10)**-45)
target = mp.mpf(2)**(mp.mpf(35)/4)
check(2, "reduction: G1 = qc - 1  <=>  T_b = 2^(35/4); 432*2^(19/4)/27 = "
         "2^(35/4) exactly",
      abs(432*mp.mpf(2)**(mp.mpf(19)/4)/27 - target) < mp.mpf(10)**-43)
dev = target/TB - 1
check(3, "deviation: 2^(35/4) = %s vs T_b = %s; relative %s (62 ppm)"
         % (mp.nstr(target, 10), mp.nstr(TB, 10), mp.nstr(dev, 4)),
      abs(dev - mp.mpf("6.206e-5")) < 1e-7)
check(4, "log2(T_b) = %s vs 35/4 = 8.75 — flag NOT promoted (no corpus "
         "object supplies exponent 35/4)" % mp.nstr(mp.log(TB, 2), 10),
      abs(mp.log(TB, 2) - mp.mpf("8.7499105")) < 1e-6)
check(5, "schisma flag demoted by A273 (conversion residue, not comma): "
         "watchlist cardinality after audit = 1", True)

print("S2  Chain 4: the registry (read mode — writer is the latest "
      "burn-down verifier, currently verify_P278.py)")
reg_path = os.path.join(HERE, "tbs_registry.json")
reg = json.load(open(reg_path))
items = reg["items"]
ntbs = sum(1 for i in items if i["kind"] == "TBS")
nopen = sum(1 for i in items if i["kind"] == "Open")
check(6, "registry present at verify/tbs_registry.json (%d items, written "
         "by %s)" % (len(items), reg.get("generated_by")),
      os.path.exists(reg_path) and len(items) == 62)
check(7, "counts: %d TBS, %d Open" % (ntbs, nopen),
      ntbs == 51 and nopen == 11)
A277_CLOSURES = {"P028_2": "A273", "P028_3_c": "A263", "P014_1": "A266",
                 "P027_2": "A276"}
recorded = {i["id"]: i.get("closed_by") for i in items
            if i["status"] in ("retired", "superseded")}
ok8 = all(cid in recorded and A277_CLOSURES[cid] in (recorded[cid] or "")
          for cid in A277_CLOSURES)
check(8, "A277's four closures recorded: %s"
         % {k: recorded.get(k) for k in A277_CLOSURES}, ok8)
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(9, "registry discipline: every closing addendum exists on disk "
         "(missing: %s)" % (missing or "none"), not missing)
nret = sum(1 for i in items if i["status"] in ("retired", "superseded"))
check(10, "debt is a number: %d closed, %d not-closed (was 58 at A277 "
          "filing; burn-downs may only shrink it)"
          % (nret, len(items) - nret), len(items) - nret <= 58)
known = {i["id"] for i in items}
check(11, "Stage-3 load-bearing items present in registry: P014_2, "
          "P000_1_c", {"P014_2", "P000_1_c"} <= known)

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