#!/usr/bin/env python3
"""reproduce_row33_p2.py [--group DIR] [--served-record FILE] [--out DIR] [--bar D] [--plant-pos N] -- the row-33 P2
higher-order-twins data shelf reproduced from the shelf: at the further point P2 = (s, t, m^2) = (-3/2, -1/4, 1) the eight
fixed-eps values of the dispersive evaluator at dps 140 (the vendored EVAL receipts under evals/, `I_disp` at full precision)
are compared with the target sample of the two vendored AMFlow grids at auxiliary-mass orders 400 and 500 (grids/; the ball
midpoints of result[0] = the integral with indices [1,1,1,2,1,2,1,1] at eps = 2^-k, k = 6..13) by the comparator's rules,
copied VERBATIM below and marked: per eps the members vs_x500, vs_x400, x400_vs_x500 (the twins' own agreement = the grids'
certified digits at that eps), quad_L7_L8 (the evaluator's own two-level quadrature pair, read from the receipt's diag),
the count = int(min(vs_x500, quad_L7_L8, x400_vs_x500)) (never rounded), and the planted-digit control (one significant
digit of the dps-140 value changed at position 48: the agreement with the x500 grid must fall under the bar and FAIL by
name).  Every recomputed member and count is compared with the vendored compare receipt (compare/) as the FLOAT PRINTED
THERE (the JSON literal; the tolerance is exact equality of the doubles), the cell figure (int(min) over the eight counts),
the range and the twins' worst pair are printed, and the dps-110 member is recomputed from the SERVED points/P2/record.json
two directories up (../vendor_row33_points/points/P2/record.json, pinned by sha256 below; a mismatch refuses by name, exit 2):
that record carries the dps-110 value as a 40-significant-digit string, so the member is reproduced TO THE PRECISION A
40-DIGIT STRING ALLOWS and is reported beside the compare receipt's two_precision_110_140 (computed by the comparator from
the record's full dps-110 string, which is not on any shelf) with the difference; it is not part of the exit condition.
Seconds (mpmath at dps 400 over 8 eps x 5 members).  Nothing is written outside --out (a fresh directory; refused if it
exists or lies inside the bundle).

WHAT IT PINS.  Every vendored object is read only after its sha256 equals its row in VENDOR_MANIFEST.sha256 (a mismatch
refuses, exit 3; a missing file exit 4).  The compare receipt names each evaluator receipt as "<file name> (sha256 <hex>)"
with the hex of the object AS EMITTED; the vendored copies differ from the emitted bytes in their re-cut provenance fields
only, never in a value string, so each is located through the VENDOR_MANIFEST header line "# vendored_from: <file> <- sha256
<hex>" and its `k`, `dps`, `status` and `point` fields are asserted.  The two grids are byte-identical to the emitted objects
(no field moved): their manifest rows equal the compare receipt's grids.*.sha256 and the leg receipts' out.sha256, asserted.
The served record is pinned by SERVED_RECORD_SHA256.

THE RULE (the compare receipt's `rule` field: agree(a, b) = -log10(|a - b| / |b|) at mp.dps 400 on the full strings; counts
int(min), never round()); the functions marked VERBATIM are copied from the comparator compare_ROW33PP.py, vendored beside
under compare/ as a text object (its docstring re-cut; not run from this shelf).

Exit 0 when every convention-A member and count equals the compare receipt's as printed, the cell figure and the range
equal the receipt's, and the planted control FAILS by name at every eps (REPRODUCED: True); 1 when any of those differs;
2 when the served record's sha256 differs from the pin; 3 a shelf object's sha256 differs from its VENDOR_MANIFEST row;
4 a missing object; 5 --out exists or lies inside the bundle.  python3 + mpmath."""
import argparse
import hashlib
import json
import os
import re
import subprocess
import sys

import mpmath as mp

HERE = os.path.dirname(os.path.abspath(__file__))
SERVED_RECORD_REL = os.path.join("..", "vendor_row33_points", "points", "P2", "record.json")
SERVED_RECORD_SHA256 = "b9960411bca7c40d0235d91223b93e2c5bd2e9b1803c475a7b3fff74ad9a4f4d"
TARGET = [1, 1, 1, 2, 1, 2, 1, 1]
POINT = {"s": "-3/2", "t": "-1/4", "msq": "1"}
GRID_X = {400: "grids/LBL3VP_P2_x400.json", 500: "grids/LBL3VP_P2_x500.json"}
LEG_X = {400: "grids/LBL3VP_P2_x400_RECEIPT_20260910T042548Z.json", 500: "grids/LBL3VP_P2_x500_RECEIPT_20260910T042751Z.json"}
COMPARE_REL = "compare/COMPARE_ROW33PP_P2_20260910T045045Z.json"

