#!/usr/bin/env python3
"""
RU–String Host Bridge Extractor (minimal reproducibility tool)

Purpose:
- Treat RU as the universality engine.
- Treat string/CFT fusion data as host structures.
- Emit auditable objects:
  - bridge wrapper (sources/ru_bridge/bridge_certificate_*.json)
  - RU robust certificate instance (sources/ru/robust_certificate_*.json)

This tool intentionally supports a small set of bundled, audited examples.
It is meant as a reproducibility anchor and a template for extension.
"""

from __future__ import annotations

import argparse
import hashlib
import json
import math
import os
from dataclasses import dataclass
from typing import Any, Dict, List, Tuple, Optional

try:
    import jsonschema  # type: ignore
except Exception:
    jsonschema = None  # fallback validation


def sha256_json(d: Dict[str, Any]) -> str:
    b = json.dumps(d, sort_keys=True).encode("utf-8")
    return "sha256:" + hashlib.sha256(b).hexdigest()


def mm(X: List[List[float]], Y: List[List[float]]) -> List[List[float]]:
    return [
        [sum(X[i][k] * Y[k][j] for k in range(len(Y))) for j in range(len(Y[0]))]
        for i in range(len(X))
    ]


def min_entry(M: List[List[float]]) -> float:
    return float(min(min(r) for r in M))


def max_entry(M: List[List[float]]) -> float:
    return float(max(max(r) for r in M))


def tanh(x: float) -> float:
    return float(math.tanh(x))


def compute_projective_params(W: List[List[float]]) -> Tuple[float, float, float]:
    """
    Given a strictly positive matrix W, return:
    - delta = min entry
    - U = max entry
    - tau = tanh( (2 log(U/delta))/4 )
    This matches the rate_pack formula in the bundled certificate schema examples.
    """
    delta = min_entry(W)
    U = max_entry(W)
    if delta <= 0:
        raise ValueError("W must be strictly positive to compute Doeblin delta>0.")
    Delta = 2.0 * math.log(U / delta)
    tau = tanh(Delta / 4.0)
    return delta, U, tau


def ensure_dir(p: str) -> None:
    os.makedirs(p, exist_ok=True)


def load_json(path: str) -> Dict[str, Any]:
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def dump_json(path: str, obj: Dict[str, Any]) -> None:
    ensure_dir(os.path.dirname(path))
    with open(path, "w", encoding="utf-8") as f:
        json.dump(obj, f, indent=2)


def validate_against_schema(instance_path: str, schema_path: str) -> Tuple[bool, str]:
    inst = load_json(instance_path)
    sch = load_json(schema_path)
    if jsonschema is None:
        # Minimal fallback: required keys only
        req = sch.get("required", [])
        missing = [k for k in req if k not in inst]
        if missing:
            return False, f"Missing required keys (fallback validation): {missing}"
        return True, "OK (fallback validation: required keys present; install jsonschema for full validation)."
    try:
        jsonschema.validate(instance=inst, schema=sch)
        return True, "OK (jsonschema)"
    except Exception as e:
        return False, f"Validation error: {e}"


@dataclass
class Paths:
    root: str

    @property
    def sources(self) -> str:
        return os.path.join(self.root, "sources")

    @property
    def ru(self) -> str:
        return os.path.join(self.sources, "ru")

    @property
    def ru_bridge(self) -> str:
        return os.path.join(self.sources, "ru_bridge")

    @property
    def host_data(self) -> str:
        return os.path.join(self.sources, "host_data")


