#!/usr/bin/env python3
"""pentagon-evaluate.py -- the one-loop massless pentagon of the mpl-suite page through O(eps^0).

Closed form (the paper's Eq. (20), the BDK v-form; measure d^D l/(i pi^{D/2}), D = 4 - 2 eps,
propagators 1/q^2, no e^{eps gamma_E} factor):

    I_5 = r_Gamma sum_{j=1}^5 [1/(v_{j-2} v_{j-1} v_j)]
              * [(-v_{j-2})(-v_{j-1})(-v_j)/((-v_{j+1})(-v_{j+2}))]^(-eps)
              * [1/eps^2 + 2 Li_2(1 - v_{j+3}/v_{j+1}) + 2 Li_2(1 - v_j/v_{j+2}) - pi^2/6] + O(eps),
    r_Gamma = Gamma(1+eps) Gamma(1-eps)^2/Gamma(1-2eps)
            = 1 - gamma_E eps + (gamma_E^2/2 - pi^2/12) eps^2 + O(eps^3),

with v_i = s_{i,i+1} the five cyclic Mandelstams (indices mod 5), expanded here to its three Laurent
coefficients eps^-2, eps^-1, eps^0.  The eps^-2 coefficient is sum_j 1/(v_{j-2} v_{j-1} v_j) exactly
(-3/8 at the reference point below).

The sum of box functions
    S = sum_{i=1}^5 B_i,   B_i = Li_2(1 - v_i/v_{i+2}) + Li_2(1 - v_i/v_{i+3}) + (1/2) log^2(v_{i+2}/v_{i+3}),
is what the row's weight-two fit sampled and recovered (unit weights: all five coefficients exactly 1);
it is NOT the pentagon's finite part in any normalisation and is kept below as a labelled secondary
tier.  Until 2026-09-11 this script's docstring and gate presented S as I_5; the auxiliary-mass-flow
Laurent coefficients vendored beside it refute that reading by object (S and the pentagon's eps^0
coefficient share no digit at the reference point; the run prints the figure).

DOMAIN: Euclidean points with all v_i < 0 (same sign), so every ratio v_i/v_j is positive, every Li_2
argument real < 1 and every log real: the three coefficients and S are real.  Singular locus: v_i = 0
and v_i = v_{i+2} (the d_i letters).

REFERENCE (vendor_row5_i5/ beside this script; the three files read are sha256-pinned in PINS below and
a mismatch is REFUSED before anything is computed; pentagon-weight3-check.py --i5 pins the whole
directory and re-derives the runs' comparison receipt):
    the withheld point (v_1, ..., v_5) = (-1,-2,-3,-4,-5): the pentagon's Laurent coefficients
    eps^-2, eps^-1, eps^0 as balls '[mid +/- rad]' from two auxiliary-mass-flow runs of the massless
    five-propagator family at goals 60 and 40 (amflow_out_g60.json, amflow_out_g40.json; the [1,1,1,1,1]
    entry), and the runs' comparison receipt ITEM49_COMPARE.json, whose pair_goal40_vs_goal60 table
    records the two runs' agreement per order (85.44 / 76.92 / 69.26 digits at eps^-2 / eps^-1 / eps^0)
    and whose reportable count over the runs' eight targets is 68 (68.84; the figure the page
    prints for this row).
GATE (exit 0 only if every item holds): (i) the v-form agrees with the goal-60 midpoints at every
    order to >= min(dps - 10, the pair digits of that order); (ii) the pair digits recomputed here
    from the two vendored outputs at the comparison receipt's precision (dps 130) equal its rows;
    (iii) the eps^-2 coefficient in exact rational arithmetic reproduces the goal-60 ball; (iv) the
    v-form is Z5-cyclic at a non-symmetric point to >= dps - 10 digits; (v) the Laurent truncation
    |I_5(eps) - (c_-2/eps^2 + c_-1/eps + c_0)| at a small eps is O(eps); (vi) a PLANTED sign flip of
    one prefactor (R_3 -> -R_3) is detected (it agrees with the reference to less than one digit);
    (vii) the dilogarithms re-evaluated by quadrature, Li_2(z) = -int_0^1 log(1 - z t)/t dt,
    reproduce the eps^0 coefficient to >= 40 digits; and, in the secondary tier, S(-1,-2,-3,-4,-5)
    reproduces its 40-digit literal of record, S(-1,-1,-1,-1,-1) = 0 (the weight-one telescope) to
    < 10^-(dps-10), and S is Z5-cyclic.  At dps 130 the v-form agrees with the goal-60 balls to
    114.57 / 110.56 / 107.89 digits (each capped by the ball's own radius); the count of record stays 68,
    the pair floor.

Requirements: python3 + mpmath ONLY (json/hashlib/argparse stdlib).  mp.dps is set INSIDE main()
after argparse.  Runs in about a second at the default dps.

EXIT CODE: 0 PASS; 1 a gate failed by name (--mutate and --plant-flip must produce this); 2 usage;
3 a pinned file's sha256 differs from PINS (REFUSED by name, nothing computed); 4 a pinned file is
missing (the message names the files to download beside this script).

CLI:
  python3 pentagon-evaluate.py                                # the gate at dps 60 + the secondary tier
  python3 pentagon-evaluate.py --dps 130                      # the comparison receipt's precision
  python3 pentagon-evaluate.py --point=-1,-3/2,-2,-7/3,-5    # the three coefficients (and S) at another Euclidean v (note the "=": the value starts with "-")
  python3 pentagon-evaluate.py --check                        # two-precision rule: rerun at dps+60, diff
  python3 pentagon-evaluate.py --mutate                       # one digit of the vendored goal-60 eps^0 midpoint changed in memory (rc 1)
  python3 pentagon-evaluate.py --plant-flip                   # the R_3 sign flip applied to the gated value (rc 1)
"""