# ---- VERBATIM from compare_ROW33PP.py (the comparator of record; the compare receipt's `rule` field states the rule) ----
mp.mp.dps = 400
KS = [6, 7, 8, 9, 10, 11, 12, 13]
def parse_ball_mid(s):
    m = re.match(r"\s*\[?\s*([-+]?[0-9.]+(?:[eE][-+]?\d+)?)", s); assert m, s[:60]; return mp.mpf(m.group(1))
def agree(a, b):
    a = mp.mpf(a); b = mp.mpf(b)
    if a == b: return 400.0
    if b == 0: return 0.0
    return float(-mp.log10(abs(a - b) / abs(b)))
def grid_samples(path):
    d = json.load(open(path)); r = d["result"][0]; assert r["integral"]["indices"][:8] == [1, 1, 1, 2, 1, 2, 1, 1]; out = {}
    for s in r["samples"]:
        e = mp.mpf(s["eps"]["re"]); k = int(mp.nint(-mp.log(e, 2))); assert abs(e - mp.mpf(2) ** (-k)) < mp.mpf("1e-300"), s["eps"]["re"][:30]; out[k] = {"re": parse_ball_mid(s["value"]["re"]), "raw": s["value"]["re"][:140]}
    return out, d
def plant(s, pos):
    digits = [i for i, c in enumerate(s) if c.isdigit()]; sig = [i for i in digits if s[:i].lstrip("-0.").strip("-") != "" or s[i] != "0"]
    i = sig[pos - 1]; c = s[i]; return s[:i] + ("1" if c != "1" else "2") + s[i + 1:]
# ---- end of the VERBATIM block ----


def sha(p):
    return hashlib.sha256(open(p, "rb").read()).hexdigest()


def stamp():
    return subprocess.run(["date", "-u", "+%Y-%m-%dT%H:%M:%SZ"], capture_output=True, text=True).stdout.strip()


def refuse(code, msg):
    print("REFUSED (%d): %s" % (code, msg))
    sys.exit(code)


def manifest_rows(path):
    rows, vfrom = {}, {}
    for line in open(path):
        line = line.rstrip("\n")
        m = re.match(r"^# vendored_from: (\S+) <- sha256 ([0-9a-f]{64}) ", line)
        if m:
            vfrom[m.group(2)] = m.group(1)
        elif line and not line.startswith("#"):
            h, f = line.split(None, 1)
            rows[f.strip()] = h
    return rows, vfrom


def pinned(group, rows, rel, consumed):
    p = os.path.join(group, rel)
    if rel not in rows:
        refuse(4, "%s is not a row of VENDOR_MANIFEST.sha256" % rel)
    if not os.path.isfile(p):
        refuse(4, "%s is missing from the shelf" % rel)
    h = sha(p)
    if h != rows[rel]:
        refuse(3, "%s sha256 %s differs from its VENDOR_MANIFEST row %s" % (rel, h, rows[rel]))
    consumed[rel] = h
    return p


def hex_of(field):
    m = re.search(r"\(sha256 ([0-9a-f]{64})\)", field)
    return m.group(1) if m else None