def build_fibonacci_contraction(paths: Paths, alpha: float = 0.2) -> Tuple[str, str, str]:
    """
    Real host contraction certificate from Fibonacci fusion data.
    Outputs:
    - model file under ru_bridge
    - robust certificate under ru
    - bridge wrapper under ru_bridge
    """
    fib = load_json(os.path.join(paths.host_data, "fibonacci_fusion_data.json"))
    N_tau = fib["fusion_matrices"]["N_tau"]["matrix_A_kj"]
    N2 = mm(N_tau, N_tau)

    delta, U, tau = compute_projective_params(N2)
    M = float(max_entry(N_tau))

    model = {
        "name": "Real host contraction certificate: Fibonacci fusion sector",
        "host_data": "sources/host_data/fibonacci_fusion_data.json",
        "positivity_cone": "R_+^2 in basis (1,tau)",
        "templates": {
            "N_tau": {"matrix": N_tau, "meaning": "Fibonacci fusion matrix for tau extracted from host_data"},
            "I": {"matrix": [[1, 0], [0, 1]], "meaning": "Identity step (non-tight) used to create a strict tight gap", "cost": alpha},
        },
        "constraint_graph": {
            "states": ["v0", "v1"],
            "edges": [
                {"id": "eT00", "from": "v0", "to": "v0", "template": "N_tau", "cost": 0.0},
                {"id": "eT01", "from": "v0", "to": "v1", "template": "N_tau", "cost": 0.0},
                {"id": "eT10", "from": "v1", "to": "v0", "template": "N_tau", "cost": 0.0},
                {"id": "eI00", "from": "v0", "to": "v0", "template": "I", "cost": alpha},
                {"id": "eI11", "from": "v1", "to": "v1", "template": "I", "cost": alpha},
            ],
            "notes": "For alpha>0, identity edges are non-tight; the tight core uses N_tau edges only.",
        },
        "doeblin_witness": {
            "word": ["N_tau", "N_tau"],
            "L": 2,
            "product_matrix": N2,
            "delta_min_entry": delta,
            "U_max_entry": U,
            "tau_unperturbed": tau,
            "note": "N_tau^2 is strictly positive, giving a length-2 Doeblin witness.",
        },
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0, 0.0]},
        "tight_core": {
            "tight_edges": ["eT00", "eT01", "eT10"],
            "tight_gap_gamma": float(alpha),
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": float(alpha / 2.0),
            "tight_graph_hash": "sha256:" + hashlib.sha256("eT00|eT01|eT10".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 1, "periods": [1]},
            "degeneracy_report": {"all_edges_tight": False, "gamma_is_positive": True, "note": "Tight core is stable by gamma=alpha>0."},
        },
        "doeblin": {
            "word": ["N_tau", "N_tau"],
            "L": 2,
            "M_bound": float(M),
            "U_bound": float(U),
            "delta": float(delta),
            "eps_doeblin": 0.05,
            "delta_prime_formula": "delta_prime(eps) = delta - L*(M+eps)^(L-1)*eps",
            "U_prime_formula": "U_prime(eps) = U + L*(M+eps)^(L-1)*eps",
        },
        "recurrence": {
            "mode": "combinatorial",
            "eps_recurrence": 0.05,
            "details": {
                "rc1_holds": True,
                "L_syn": 2,
                "gap_bound_B": 0,
                "og4_avoidance_cycle": None,
                "hypothesis_type": None,
                "margin": None,
                "note": "On the tight core, all edges carry N_tau; the length-2 Doeblin block occurs with B=0.",
            },
        },
        "rate_pack": {
            "projective_diameter_bound": float(2.0 * math.log(float(U) / float(delta))),
            "tau_unperturbed": float(tau),
            "tau_prime_formula": "tau_prime(eps) = tanh( (2*log(U_prime(eps)/delta_prime(eps)))/4 )",
            "eps_rate": 0.05,
            "kappa_prime_formula": "kappa_prime(eps) = -log(tau_prime(eps))/L   (L=2)",
        },
        "eps_star": {"eps_c_star": float(alpha / 2.0), "eps_A_star": 0.05},
    }

    bridge = {
        "string_context": {
            "name": "Real host: Fibonacci fusion sector (RCFT/MTC)",
            "description": "A standard finite fusion system used as a host structure. RU certifies projective contraction for a concrete constrained propagation built from N_tau.",
            "finite_sector": "Labels {1,tau} with fusion matrix N_tau and a 2-state constraint graph.",
            "positivity_cone": "R_+^2",
        },
        "reduction": {
            "state_graph": "States v0,v1; tight edges use N_tau; identity loops are non-tight for alpha>0.",
            "templates": "T_e = N_tau from sources/host_data/fibonacci_fusion_data.json; optional I is non-tight.",
            "cost_model": "c(N_tau edges)=0, c(identity loops)=alpha>0; tight gap gamma=alpha.",
            "constraints": "Subshift induced by the constraint graph; tight core is aperiodic and uses N_tau only.",
        },
        "ru_certificate_refs": {
            "robust_certificate_schema": "sources/ru/robust_certificate_schema.json",
            "robust_certificate_instance": "sources/ru/robust_certificate_fibonacci_realhost_contraction.json",
            "global_report_schema": "sources/ru/global_universality_report_schema.json",
            "global_report_instance": None,
        },
        "universality_claim": {
            "claim_level": "in_class_universality",
            "conclusion": "Length-2 Doeblin witness exists (N_tau,N_tau), RC1 holds; hence normalized products contract projectively with an explicit exponential rate.",
            "quantitative_rate": "See robust certificate rate_pack.",
        },
        "scope": {
            "assumptions": ["Host templates equal real N_tau from host_data.", "alpha>0 separates identity loops from tight core."],
            "limitations": ["Certificate is for this explicit constrained host instance; other constraints/objectives may change conclusions."],
        },
    }

    model_path = os.path.join(paths.ru_bridge, "fibonacci_realhost_contraction_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_fibonacci_realhost_contraction.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_fibonacci_realhost_contraction.json")

    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)

    return model_path, robust_path, bridge_path




