"""RUN-039 - Round 36: the depth-30 batch complete, and the first frontier kept as a proof object.

Round 36 replays cells 75 and 76's certificates from their bytes (10948/10948, 10932/10932), which with their
dominance audits completes the depth-30 batch - seven publication candidates of seven; and puts DFRONT-v0.1 to
work: cell 33's depth-36 frontier, lost with the runtime, is rebuilt from the witness root to Round 26's
durable counts - 129,401 nodes, 14,027 pending boxes, the volume exactly - and kept as 126,327 bytes of
dyadic box codes. It queues twelve depth-32 cells and rebuilds cell 49's tree (19,971 nodes, 9,986 leaves).
Here both certificates are replayed in this tree's integer arithmetic; cell 33 is lifted here to depth 36
and its open boxes, turned into dyadic codes, set against the DFRONT file box for box; cell 49 is lifted
here and its tree encoded in the package's convention and hashed against its manifest; the depth-32 queue
against this tree's atlas and Round 29's markers.

Checks
  A0 anchors      the numbers and formulas below occur in Round 36 as written
  W1 replay       sec. 0-3: cells 75 and 76's certificates - format, and every vertex in this tree's arithmetic
  W2 dfront       sec. 5-7: the DFRONT files decoded from the spec; cell 33's frontier against this tree's lift
  W3 cell 49      sec. 11: cell 49's tree lifted here, encoded and hashed against its manifest
  W4 queue        sec. 11: the depth-32 queue against this tree's atlas and Round 29's markers
  W5 stages       sec. 3-4, 8-10: the stage counts; the geometry unchanged; the recovery audit
  W6 code         what the package ships, read after the rebuild and never run
  P1 package      the shard files, the certificate records, the DFRONT records, the dashboard and the crystal agree
  P2 package      VALIDATION against the archive; its checks from the data
  R1 registry     Round 36's judgments reviewed, the first-used status defined

Usage: python code/run039_round36_dfront.py [--drill] [--blind CID]
"""
import argparse
import collections
import copy
import hashlib
import io
import json
import math
import re
import struct
import zipfile
from fractions import Fraction
from multiprocessing import Pool

import gate
import registry
import run008_round05_saturation_gate as r8
import run009_round06_witness_exchange as r9
import run019_round16_global_pilot as r19
import run023_round20_mixed_escalation as r23
import run027_round24_residual_joint as r27
import run029_round26_full_atlas as r29
import run030_round27_interval_replay as r30
import run031_round28_exact_root as r31
import run032_round29_marker_upper as r32
import run033_round30_a1_replay as r33
import run035_round32_bulk_wave as r35
import run036_round33_dominance as r36
import run037_round34_rhcert as r37
import run038_round35_rhcert_production as r38
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_36_Package_v0.1.zip!/"
DOC = PKG + "AMRAL_Lebesgue_Finite_Closure_Round_36_Depth30_DFRONT_Recovery_v0.1.md"
CRYSTAL = PKG + "AMRAL_LUC_FC_State_Crystal_Round_36_v0.1.md"
SHARD = {n: PKG + f"AMRAL_LUC_FC_Round_36_PUBLICATION_CANDIDATE_SHARD_{n}.json" for n in (75, 76)}
DASH = PKG + "AMRAL_LUC_FC_Round_36_COVERAGE_DASHBOARD.json"
BATCH = PKG + "AMRAL_LUC_FC_Round_36_DEPTH30_BATCH_COMPLETE.json"
DSPEC = PKG + "AMRAL_LUC_FC_Round_36_DFRONT_IMPLEMENTATION_SPEC_v0.1.json"
AUDIT = PKG + "AMRAL_LUC_FC_Round_36_GEOMETRY_RECOVERY_AUDIT.json"
QUEUE = PKG + "AMRAL_LUC_FC_Round_36_DEPTH32_QUEUE.json"
CELL49 = PKG + "AMRAL_LUC_FC_Round_36_CELL49_SHARD_STATUS.json"
VALIDATION = PKG + "AMRAL_LUC_FC_Round_36_VALIDATION.json"
CERTZIP = {n: f"AMRAL_LUC_FC_Round_36_Cell{n}_RHCert.zip" for n in (75, 76)}
CERT = {n: PKG + CERTZIP[n] + "!/" for n in (75, 76)}
DZIP = PKG + "AMRAL_LUC_FC_Round_36_Cell33_DFRONT.zip!/"
REF = PKG + "AMRAL_LUC_FC_Round_36_reference/"
D33 = REF + "AMRAL_LUC_FC_Round_36_CELL33_DFRONT.bin"
D33_MAN = REF + "AMRAL_LUC_FC_Round_36_CELL33_DFRONT_MANIFEST.json"
D33_SUP = REF + "AMRAL_LUC_FC_Round_36_CELL33_DFRONT_RECOVERY_SUPPLEMENT.json"
DTEST = REF + "AMRAL_LUC_FC_Round_36_DFRONT_TEST_FRONTIER.bin"
DVAL = REF + "AMRAL_LUC_FC_Round_36_DFRONT_VALIDATION.json"
M49 = REF + "manifest.json"
LOG = TREE / "data" / "gate-logs" / "run039-round36-dfront.json"
MANIFEST = TREE / "data" / "SOURCE_MANIFEST.v1.json"
KERNEL = "main.zip!/AMRAL_LUC_FC_Round_19_Package_v0.1.zip!/AMRAL_LUC_FC_Round_19_reference/official_exact_kernel_minimal.py"
SCHEDULER = "main.zip!/AMRAL_LUC_FC_Round_26_Package_v0.1.zip!/AMRAL_LUC_FC_Round_26_reference/wave_scheduler.py"

T = 0.835
PAIR = (75, 76)
DEPTH33, DEPTH49 = 36, 32


# ---------------------------------------------------------------- DFRONT-v0.1, decoded from the spec file alone