import argparse
import hashlib
import json
import os
import re
import sys
import time
from fractions import Fraction

import mpmath as mp

sys.stdout.reconfigure(line_buffering=True)

HERE = os.path.dirname(os.path.abspath(__file__))
EXIT_OK, EXIT_GATE, EXIT_USAGE, EXIT_PIN, EXIT_MISSING = 0, 1, 2, 3, 4

# --- PINS (the three vendored files this script reads, by sha256; pentagon-weight3-check.py pins all of vendor_row5_i5/) ---
PINS = {
    "vendor_row5_i5/amflow_out_g60.json": "f0cfaabb57de4f310e08974301d0b0ffbc03cf60edad3487acb509d2691d5320",
    "vendor_row5_i5/amflow_out_g40.json": "a08883b6d9ec31c92863ef0bc7b3eadb5f76ab650e0dc822b4587cd139a17b36",
    "vendor_row5_i5/ITEM49_COMPARE.json": "63ebd9a97d01b8b4b1f6e0ff1f48248d3e35a1817256b021d226d1aa8da4f7e1",
}
# --- END PINS ---

GATE_PT = "-1,-2,-3,-4,-5"      # the withheld point of the two vendored runs
SYM_PT = "-1,-1,-1,-1,-1"       # S = 0 exactly there (telescope)
STRUCT_PT = "-2,-3,-5,-7,-11"   # non-symmetric point for the Z5 structural checks
PENT = (1, 1, 1, 1, 1)
ORDERS = (-2, -1, 0)
RECORD_DPS = 130                # the comparison receipt's working precision (its pair table is reproduced at it)
# S at GATE_PT: the 40-digit literal of record of the sum of box functions (the fit's object, NOT the pentagon)
SUM_B_LITERAL = "-0.6710230862615532015524077007309454537779"


def mprat(s):
    fr = Fraction(s)
    return mp.mpf(fr.numerator) / mp.mpf(fr.denominator)


def parse_v(s):
    v = [mprat((t)) for t in s.split(",")]
    assert len(v) == 5, "need 5 comma-separated v_i"
    assert all(x < 0 for x in v) or all(x > 0 for x in v), \
        "documented domain: all v_i of the same sign (Euclidean: all v_i < 0)"
    return v


