"""RUN-028 - Round 25: the deep single-witness closure wave on the twelve reference cells.

Round 25 runs B7 alone, deeper, on all twelve of Round 23's cells, checkpointing at depths 30, 32,
34 and 36: all twelve close, with closure depths 30 <= D_j <= 36 (max 36, mean 32.5, median 32),
a budget-coverage curve 3, 7, 11, 12, 340540 nodes in all, and an empty joint residual. It proves
that the unresolved placement volume never grows under refinement, shows on cell 7 that the
pending-leaf count can grow while that volume collapses, and makes B7-first the production
order. Here every tree is rebuilt with exact cores to closure, every checkpoint and every
closing depth is compared, and the statistics are recomputed from the trees.

Checks
  A0 anchors      the numbers and formulas below occur in Round 25 as written
  W1 theorems     sec. 8-10, 14-15: volume monotonicity on every tree; the capacity curve; D*
  W2 closures     sec. 2, 19-20: nodes, CERT leaves and the forest identity of all twelve trees
  W3 checkpoints  the ledger's checkpoints against the same trees cut at those depths
  W4 depths       sec. 1-4: closure depth as defined, against the ledger's; the statistics
  W5 cell 7       sec. 7, 11: its volumes, pending counts and contraction
  W6 residual     sec. 5, 12: the singleton cover and the joint residual
  W7 code         what the package ships, read after the rebuild and never run
  P1 package      the ledger, the policy, the crystal and the text agree
  P2 package      VALIDATION against the archive; its checks from the data
  R1 registry     Round 25's judgments reviewed, first-used statuses defined

Usage: python code/run028_round25_closure_wave.py [--drill] [--blind CID]
"""
import argparse
import copy
import hashlib
import inspect
import json
import math
from multiprocessing import Pool

import numpy as np

import gate
import registry
import run008_round05_saturation_gate as r8
import run009_round06_witness_exchange as r9
import run011_round08_conditional_lift as r11
import run012_round09_adaptive_atlas as r12
import run013_round10_reference_dry_run as r13
import run019_round16_global_pilot as r19
import run020_round17_d3_cpg as r20
import run022_round19_necessity_lift as r22
import run023_round20_mixed_escalation as r23
import run025_round22_fourier_pareto as r25
import run026_round23_portfolio_closure as r26
import run027_round24_residual_joint as r27
from corpus import SOURCES, TREE, source_bytes, walk_sources
from run010_round07_minimizer_atlas import d_star, t_text

PKG = "main.zip!/AMRAL_LUC_FC_Round_25_Package_v0.1.zip!/"
DOC = PKG + "AMRAL_Lebesgue_Finite_Closure_Round_25_Deep_B7_Closure_Wave_v0.1.md"
CRYSTAL = PKG + "AMRAL_LUC_FC_State_Crystal_Round_25_v0.1.md"
LEDGER = PKG + "AMRAL_LUC_FC_Round_25_CLOSURE_LEDGER.json"
POLICY = PKG + "AMRAL_LUC_FC_Round_25_STOPPING_POLICY.json"
VALIDATION = PKG + "AMRAL_LUC_FC_Round_25_VALIDATION.json"
REF = PKG + "AMRAL_LUC_FC_Round_25_reference/"
WAVE = REF + "r25_incremental_wave.py"
LOG = TREE / "data" / "gate-logs" / "run028-round25-closure-wave.json"
CACHE = TREE / "data" / "cache" / "run028-wave.json"
MANIFEST = TREE / "data" / "SOURCE_MANIFEST.v1.json"

T, TM = 0.835, 0.8365
EXACT_MAX, PKG_PAD = 36, 1e-10
ROOT7 = 2 * math.pi / 7 * (2 * t_text(7, d_star(TM))) ** 2