def decode_dfront(b):
    """the header (<8sHHII: magic, version, cell, a depth field, box count), a 32-byte dependency hash and a
    32-byte parent hash, then per box six uvarints k_phi, m_phi, k_x, m_x, k_y, m_y"""
    magic, version, cell, field, count = struct.unpack_from("<8sHHII", b, 0)
    i = struct.calcsize("<8sHHII")
    dep, parent = b[i:i + 32].hex(), b[i + 32:i + 64].hex()
    i += 64
    boxes = []
    for _ in range(count):
        v = []
        for _ in range(6):
            x, i = r37.uvarint(b, i)
            v.append(x)
        boxes.append(tuple(v))
    return {"magic": magic.decode(), "version": version, "cell": cell, "field": field, "count": count, "dependency": dep, "parent": parent,
            "consumed": i == len(b)}, boxes


def uvar(n):
    out = bytearray()
    while n >= 128:
        out.append(n & 127 | 128)
        n >>= 7
    out.append(n)
    return bytes(out)


def encode_dfront(boxes, cell, base_depth, dependency, parent="0" * 64):
    """DFRONT-v0.1 written from the spec: the header, the two hashes, the boxes in canonical order"""
    out = bytearray(struct.pack("<8sHHII", b"DFRONT01", 1, cell, base_depth, len(boxes))) + bytes.fromhex(dependency) + bytes.fromhex(parent)
    for b in sorted(boxes):
        for v in b:
            out += uvar(v)
    return bytes(out)


def disjoint(boxes):
    """exact pairwise interior-disjointness of dyadic boxes: two boxes overlap in their interiors iff on every
    axis one interval holds the other (dyadic intervals nest or are interior-disjoint); a sweep over the
    phi axis's integer endpoints on the finest common grid"""
    kmax = max(b[0] for b in boxes)
    events = sorted([(b[1] << (kmax - b[0]), 1, i) for i, b in enumerate(boxes)] + [((b[1] + 1) << (kmax - b[0]), 0, i) for i, b in enumerate(boxes)])
    active = set()
    for _, kind, i in events:
        if kind == 0:
            active.discard(i)
            continue
        bi = boxes[i]
        for j in active:
            bj = boxes[j]
            if all(_nest(bi[2 * a], bi[2 * a + 1], bj[2 * a], bj[2 * a + 1]) for a in (1, 2)):
                return False
        active.add(i)
    return True


def _nest(k1, m1, k2, m2):
    return (m1 >> (k1 - k2)) == m2 if k1 >= k2 else (m2 >> (k2 - k1)) == m1


def codes(frontier, depth):
    """this tree's open boxes (hex paths with a leading 1, 0 the lower child) as dyadic codes, by the one
    split sequence: (k, m) goes to (k + 1, 2m) on the lower child, (k + 1, 2m + 1) on the upper"""
    seq = r30.split_sequence(depth)
    out = []
    for x in frontier:
        k, m = [0, 0, 0], [0, 0, 0]
        for d, bit in enumerate(bin(int(x, 16))[3:]):
            a = seq[d][0]
            k[a] += 1
            m[a] = 2 * m[a] + int(bit)
        out.append((k[0], m[0], k[1], m[1], k[2], m[2]))
    return sorted(out)


def lift33_compute(path):
    box = r35.cell_box(path)
    with Pool(14) as pool:
        return r29.lift_pad(pool, box["center"], box["half"], DEPTH33, r30.PKG_PAD)


def lift33_computed(path):
    """cell 33 lifted here to depth 36 under the package's pad (RUN-029's padded lift)"""
    return r35._cached("run039-cell33.json", [lift33_compute, r29.lift_pad, r35.cell_box, r8, r9, r19, r23, r27, r29, r30, path.encode()],
                       lambda: lift33_compute(path))


# ---------------------------------------------------------------- cell 49: the tree, encoded and hashed