def main():
    ap = argparse.ArgumentParser(description="the row-33 P2 higher-order-twins data shelf reproduced from the shelf (seconds; python3 + mpmath)")
    ap.add_argument("--group", default=HERE, help="the shelf directory (default: this script's directory)")
    ap.add_argument("--served-record", default=None, help="the served points/P2/record.json (default: ../vendor_row33_points/points/P2/record.json from the shelf)")
    ap.add_argument("--out", default=None, help="a fresh output directory (default: ./reproduce_row33_p2_<stamp> under the working directory; refused if it exists or lies inside the bundle)")
    ap.add_argument("--bar", type=float, default=50.0, help="the bar in digits for the planted control and the PASS reading (default 50, the compare receipt's)")
    ap.add_argument("--plant-pos", type=int, default=48, help="the significant-digit position of the planted control (default 48, the compare receipt's)")
    a = ap.parse_args()
    G = os.path.abspath(a.group)
    bundle = os.path.dirname(G)
    st = stamp()
    out = os.path.abspath(a.out) if a.out else os.path.join(os.getcwd(), "reproduce_row33_p2_" + st.replace("-", "").replace(":", ""))
    if os.path.exists(out):
        refuse(5, "--out %s exists (a fresh directory is required)" % out)
    if os.path.commonpath([out, bundle]) == bundle:
        refuse(5, "--out %s lies inside the bundle %s (write outside it)" % (out, bundle))
    vm = os.path.join(G, "VENDOR_MANIFEST.sha256")
    if not os.path.isfile(vm):
        refuse(4, "VENDOR_MANIFEST.sha256 is missing from %s" % G)
    rows, vfrom = manifest_rows(vm)
    consumed = {}
    # the served record (pinned by sha256; refused by name on a mismatch)
    rec_path = os.path.abspath(a.served_record) if a.served_record else os.path.normpath(os.path.join(G, SERVED_RECORD_REL))
    if not os.path.isfile(rec_path):
        refuse(4, "the served record %s is missing (the shelf must sit beside vendor_row33_points/ as served)" % rec_path)
    rec_sha = sha(rec_path)
    if rec_sha != SERVED_RECORD_SHA256:
        refuse(2, "the served points/P2/record.json sha256 %s differs from the pin %s: the dps-110 member is not read" % (rec_sha, SERVED_RECORD_SHA256))
    rec = json.load(open(rec_path))
    if rec["point"]["tag"] != "P2" or rec["point"]["s"] != POINT["s"] or rec["point"]["t"] != POINT["t"] or rec["dps"] != 110:
        refuse(2, "the served record is not the dps-110 run at P2")
    # the compare receipt and the two grids
    cmp_path = pinned(G, rows, COMPARE_REL, consumed)
    C = json.load(open(cmp_path))
    grids, legs, O = {}, {}, {}
    for xo, rel in GRID_X.items():
        p = pinned(G, rows, rel, consumed)
        if C["grids"]["x%d" % xo]["sha256"] != rows[rel]:
            refuse(3, "the compare receipt names the x%d grid by sha256 %s; the vendored grid's row is %s" % (xo, C["grids"]["x%d" % xo]["sha256"], rows[rel]))
        O[xo], grids[xo] = grid_samples(p)
        if grids[xo]["options"]["x_order"] != xo or grids[xo]["mode"] != "black_box_amflow":
            refuse(3, "the x%d grid's options.x_order / mode are not %d / black_box_amflow" % (xo, xo))
        lp = pinned(G, rows, LEG_X[xo], consumed)
        legs[xo] = json.load(open(lp))
        if legs[xo]["out"]["sha256"] != rows[rel] or legs[xo]["config"]["x_order"] != xo or legs[xo]["config"]["numeric_values"] != POINT or not legs[xo]["DONE"]["done"]:
            refuse(3, "the x%d leg receipt does not name the vendored grid (out.sha256), the order %d, the point %s and DONE" % (xo, xo, POINT))
        if not all(k in O[xo] for k in KS):
            refuse(3, "the x%d grid carries no sample at some k in %s" % (xo, KS))
    # the eight evaluator receipts, located through the vendored_from header by the hex the compare receipt names
    evals = {}
    for k in KS:
        pe = C["per_eps"][str(k)]
        hexk = hex_of(pe["eval_file"]) or pe.get("eval_sha256")
        if hexk not in vfrom:
            refuse(4, "no vendored_from line carries the eps 2^-%d evaluator receipt's emitted sha256 %s" % (k, hexk))
        rel = vfrom[hexk]
        p = pinned(G, rows, rel, consumed)
        d = json.load(open(p))
        if str(d.get("k")) != str(k) or d.get("status") != "DONE" or d.get("dps") != 140 or d["point"]["s"] != POINT["s"] or d["point"]["t"] != POINT["t"]:
            refuse(3, "%s is not the DONE dps-140 receipt at eps 2^-%d at P2" % (rel, k))
        evals[k] = (rel, d)
    # ---- the recomputation, the comparator's rules ----
    bar = a.bar
    per, counts_A, counts_B40, ctrl, diffs = {}, {}, {}, {}, []
    def cmpf(name, got, want):
        eq = (got == want)
        if not eq:
            diffs.append({"leaf": name, "recomputed": got, "receipt": want})
        return eq
    for k in KS:
        rel, d = evals[k]
        v = d["I_disp"]
        pe = C["per_eps"][str(k)]
        M = pe["members"]
        m = {"vs_x500": agree(v, O[500][k]["re"]), "vs_x400": agree(v, O[400][k]["re"]), "x400_vs_x500": agree(O[400][k]["re"], O[500][k]["re"]), "quad_L7_L8": d["diag"]["quad_agree"]}
        cA = int(min(m["vs_x500"], m["x400_vs_x500"], m["quad_L7_L8"]))
        pl = plant(v, a.plant_pos); dpl = agree(pl, O[500][k]["re"])
        fails = dpl < bar
        # the dps-110 member from the served record's 40-digit string (the precision a 40-digit string allows)
        rec40 = rec["fixed_eps"]["per_eps"][str(k)]["I_disp_40d"]
        tp40 = agree(rec40, v)
        cB40 = int(min(tp40, m["vs_x500"]))
        i40 = mp.nstr(mp.mpf(v), 40); o40 = mp.nstr(O[500][k]["re"], 40)
        eq = {n: cmpf("per_eps[%d].members.%s" % (k, n), m[n], M[n]) for n in ("vs_x500", "vs_x400", "x400_vs_x500", "quad_L7_L8")}
        eq["count_A"] = cmpf("per_eps[%d].count_A_int_min" % k, cA, pe["count_A_int_min"])
        eq["d_planted"] = cmpf("per_eps[%d].planted_control.d_planted" % k, dpl, pe["planted_control"]["d_planted"])
        eq["fails_by_name"] = cmpf("per_eps[%d].planted_control.fails_by_name" % k, fails, True) and pe["planted_control"]["fails_by_name"] is True
        eq["I_disp_40d"] = cmpf("per_eps[%d].I_disp_40d" % k, i40, pe["I_disp_40d"])
        eq["O500_40d"] = cmpf("per_eps[%d].O500_40d" % k, o40, pe["O500_40d"])
        counts_A[k] = cA; counts_B40[k] = cB40
        ctrl[k] = {"position": a.plant_pos, "d_planted": dpl, "fails_by_name": fails, "rc": 1 if fails else 0}
        per[k] = {"eval_receipt": rel, "eval_sha256_vendored": consumed[rel], "eval_sha256_emitted": vfrom and next(h for h, f in vfrom.items() if f == rel),
                  "members": m, "count_A_int_min": cA, "planted_control": ctrl[k], "I_disp_40d": i40, "O500_40d": o40,
                  "dps110_member_from_served_40d": {"served_I_disp_40d": rec40, "two_precision_110_140_from_40d": tp40, "compare_receipt_two_precision_110_140": M["two_precision_110_140"],
                                                    "difference": tp40 - M["two_precision_110_140"], "count_B_from_40d": cB40, "compare_receipt_count_B": pe["count_B_int_min"],
                                                    "served_record_agreement_d_vs_x200_grid": rec["fixed_eps"]["per_eps"][str(k)]["agreement_d"]},
                  "equal_to_receipt": eq}
        print("eps 2^-%-2d  vs_x500 %.2f  vs_x400 %.2f  x400_vs_x500 %.2f  quad_L7_L8 %.2f  count_A %d  planted(%d) %.2f %s  | dps-110 member from the served 40-digit string %.2f (receipt %.2f, difference %+.2e; count_B %d vs %d)  | equal to the receipt: %s"
              % (k, m["vs_x500"], m["vs_x400"], m["x400_vs_x500"], m["quad_L7_L8"], cA, a.plant_pos, dpl, "FAIL by name" if fails else "NOT FAILED", tp40, M["two_precision_110_140"], tp40 - M["two_precision_110_140"], cB40, pe["count_B_int_min"], all(eq.values())))
    cell = min(counts_A.values()); rng = [min(counts_A.values()), max(counts_A.values())]
    worst_pair = min(per[k]["members"]["x400_vs_x500"] for k in KS); best_pair = max(per[k]["members"]["x400_vs_x500"] for k in KS)
    vs500 = [per[k]["members"]["vs_x500"] for k in KS]; l78 = [per[k]["members"]["quad_L7_L8"] for k in KS]
    cmpf("cell_figure_A", cell, C["cell_figure_A"]); cmpf("range_A", rng, C["range_A"])
    cmpf("counts_A", {str(k): counts_A[k] for k in KS}, C["counts_A"])
    all_fail = all(ctrl[k]["fails_by_name"] for k in KS)
    reproduced = (not diffs) and all_fail
    print("the cell figure (int(min) over the eight counts): %d; the range: %d-%d; vs the x500 grid %.2f-%.2f; the L7/L8 pairs %.2f-%.2f; the twins' own pair (x400 vs x500) %.2f at worst, %.2f at best; the planted controls FAIL by name at every eps: %s; bar %g"
          % (cell, rng[0], rng[1], min(vs500), max(vs500), min(l78), max(l78), worst_pair, best_pair, all_fail, bar))
    tp = [per[k]["dps110_member_from_served_40d"]["two_precision_110_140_from_40d"] for k in KS]; dd = [per[k]["dps110_member_from_served_40d"]["difference"] for k in KS]
    print("the dps-110 member from the served record's 40-digit strings: %.2f-%.2f (the compare receipt's, from the full dps-110 strings: %.2f-%.2f; differences %.2e..%.2e; the counts under convention B %s vs the receipt's %s) -- reproduced to the precision a 40-digit string allows; not an exit condition"
          % (min(tp), max(tp), min(per[k]["dps110_member_from_served_40d"]["compare_receipt_two_precision_110_140"] for k in KS), max(per[k]["dps110_member_from_served_40d"]["compare_receipt_two_precision_110_140"] for k in KS), min(dd), max(dd), [counts_B40[k] for k in KS], [C["counts_B"][str(k)] for k in KS]))
    print("REPRODUCED: %s (leaves differing %d; tolerance: equality of the doubles as printed in the compare receipt; the planted controls FAIL by name %s)" % (reproduced, len(diffs), all_fail))
    os.makedirs(out)
    R = {"receipt": "reproduce_row33_p2 -- the row-33 P2 higher-order-twins data shelf reproduced from the shelf: the eight dps-140 fixed-eps values vs the x400 / x500 AMFlow grids' target sample [1,1,1,2,1,2,1,1] at P2 = (-3/2, -1/4, 1); per eps the members, the count = int(min), the planted-digit control; every convention-A leaf compared with the vendored compare receipt as printed; the dps-110 member from the served record's 40-digit strings",
         "stamp_utc": st, "point": POINT, "target_indices": TARGET, "bar_d": bar, "mp_dps": mp.mp.dps, "plant_pos": a.plant_pos,
         "rule": C["rule"], "tolerance": "equality of the doubles as printed in the compare receipt (the JSON literals)",
         "inputs": {"group": os.path.basename(G), "vendor_manifest_rows_consumed": consumed, "rows_consumed_digest_sha256": hashlib.sha256("\n".join("%s  %s" % (consumed[r], r) for r in sorted(consumed)).encode()).hexdigest(),
                    "vendor_manifest_sha256_at_this_run": sha(vm), "served_record": {"path_relative_to_the_shelf": SERVED_RECORD_REL if not a.served_record else "(given)", "file": os.path.basename(rec_path), "sha256": rec_sha, "pin": SERVED_RECORD_SHA256},
                    "compare_receipt": {"file": os.path.basename(cmp_path), "sha256_vendored": consumed[COMPARE_REL], "stamp_utc": C["stamp_utc"]},
                    "grids": {"x%d" % xo: {"file": os.path.basename(GRID_X[xo]), "sha256": consumed[GRID_X[xo]], "x_order": grids[xo]["options"]["x_order"], "leg_receipt": os.path.basename(LEG_X[xo]), "leg_wall": legs[xo]["gnu_time"]["wall"], "leg_maxrss_kb": legs[xo]["gnu_time"]["maxrss_kb"]} for xo in (400, 500)}},
         "per_eps": {str(k): per[k] for k in KS}, "counts_A": {str(k): counts_A[k] for k in KS}, "cell_figure_A": cell, "range_A": rng,
         "vs_x500_min_max": [min(vs500), max(vs500)], "quad_L7_L8_min_max": [min(l78), max(l78)], "x400_vs_x500_worst_best": [worst_pair, best_pair],
         "dps110_member_from_served_40d_min_max": [min(tp), max(tp)], "dps110_member_differences_min_max": [min(dd), max(dd)], "counts_B_from_40d": {str(k): counts_B40[k] for k in KS},
         "leaves_differing": diffs, "planted_controls_all_fail_by_name": all_fail, "reproduced": reproduced,
         "PRODUCER": {"script": os.path.basename(__file__), "script_sha256": sha(os.path.abspath(__file__)), "mpmath": mp.__version__, "python": sys.version.split()[0], "stamp_source": "date -u"}}
    rp = os.path.join(out, "REPRODUCE_ROW33_P2.json")
    fd = os.open(rp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
    with os.fdopen(fd, "w") as f:
        json.dump(R, f, indent=1)
    print("receipt -> %s (sha256 %s)" % (rp, sha(rp)))
    return 0 if reproduced else 1


if __name__ == "__main__":
    sys.exit(main())