ANCHORS = {
    "W1": [r"V_d=\sum_{C\in\mathcalP_d}\operatorname{Vol}(C).", r"V_{d+1}\leV_d.", r"\rho_{d,\Delta}=\frac{V_{d+\Delta}}{V_d}.",
           r"\Gamma_{B_7}(30)=3,", r"\Gamma_{B_7}(32)=7,", r"\Gamma_{B_7}(34)=11,", r"\Gamma_{B_7}(36)=12.", r"D_\star=36."],
    "W2": ["|0|30|18,555|9,278|", "|1|32|22,009|11,005|", "|2|32|26,189|13,095|", "|3|34|36,193|18,097|", "|4|32|21,271|10,636|",
           "|5|30|18,509|9,255|", "|6|34|31,209|15,605|", "|7|36|45,401|22,701|", "|8|32|26,439|13,220|", "|9|34|41,077|20,539|",
           "|10|34|31,793|15,897|", "|11|30|21,895|10,948|", r"N=2L-1.", r"$$\boxed{340540.}$$", r"\approx28378.", r"$$\boxed{45401}$$"],
    "W4": [r"\boxed{30\leD_j\le36.}", r"D_j=\min\{d:I_{j,B_7}^{(d)}=1\}.", r"D_{\max}=36.", r"\barD=32.5.", r"$$\boxed{32.}$$",
           r"F(d)=\frac1m\left|\{j:D_j\led\}\right|.", r"3/12=25\%.", r"7/12\approx58.33\%.", r"11/12\approx91.67\%.", r"12/12=100\%.",
           r"|\mathcalR_{30}|=9,", r"|\mathcalR_{32}|=5,", r"|\mathcalR_{34}|=1,", r"|\mathcalR_{36}|=0."],
    "W5": [r"1793\text{pending},", r"1918\text{pending}.", r"3.89\times10^{-6}\to2.60\times10^{-7}.", r"$$15\times.$$",
           r"V_{22}\approx3.33\times10^{-5},", r"V_{24}\approx1.05\times10^{-5},", r"V_{26}\approx3.89\times10^{-6},",
           r"V_{28}\approx9.90\times10^{-7},", r"V_{30}\approx2.60\times10^{-7},", r"V_{32}\approx4.22\times10^{-8},",
           r"V_{34}\approx1.61\times10^{-10},", r"V_{36}=0."],
    "W6": [r"\boxed{12/12}", r"\mathcalW_{\rmref}=\{B_7\}", r"\boxed{\varnothing.}", r"I_{j,B_7}=1\qquad\forallj=0,\ldots,11.",
           r"\text{12-CELLREFERENCESINGLETON}B_7\text{COVER:COMPLETE}", r"\text{REFERENCEJOINTRESIDUAL:EMPTY}",
           r"\text{77-CELL/GLOBALRESULT:NOTYETCOMPUTED}", r"\Lambda(D,B_3,B_5,B_7)\ge0.835."],
}

CLAIMS = {
    # the least depth at which each tree has no open box (sec. 1's D_j), cell 0-11
    "closure_depths": [30, 31, 31, 34, 31, 30, 33, 35, 32, 34, 33, 30],
    "true_statistics": {"max": 35, "mean": 32.0, "median": 31.5},
    "checkpoints_exact": True,
    "slack_offset_is_pad": True,
    "cell7_ratio_26_30": 14.96,
    "code_facts": {"lines": 64, "computes": True, "reads_outside_package": True, "loads_round19_modules": True,
                   "checkpoints": [22, 24, 26, 28, 30, 32, 34, 36, 38]},
}

# ---------------------------------------------------------------- the exact lift, with the least new slack at each depth

def exact_lift(pool, c, h, max_depth):
    """RUN-027's exact-core B7 lift; per depth (nodes, closed, open, least slack of the boxes
    closed at that depth)"""
    tn = t_text(7, d_star(TM))
    level = [((math.pi / 7, 0.0, 0.0), (math.pi / 7, tn, tn))]
    per, nodes, closed = {}, 0, 0
    for d in range(max_depth + 1):
        areas = pool.map(r27._exact, [(list(c), list(h), wc, wh) for wc, wh in level], chunksize=8)
        nodes += len(level)
        nxt, opened, slack = [], 0, None
        for (wc, wh), area in zip(level, areas):
            lb = math.pi / 4 if area is None else area - r19.PAD
            if lb >= T:
                closed += 1
                slack = lb - T if slack is None else min(slack, lb - T)
                continue
            opened += 1
            if d == max_depth:
                continue
            trial = []
            for a in range(3):
                hh = list(wh)
                hh[a] /= 2
                trial.append(r23.delta_n(7, hh))
            a = int(np.argmin(trial))
            hh = list(wh)
            hh[a] /= 2
            lo, hi = list(wc), list(wc)
            lo[a] -= hh[a]
            hi[a] += hh[a]
            nxt += [(tuple(lo), tuple(hh)), (tuple(hi), tuple(hh))]
        per[d] = [nodes, closed, opened, slack]
        level = nxt
        if not level:
            break
    return per