def pack(bits):
    out = bytearray((len(bits) + 7) // 8)
    for i, b in enumerate(bits):
        if b:
            out[i >> 3] |= 1 << (7 - (i & 7))
    return bytes(out)


def encode(leaf_paths, depth):
    """a tree from its leaf paths in the package's convention: preorder, 1 an internal node, the lower child
    first; per internal node its split axis in 2 bits, high bit first (from the one split sequence)"""
    leaves = set(leaf_paths)
    seq = r31.float_sequence(t_text(7, d_star(r31.TM)), depth)
    top, axes, stack = [], [], [""]
    while stack:
        p = stack.pop()
        if p in leaves:
            top.append(0)
            continue
        top.append(1)
        a = seq[len(p)][0]
        axes.extend(((a >> 1) & 1, a & 1))
        stack.extend((p + "1", p + "0"))
    return top, axes


def lift49_compute(path):
    box = r35.cell_box(path)
    with Pool(14) as pool:
        return [[p, area] for p, _, _, area in r30.leaves_with_paths(pool, box["center"], box["half"], DEPTH49)]


def lift49_computed(path):
    return r35._cached("run039-cell49.json", [lift49_compute, r30.leaves_with_paths, r35.cell_box, r8, r9, r19, r23, r27, r30, path.encode()],
                       lambda: lift49_compute(path))


def load_inputs():
    blobs = {n: source_bytes(n) for n in SOURCES}
    r33ref = r36.REF
    want = {r33ref + f"cell{n}_{k}" for n in PAIR for k in ("manifest.json", "topology.bin")} | {r38.REF + f"cell{n}_mpmath_leaf_ledger.json" for n in PAIR} \
        | {r29.LEDGER} | {r32.REF + f"marker_{c:02d}.json" for c in range(77)}
    got = {leaf.id: d for leaf, d in walk_sources(blobs, keep=lambda l: l.id.startswith(PKG) or l.id in want) if d is not None}
    sha = lambda b: hashlib.sha256(b).hexdigest()
    outer = zipfile.ZipFile(io.BytesIO(source_bytes("main.zip")))
    pkg = zipfile.ZipFile(io.BytesIO(outer.read(PKG.split("!/")[1])))
    certs, cells = {}, {}
    for n in PAIR:
        z = pkg.read(CERTZIP[n])
        rec = [k for k in got if k.startswith(CERT[n]) and k.endswith("_RHCERT_REPLAY.json")][0]
        certs[str(n)] = {"rhcert": got[CERT[n] + f"cell{n}.rhcert"], "rhidx": got[CERT[n] + f"cell{n}.rhidx"], "manifest": json.loads(got[CERT[n] + "rhcert_manifest.json"]),
                         "record": json.loads(got[rec]), "zip": [len(z), sha(z)], "digests": [sha(got[CERT[n] + f"cell{n}.rhcert"]), sha(got[CERT[n] + f"cell{n}.rhidx"])]}
        cells[str(n)] = {"manifest": json.loads(got[r33ref + f"cell{n}_manifest.json"]), "topology": got[r33ref + f"cell{n}_topology.bin"],
                         "ledger": json.loads(got[r38.REF + f"cell{n}_mpmath_leaf_ledger.json"])}
    dz = pkg.read("AMRAL_LUC_FC_Round_36_Cell33_DFRONT.zip")
    return {"text": got[DOC].decode("utf-8"), "crystal": got[CRYSTAL].decode("utf-8"), "shards": {str(n): json.loads(got[p]) for n, p in SHARD.items()},
            "dashboard": json.loads(got[DASH]), "batch": json.loads(got[BATCH]), "dspec": json.loads(got[DSPEC]), "audit": json.loads(got[AUDIT]),
            "queue": json.loads(got[QUEUE]), "cell49": json.loads(got[CELL49]), "validation": json.loads(got[VALIDATION]), "certs": certs, "cells": cells,
            "dfront": {"cell33": got[D33], "test": got[DTEST], "manifest": json.loads(got[D33_MAN]), "supplement": json.loads(got[D33_SUP]),
                       "validation": json.loads(got[DVAL]), "zip": [len(dz), sha(dz)],
                       "copies_equal": [got[D33] == got[DZIP + "AMRAL_LUC_FC_Round_36_CELL33_DFRONT.bin"],
                                        got[D33_MAN] == got[DZIP + "AMRAL_LUC_FC_Round_36_CELL33_DFRONT_MANIFEST.json"],
                                        got[DSPEC] == got[DZIP + "AMRAL_LUC_FC_Round_36_DFRONT_IMPLEMENTATION_SPEC_v0.1.json"],
                                        got[REF + "r36_dfront_codec.py"] == got[DZIP + "r36_dfront_codec.py"]],
                       "digests": {k: sha(got[p]) for k, p in (("cell33", D33), ("test", DTEST), ("validation", DVAL), ("manifest", D33_MAN))}},
            "manifest49": json.loads(got[M49]), "ledger26": json.loads(got[r29.LEDGER]),
            "markers": {c: json.loads(got[r32.REF + f"marker_{c:02d}.json"]) for c in range(77)},
            "code": {k[len(REF):]: v.decode("utf-8") for k, v in got.items() if k.startswith(REF) and k.endswith(".py")},
            "code_digests": {k[len(REF):]: sha(v) for k, v in got.items() if k.startswith(REF) and k.endswith(".py")},
            "manifest": json.loads(MANIFEST.read_text(encoding="utf-8"))}


def world(inputs):
    c = inputs["cells"]
    return {**inputs,
            "replay": {str(n): r35._cached(f"run039-replay{n}.json", [r37.decode, r37.uvarint, r37.replay, r38.replay_compute, r33.base_cores, r35.cell_box,
                                                                      r8, r9, r19, r30, r31, inputs["certs"][str(n)]["rhcert"] + c[str(n)]["topology"]],
                                           lambda n=n: r38.replay_compute(inputs["certs"][str(n)]["rhcert"], c[str(n)])) for n in PAIR},
            "lift33": lift33_computed(inputs["dfront"]["manifest"]["base_path"]), "lift49": lift49_computed(inputs["manifest49"]["base_path"])}


ANCHORS = {
    "W1": [r"10948\text{leaves},\qquad2{,}627{,}357\text{rationalvertices}.", r"44{,}382{,}455.", r"\boxed{10948/10948\text{PASS}}.", r"6.2517761412\times10^{-8}>0.",
           r"10932\text{leaves},\qquad2{,}617{,}252\text{rationalvertices}.", r"44{,}229{,}325\text{bytes}.", r"\boxed{10932/10932\text{PASS}}.", r"2.0477267270\times10^{-8}>0.",
           r"1690\text{uniquestates},\quad0\text{failures}.", r"1688\text{uniquestates},\quad0\text{failures}."],
    "W2": [r"\boxed{129401\text{nodes}}", r"\boxed{14027\text{pendingboxes}}", r"V_{36}=2.9748317031636626\times10^{-8}", r"\boxed{126327\text{bytes}}.",
           r"(k,m)\xrightarrow{L}(k+1,2m),", r"(k,m)\xrightarrow{R}(k+1,2m+1).", r"0\lem<2^k", r"N=129401,", r"L_{\rmpending}=14027,", r"N_{\rmrebuild}=129401",
           r"L_{\rmpending,rebuild}=14027", r"\texttt{CELL33-DFRONT-RECOVERY:PASS}."],
    "W3": [r"19971\text{nodes},\quad9986\text{leaves}."],
    "W4": [r"\boxed{12\text{closure-depth-32cells}}.", r"49,\64,\66,\12,\59,\57,\ldots"],
    "W5": [r"\{47,48,68,69,70,75,76\}", r"7/7\text{arepublication-candidateshards}.", r"\text{Depth-30PublicationBatch}=7/7.", r"7/77\approx9.09\%.", r"7/66\approx10.61\%.",
           r"\boxed{59}", r"\text{proof-stateeffect}=0.", r"\boxed{66/77}."],
    "P1": [r"a_{\mathrm{Leb}}\ge0.835\text{NOTCERTIFIED}."],
}

CLAIMS = {
    "replay_claim": {"75": {"header": ["L34RHC01", 18, 10948], "consumed": True, "index": [True, True, True], "ledger": [10948, 10948, 2627357], "replay": [10948, 10948, 0],
                            "least": [8258, "11010110100110111101000001111", 6.251776141237558e-08], "is_record": [True, True], "to_ledger": 2.6e-17},
                     "76": {"header": ["L34RHC01", 18, 10932], "consumed": True, "index": [True, True, True], "ledger": [10932, 10932, 2617252], "replay": [10932, 10932, 0],
                            "least": [9570, "11010110110100101111001110011", 2.0477267269918978e-08], "is_record": [True, True], "to_ledger": 2.7e-17}},
    "dfront_claim": {"test": {"header": ["DFRONT01", 1, 31, 40, 2], "consumed": True, "canonical": True, "ranges": True, "disjoint": True, "volume": "1/2", "parent_zero": False},
                     "cell33": {"header": ["DFRONT01", 1, 33, 40, 14027], "consumed": True, "canonical": True, "ranges": True, "disjoint": True, "volume": "14027/68719476736",
                                "parent_zero": True},
                     "mine": {"boxes_equal": True, "bytes_equal": True, "counts": [129401, 50674, 14027], "manifest": [True, True, True], "volume": [True, True],
                              "least_slack": 3.362067513e-09, "slack_difference": 6e-16, "payload_ulps": [5, 6, 4], "payload": [True, True, True]}},
    "cell49_claim": {"counts": [19971, 9985, 9986, 19971, 9985, 9986, 19971], "digests": [True, True], "base_ulps": [5, 6], "base": [True, True], "depth": [31, 32],
                     "least_slack": ["01000100100100101111101", 4.494058015e-08, 3e-16]},
    "queue_claim": {"cells": True, "count": [12, 12], "rows": 12, "order": True, "first": [49, 64, 66, 12, 59, 57], "margin_source": True},
    "stages_claim": {"cells": [47, 48, 68, 69, 70, 75, 76], "counts": [True, True, True, True, True, True],
                     "batch": [[47, 48, 68, 69, 70, 75, 76], "DEPTH30-BATCH-PUBLICATION-CANDIDATE-COMPLETE", True, True], "geometry": [66, 11, 51, 0, [33]],
                     "audit": ["RECOVERY-PASS-FOR-CELL33 / OTHER-RESIDUAL-FRONTS-STILL-NEED-RECOVERY", "COMPUTE-DEFERRED-NO-STATE-CHANGE", "NONE", "PASS"]},
    "code_facts": {"lines": {"r36_dfront_codec.py": 101, "r36_generate_shard_from_ledger.py": 57, "r36_rebuild_dfront_cell33.py": 31},
                   "digests_pinned": {"codec": True, "kernel": True, "scheduler": True}, "dependency_hash": True,
                   "codec": {"header": True, "canonical": True, "checked": True, "self_test": [("70", "40")]},
                   "rebuild": {"end": ["36"], "pad": ["1e-10"], "fallback": True, "hash": True}, "generator": {"float_halving": True, "stops_open": True, "lower_first": True}},
}


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


def ulps(a, b):
    """the largest distance between two floats or float vectors, in units in the last place of the second"""
    a, b = (a, b) if isinstance(a, list) else ([a], [b])
    return max(round(abs(x - y) / math.ulp(y)) for x, y in zip(a, b))


def sig(x, n=4):
    return float(f"{x:.{n - 1}e}")


def w1_replay(w):
    """sec. 0-3: cells 75 and 76's certificates - the header, the index, each leaf's density and hull count
    against Round 35's ledgers - and every stored vertex in its tagged core under this tree's integer
    arithmetic; the least margin and each chunk's against the replay record"""
    out, got = [], {}
    for n in map(str, PAIR):
        c, led, res = w["certs"][n], w["cells"][n]["ledger"], w["replay"][n]
        head, leaves = r37.decode(c["rhcert"])
        ih, offs = r37.decode_index(c["rhidx"])
        rec = c["record"]
        k = min(range(len(res)), key=lambda i: res[i]["margin"])
        got[n] = {"header": [head["magic"], head["exponent"], head["count"]], "consumed": head["end"] == len(c["rhcert"]),
                  "index": [ih["count"] == head["count"] + 1, ih["size_matches"], offs == [s for s, _, _ in leaves] + [head["end"]]],
                  "ledger": [sum(d == x["density"] for (_, d, _), x in zip(leaves, led)), sum(len(v) == x["vertices"] for (_, _, v), x in zip(leaves, led)),
                             sum(len(v) for _, _, v in leaves)],
                  "replay": [sum(r["pass"] for r in res), sum(r["convex"] for r in res), sum(r["refused"] for r in res)],
                  "least": [k, led[k]["path"], res[k]["margin"]], "is_record": [res[k]["margin"] == rec["minimum_margin_decimal"],
                                                                                 all(min(r["margin"] for r in res[ch["start"]:ch["end"]]) == ch["minimum_margin_decimal"]
                                                                                     for ch in rec["chunks"])],
                  "to_ledger": sig(max(abs(r["margin"] - x["margin_decimal"]) for r, x in zip(res, led)), 2)}
    if any(not v["consumed"] or not all(v["index"]) or v["ledger"][0] != len(w["cells"][n]["ledger"]) or v["replay"][0] != len(w["cells"][n]["ledger"])
           or v["replay"][2] or not all(v["is_record"]) for n, v in got.items()) or got != w["replay_claim"]:
        out.append(f"cells 75 and 76's certificates: {got}")
    w["w1"] = got
    return out


def w2_dfront(w):
    """sec. 5-7: both DFRONT files decoded from the spec - canonical order, 0 <= m < 2^k, exact interior
    disjointness, the exact relative volume - and cell 33's against this tree's own lift of cell 33 to depth 36
    under the package's pad: the same boxes, one for one, and the nodes, closed leaves, pending boxes, volume
    and least closed slack of the manifest; the dependency payload's base box and t7 in ulps from this tree's
    (here the exact box rounded once, there accumulated in floating point)"""
    out, d = [], w["dfront"]
    got = {}
    for name in ("test", "cell33"):
        head, boxes = decode_dfront(d[name])
        got[name] = {"header": [head["magic"], head["version"], head["cell"], head["field"], head["count"]], "consumed": head["consumed"],
                     "canonical": boxes == sorted(set(boxes)), "ranges": all(0 <= b[2 * a + 1] < 2 ** b[2 * a] for b in boxes for a in range(3)),
                     "disjoint": disjoint(boxes), "volume": str(sum(Fraction(1, 2 ** (b[0] + b[2] + b[4])) for b in boxes)), "parent_zero": set(head["parent"]) == {"0"}}
    m, lift = d["manifest"], w["lift33"]
    head, boxes = decode_dfront(d["cell33"])
    per = lift["per"][str(DEPTH33)] if str(DEPTH33) in lift["per"] else lift["per"][DEPTH33]
    slack = min(v[3] for v in lift["per"].values() if v[3] is not None)
    box = r35.cell_box(m["base_path"])
    pay = m["dependency_payload"]
    got["mine"] = {"boxes_equal": codes(lift["frontier"], DEPTH33) == boxes,
                   "bytes_equal": encode_dfront(codes(lift["frontier"], DEPTH33), m["cell"], len(m["base_path"]), m["dependency_hash_sha256"]) == d["cell33"],
                   "counts": [per[0], per[1], per[2]],
                   "manifest": [per[0] == m["nodes"] == d["supplement"]["recovered_nodes"], per[1] == m["cert_leaves"], per[2] == m["pending_count"] == head["count"]],
                   "volume": [str(Fraction(per[2], 2 ** DEPTH33)) == m["relative_volume_fraction"], near(per[2] * r30.ROOT7 / 2 ** DEPTH33, m["unresolved_volume"], 1e-22)],
                   "least_slack": sig(slack, 10), "slack_difference": sig(abs(slack - m["worst_cert_slack"]), 1),
                   "payload_ulps": [ulps(box["center"], pay["base_center"]), ulps(box["half"], pay["base_half"]), ulps(t_text(7, d_star(r31.TM)), pay["t7"])],
                   "payload": [pay["end_depth"] == DEPTH33, head["dependency"] == m["dependency_hash_sha256"], head["cell"] == m["cell"]]}
    ok = all(v["consumed"] and v["canonical"] and v["ranges"] and v["disjoint"] for k, v in got.items() if k != "mine") \
        and got["mine"]["boxes_equal"] and got["mine"]["bytes_equal"] and all(got["mine"]["manifest"]) and all(got["mine"]["volume"]) and all(got["mine"]["payload"]) \
        and max(got["mine"]["payload_ulps"]) <= 8
    if not ok or got != w["dfront_claim"]:
        out.append(f"the frontiers: {got}")
    w["w2"] = got
    return out


def w3_cell49(w):
    """sec. 11: cell 49 lifted here to depth 32; its tree encoded in the package's convention and hashed
    against the manifest, which ships no bits; its least slack; its base box in ulps from this tree's"""
    out, m, lift = [], w["manifest49"], w["lift49"]
    top, axes = encode([p for p, _ in lift], DEPTH49)
    slack = min((a - r30.PKG_PAD - T, p) for p, a in lift)
    got = {"counts": [len(top), sum(top), len(top) - sum(top), m["nodes"], m["internal_nodes"], m["leaves"], m["ledger_nodes_reference"]],
           "digests": [hashlib.sha256(pack(top)).hexdigest() == m["topology_sha256"] == w["cell49"]["topology_sha256"],
                       hashlib.sha256(pack(axes)).hexdigest() == m["axis_sha256"] == w["cell49"]["axis_sha256"]],
           "base_ulps": [ulps(r35.cell_box(m["base_path"])["center"], m["base_center"]), ulps(r35.cell_box(m["base_path"])["half"], m["base_half"])],
           "base": [r31.base_axes(m["base_path"])[0] == m["base_axis_trace"], m["base_path"] == w["ledger26"]["cells"][49]["path"]],
           "depth": [max(len(p) for p, _ in lift), m["closure_depth"]], "least_slack": [slack[1], sig(slack[0], 10), sig(abs(slack[0] - m["worst_reference_slack"]), 1)]}
    c = got["counts"]
    if not all(got["digests"]) or not all(got["base"]) or max(got["base_ulps"]) > 8 or not (c[0] == c[3] == c[6] and c[1] == c[4] and c[2] == c[5]) or got != w["cell49_claim"]:
        out.append(f"cell 49: {got}")
    w["w3"] = got
    return out


def w4_queue(w):
    """sec. 11: the depth-32 queue - its twelve cells the Round 26 ledger's closing at 32 (whose rows RUN-029
    matched to this tree's trees), their paths, node counts and marker margins the ledger's, and the order its
    rule gives: fewer nodes first, then the larger marker margin"""
    out, q, L = [], w["queue"], w["ledger26"]["cells"]
    rows = q["cells"]
    at32 = sorted(c["cell"] for c in L if c["known_closure_depth"] == 32)
    got = {"cells": sorted(r["cell"] for r in rows) == at32, "count": [len(rows), q["cell_count"]],
           "rows": sum((r["path"], r["nodes_at_depth32"], r["marker_margin"], r["closure_depth"]) == (L[r["cell"]]["path"], L[r["cell"]]["nodes_at_depth36"],
                                                                                                   L[r["cell"]]["marker_margin"], 32) for r in rows),
           "order": [r["cell"] for r in rows] == [r["cell"] for r in sorted(rows, key=lambda r: (r["nodes_at_depth32"], -r["marker_margin"]))],
           "first": [r["cell"] for r in rows[:6]], "margin_source": all(r["marker_margin"] != w["markers"][r["cell"]]["final"]["margin_decimal"] for r in rows)}
    if not got["cells"] or got["rows"] != len(rows) or not got["order"] or got != w["queue_claim"]:
        out.append(f"the depth-32 queue: {got}")
    w["w4"] = got
    return out


def w5_stages(w):
    """sec. 3-4, 8-10: the stage counts - the seven depth-30 cells all candidates, 59 at a lower stage; no new
    geometry, the depth-38 attempt without effect; the recovery audit"""
    out, d, b, a = [], w["dashboard"], w["batch"], w["audit"]
    ar = d["arithmetic_pipeline"]
    pc = sorted(ar["publication_candidate_cells"])
    got = {"cells": pc, "counts": [ar["publication_candidate_count"] == len(pc), near(ar["publication_candidate_fraction_global"], len(pc) / 77, 1e-15),
                                   near(ar["publication_candidate_fraction_of_known_geometry_complete"], len(pc) / 66, 1e-15),
                                   ar["geometry_complete_arithmetic_pending_count"] == d["geometry"]["known_complete"] - len(pc),
                                   sorted(ar["arithmetic_closed_or_better_cells"]) == pc, d["depth30_batch"]["cells"] == b["cells"] == pc],
           "batch": [b["cells"], b["status"], b["all_publication_candidate"], [e["cell"] for e in b["entries"]] == b["cells"]],
           "geometry": [d["geometry"]["known_complete"], d["geometry"]["residual"], d["geometry"]["latest_exact_common_budget"]["complete"],
                        d["geometry"]["round36_new_geometry_closures"], d["geometry"]["durably_recovered_frontier_cells"]],
           "audit": [a["status"], a["depth38_attempt"]["status"], a["depth38_attempt"]["proof_state_effect"], a["cell33_rebuild"]["status"]]}
    if not all(got["counts"]) or got != w["stages_claim"]:
        out.append(f"the stages: {got}")
    w["w5"] = got
    return out


def w6_code(w):
    """what the package ships, read after the rebuild and never run: the DFRONT codec, cell 33's rebuild, and
    the shard generator from a ledger"""
    m = w["dfront"]["manifest"]
    pay, leaves = m["dependency_payload"], {row[0]: row[2] for row in w["manifest"]["leaves"]}
    facts = {"lines": {k: v.count("\n") for k, v in sorted(w["code"].items())}, "digests_pinned": {
        "codec": w["code_digests"]["r36_dfront_codec.py"] == w["dspec"]["implementation_sha256"] == w["dfront"]["validation"]["implementation_sha256"],
        "kernel": pay["kernel_sha256"] == leaves[KERNEL], "scheduler": pay["scheduler_sha256"] == leaves[SCHEDULER]},
        "dependency_hash": hashlib.sha256(json.dumps(pay, sort_keys=True, separators=(",", ":")).encode()).hexdigest() == m["dependency_hash_sha256"]}
    facts.update(code_probes(w["code"]))
    w["w6"] = facts
    return [] if facts == w["code_facts"] else [f"the scripts: {facts}"]


def code_probes(code):
    """read, never run: the codec writes the boxes sorted and deduplicated, checked disjoint, under the header
    <8sHHII (magic, version, cell, base depth, count); its own self-test writes a full partition of cell 70, not
    the shipped test frontier; the rebuild's lower bound is the exact hull less the pad, a kernel exception
    falling back to the a-priori bound; the shard generator builds its base box by halving in floating point
    and stops if a box is still open at the closure depth"""
    codec, rebuild, gen = (code[k].replace(" ", "") for k in ("r36_dfront_codec.py", "r36_rebuild_dfront_cell33.py", "r36_generate_shard_from_ledger.py"))
    return {"codec": {"header": "struct.pack('<8sHHII',MAGIC,VERSION,cell_id,base_depth,len(boxes))" in codec, "canonical": "boxes=sorted(set(boxes))" in codec,
                      "checked": "verify_disjoint(boxes)" in codec.split("defencode")[1].split("defdecode")[0], "self_test": re.findall(r"encode\(front,(\d+),(\d+),dep\)", codec)},
            "rebuild": {"end": re.findall(r"END=(\d+)", rebuild), "pad": re.findall(r"hull_area_exact\(\[[^\]]*\]\)-([0-9.e-]+)\)", rebuild),
                        "fallback": "exceptException:pass" in rebuild, "hash": "json.dumps(dep_payload,sort_keys=True,separators=(',',':'))" in rebuild},
            "generator": {"float_halving": "q=h[a]/2;h[a]=q;c[a]+=qifb=='1'else-q" in gen, "stops_open": "ifd>=maxd:raiseRuntimeError" in gen,
                          "lower_first": "stack.append((R[0],R[1],d+1,p+'1'));stack.append((L[0],L[1],d+1,p+'0'))" in gen}}


def p1_package(w):
    out, d = [], w["dfront"]
    leaves = {row[0]: row for row in w["manifest"]["leaves"]}
    for n in map(str, PAIR):
        c, sh = w["certs"][n], w["shards"][n]
        m, rec, ce = c["manifest"], c["record"], sh["certificate_entity"]
        if (m["certificate_sha256"], m["index_sha256"], m["certificate_bytes"], m["index_bytes"]) != (c["digests"][0], c["digests"][1], len(c["rhcert"]), len(c["rhidx"])) \
                or (rec["certificate_sha256"], rec["leaf_count"], rec["vertex_count_total"], rec["minimum_margin_decimal"], rec["failures"]) \
                != (m["certificate_sha256"], m["leaf_count"], m["vertex_count_total"], m["minimum_margin_decimal"], 0) \
                or [ch["start"] for ch in rec["chunks"]] != [0] + [ch["end"] for ch in rec["chunks"][:-1]] or rec["chunks"][-1]["end"] != m["leaf_count"] \
                or (ce["raw_sha256"], ce["raw_bytes"], ce["index_sha256"], ce["leaf_count"], ce["vertex_count_total"], ce["minimum_margin_decimal"], ce["compressed_bytes"], ce["compressed_sha256"]) \
                != (m["certificate_sha256"], m["certificate_bytes"], m["index_sha256"], m["leaf_count"], m["vertex_count_total"], m["minimum_margin_decimal"], c["zip"][0], c["zip"][1]) \
                or sh["geometry"] != w["cells"][n]["manifest"] or (sh["status"], sh["publication_candidate"]) != ("PUBLICATION-CANDIDATE-SHARD", True) \
                or m["density_counts"] != {str(k): v for k, v in sorted(collections.Counter(x["density"] for x in w["cells"][n]["ledger"]).items())}:
            out.append(f"cell {n}: the manifest, the replay record and the shard file")
    for e in w["batch"]["entries"]:
        ids = [k for k in leaves if k.endswith("/" + e["manifest"])]
        if len(ids) != 1 or leaves[ids[0]][2] != e["manifest_sha256"] or e["status"] != "PUBLICATION-CANDIDATE-SHARD":
            out.append(f"the batch's entry for cell {e['cell']} against the archive")
    m, sup = d["manifest"], d["supplement"]
    if not all(d["copies_equal"]) or m["frontier_sha256"] != hashlib.sha256(d["cell33"]).hexdigest() or m["frontier_bytes"] != len(d["cell33"]) \
            or sup["original_manifest_sha256"] != d["digests"]["manifest"] or not sup["three_invariant_recovery_pass"] \
            or d["validation"]["reference_sha256"] != hashlib.sha256(d["test"]).hexdigest() or d["validation"]["reference_bytes"] != len(d["test"]) \
            or w["audit"]["cell33_rebuild"]["frontier_sha256"] != m["frontier_sha256"] or w["audit"]["cell33_rebuild"]["frontier_bytes"] != len(d["cell33"]) \
            or (w["audit"]["cell33_rebuild"]["recovered_nodes"], w["audit"]["cell33_rebuild"]["recovered_pending"]) != (sup["recovered_nodes"], m["pending_count"]):
        out.append("the DFRONT records against the frontier bytes and each other")
    c49, m49 = w["cell49"], w["manifest49"]
    if (c49["nodes"], c49["leaves"], c49["topology_sha256"], c49["axis_sha256"], c49["worst_reference_slack"], c49["closure_depth"]) \
            != (m49["nodes"], m49["leaves"], m49["topology_sha256"], m49["axis_sha256"], m49["worst_reference_slack"], m49["closure_depth"]):
        out.append("cell 49's status against its manifest")
    crystal = gate.squash(w["crystal"])
    for frag in (r"\boxed{\{47,48,68,69,70,75,76\}}", "-2,627,357vertices", "-2,617,252vertices", "-nodes129,401=durableledger", "-pending14,027=durableledger",
                 "-frontierbytes126,327", r"19971\text{nodes},\quad9986\text{leaves}."):
        if frag not in crystal:
            out.append(f"crystal: {frag}")
    w["p1"] = {"batch_entries": len(w["batch"]["entries"])}
    return out


def p2_package(w):
    out, v = [], w["validation"]
    leaves = {row[0]: row for row in w["manifest"]["leaves"]}
    for key, leaf_id, text in (("round36", 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["file"] != leaf_id.split("/")[-1] \
                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 (("coverage_dashboard_sha256", DASH), ("cell75_candidate_sha256", SHARD[75]), ("cell76_candidate_sha256", SHARD[76]),
                         ("dfront_implementation_sha256", DSPEC), ("cell33_original_manifest_sha256", D33_MAN), ("cell33_recovery_supplement_sha256", D33_SUP),
                         ("cell33_dfront_sha256", D33), ("geometry_recovery_audit_sha256", AUDIT), ("depth32_queue_sha256", QUEUE), ("cell49_status_sha256", CELL49)):
        if v[key] != leaves[leaf_id][2]:
            out.append(f"VALIDATION {key} against the archive")
    if [v["cell75_rhcert_zip_sha256"], v["cell76_rhcert_zip_sha256"], v["cell33_dfront_zip_sha256"]] != [w["certs"]["75"]["zip"][1], w["certs"]["76"]["zip"][1], w["dfront"]["zip"][1]]:
        out.append("VALIDATION's package digests")
    sh, d, b, sup, m49 = w["shards"], w["dashboard"], w["batch"], w["dfront"]["supplement"], w["manifest49"]
    kc = {"cell75_publication_candidate": sh["75"]["publication_candidate"] is True, "cell76_publication_candidate": sh["76"]["publication_candidate"] is True,
          "cell75_bytes_replay_all": w["certs"]["75"]["record"]["status"] == "PASS" and w["certs"]["75"]["record"]["failures"] == 0,
          "cell76_bytes_replay_all": w["certs"]["76"]["record"]["status"] == "PASS" and w["certs"]["76"]["record"]["failures"] == 0,
          "depth30_batch_all_7": b["all_publication_candidate"] is True and len(b["cells"]) == 7, "publication_candidate_count_7": d["arithmetic_pipeline"]["publication_candidate_count"] == 7,
          "geometry_unchanged_66": d["geometry"]["known_complete"] == 66, "dfront_validation_pass": w["dfront"]["validation"]["status"] == "PASS",
          "cell33_three_invariants": sup["three_invariant_recovery_pass"] is True, "cell33_node_match": sup["node_count_match"] is True,
          "cell33_pending_match": sup["pending_count_match"] is True, "cell33_volume_exact": sup["volume_exact_match"] is True,
          "cell49_node_count_match": m49["node_count_match"] is True, "no_global_claim": d["global_lebesgue_claim"] is False}
    if kc != v["checks"] or v["status"] != "PASS":
        out.append(f"VALIDATION checks {kc}")
    w["p2"] = kc
    return out


R36_DEFINITIONS = {"DFRONT PASS": ("in-line", "sec. 13: a frontier rebuilt from the root, kept as DFRONT codes, and matching the durable counts it must")}
_CERT = ("replayed here from the bytes in this tree's integer arithmetic - every vertex in its tagged core, convex, the exact area; the "
         "least margin and each chunk's are the record's, every density and hull count Round 35's ledger's (W1)")
_PC = ("the bytes pass under this tree's own arithmetic (W1), their ledgers and markers checked in RUN-038; the MPFR dominance is not "
       "recomputed here")
_D33 = ("this tree's own lift of cell 33 to depth 36 under the package's pad has the same 14,027 open boxes, code for code, and the "
        "manifest's nodes, closed leaves, volume and least slack (W2)")
R36_REVIEWS = [
    ("PASS", "10948/10948", "computation", "PASS", _CERT),
    ("PASS", "10932/10932", "computation", "PASS", _CERT),
    ("PASS", "CELL33-DFRONT-RECOVERY", "computation", "PASS", _D33),
    ("PUBLICATION-CANDIDATE-SHARD", "", "computation", "PASS", _PC),
    ("PUBLICATION-CANDIDATE-SHARD", "", "computation", "PASS", _PC),
    ("NOT CERTIFIED", "a_{Leb}≥0.835", "reading", "PASS", "true"),
    ("NOT CERTIFIED", "a_{Leb}≥0.835", "reading", "PASS", "true"),
    ("DFRONT PASS", "runtime state recovery →", "computation", "PASS", _D33),
]


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


CHECKS = {"A0": gate.anchors_check(ANCHORS), "W1": w1_replay, "W2": w2_dfront, "W3": w3_cell49, "W4": w4_queue, "W5": w5_stages, "W6": w6_code,
          "P1": p1_package, "P2": p2_package, "R1": r1_registry}
DEPENDS = {"A0": {"text"}, "W1": {"certs", "cells", "replay", "replay_claim"}, "W2": {"dfront", "lift33", "dfront_claim"},
           "W3": {"manifest49", "lift49", "cell49", "ledger26", "cell49_claim"}, "W4": {"queue", "ledger26", "markers", "queue_claim"},
           "W5": {"dashboard", "batch", "audit", "stages_claim"}, "W6": {"code", "code_digests", "dspec", "dfront", "manifest", "code_facts"},
           "P1": {"certs", "shards", "cells", "batch", "manifest", "dfront", "audit", "cell49", "manifest49", "crystal"},
           "P2": {"validation", "manifest", "text", "crystal", "certs", "dfront", "shards", "dashboard", "batch", "manifest49"}, "R1": {"registry", "definitions", "reviews"}}


def drill_cases(base):
    text, c, d = base["text"], base["cells"], base["dfront"]

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

    def flip_last_box(b):
        return b[:-1] + bytes([b[-1] ^ 1])

    return [
        ("K0-unmodified", "control", {}, set()),
        ("K1-doc-crlf", "control", {"text": text.replace("\n", "\r\n")}, set()),
        ("K2-queue-keys-sorted", "control", {"queue": json.loads(json.dumps(base["queue"], sort_keys=True))}, set()),
        ("K3-batch-keys-sorted", "control", {"batch": json.loads(json.dumps(base["batch"], sort_keys=True))}, set()),
        ("M1-doc-count", "mutation", {"text": text.replace(r"\boxed{14027\text{ pending boxes}}", r"\boxed{14028\text{ pending boxes}}")}, {"A0"}),
        ("M2-replay-refused", "mutation", {"replay": edit(base["replay"], lambda x: x["76"][5].update(refused=1, **{"pass": False}))}, {"W1"}),
        ("M3-ledger-density", "mutation", {"cells": edit(c, lambda x: x["75"]["ledger"][9].update(density=2 * x["75"]["ledger"][9]["density"]))}, {"W1", "P1"}),
        ("M4-dfront-box", "mutation", {"dfront": edit(d, lambda x: x.update(cell33=flip_last_box(x["cell33"])))}, {"W2", "P1"}),
        ("M5-lift-open", "mutation", {"lift33": edit(base["lift33"], lambda x: x.update(frontier=x["frontier"][:-1]))}, {"W2"}),
        ("M6-manifest49", "mutation", {"manifest49": edit(base["manifest49"], lambda x: x.update(axis_sha256="0" * 64))}, {"W3", "P1"}),
        ("M7-queue-order", "mutation", {"queue": edit(base["queue"], lambda x: x["cells"].__setitem__(slice(0, 2), x["cells"][1::-1]))}, {"W4"}),
        ("M8-queue-nodes", "mutation", {"queue": edit(base["queue"], lambda x: x["cells"][5].update(nodes_at_depth32=22262))}, {"W4"}),
        ("M9-dashboard", "mutation", {"dashboard": edit(base["dashboard"], lambda x: x["arithmetic_pipeline"].update(geometry_complete_arithmetic_pending_count=58))},
         {"W5"}),
        ("M10-code-claim", "mutation", {"code_facts": {}}, {"W6"}),
        ("M10b-payload-kernel", "mutation", {"dfront": edit(d, lambda x: x["manifest"]["dependency_payload"].update(kernel_sha256="0" * 64))}, {"W6"}),
        ("M11-batch-digest", "mutation", {"batch": edit(base["batch"], lambda x: x["entries"][2].update(manifest_sha256="0" * 64))}, {"P1"}),
        ("M12-crystal", "mutation", {"crystal": base["crystal"].replace("2,617,252", "2,617,253")}, {"P1"}),
        ("M13-validation-digest", "mutation", {"validation": {**base["validation"], "depth32_queue_sha256": "0" * 64}}, {"P2"}),
        ("M14-validation-check", "mutation", {"validation": {**base["validation"], "checks": {**base["validation"]["checks"], "cell33_node_match": False}}}, {"P2"}),
        ("M15-review-dropped", "mutation", {"reviews": list(R36_REVIEWS[1:])}, {"R1"}),
    ]


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--drill", action="store_true")
    ap.add_argument("--blind", metavar="CID")
    args = ap.parse_args()
    base = world(load_inputs())

    def build():
        return {**base, "registry": registry.load(), "definitions": dict(R36_DEFINITIONS), "reviews": list(R36_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", "p1", "p2"):
        print(key, "=", json.dumps(w.get(key), default=float, ensure_ascii=False))
    if not args.drill:
        return
    cases = drill_cases(base)
    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-039", "subject": "Round 36: the depth-30 batch complete, and the first frontier kept as a proof object",
           "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", "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("R36", "RUN-039", R36_DEFINITIONS, R36_REVIEWS)
        print(f"registry: {len(R36_DEFINITIONS)} definitions, {len(R36_REVIEWS)} reviews recorded for R36")


if __name__ == "__main__":
    main()