def build_fibonacci_og4_idle(paths: Paths) -> Tuple[str, str, str]:
    """
    Real-host OG4 obstruction: Fibonacci fusion with a tight idle/identity loop (avoidable Doeblin).
    """
    fib = load_json(os.path.join(paths.host_data, "fibonacci_fusion_data.json"))
    N_tau = fib["fusion_matrices"]["N_tau"]["matrix_A_kj"]
    N2 = mm(N_tau, N_tau)
    delta, U, tau = compute_projective_params(N2)
    M = float(max_entry(N_tau))

    model = {
        "name": "Real host OG4: Fibonacci fusion with free idle channel",
        "host_data": "sources/host_data/fibonacci_fusion_data.json",
        "positivity_cone": "R_+^2 in basis (1,tau)",
        "templates": {
            "N_tau": {"matrix": N_tau, "meaning": "Fibonacci fusion matrix for tau"},
            "I": {"matrix": [[1, 0], [0, 1]], "meaning": "Idle/identity step (tight at alpha=0)"},
        },
        "constraint_graph": {
            "states": ["v0"],
            "edges": [
                {"id": "eT", "from": "v0", "to": "v0", "template": "N_tau", "cost": 0.0},
                {"id": "eI", "from": "v0", "to": "v0", "template": "I", "cost": 0.0},
            ],
            "notes": "Both edges are tight. Doeblin block exists (N_tau,N_tau) but is avoidable by staying on eI forever.",
        },
        "doeblin_witness": {"word": ["N_tau", "N_tau"], "L": 2, "product_matrix": N2, "delta_min_entry": delta, "U_max_entry": U, "tau_unperturbed": tau},
        "og4_witness": {"avoidance_cycle": ["eI"], "explanation": "Infinite tight path eI^∞ avoids any Doeblin block using N_tau."},
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0]},
        "tight_core": {
            "tight_edges": ["eT", "eI"],
            "tight_gap_gamma": 1.0,
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": 1.0,
            "tight_graph_hash": "sha256:" + hashlib.sha256("eT|eI".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 1, "periods": [1]},
            "degeneracy_report": {"all_edges_tight": True, "gamma_is_positive": True, "note": "OG4: all edges tight; recurrence fails via avoidance cycle eI."},
        },
        "doeblin": {
            "word": ["N_tau", "N_tau"],
            "L": 2,
            "M_bound": float(M),
            "U_bound": float(U),
            "delta": float(delta),
            "eps_doeblin": 0.05,
            "delta_prime_formula": "delta_prime(eps) = delta - L*(M+eps)^(L-1)*eps",
            "U_prime_formula": "U_prime(eps) = U + L*(M+eps)^(L-1)*eps",
        },
        "recurrence": {
            "mode": "combinatorial",
            "eps_recurrence": 1.0,
            "details": {
                "rc1_holds": False,
                "L_syn": None,
                "gap_bound_B": None,
                "og4_avoidance_cycle": ["eI"],
                "hypothesis_type": None,
                "margin": None,
                "note": "OG4 witness: tight idle loop avoids mixing blocks.",
            },
        },
        "rate_pack": {
            "projective_diameter_bound": float(2.0 * math.log(float(U) / float(delta))),
            "tau_unperturbed": float(tau),
            "tau_prime_formula": "tau_prime(eps) = tanh( (2*log(U_prime(eps)/delta_prime(eps)))/4 )",
            "eps_rate": 0.05,
            "kappa_prime_formula": "kappa_prime(eps) = -log(tau_prime(eps))/L   (L=2)  (not globally forced due to OG4)",
        },
        "eps_star": {"eps_c_star": 1.0, "eps_A_star": 0.05},
    }

    bridge = {
        "string_context": {
            "name": "Real host: Fibonacci fusion with idle channel (OG4)",
            "description": "Real Fibonacci fusion host where a tight idle loop creates avoidable Doeblin.",
            "finite_sector": "Labels {1,tau} with N_tau and I.",
            "positivity_cone": "R_+^2",
        },
        "reduction": {
            "state_graph": "One state v0 with two tight edges eT (N_tau) and eI (I).",
            "templates": "N_tau from sources/host_data/fibonacci_fusion_data.json; I identity.",
            "cost_model": "All costs 0 (tight).",
            "constraints": "All words over {eT,eI}; OG4 via eI^∞.",
        },
        "ru_certificate_refs": {
            "robust_certificate_schema": "sources/ru/robust_certificate_schema.json",
            "robust_certificate_instance": "sources/ru/robust_certificate_fibonacci_realhost_og4_idle_avoidable.json",
            "global_report_schema": "sources/ru/global_universality_report_schema.json",
            "global_report_instance": None,
        },
        "universality_claim": {"claim_level": "non_universality_obstruction", "conclusion": "OG4 avoidable Doeblin via tight idle loop.", "quantitative_rate": "Not applicable."},
        "scope": {"assumptions": ["Idle loop is tight."], "limitations": ["Restricting constraints could remove OG4."]},
    }

    model_path = os.path.join(paths.ru_bridge, "fibonacci_realhost_og4_idle_avoidable_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_fibonacci_realhost_og4_idle_avoidable.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_fibonacci_realhost_og4_idle_avoidable.json")
    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)
    return model_path, robust_path, bridge_path