def compute():
    with Pool(14) as pool:
        _, cells = r26.twelve(pool)
        return {"cells": [{k: c[k] for k in ("path", "outer", "center", "half")} for c in cells],
                "trees": [exact_lift(pool, c["center"], c["half"], EXACT_MAX) for c in cells]}


def _code_key(files):
    digest = hashlib.sha256()
    for fn in (exact_lift, compute):
        digest.update(inspect.getsource(fn).encode())
    for mod in (r8, r9, r11, r12, r13, r19, r20, r22, r23, r25, r26, r27):
        digest.update(open(mod.__file__, "rb").read())
    digest.update(files)
    digest.update(repr((EXACT_MAX,)).encode())
    return digest.hexdigest()


_COMPUTED = {}


def computed(key_bytes):
    key = _code_key(key_bytes)
    if key not in _COMPUTED:
        if CACHE.exists():
            cached = json.loads(CACHE.read_text(encoding="utf-8"))
            if cached.get("key") == key:
                _COMPUTED[key] = cached["results"]
        if key not in _COMPUTED:
            _COMPUTED[key] = json.loads(json.dumps(compute()))
            CACHE.parent.mkdir(parents=True, exist_ok=True)
            CACHE.write_text(json.dumps({"key": key, "results": _COMPUTED[key]}) + "\n", encoding="utf-8")
    return _COMPUTED[key]


# ---------------------------------------------------------------- checks

def near(a, b, tol):
    return abs(a - b) <= tol


def at(per, d):
    return tuple(r23.at({k: v[:3] for k, v in per.items()}, d))


def closing_depth(per):
    last = max(per, key=int)
    return int(last) if per[last][2] == 0 else None


def volume(per, d):
    return at(per, d)[2] / 2 ** d * ROOT7


def w1_theorems(w):
    """sec. 9: the open volume never grows, on every tree and every level; sec. 14-15"""
    out, trees = [], w["computed"]["trees"]
    worst = max(volume(per, d + 1) - volume(per, d) for per in trees for d in range(EXACT_MAX))
    grows = sum(at(per, d + 1)[2] > at(per, d)[2] for per in trees for d in range(EXACT_MAX))
    depths = [closing_depth(per) for per in trees]
    capacity = {d: sum(x <= d for x in depths) for d in (30, 32, 34, 36)}
    policy = w["policy"]["unresolved_volume"]
    if worst > 0 or capacity != {30: 3, 32: 7, 34: 11, 36: 12} or "V_{d+1} <= V_d" not in policy["monotonicity"]:
        out.append(f"volume growth {worst:.1e}; capacity {capacity}")
    w["w1"] = {"largest_volume_increase": worst, "levels_where_open_count_grows": grows, "capacity": capacity,
               "least_common_budget": max(depths)}
    return out


def w2_closures(w):
    out, trees, cells = [], w["computed"]["trees"], w["ledger"]["cells"]
    for rec, per, cell in zip(cells, trees, w["computed"]["cells"]):
        last = max(per, key=int)
        nodes, closed, opened = per[last][:3]
        if (nodes, closed, opened) != (rec["nodes"], rec["cert_leaves"], rec["pending_leaves"]) or nodes != 2 * closed - 1 \
                or rec["path"] != cell["path"] or not near(rec["marker_outer"], cell["outer"], 1e-13) or not rec["marker_outer"] < T:
            out.append(f"cell {rec['cell']}: {nodes, closed, opened} against {rec['nodes'], rec['cert_leaves'], rec['pending_leaves']}")
    total = sum(per[max(per, key=int)][0] for per in trees)
    L = w["ledger"]
    if total != L["total_independent_tree_nodes"] or max(per[max(per, key=int)][0] for per in trees) != L["max_tree_nodes"]:
        out.append(f"total nodes {total}")
    w["w2"] = {"total_nodes": total, "mean_nodes": total / len(trees)}
    return out