def box_sum(v, li2=mp.polylog):
    """S = sum_i B_i, the sum of the five box functions (the weight-two fit's object; NOT the pentagon)."""
    def L2(z):
        return li2(2, z) if li2 is mp.polylog else li2(z)
    tot = mp.mpf(0)
    for i in range(5):
        a, b, c = v[i], v[(i + 2) % 5], v[(i + 3) % 5]
        tot += L2(1 - a / b) + L2(1 - a / c) + mp.log(b / c)**2 / 2
    return tot


def r_gamma_coeffs():
    """r_Gamma = 1 + r1 eps + r2 eps^2 + O(eps^3): r1 = -gamma_E, r2 = gamma_E^2/2 - pi^2/12 (from ln Gamma(1+x) =
    -gamma_E x + sum_{k>=2} (-1)^k zeta(k) x^k / k)."""
    return -mp.euler, mp.euler**2 / 2 - mp.pi**2 / 12


def vform(v, li2=mp.polylog, flip=None):
    """The pentagon's Laurent coefficients (c_-2, c_-1, c_0) from the BDK v-form (r_Gamma expanded);
    flip = j plants R_j -> -R_j (the control)."""
    def L2(z):
        return li2(2, z) if li2 is mp.polylog else li2(z)

    def V(i):
        return v[(i - 1) % 5]
    r1, r2 = r_gamma_coeffs()
    c2 = c1 = c0 = mp.mpf(0)
    for j in range(1, 6):
        R = 1 / (V(j - 2) * V(j - 1) * V(j))
        if flip == j:
            R = -R
        X = ((-V(j - 2)) * (-V(j - 1)) * (-V(j))) / ((-V(j + 1)) * (-V(j + 2)))
        L = mp.log(X)
        fin = 2 * L2(1 - V(j + 3) / V(j + 1)) + 2 * L2(1 - V(j) / V(j + 2)) - mp.pi**2 / 6
        c2 += R
        c1 += R * (r1 - L)
        c0 += R * (r2 - r1 * L + L**2 / 2 + fin)
    return c2, c1, c0


def vform_pole_exact(pt):
    """The eps^-2 coefficient sum_j 1/(v_{j-2} v_{j-1} v_j) in exact rational arithmetic."""
    fr = [Fraction(t) for t in pt.split(",")]
    return sum(Fraction(1) / (fr[(j - 3) % 5] * fr[(j - 2) % 5] * fr[(j - 1) % 5]) for j in range(1, 6))


def vform_eps(v, eps):
    """I_5 at a finite eps from the v-form with r_Gamma kept exact (for the truncation check only)."""
    def V(i):
        return v[(i - 1) % 5]
    tot = mp.mpf(0)
    for j in range(1, 6):
        R = 1 / (V(j - 2) * V(j - 1) * V(j))
        X = ((-V(j - 2)) * (-V(j - 1)) * (-V(j))) / ((-V(j + 1)) * (-V(j + 2)))
        fin = 2 * mp.polylog(2, 1 - V(j + 3) / V(j + 1)) + 2 * mp.polylog(2, 1 - V(j) / V(j + 2)) - mp.pi**2 / 6
        tot += R * X**(-eps) * (1 / eps**2 + fin)
    return mp.gamma(1 + eps) * mp.gamma(1 - eps)**2 / mp.gamma(1 - 2 * eps) * tot


def li2_quad(z):
    """Independent control: Li_2(z) = -int_0^1 log(1 - z t)/t dt."""
    if z == 0:
        return mp.mpf(0)
    return -mp.quad(lambda t: mp.log(1 - z * t) / t, [0, 1])


def digits_agree(a, b):
    a, b = mp.mpf(a), mp.mpf(b)
    if a == b:
        return float(mp.mp.dps)
    if b == 0:
        return float(-mp.log10(abs(a))) if a != 0 else float(mp.mp.dps)
    return float(-mp.log10(abs((a - b) / b)))