def build_fibonacci_og1_period2(paths: Paths) -> Tuple[str, str, str]:
    """
    Real-host OG1 obstruction: Fibonacci fusion constrained on a strict 2-cycle => period 2 tight SCC.
    """
    fib = load_json(os.path.join(paths.host_data, "fibonacci_fusion_data.json"))
    N_tau = fib["fusion_matrices"]["N_tau"]["matrix_A_kj"]
    N2 = mm(N_tau, N_tau)
    delta, U, tau = compute_projective_params(N2)
    M = float(max_entry(N_tau))

    model = {
        "name": "Real host OG1: Fibonacci fusion on strict 2-cycle",
        "host_data": "sources/host_data/fibonacci_fusion_data.json",
        "positivity_cone": "R_+^2 in basis (1,tau)",
        "templates": {"N_tau": {"matrix": N_tau, "meaning": "Fibonacci fusion matrix for tau"}},
        "constraint_graph": {
            "states": ["p0", "p1"],
            "edges": [
                {"id": "e01", "from": "p0", "to": "p1", "template": "N_tau", "cost": 0.0},
                {"id": "e10", "from": "p1", "to": "p0", "template": "N_tau", "cost": 0.0},
            ],
            "notes": "All tight paths alternate states, so SCC period is 2.",
        },
        "periodicity_witness": {"tight_scc_period": 2, "explanation": "All cycles have even length; gcd=2."},
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0, 0.0]},
        "tight_core": {
            "tight_edges": ["e01", "e10"],
            "tight_gap_gamma": 1.0,
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": 1.0,
            "tight_graph_hash": "sha256:" + hashlib.sha256("e01|e10".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 0, "periods": [2]},
            "degeneracy_report": {"all_edges_tight": True, "gamma_is_positive": True, "note": "OG1 periodic-core witness: period 2 tight SCC."},
        },
        "doeblin": {
            "word": ["N_tau", "N_tau"],
            "L": 2,
            "M_bound": float(M),
            "U_bound": float(U),
            "delta": float(delta),
            "eps_doeblin": 0.05,
            "delta_prime_formula": "delta_prime(eps) = delta - L*(M+eps)^(L-1)*eps",
            "U_prime_formula": "U_prime(eps) = U + L*(M+eps)^(L-1)*eps",
        },
        "recurrence": {
            "mode": "combinatorial",
            "eps_recurrence": 1.0,
            "details": {"rc1_holds": None, "L_syn": None, "gap_bound_B": None, "og4_avoidance_cycle": None, "hypothesis_type": None, "margin": None, "note": "Period-2 tight SCC; strongest aperiodic universality obstructed."},
        },
        "rate_pack": {
            "projective_diameter_bound": float(2.0 * math.log(float(U) / float(delta))),
            "tau_unperturbed": float(tau),
            "tau_prime_formula": "tau_prime(eps) = tanh( (2*log(U_prime(eps)/delta_prime(eps)))/4 )",
            "eps_rate": 0.05,
            "kappa_prime_formula": "kappa_prime(eps) = -log(tau_prime(eps))/L   (L=2)  (aperiodic claim obstructed)",
        },
        "eps_star": {"eps_c_star": 1.0, "eps_A_star": 0.05},
    }

    bridge = {
        "string_context": {"name": "Real host: Fibonacci fusion strict 2-cycle (OG1)", "description": "Real host constraint forces period-2 tight SCC.", "finite_sector": "Two states p0,p1 with N_tau edges.", "positivity_cone": "R_+^2"},
        "reduction": {"state_graph": "p0↔p1 strict 2-cycle.", "templates": "N_tau from host_data.", "cost_model": "All costs 0.", "constraints": "All tight paths alternate; period 2."},
        "ru_certificate_refs": {"robust_certificate_schema": "sources/ru/robust_certificate_schema.json", "robust_certificate_instance": "sources/ru/robust_certificate_fibonacci_realhost_og1_period2.json", "global_report_schema": "sources/ru/global_universality_report_schema.json", "global_report_instance": None},
        "universality_claim": {"claim_level": "non_universality_obstruction", "conclusion": "OG1 periodic-core obstruction to aperiodic universality.", "quantitative_rate": "Not applicable."},
        "scope": {"assumptions": ["Strict 2-cycle constraint."], "limitations": ["Even-iterate contraction can be studied separately."]},
    }

    model_path = os.path.join(paths.ru_bridge, "fibonacci_realhost_og1_period2_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_fibonacci_realhost_og1_period2.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_fibonacci_realhost_og1_period2.json")
    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)
    return model_path, robust_path, bridge_path