def w3_checkpoints(w):
    """the ledger's checkpoints against the same trees cut at those depths; the new-slack column
    differs from this tree's by the pad (1e-9 here, 1e-10 there)"""
    out, trees = [], w["computed"]["trees"]
    exact, offsets = True, []
    for rec, per in zip(w["ledger"]["cells"], trees):
        prev = -1
        for cp in rec["checkpoints"] or []:
            d = cp["depth"]
            n, cl, o = at(per, d)
            if (n, cl, o) != (cp["nodes_cumulative"], cp["cert_leaves_cumulative"], cp["pending_leaves"]) \
                    or not near(cp["unresolved_volume"], o / 2 ** d * ROOT7, 1e-12 * max(cp["unresolved_volume"], 1e-30)):
                exact = False
                out.append(f"cell {rec['cell']} depth {d}: {n, cl, o}")
            new = [per[str(k)][3] for k in range(prev + 1, d + 1) if str(k) in per and per[str(k)][3] is not None]
            if new and "worst_new_slack" in cp:
                offsets.append(cp["worst_new_slack"] - min(new))
            prev = d
    pad_offset = all(near(x, r19.PAD - PKG_PAD, 1e-14) for x in offsets)
    if exact != w["checkpoints_exact"] or pad_offset != w["slack_offset_is_pad"]:
        out.append(f"checkpoints exact {exact}; slack offsets {min(offsets):.3e}..{max(offsets):.3e}")
    w["w3"] = {"checkpoints": sum(len(r["checkpoints"] or []) for r in w["ledger"]["cells"]), "slack_offsets": [min(offsets), max(offsets)]}
    return out


def w4_depths(w):
    """sec. 1 defines D_j as the least depth with no open box; the ledger records the checkpoint"""
    out, trees, L = [], w["computed"]["trees"], w["ledger"]
    depths = [closing_depth(per) for per in trees]
    recorded = [c["closure_depth"] for c in L["cells"]]
    stats = {"max": max(depths), "mean": round(sum(depths) / len(depths), 4), "median": float(np.median(depths))}
    checkpoint = [min(b for b in (30, 32, 34, 36) if b >= d) for d in depths]
    if depths != w["closure_depths"] or stats != w["true_statistics"] or checkpoint != recorded \
            or (L["max_closure_depth"], L["mean_closure_depth"], L["median_closure_depth"]) != (max(recorded), sum(recorded) / 12, float(np.median(recorded))):
        out.append(f"closing depths {depths}, statistics {stats}; ledger {recorded}")
    cov = {str(d): sorted(i for i, x in enumerate(depths) if x > d) for d in (30, 32, 34, 36)}
    if any(cov[d] != L["coverage_curve"][d]["residual_cells"] for d in cov):
        out.append(f"coverage residuals {cov}")
    w["w4"] = {"closing_depths": depths, "ledger_depths": recorded, "earlier_than_recorded": [i for i, (a, b) in enumerate(zip(depths, recorded)) if a < b],
               "statistics": stats, "odd_depth_coverage": {d: sum(x <= d for x in depths) for d in (31, 33, 35)}}
    return out


def w5_cell7(w):
    out, per = [], w["computed"]["trees"][7]
    vols = {d: volume(per, d) for d in range(22, 37, 2)}
    text = {22: 3.33e-5, 24: 1.05e-5, 26: 3.89e-6, 28: 9.90e-7, 30: 2.60e-7, 32: 4.22e-8, 34: 1.61e-10, 36: 0.0}
    if any((not near(vols[d], v, 5e-3 * v) if v else vols[d] != 0) for d, v in text.items()) \
            or (at(per, 26)[2], at(per, 30)[2]) != (1793, 1918) or not near(vols[26] / vols[30], w["cell7_ratio_26_30"], 0.01):
        out.append(f"cell 7: {vols}, pending {at(per, 26)[2]}, {at(per, 30)[2]}")
    w["w5"] = {"volumes": vols, "pending_26_30": [at(per, 26)[2], at(per, 30)[2]], "ratio_26_30": vols[26] / vols[30]}
    return out


