# E4: TRIALS-FACTOR PROBABILITY COMPUTATION (2026-07-02)
# HONESTY-GUARD MAXIMAL: conservative = larger space, fewer effective hits, worst null headline.
# Inputs: E2 enumerated 10-dim address space; E3 collapsed hit table (floor=5/central=6/maximal=7).
# Corpus anchors: appendix_AU app:de-status (9-prefactor grammar, n in [50,64], 135 candidates,
# generous band rho_L^{1/4} in [1.8,2.8] meV, 3/135); appendix_Z thm:weinberg (3/13);
# ledger 2026-07-01 (alpha = SELECTOR of k_max=60, excluded as hit).

import math, json

# ---------- helpers ----------
def z_one_sided(p):
    """one-sided Gaussian sigma for tail probability p (bisection on 0.5*erfc(z/sqrt2))"""
    if p >= 0.5: return 0.0
    lo, hi = 0.0, 40.0
    for _ in range(200):
        mid = 0.5*(lo+hi)
        if 0.5*math.erfc(mid/math.sqrt(2)) > p: lo = mid
        else: hi = mid
    return 0.5*(lo+hi)

alpha = 1/137.035999084
E_P_meV = 1.220890e28 * 1e3   # Planck energy in meV (1.2209e28 eV)

# =====================================================================
# PART A — corpus-grounded per-dimension in-window evidence (for NULL-1)
# =====================================================================
A = {}

# A1. AU grammar scan reproduction: rho_L^{1/4} = (pref)^{1/4} * alpha^{n/4} * E_P
prefs = {"1":1.0, "3/8pi":3/(8*math.pi), "1/8pi":1/(8*math.pi), "3/4pi":3/(4*math.pi),
         "1/4pi":1/(4*math.pi), "1/2":0.5, "2":2.0, "pi":math.pi, "1/pi":1/math.pi}
band = (1.8, 2.8)  # meV, AU's generous band
au_hits = []
for pn, pv in prefs.items():
    for n in range(50, 65):
        e = (pv**0.25) * (alpha**(n/4)) * E_P_meV
        if band[0] <= e <= band[1]:
            au_hits.append((pn, n, round(e, 3)))
A["AU_scan"] = {"candidates": 135, "hits": au_hits, "n_hits": len(au_hits)}
# Lambda-exponent uniqueness: rung spacing 137^{1/4}=3.42 in energy -> only n=57 in ANY O(1) band
rung = 137.036**0.25
A["rung_spacing_energy"] = round(rung, 3)
# => N_gen in-window count: n = 60 - N_gen, N_gen in {1..6}; only N_gen=3 gives n=57 -> 1/6
ngen_hits = [g for g in range(1, 7) if 60-g == 57]
A["Ngen_in_window"] = f"{len(ngen_hits)}/6"

# A2. q1 -> k_max -> alpha tail (proxy: alpha^-1 scales ~ linearly with k_max; E2 computed
# q1>=9 -> k_max>=411 -> alpha^-1 ratio >2.8; here q1=1->k_max~20, q1=6->k_max~120)
q1_kmax = {1: 20, 3: 60, 6: 120}
q1_alpha_inv = {q: 137.036*(k/60) for q, k in q1_kmax.items()}
# any alpha^-1 shift >>1% destroys the ENTIRE alpha-ladder (H0, rho_L, a0, Omega_chi): miss
q1_hits = [q for q, ai in q1_alpha_inv.items() if abs(ai-137.036)/137.036 < 0.01]
A["q1_alpha_inv_proxy"] = {str(q): round(v, 1) for q, v in q1_alpha_inv.items()}
A["q1_in_window"] = f"{len(q1_hits)}/3"

# A3. sin^2 thetaW rival partitions (unification-normalization values)
s2w_obs = 0.23122
partitions = {"SM(3,2,1) TrY2=10": 3/13, "Pati-Salam": 3/8, "SU(5)": 3/8,
              "flipped SU(5)xU(1)": 3/8, "trinification": 3/8, "LR-symmetric": 0.25,
              "SMxU(1)_B-L (TrY2=10 degenerate)": 3/13}  # conservative: grant B-L the SM value
part_hits = [k for k, v in partitions.items() if abs(v-s2w_obs)/s2w_obs < 0.004]
A["s2w_rivals"] = {k: round(v, 4) for k, v in partitions.items()}
A["partition_in_window"] = f"{len(part_hits)}/7"

# A4. chi primordial states (ledger 2567-2579) vs Omega_chi h^2 = 0.1200 +/- 0.0012 (2sigma window)
chi_states = {"Plancherel": 0.118, "Mathieu": 0.092, "uniform": 0.138, "qdim": 0.124}
chi_hits = [k for k, v in chi_states.items() if abs(v-0.1200) <= 2*0.0012 + 0.0017*0.118]
A["chi_in_window"] = f"{len(chi_hits)}/4  ({chi_hits})"

# =====================================================================
# NULL-1 (ADDRESS NULL): every address equally likely; p1 = M/N_cons
# =====================================================================
# conservative dimension sizes (E2 final):
dims = {"q1": 3, "partition": 7, "Ngen": 6, "padding": 2, "assembly": 8,
        "CKM": 8, "grammar": 9, "sign": 16, "axiom": 16, "chi": 4}