def build_ising_og3(paths: Paths, alpha: float = 0.15) -> Tuple[str, str, str]:
    """
    Real-host OG3 obstruction: Ising fusion admits no Doeblin block on full cone (support dichotomy).
    """
    ising = load_json(os.path.join(paths.host_data, "ising_fusion_data.json"))
    N_sigma = ising["fusion_matrices"]["N_sigma"]["matrix_A_kj"]
    N_psi = ising["fusion_matrices"]["N_psi"]["matrix_A_kj"]

    model = {
        "name": "OG3 from real Ising fusion data",
        "host_data": "sources/host_data/ising_fusion_data.json",
        "positivity_cone": "R_+^3 in basis (1,psi,sigma)",
        "templates": {
            "N_sigma": {"matrix": N_sigma, "meaning": "Ising fusion matrix for sigma"},
            "N_psi": {"matrix": N_psi, "meaning": "Ising fusion matrix for psi"},
            "I": {"matrix": [[1, 0, 0], [0, 1, 0], [0, 0, 1]], "meaning": "Identity (non-tight)", "cost": alpha},
        },
        "constraint_graph": {"states": ["t0"], "edges": [{"id": "eS", "from": "t0", "to": "t0", "template": "N_sigma", "cost": 0.0}, {"id": "eP", "from": "t0", "to": "t0", "template": "N_psi", "cost": 0.0}, {"id": "eI", "from": "t0", "to": "t0", "template": "I", "cost": alpha}]},
        "og3_witness": {"claim": "No Doeblin word exists on full cone due to bipartite support invariant.", "mechanism": "sigma toggles between span{sigma} and span{1,psi}; psi permutes {1,psi} and fixes sigma."},
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0]},
        "tight_core": {
            "tight_edges": ["eS", "eP"],
            "tight_gap_gamma": float(alpha),
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": float(alpha / 2.0),
            "tight_graph_hash": "sha256:" + hashlib.sha256("eS|eP".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 1, "periods": [1]},
            "degeneracy_report": {"all_edges_tight": False, "gamma_is_positive": True, "note": "OG3: aperiodic tight SCC but no Doeblin on full cone."},
        },
        "doeblin": {"word": ["N_sigma", "N_sigma"], "L": 2, "M_bound": 2.0, "U_bound": 2.0, "delta": 0.0, "eps_doeblin": 0.0, "delta_prime_formula": "Not applicable (OG3).", "U_prime_formula": "Not applicable (OG3)."},
        "recurrence": {"mode": "combinatorial", "eps_recurrence": float(alpha / 2.0), "details": {"rc1_holds": None, "L_syn": None, "gap_bound_B": None, "og4_avoidance_cycle": None, "hypothesis_type": None, "margin": None, "note": "OG3 obstruction."}},
        "rate_pack": {"projective_diameter_bound": 0.0, "tau_unperturbed": 1.0, "tau_prime_formula": "Not applicable.", "eps_rate": 0.0, "kappa_prime_formula": "Not applicable."},
        "eps_star": {"eps_c_star": float(alpha / 2.0), "eps_A_star": 0.0},
    }

    bridge = {
        "string_context": {"name": "Real host: Ising fusion ring (OG3)", "description": "Ising fusion has no Doeblin on full cone.", "finite_sector": "Labels {1,psi,sigma}.", "positivity_cone": "R_+^3"},
        "reduction": {"state_graph": "Single state t0 with sigma/psi steps.", "templates": "N_sigma,N_psi from host_data; optional identity non-tight.", "cost_model": "c(sigma)=c(psi)=0; c(I)=alpha>0.", "constraints": "All words over {sigma,psi}."},
        "ru_certificate_refs": {"robust_certificate_schema": "sources/ru/robust_certificate_schema.json", "robust_certificate_instance": "sources/ru/robust_certificate_og3_ising_fusion.json", "global_report_schema": "sources/ru/global_universality_report_schema.json", "global_report_instance": None},
        "universality_claim": {"claim_level": "non_universality_obstruction", "conclusion": "OG3 no-Doeblin on full cone.", "quantitative_rate": "Not applicable."},
        "scope": {"assumptions": ["Full cone statement."], "limitations": ["Restricted faces may differ."]},
    }

    model_path = os.path.join(paths.ru_bridge, "og3_ising_fusion_no_doeblin_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_og3_ising_fusion.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_og3_ising_fusion.json")
    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)
    return model_path, robust_path, bridge_path