def w6_residual(w):
    trees, L = w["computed"]["trees"], w["ledger"]
    closed = all(closing_depth(per) is not None for per in trees)
    sp = L["singleton_portfolio"]
    ok = closed and sp["strict_reference_edges"] == 12 and sp["joint_admissible_residual_cells"] == [] and L["all_cells_complete"]
    w["w6"] = {"all_close": closed}
    return [] if ok else ["the singleton cover"]


def w7_code(w):
    """the shipped runner, read after the rebuild"""
    import re
    code = w["wave_code"]
    facts = {"lines": code.count("\n"), "computes": "hull_area_exact" in code and "erode_reuleaux" in code,
             "reads_outside_package": bool(re.search(r"Path\(['\"]/", code)),
             "loads_round19_modules": "Round_19_reference/continuation_probe.py" in code,
             "checkpoints": sorted(int(x) for x in re.search(r"for end in \[([0-9, ]+)\]", code).group(1).split(","))}
    w["w7"] = facts
    return [] if facts == w["code_facts"] else [f"the runner: {facts}"]


def p1_package(w):
    out, L, text = [], w["ledger"], gate.squash(w["text"])
    for c in L["cells"]:
        row = f"|{c['cell']}|{c['closure_depth']}|{c['nodes']:,}|{c['cert_leaves']:,}|"
        if row not in text:
            out.append(f"sec. 2's row for cell {c['cell']}")
    if L["coverage_curve"] != w["policy"]["reference_coverage"] or w["policy"]["budget_wave"] != [30, 32, 34, 36]:
        out.append("the policy against the ledger")
    crystal = gate.squash(w["crystal"])
    depths = ",".join(str(c["closure_depth"]) for c in L["cells"])
    for frag in (f"[{depths}].", r"\boxed{36}.", "-depth30:3/12", "-depth32:7/12", "-depth34:11/12", "-depth36:12/12"):
        if frag not in crystal:
            out.append(f"crystal: {frag}")
    w["p1"] = {"rows": len(L["cells"])}
    return out


def p2_package(w):
    import re
    out, v = [], w["validation"]
    leaves = {row[0]: row for row in w["manifest"]["leaves"]}
    for key, leaf_id, text in (("round25", DOC, w["text"]), ("state_crystal", CRYSTAL, w["crystal"])):
        rec, (_, size, digest) = v[key], leaves[leaf_id]
        n = text.count("$$")
        if rec["sha256"] != digest or rec["bytes"] != size or not rec["utf8"] \
                or rec["double_dollar_count"] != n or rec["double_dollar_even"] != (n % 2 == 0) \
                or rec["contains_unicode_escape_sequence"] != bool(re.search(r"\\u[0-9a-fA-F]{4}", text)) \
                or rec["contains_bracket_math_delimiter"] != bool(re.search(r"\\[\[\]()]", text)):
            out.append(f"VALIDATION {key} against the archive and the document")
    for key, leaf_id in (("closure_ledger_sha256", LEDGER), ("stopping_policy_sha256", POLICY)):
        if v[key] != leaves[leaf_id][2]:
            out.append(f"VALIDATION {key} against the archive")
    L = w["ledger"]
    cov = L["coverage_curve"]
    kc = {"all_12_complete": L["all_cells_complete"] and all(c["pending_leaves"] == 0 for c in L["cells"]),
          "max_depth_36": L["max_closure_depth"] == 36, "coverage_30_is_3": cov["30"]["closed_cells"] == 3,
          "coverage_32_is_7": cov["32"]["closed_cells"] == 7, "coverage_34_is_11": cov["34"]["closed_cells"] == 11,
          "coverage_36_is_12": cov["36"]["closed_cells"] == 12,
          "all_forest_identities": all(c["nodes"] == 2 * c["cert_leaves"] - 1 for c in L["cells"]),
          "all_markers_below_target": all(c["marker_outer"] < T for c in L["cells"]),
          "joint_reference_residual_empty": L["singleton_portfolio"]["joint_admissible_residual_cells"] == [],
          "no_global_claim": L["global_lebesgue_claim"] is False}
    if kc != v["checks"] or v["status"] != "PASS":
        out.append(f"VALIDATION checks {kc}")
    w["p2"] = kc
    return out