# hit-compatible counts per dim (CONSERVATIVE = generous to rivals; computed/granted):
#  q1: 1 (A2 computed)              partition: 2 (A3: SM + granted B-L degenerate)
#  Ngen: 1 (A1 computed)            padding: 2 (both k_max=60, lem:E_bundle_kmax60 -> degenerate)
#  assembly: 2 (worst alternate 30.5% off alpha = hit-dead, but GRANT 2 as theta12 carrier)
#  CKM: 2 (only 43/2 branch documented; grant a 2nd)   grammar: 3 (A1 computed: 3 prefactors)
#  sign: 16 (hits sign-insensitive -> all pass)        axiom: 16 (all pass, maximally generous)
#  chi: 1 (A4 computed)
hits_per_dim = {"q1": 1, "partition": 2, "Ngen": 1, "padding": 2, "assembly": 2,
                "CKM": 2, "grammar": 3, "sign": 16, "axiom": 16, "chi": 1}
N_cons = math.prod(dims.values())
M = math.prod(hits_per_dim.values())
p1 = M/N_cons
NULL1 = {"N_addresses": N_cons, "M_matching": M, "p": p1, "Z": z_one_sided(p1)}

# =====================================================================
# NULL-2 (MAGNITUDE NULL, App CE methodology): p_i = 2*f_i (span 1, MORE
# conservative than per-decade), hits independent; matches E3 arithmetic.
# =====================================================================
f = {"s2w": 0.0019, "theta12": 0.037, "CKM(sin2b)": 0.016, "H0LamA0": 0.013, "Omega_chi": 0.017}
p_floor = math.prod(2*x for x in f.values())
f_a0coef = abs(0.1708-0.1713)/0.1713            # a0 coefficient residual (central 6th hit)
p_central = p_floor * 2*f_a0coef
p_alphas = min(1.0, 10 * 2*0.0068)              # alpha_s with x10 selection-trials penalty
p_maximal = p_central * p_alphas
NULL2 = {"per_hit_2f": {k: round(2*v, 5) for k, v in f.items()},
         "floor5": {"p": p_floor, "Z": z_one_sided(p_floor)},
         "central6": {"p": p_central, "Z": z_one_sided(p_central)},
         "maximal7": {"p": p_maximal, "Z": z_one_sided(p_maximal)}}

# =====================================================================
# NULL-3 (WORST-CASE): per-hit maximal look-elsewhere. p_i = min(1, V_i*2f_i),
# V_i = number of distinct grammar-producible candidate values for hit i, with
# every HONEST-HOLE menu charged at its maximal evaluated size; a hit whose
# V*2f >= 1 is DISCARDED (contributes factor 1 = zero evidence).
# =====================================================================
V = {"s2w": 7,            # all 7 partitions as distinct values (tail proven value-degenerate)
     "theta12": 16,       # 8 assembly alternates x 2 sign (hole: evaluated list, no classification)
     "CKM(sin2b)": 120,   # 8 branch menu x 15-integer eta-bar hole menu (AU-sized, unclassified)
     "H0LamA0": 9,        # 9 prefactors; the x15 exponent charge is PROVEN double-counting (R2:
                          #   57 = k_max - N_gen is already varied by the q1 and N_gen dimensions)
     "Omega_chi": 4}      # 4 evaluated measures; continuous hostile charge = window/range
p3_terms = {k: min(1.0, V[k]*2*f[k]) for k in f}
# continuous hostile alternative for chi: window/range over evaluated span [0.092,0.138]
chi_cont = (2*0.017*0.118)/(0.138-0.092)
p3_terms["Omega_chi"] = max(p3_terms["Omega_chi"], chi_cont)   # take the WORSE of the two
p3 = math.prod(p3_terms.values())
surviving = [k for k, v in p3_terms.items() if v < 1.0]
NULL3 = {"per_hit": {k: round(v, 4) for k, v in p3_terms.items()},
         "discarded_hits": [k for k in p3_terms if p3_terms[k] >= 1.0],
         "surviving_hits": surviving, "p": p3, "Z": z_one_sided(p3)}
# paranoid ladder (also discard chi / also discard H0-block):
p3_no_chi = math.prod(v for k, v in p3_terms.items() if k != "Omega_chi")
p3_only_s2w = p3_terms["s2w"]
NULL3["paranoid_also_drop_chi"] = {"p": p3_no_chi, "Z": z_one_sided(p3_no_chi)}
NULL3["paranoid_s2w_only"] = {"p": p3_only_s2w, "Z": z_one_sided(p3_only_s2w)}

# =====================================================================
# SENSITIVITY: skeptics halve the effective-hit count (keep the LOOSEST windows,
# i.e. worst case for DFD)
# =====================================================================
loosest3 = sorted((2*x for x in f.values()), reverse=True)[:3]   # 5 -> 3 (round up of 2.5)
loosest2 = loosest3[:2]                                          # 5 -> 2 (round down)
sens = {"NULL2_3hits": {"p": math.prod(loosest3), "Z": z_one_sided(math.prod(loosest3))},
        "NULL2_2hits": {"p": math.prod(loosest2), "Z": z_one_sided(math.prod(loosest2))}}
n3_sorted = sorted((v for v in p3_terms.values() if v < 1.0), reverse=True)
sens["NULL3_halved(worst2)"] = {"p": math.prod(n3_sorted[:2]), "Z": z_one_sided(math.prod(n3_sorted[:2]))}

# =====================================================================
# HEADLINE = WORST p across the three nulls
# =====================================================================
candidates = {"NULL1_address": p1, "NULL2_magnitude_floor": p_floor, "NULL3_worst_case": p3}
head_name = max(candidates, key=candidates.get)
HEAD = {"null": head_name, "p": candidates[head_name], "Z": z_one_sided(candidates[head_name])}

out = {"A_evidence": A, "NULL1": NULL1, "NULL2": NULL2, "NULL3": NULL3,
       "sensitivity": sens, "HEADLINE": HEAD}
print(json.dumps(out, indent=1, default=str))
with open("E4_results.json", "w") as fh:
    json.dump(out, fh, indent=1, default=str)