def build_ising_og2_projection(paths: Paths, alpha: float = 0.15) -> Tuple[str, str, str]:
    """
    Real-host-derived OG2 obstruction: Ising fusion + even-sector projection yields active-face inconsistency.
    """
    ising = load_json(os.path.join(paths.host_data, "ising_fusion_data.json"))
    N_sigma = ising["fusion_matrices"]["N_sigma"]["matrix_A_kj"]
    N_psi = ising["fusion_matrices"]["N_psi"]["matrix_A_kj"]
    P_even = [[1, 0, 0], [0, 1, 0], [0, 0, 0]]
    P_after_sigma = mm(P_even, N_sigma)

    model = {
        "name": "OG2 from Ising fusion + projection constraint",
        "host_data": "sources/host_data/ising_fusion_data.json",
        "positivity_cone": "R_+^3 in basis (1,psi,sigma)",
        "templates": {
            "N_sigma": {"matrix": N_sigma, "meaning": "Ising fusion matrix for sigma"},
            "N_psi": {"matrix": N_psi, "meaning": "Ising fusion matrix for psi"},
            "P_even": {"matrix": P_even, "meaning": "Projection enforcing even sector {1,psi}"},
            "P_after_sigma": {"matrix": P_after_sigma, "meaning": "P_even ∘ N_sigma"},
            "I": {"matrix": [[1, 0, 0], [0, 1, 0], [0, 0, 1]], "meaning": "Identity (non-tight)", "cost": alpha},
        },
        "constraint_graph": {
            "states": ["s0_even", "s1_bulk"],
            "edges": [
                {"id": "e00", "from": "s0_even", "to": "s0_even", "template": "P_even", "cost": 0.0},
                {"id": "e11", "from": "s1_bulk", "to": "s1_bulk", "template": "P_even", "cost": 0.0},
                {"id": "e01", "from": "s0_even", "to": "s1_bulk", "template": "N_sigma", "cost": 0.0},
                {"id": "e10", "from": "s1_bulk", "to": "s0_even", "template": "P_after_sigma", "cost": 0.0},
                {"id": "eI0", "from": "s0_even", "to": "s0_even", "template": "I", "cost": alpha},
                {"id": "eI1", "from": "s1_bulk", "to": "s1_bulk", "template": "I", "cost": alpha},
            ],
            "notes": "OG2: e10 requires sigma at s1_bulk, but e11 kills sigma at s1_bulk.",
        },
        "og2_witness": {"forced_support": "e10 nonzero only on sigma input", "killing_constraint": "e11 kills sigma", "contradiction": "s1_bulk must both include and exclude sigma."},
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0, 0.0]},
        "tight_core": {
            "tight_edges": ["e00", "e11", "e01", "e10"],
            "tight_gap_gamma": float(alpha),
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": float(alpha / 2.0),
            "tight_graph_hash": "sha256:" + hashlib.sha256("e00|e11|e01|e10".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 1, "periods": [1]},
            "degeneracy_report": {"all_edges_tight": False, "gamma_is_positive": True, "note": "OG2 active-face inconsistency."},
        },
        "doeblin": {"word": ["N_sigma", "N_sigma"], "L": 2, "M_bound": 2.0, "U_bound": 2.0, "delta": 0.0, "eps_doeblin": 0.0, "delta_prime_formula": "Not applicable (OG2).", "U_prime_formula": "Not applicable (OG2)."},
        "recurrence": {"mode": "combinatorial", "eps_recurrence": float(alpha / 2.0), "details": {"rc1_holds": None, "L_syn": None, "gap_bound_B": None, "og4_avoidance_cycle": None, "hypothesis_type": None, "margin": None, "note": "OG2 obstruction."}},
        "rate_pack": {"projective_diameter_bound": 0.0, "tau_unperturbed": 1.0, "tau_prime_formula": "Not applicable.", "eps_rate": 0.0, "kappa_prime_formula": "Not applicable."},
        "eps_star": {"eps_c_star": float(alpha / 2.0), "eps_A_star": 0.0},
    }

    bridge = {
        "string_context": {"name": "Real host-derived: Ising fusion + projection (OG2)", "description": "Ising fusion plus even-sector projection yields OG2 inconsistency.", "finite_sector": "Labels {1,psi,sigma}.", "positivity_cone": "R_+^3"},
        "reduction": {"state_graph": "Two states s0_even,s1_bulk with projection self-loops and sigma-return edge.", "templates": "Ising fusion matrices + P_even projection.", "cost_model": "Identity loops non-tight by alpha>0.", "constraints": "OG2 contradiction between e10 and e11."},
        "ru_certificate_refs": {"robust_certificate_schema": "sources/ru/robust_certificate_schema.json", "robust_certificate_instance": "sources/ru/robust_certificate_og2_ising_projection_inconsistency.json", "global_report_schema": "sources/ru/global_universality_report_schema.json", "global_report_instance": None},
        "universality_claim": {"claim_level": "non_universality_obstruction", "conclusion": "OG2 active-face inconsistency.", "quantitative_rate": "Not applicable."},
        "scope": {"assumptions": ["Projection constraint is imposed."], "limitations": ["A physically consistent boundary would avoid this contradiction."]},
    }

    model_path = os.path.join(paths.ru_bridge, "og2_ising_projection_inconsistency_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_og2_ising_projection_inconsistency.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_og2_ising_projection_inconsistency.json")
    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)
    return model_path, robust_path, bridge_path