R25_DEFINITIONS = {
    "EMPTY": ("in-line", "sec. 0: no reference cell is left for joint admission"),
    "NOT YET COMPUTED": ("in-line", "sec. 0: the 77-cell and global results have not been run"),
}
R25_REVIEWS = [
    ("COMPLETE", "12-CELL REFERENCE SINGLETON B_7 COVER", "computation", "PASS",
     "all twelve exact trees close, node for node (W2); the recorded closure depths are the checkpoints 30/32/34/36, and six "
     "cells close a level earlier (W4)"),
    ("EMPTY", "REFERENCE JOINT RESIDUAL", "computation", "PASS", "every cell has its B7 edge (W6)"),
    ("JOINT-REDUNDANT", "all cells end at", "computation", "PASS", "every cell has a strict B7 edge (W2, W6)"),
    ("NOT YET COMPUTED", "77-CELL / GLOBAL RESULT", "reading", "PASS", "true: only the twelve are run, here and in the package"),
    ("STILL COMPUTE-DEFERRED", "a_{Leb}≥0.8350", "n/a", "n/a", "sec. 0's boxed summary; read from census v5 on (RUN-003)"),
]


def r1_registry(w):
    return registry.completeness(w["registry"], "R25", w["definitions"], w["reviews"])


CHECKS = {"A0": gate.anchors_check(ANCHORS), "W1": w1_theorems, "W2": w2_closures, "W3": w3_checkpoints, "W4": w4_depths,
          "W5": w5_cell7, "W6": w6_residual, "W7": w7_code, "P1": p1_package, "P2": p2_package, "R1": r1_registry}
DEPENDS = {"A0": {"text"}, "W1": {"computed", "policy"}, "W2": {"computed", "ledger"},
           "W3": {"computed", "ledger", "checkpoints_exact", "slack_offset_is_pad"},
           "W4": {"computed", "ledger", "closure_depths", "true_statistics"},
           "W5": {"computed", "cell7_ratio_26_30"}, "W6": {"computed", "ledger"}, "W7": {"wave_code", "code_facts"},
           "P1": {"ledger", "policy", "text", "crystal"},
           "P2": {"validation", "manifest", "text", "crystal", "ledger"},
           "R1": {"registry", "definitions", "reviews"}}