def agree_ball(a, mid, rad):
    """Digits of a vs a ball's midpoint, capped by the ball's own relative radius (an agreement past the
    reference's certified width would certify nothing)."""
    d = digits_agree(a, mp.mpf(mid))
    m, r = mp.mpf(mid), mp.mpf(rad)
    if r > 0 and m != 0:
        d = min(d, float(-mp.log10(r / abs(m))))
    return d


def dig_pair(a, b):
    """The comparison receipt's measure for the goal-40 / goal-60 pair: -log10(|a-b| / max(|a|,|b|)); identical
    strings quote the working dps."""
    a, b = mp.mpf(a), mp.mpf(b)
    if a == b:
        return float(mp.mp.dps)
    ref = max(abs(a), abs(b))
    return float(-mp.log10(abs(a - b) / ref)) if ref != 0 else float(mp.mp.dps)


BALL = re.compile(r"^\[\s*(\S+)\s*\+/-\s*(\S+)\s*\]$")


def ball(s):
    """'[mid +/- rad]' -> (mid, rad) as strings; a bare number -> (s, '0')."""
    m = BALL.match(s.strip())
    return (m.group(1), m.group(2)) if m else (s.strip(), "0")


def sha256_file(p):
    h = hashlib.sha256()
    with open(p, "rb") as fh:
        for chunk in iter(lambda: fh.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()


def check_pins():
    """Every file of PINS present and byte-identical to its pin, before anything is computed."""
    missing = [rel for rel in PINS if not os.path.exists(os.path.join(HERE, rel))]
    if missing:
        print("pentagon-evaluate MISSING: %s not found beside this script; download vendor_row5_i5/ from the same "
              "page (the two auxiliary-mass-flow outputs and ITEM49_COMPARE.json); nothing computed" % ", ".join(missing))
        sys.exit(EXIT_MISSING)
    for rel, want in PINS.items():
        got = sha256_file(os.path.join(HERE, rel))
        if got != want:
            pos = next(i + 1 for i in range(64) if got[i] != want[i])
            print("pentagon-evaluate REFUSED: %s sha256 %s != pinned %s (first differing hex position %d of 64) -- "
                  "the shipped file was altered; nothing computed" % (rel, got, want, pos))
            sys.exit(EXIT_PIN)
    return len(PINS)


def load_reference():
    """The [1,1,1,1,1] Laurent balls of the two runs (orders -2..0) and the comparison receipt's pair rows."""
    runs = {}
    for g in (60, 40):
        d = json.load(open(os.path.join(HERE, "vendor_row5_i5", "amflow_out_g%d.json" % g)))
        ent = next(r for r in d["result"] if tuple(r["integral"]["indices"]) == PENT)
        co = {int(c["order"]): c["value"] for c in ent["coefficients"]}
        for o in ORDERS:
            assert co[o]["im"].strip() in ("0", "0.0"), "a nonzero imaginary part in the vendored output"
        runs[g] = {o: ball(co[o]["re"]) for o in ORDERS}
    cmp = json.load(open(os.path.join(HERE, "vendor_row5_i5", "ITEM49_COMPARE.json")))
    pair_rec = {o: float(cmp["pair_goal40_vs_goal60"][str(list(PENT))][str(o)]) for o in ORDERS}
    return runs, pair_rec, cmp


def main():
    ap = argparse.ArgumentParser(description="Row 05: the one-loop massless pentagon through O(eps^0), the BDK v-form, "
                                 "gated against the vendored auxiliary-mass-flow pair; the sum of box functions as a secondary tier")
    ap.add_argument("--dps", type=int, default=60)
    ap.add_argument("--point", action="append", default=[],
                    help="extra point 'v1,v2,v3,v4,v5' (rational strings, all of one sign; write --point=... since the value starts with '-'); repeatable")
    ap.add_argument("--check", action="store_true", help="two-precision rule: rerun at dps+60")
    ap.add_argument("--mutate", action="store_true",
                    help="change one digit of the vendored goal-60 eps^0 midpoint in memory; run must exit nonzero")
    ap.add_argument("--plant-flip", action="store_true",
                    help="apply the planted R_3 -> -R_3 sign flip to the GATED v-form; run must exit nonzero")
    ap.add_argument("--control-dps", type=int, default=40,
                    help="dps for the independent quadrature control (default 40)")
    args = ap.parse_args()
    if args.dps < 20:
        print("pentagon-evaluate REFUSED (usage): --dps must be >= 20")
        return EXIT_USAGE

    t0 = time.time()
    npins = check_pins()
    runs, pair_rec, cmp = load_reference()
    mp.mp.dps = args.dps + 10
    fails = []

    print("pentagon  the one-loop massless pentagon through O(eps^0): the BDK v-form I_5 = r_Gamma sum_j R_j X_j^(-eps) "
          "[1/eps^2 + 2 Li2(1 - v_{j+3}/v_{j+1}) + 2 Li2(1 - v_j/v_{j+2}) - pi^2/6], R_j = 1/(v_{j-2} v_{j-1} v_j), "
          "X_j = (-v_{j-2})(-v_{j-1})(-v_j)/((-v_{j+1})(-v_{j+2}))")
    print(f"dps={args.dps} (+10 guard); domain: all v_i of one sign (Euclidean v_i < 0); measure d^D l/(i pi^(D/2)), no e^(eps gamma_E)")
    print(f"[pins] {npins} vendored files verified by sha256 ({', '.join(PINS)})")
    if args.mutate:
        mid, rad = runs[60][0]
        k = 20
        while not mid[k].isdigit():
            k += 1
        runs[60][0] = (mid[:k] + str((int(mid[k]) + 1) % 10) + mid[k + 1:], rad)
        print(f"[mutate] character {k} of the vendored goal-60 eps^0 midpoint changed in memory (this run MUST exit nonzero)")
    flip = 3 if args.plant_flip else None
    if flip:
        print("[plant-flip] the sign of R_3 is flipped in the GATED v-form (this run MUST exit nonzero)")

    print(f"\n[reference] the withheld point ({GATE_PT}): the [1,1,1,1,1] Laurent coefficients of the two vendored runs, balls [mid +/- rad]:")
    for o in ORDERS:
        m60, r60 = runs[60][o]
        m40, r40 = runs[40][o]
        print(f"  eps^{o:<2}  goal 60: {m60[:52]}{'...' if len(m60) > 52 else ''} +/- {r60}   |   goal 40: {m40[:44]}{'...' if len(m40) > 44 else ''} +/- {r40}")

    # ---- the v-form at the gate point
    v = parse_v(GATE_PT)
    c = vform(v, flip=flip)
    print(f"\n[v-form] at ({GATE_PT}), dps {args.dps}:")
    print(f"  {'order':>6} | {'coefficient (computed now)':>48} | vs goal 60 (capped by its radius) | need")
    d_v = {}
    for i, o in enumerate(ORDERS):
        d = agree_ball(c[i], *runs[60][o])
        need = min(args.dps - 10, pair_rec[o])
        d_v[o] = d
        ok = d >= need
        print(f"  eps^{o:<2} | {mp.nstr(c[i], 45):>48} | {d:8.2f} d | >= {need:.2f} {'ok' if ok else 'FAIL'}")
        if not ok:
            fails.append(f"v-form eps^{o}: {d:.2f} d < {need:.2f} d" + (" (mutated in memory)" if args.mutate and o == 0 else "")
                         + (" (planted flip)" if flip else ""))
    pole = vform_pole_exact(GATE_PT)
    d_pole = agree_ball(mprat(str(pole)), *runs[60][-2])
    print(f"  eps^-2 exactly: sum_j R_j = {pole} (rational arithmetic); vs the goal-60 ball {d_pole:.2f} d")
    if d_pole < min(args.dps - 10, pair_rec[-2]):
        fails.append("the exact eps^-2 coefficient does not reproduce the goal-60 ball")

    # ---- the pair, recomputed at the receipt's precision
    with mp.workdps(RECORD_DPS):
        pair_now = {o: dig_pair(runs[40][o][0], runs[60][o][0]) for o in ORDERS}
    same = all(abs(pair_now[o] - pair_rec[o]) < 1e-6 for o in ORDERS)
    print(f"\n[pair] goal 40 vs goal 60 recomputed here at dps {RECORD_DPS}: " + " / ".join(f"{pair_now[o]:.2f}" for o in ORDERS)
          + "; the comparison receipt's rows " + " / ".join(f"{pair_rec[o]:.2f}" for o in ORDERS)
          + f" (eps^-2 / eps^-1 / eps^0) -> {'equal' if same else 'DIFFERENT'} (tolerance 1e-6)")
    if not same:
        fails.append("the recomputed goal-40 / goal-60 pair differs from the comparison receipt's rows" + (" (mutated in memory)" if args.mutate else ""))
    rep = cmp["reportable_digits"]
    print(f"  the count of record: {int(float(rep['value']))} = the integer part of the receipt's reportable value {float(rep['value']):.2f} "
          f"(min over {', '.join(rep['members'])}; the pair floor over the runs' eight targets at eps^-2..eps^0) -- the page's figure for this row")

    # ---- structural checks at a non-symmetric point
    w = parse_v(STRUCT_PT)
    base = vform(w)
    dcyc = min(min(digits_agree(base[i], vform(w[k:] + w[:k])[i]) for i in range(3)) for k in range(1, 5))
    tele = sum(mp.log(w[(i + 2) % 5] / w[(i + 3) % 5]) for i in range(5))
    print(f"\n[structure] at ({STRUCT_PT}): Z5 cyclic invariance of the three coefficients {dcyc:.1f} d (all 4 shifts; need >= {args.dps - 10}); "
          f"weight-1 telescope |sum_i log(v_(i+2)/v_(i+3))| = {mp.nstr(abs(tele), 3)}")
    if dcyc < args.dps - 10:
        fails.append(f"Z5 invariance of the v-form {dcyc:.1f} d < {args.dps - 10} d")

    # ---- the Laurent truncation
    e10 = min(30, args.dps // 4)
    eps = mp.mpf(10) ** (-e10)
    cc = vform(v)
    resid = abs(vform_eps(v, eps) - (cc[0] / eps**2 + cc[1] / eps + cc[2]))
    trunc_ok = resid < eps * 1000
    print(f"[truncation] |I_5(eps) - (c_-2/eps^2 + c_-1/eps + c_0)| at eps = 1e-{e10}: {mp.nstr(resid, 5)} (O(eps): {'yes' if trunc_ok else 'NO'})")
    if not trunc_ok:
        fails.append("the Laurent truncation residual is not O(eps)")

    # ---- the planted control (always evaluated; --plant-flip also applies it to the gated value above)
    cf = vform(v, flip=3)
    d_flip = [agree_ball(cf[i], *runs[60][o]) for i, o in enumerate(ORDERS)]
    detected = max(d_flip) < 5.0
    print(f"[control] R_3 -> -R_3 planted: agreement with the goal-60 balls {' / '.join(f'{d:.2f}' for d in d_flip)} d -> "
          + ("FAIL by name: planted prefactor sign flip detected" if detected else "CONTROL BROKEN"))
    if not detected:
        fails.append("the planted sign-flip control did not fail")

    # ---- the quadrature control
    t1 = time.time()
    saved = mp.mp.dps
    mp.mp.dps = args.control_dps + 10
    vv = parse_v(GATE_PT)
    dq = digits_agree(vform(vv, li2=li2_quad)[2], vform(vv)[2])
    ww = parse_v(STRUCT_PT)
    dq2 = digits_agree(box_sum(ww, li2=li2_quad), box_sum(ww))
    mp.mp.dps = saved
    t_ctrl = time.time() - t1
    print(f"[quadrature] Li_2 by mp.quad, dps {args.control_dps}: the eps^0 coefficient at ({GATE_PT}) {dq:.1f} d; S at ({STRUCT_PT}) {dq2:.1f} d (need >= 40)")
    if dq < 40.0 or dq2 < 40.0:
        fails.append("quadrature control below 40 d")

    # ---- the secondary tier: the sum of box functions
    print(f"\n[secondary tier: S = sum_i B_i, the sum of box functions -- the weight-two fit's object, NOT the pentagon]")
    S = box_sum(v)
    dS = digits_agree(S, mp.mpf(SUM_B_LITERAL))
    S0 = box_sum(parse_v(SYM_PT))
    dS_cyc = min(digits_agree(box_sum(w), box_sum(w[k:] + w[:k])) for k in range(1, 5))
    d_S_pent = digits_agree(S, mp.mpf(runs[60][0][0]))
    print(f"  S({GATE_PT}) = {mp.nstr(S, 40)} : {dS:.1f} d vs its 40-digit literal of record (need >= 40)")
    print(f"  S({SYM_PT}) = {mp.nstr(S0, 5)} : exact 0 by the telescope (need < 1e-{args.dps - 10})")
    print(f"  Z5 cyclic invariance of S at ({STRUCT_PT}): {dS_cyc:.1f} d")
    print(f"  S vs the pentagon's eps^0 coefficient (goal 60) at ({GATE_PT}): {d_S_pent:.2f} d -- S is not the pentagon")
    if dS < 40.0:
        fails.append(f"S literal {dS:.1f} d < 40 d")
    if abs(S0) >= mp.mpf(10) ** (-(args.dps - 10)):
        fails.append(f"|S(sym)| = {mp.nstr(abs(S0), 3)} >= 1e-{args.dps - 10}")
    if dS_cyc < args.dps - 10:
        fails.append(f"Z5 invariance of S {dS_cyc:.1f} d < {args.dps - 10} d")

    # ---- extra points
    extra = [p for p in args.point if p not in (GATE_PT,)]
    vals = {GATE_PT: (c, S)}
    if extra:
        print("\n[points] (no reference is shipped at these; the v-form's three coefficients and S):")
        for p in extra:
            vp = parse_v(p)
            cp, Sp = vform(vp), box_sum(vp)
            vals[p] = (cp, Sp)
            print(f"  ({p}): eps^-2 {mp.nstr(cp[0], 30)}  eps^-1 {mp.nstr(cp[1], 30)}  eps^0 {mp.nstr(cp[2], 30)}  |  S {mp.nstr(Sp, 30)}")

    if args.check:
        hi = args.dps + 60
        print(f"\n--check: rerunning at dps {hi} ...")
        mp.mp.dps = hi + 10
        ok = True
        tgt = args.dps - 5
        for p, (cp, Sp) in vals.items():
            vp = parse_v(p)
            c2, S2 = vform(vp, flip=flip if p == GATE_PT else None), box_sum(vp)
            ds = [digits_agree(cp[i], c2[i]) for i in range(3)] + [digits_agree(Sp, S2)]
            ok = ok and min(ds) >= tgt
            print(f"    ({p}): stable to {' / '.join(f'{d:.1f}' for d in ds)} d (eps^-2 / eps^-1 / eps^0 / S; target >= {tgt})")
        mp.mp.dps = args.dps + 10
        print(f"--check verdict: {'PASS' if ok else 'FAIL'}")
        if not ok:
            fails.append("--check two-precision rerun unstable")

    print(f"\ntimings [s]: control {t_ctrl:.2f}, TOTAL {time.time() - t0:.2f}")
    if fails:
        print(f"OVERALL FAIL: {'; '.join(fails)}")
        return EXIT_GATE
    print(f"OVERALL PASS (the pentagon's v-form at ({GATE_PT}) reproduces the goal-60 Laurent coefficients to "
          f"{' / '.join(f'{d_v[o]:.2f}' for o in ORDERS)} d at eps^-2 / eps^-1 / eps^0; the goal-40 / goal-60 pair "
          f"{' / '.join(f'{pair_now[o]:.2f}' for o in ORDERS)}; the count of record {int(float(rep['value']))})")
    return EXIT_OK


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