def build_toric_og3(paths: Paths, alpha: float = 0.15) -> Tuple[str, str, str]:
    """
    Real-host OG3 obstruction: toric code fusion templates are permutations, so no Doeblin word exists on full cone.
    """
    toric = load_json(os.path.join(paths.host_data, "toric_code_fusion_data.json"))
    N_e = toric["fusion_matrices"]["N_e"]["matrix_A_kj"]
    N_m = toric["fusion_matrices"]["N_m"]["matrix_A_kj"]
    N_eps = toric["fusion_matrices"]["N_eps"]["matrix_A_kj"]

    model = {
        "name": "OG3 from real Toric Code fusion data",
        "host_data": "sources/host_data/toric_code_fusion_data.json",
        "positivity_cone": "R_+^4 in basis (1,e,m,eps)",
        "templates": {
            "N_e": {"matrix": N_e, "meaning": "Toric code fusion matrix for e"},
            "N_m": {"matrix": N_m, "meaning": "Toric code fusion matrix for m"},
            "N_eps": {"matrix": N_eps, "meaning": "Toric code fusion matrix for eps"},
            "I": {"matrix": [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]], "meaning": "Identity (non-tight)", "cost": alpha},
        },
        "constraint_graph": {
            "states": ["t0"],
            "edges": [
                {"id": "eE", "from": "t0", "to": "t0", "template": "N_e", "cost": 0.0},
                {"id": "eM", "from": "t0", "to": "t0", "template": "N_m", "cost": 0.0},
                {"id": "eX", "from": "t0", "to": "t0", "template": "N_eps", "cost": 0.0},
                {"id": "eI", "from": "t0", "to": "t0", "template": "I", "cost": alpha},
            ],
            "notes": "Fusion templates are permutations; products remain permutations; no strictly positive product exists on full cone.",
        },
        "og3_witness": {
            "claim": "No Doeblin word exists on full cone because all templates are permutation matrices and products remain permutation matrices.",
        },
    }
    model_hash = sha256_json(model)

    robust = {
        "model_hash": model_hash,
        "perturbation_metric": {"cost_norm": "linfty", "matrix_metric": "absolute_entrywise", "matrix_norm": "linfty_entrywise"},
        "calibration": {"lambda_star": 0.0, "u_potential": [0.0]},
        "tight_core": {
            "tight_edges": ["eE", "eM", "eX"],
            "tight_gap_gamma": float(alpha),
            "tight_lipschitz_Kc": 1.0,
            "eps_tight": float(alpha / 2.0),
            "tight_graph_hash": "sha256:" + hashlib.sha256("eE|eM|eX".encode("utf-8")).hexdigest(),
            "tight_scc_summary": {"scc_count": 1, "aperiodic_scc_count": 1, "periods": [1]},
            "degeneracy_report": {"all_edges_tight": False, "gamma_is_positive": True, "note": "OG3: permutation-only templates prevent any Doeblin word on full cone."},
        },
        "doeblin": {"word": ["N_e"], "L": 1, "M_bound": 1.0, "U_bound": 1.0, "delta": 0.0, "eps_doeblin": 0.0, "delta_prime_formula": "Not applicable (OG3).", "U_prime_formula": "Not applicable (OG3)."},
        "recurrence": {"mode": "combinatorial", "eps_recurrence": float(alpha / 2.0), "details": {"rc1_holds": None, "L_syn": None, "gap_bound_B": None, "og4_avoidance_cycle": None, "hypothesis_type": None, "margin": None, "note": "OG3 obstruction."}},
        "rate_pack": {"projective_diameter_bound": 0.0, "tau_unperturbed": 1.0, "tau_prime_formula": "Not applicable.", "eps_rate": 0.0, "kappa_prime_formula": "Not applicable."},
        "eps_star": {"eps_c_star": float(alpha / 2.0), "eps_A_star": 0.0},
    }

    bridge = {
        "string_context": {"name": "Real host: Toric code fusion (OG3)", "description": "Permutation-only fusion templates prevent mixing on full cone.", "finite_sector": "Labels {1,e,m,eps}.", "positivity_cone": "R_+^4"},
        "reduction": {"state_graph": "Single state t0 with fusion steps.", "templates": "Fusion matrices from sources/host_data/toric_code_fusion_data.json.", "cost_model": "Fusion edges cost 0; identity non-tight with alpha>0.", "constraints": "All words over {e,m,eps}."},
        "ru_certificate_refs": {"robust_certificate_schema": "sources/ru/robust_certificate_schema.json", "robust_certificate_instance": "sources/ru/robust_certificate_og3_toric_code_fusion.json", "global_report_schema": "sources/ru/global_universality_report_schema.json", "global_report_instance": None},
        "universality_claim": {"claim_level": "non_universality_obstruction", "conclusion": "OG3: toric code fusion is permutation-only, hence no Doeblin word exists on full cone.", "quantitative_rate": "Not applicable."},
        "scope": {"assumptions": ["Full cone statement."], "limitations": ["Adding non-permutation noise operators would change conclusions."]},
    }

    model_path = os.path.join(paths.ru_bridge, "og3_toric_code_fusion_no_doeblin_model.json")
    robust_path = os.path.join(paths.ru, "robust_certificate_og3_toric_code_fusion.json")
    bridge_path = os.path.join(paths.ru_bridge, "bridge_certificate_og3_toric_code_fusion.json")
    dump_json(model_path, model)
    dump_json(robust_path, robust)
    dump_json(bridge_path, bridge)
    return model_path, robust_path, bridge_path