def load_inputs():
    blobs = {n: source_bytes(n) for n in SOURCES}
    got = {leaf.id: d for leaf, d in walk_sources(blobs, keep=lambda l: l.id.startswith(PKG)) if d is not None}
    return {"text": got[DOC].decode("utf-8"), "crystal": got[CRYSTAL].decode("utf-8"), "ledger": json.loads(got[LEDGER]),
            "policy": json.loads(got[POLICY]), "validation": json.loads(got[VALIDATION]), "wave_code": got[WAVE].decode("utf-8"),
            "key_bytes": got[LEDGER], "manifest": json.loads(MANIFEST.read_text(encoding="utf-8"))}


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--drill", action="store_true")
    ap.add_argument("--blind", metavar="CID")
    args = ap.parse_args()
    inputs = load_inputs()
    results_computed = computed(inputs["key_bytes"])

    def build():
        return {**{k: v for k, v in inputs.items() if k != "key_bytes"}, "computed": results_computed,
                "registry": registry.load(), "definitions": dict(R25_DEFINITIONS), "reviews": list(R25_REVIEWS),
                **copy.deepcopy(CLAIMS)}

    if args.blind:
        CHECKS[args.blind] = lambda w: []
        args.drill = True
    w = build()
    results = {c: fn(w) for c, fn in CHECKS.items()}
    for c, f in results.items():
        print(f"{c} {'PASS' if not f else 'FAIL'}", *(f"\n     {x}" for x in f[:6]))
    for key in ("w1", "w2", "w3", "w4", "w5", "w6", "w7", "p1", "p2"):
        print(key, json.dumps(w.get(key), default=float, ensure_ascii=False)[:1200])
    if not args.drill:
        return
    L, text = inputs["ledger"], inputs["text"]

    def edit(fn):
        x = copy.deepcopy(L)
        fn(x)
        return x

    cases = [
        ("K0-unmodified", "control", {}, set()),
        ("K1-doc-crlf", "control", {"text": text.replace("\n", "\r\n")}, set()),
        ("K2-ledger-keys-sorted", "control", {"ledger": json.loads(json.dumps(L, sort_keys=True))}, set()),
        ("K3-policy-keys-sorted", "control", {"policy": json.loads(json.dumps(inputs["policy"], sort_keys=True))}, set()),
        ("M1-doc-ratio", "mutation", {"text": text.replace("$$\n15\\times.\n$$", "$$\n16\\times.\n$$")}, {"A0"}),
        ("M2-policy-monotonicity", "mutation",
         {"policy": {**inputs["policy"], "unresolved_volume": {**inputs["policy"]["unresolved_volume"], "monotonicity": "V may grow."}}}, {"W1"}),
        ("M3-cell-nodes", "mutation", {"ledger": edit(lambda x: x["cells"][9].update(nodes=x["cells"][9]["nodes"] + 2,
                                                                                    cert_leaves=x["cells"][9]["cert_leaves"] + 1))},
         {"W2", "P1"}),
        ("M4-checkpoint", "mutation",
         {"ledger": edit(lambda x: x["cells"][6]["checkpoints"][2].update(pending_leaves=x["cells"][6]["checkpoints"][2]["pending_leaves"] + 1))},
         {"W3"}),
        ("M5-slack-reading", "mutation", {"slack_offset_is_pad": False}, {"W3"}),
        ("M6-depth-claim", "mutation", {"closure_depths": [30, 32, 32, 34, 32, 30, 34, 36, 32, 34, 34, 30]}, {"W4"}),
        ("M7-statistics-claim", "mutation", {"true_statistics": {**CLAIMS["true_statistics"], "max": 36}}, {"W4"}),
        ("M8-cell7-ratio", "mutation", {"cell7_ratio_26_30": 15.5}, {"W5"}),
        ("M9-residual", "mutation", {"ledger": edit(lambda x: x["singleton_portfolio"].update(joint_admissible_residual_cells=[7]))}, {"W6", "P2"}),
        ("M10-runner-facts", "mutation", {"code_facts": {**CLAIMS["code_facts"], "computes": False}}, {"W7"}),
        ("M11-crystal", "mutation", {"crystal": inputs["crystal"].replace("- depth34: 11/12", "- depth34: 10/12")}, {"P1"}),
        ("M12-validation-digest", "mutation", {"validation": {**inputs["validation"], "closure_ledger_sha256": "0" * 64}}, {"P2"}),
        ("M13-validation-check", "mutation",
         {"validation": {**inputs["validation"], "checks": {**inputs["validation"]["checks"], "max_depth_36": False}}}, {"P2"}),
        ("M14-review-dropped", "mutation", {"reviews": list(R25_REVIEWS[1:])}, {"R1"}),
    ]
    if args.blind:
        cases = [c for c in cases if args.blind in c[3]]
    d = gate.run_drill(build, CHECKS, DEPENDS, cases)
    summary = gate.summarize(d, CHECKS)
    print(gate.report_drill(summary))
    for x in d:
        if not x["ok"]:
            print("   DRILL FAIL", x)
    if args.blind:
        n = sum(1 for x in d if args.blind in x["expected"] and args.blind not in x["tripped"])
        print(f"blind {args.blind}: drill reported it blind in {n} cases (nothing written)")
        return
    log = {"run": "RUN-028", "subject": "Round 25: the deep single-witness closure wave on the twelve reference cells",
           "document": DOC, "checks": {c: {"pass": not f, "failures": f} for c, f in results.items()},
           **{k: w.get(k) for k in ("w1", "w2", "w3", "w4", "w5", "w6", "w7", "p1", "p2")}, "drill": summary}
    LOG.write_text(json.dumps(log, ensure_ascii=False, indent=1, default=float) + "\n", encoding="utf-8")
    if not results["R1"]:
        registry.record("R25", "RUN-028", R25_DEFINITIONS, R25_REVIEWS)
        print(f"registry: {len(R25_DEFINITIONS)} definitions, {len(R25_REVIEWS)} reviews recorded for R25")


if __name__ == "__main__":
    main()