def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--root", default=".", help="Project root containing sources/")
    ap.add_argument("--example", default="fibonacci_contraction", choices=["fibonacci_contraction","fibonacci_og4_idle","fibonacci_og1_period2","ising_og3","ising_og2_projection","toric_og3"], help="Which audited example to emit")
    ap.add_argument("--alpha", type=float, default=0.2, help="Cost penalty for non-tight identity loops (where used)")
    ap.add_argument("--validate", action="store_true", help="Validate generated robust certificate against schema")
    args = ap.parse_args()

    paths = Paths(args.root)

    if args.example == "fibonacci_contraction":
        model_path, robust_path, bridge_path = build_fibonacci_contraction(paths, alpha=args.alpha)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))

        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)


    if args.example == "fibonacci_og4_idle":
        model_path, robust_path, bridge_path = build_fibonacci_og4_idle(paths)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))
        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)
        return 0

    if args.example == "fibonacci_og1_period2":
        model_path, robust_path, bridge_path = build_fibonacci_og1_period2(paths)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))
        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)
        return 0

    if args.example == "ising_og3":
        model_path, robust_path, bridge_path = build_ising_og3(paths, alpha=args.alpha)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))
        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)
        return 0

    if args.example == "ising_og2_projection":
        model_path, robust_path, bridge_path = build_ising_og2_projection(paths, alpha=args.alpha)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))
        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)
        return 0


    if args.example == "toric_og3":
        model_path, robust_path, bridge_path = build_toric_og3(paths, alpha=args.alpha)
        print("Wrote:")
        print("  model :", os.path.relpath(model_path, paths.root))
        print("  robust:", os.path.relpath(robust_path, paths.root))
        print("  bridge:", os.path.relpath(bridge_path, paths.root))
        if args.validate:
            schema_path = os.path.join(paths.ru, "robust_certificate_schema.json")
            ok, msg = validate_against_schema(robust_path, schema_path)
            print("Validation:", "PASS" if ok else "FAIL", "-", msg)
        return 0

    return 0


if __name__ == "__main__":
    raise SystemExit(main())
