#!/usr/bin/env python3
"""
Build a chamberwise global universality report for a 1-parameter family (alpha) using the shipped schema.

This script demonstrates the *global* part of the RU engine in a reproducible way:
- alpha = 0: OG4 (avoidable Doeblin) boundary chamber
- alpha > 0: contraction chamber (example uses alpha=0.2)

Outputs:
- sources/ru/global_universality_report_fibonacci_alpha_chambers.json

Usage (from project root):
  python tools/build_fibonacci_alpha_chambers_report.py

Note:
This is intentionally conservative: it is a chamberwise report, not a claim of a single uniform contraction rate across the entire interval.
"""

from __future__ import annotations
import os, json, argparse, sys

def load(p):
    with open(p,"r",encoding="utf-8") as f:
        return json.load(f)

def dump(p, obj):
    os.makedirs(os.path.dirname(p), exist_ok=True)
    with open(p,"w",encoding="utf-8") as f:
        json.dump(obj, f, indent=2)

def main()->int:
    ap=argparse.ArgumentParser()
    ap.add_argument("--root", default=".", help="Project root")
    ap.add_argument("--alpha_mix", type=float, default=0.2, help="Representative alpha>0 point")
    ap.add_argument("--alpha_max", type=float, default=0.5, help="Upper end of region for the chamber report")
    args=ap.parse_args()
    root=os.path.abspath(args.root)

    # Certificates already shipped/generated in the bundle:
    # - alpha=0 chamber: Fibonacci OG4 idle-loop obstruction
    # - alpha>0 chamber: Fibonacci contraction certificate (uses alpha_mix)
    og4_path = os.path.join(root,"sources","ru","robust_certificate_fibonacci_realhost_og4_idle_avoidable.json")
    mix_path = os.path.join(root,"sources","ru","robust_certificate_fibonacci_realhost_contraction.json")
    if not os.path.exists(og4_path) or not os.path.exists(mix_path):
        print("Missing required certificates. Run:")
        print("  python tools/ru_bridge_extractor.py --example fibonacci_contraction --validate")
        print("  python tools/ru_bridge_extractor.py --example fibonacci_og4_idle --validate")
        return 2

    og4 = load(og4_path)
    mix = load(mix_path)

    report = {
      "schema_version": "1.0",
      "theta_region": {
        "description": "One-parameter family indexed by alpha (penalty on idle/identity edges). Region: alpha in [0, alpha_max].",
        "parameterization": {"type":"box","coordinates":[{"name":"alpha","min":0.0,"max":float(args.alpha_max)}]},
        "compact": True,
        "connected": True
      },
      "perturbation_model": {
        "type": "cost_absolute",
        "metric": "linfty on costs + absolute entrywise on templates",
        "notes": "Chambers are separated by whether the idle edge is tight (alpha=0) or non-tight (alpha>0)."
      },
      "coverage": {
        "net_points": [
          {"theta":{"alpha":0.0},"certificate_id":"C_OG4"},
          {"theta":{"alpha":float(args.alpha_mix)},"certificate_id":"C_MIX"}
        ],
        "certified_balls": [
          {"center_certificate_id":"C_MIX",
           "epsilon_star":{"eps_c_star":mix["eps_star"]["eps_c_star"],"eps_A_star":mix["eps_star"]["eps_A_star"],"eps_min":min(mix["eps_star"]["eps_c_star"], mix["eps_star"]["eps_A_star"])},
           "notes":"Covers an open chamber around alpha_mix where the tight core excludes the idle edge and contraction is certified."}
        ],
        "uncovered": {
          "is_empty": False,
          "description": "Boundary at alpha=0 is an OG4 chamber (avoidable Doeblin). Chamberwise classification is provided rather than a uniform contraction claim.",
          "near_degeneracy": [{"theta":{"alpha":0.0},"reason":"idle edge becomes tight and creates an OG4 avoidance witness"}]
        }
      },
      "global_bounds": {
        "gamma0": 0.0,
        "delta0": mix["doeblin"]["delta"],
        "epsilon_global": 0.0,
        "notes": "No single uniform contraction universality across [0,alpha_max] because alpha=0 is an OG4 obstruction chamber."
      },
      "witnesses": {
        "mode":"chamberwise",
        "uniform":{"tight_scc_id":"SCC_FIB","doeblin_word":"N_tau,N_tau","notes":"Doeblin witness exists in both chambers, but recurrence differs."},
        "chambers":[
          {"id":"CH_CONTRACTION","description":"alpha>0: idle edge non-tight; tight core excludes idle; RC1 holds; contraction certified.",
           "tight_scc_id":"SCC_FIB","doeblin_word":"N_tau,N_tau","recurrence_modulus":2,"notes":"See robust_certificate_fibonacci_realhost_contraction.json"},
          {"id":"CH_OG4","description":"alpha=0: idle edge tight; Doeblin exists but avoidable via idle loop; OG4 obstruction.",
           "tight_scc_id":"SCC_FIB","doeblin_word":"N_tau,N_tau","notes":"See robust_certificate_fibonacci_realhost_og4_idle_avoidable.json"}
        ]
      },
      "conclusion": {
        "global_contraction_universality": False,
        "statement": "Across alpha in [0,alpha_max], a Doeblin witness exists throughout, but forced contraction universality holds only for alpha>0; at alpha=0 there is an explicit OG4 avoidance witness."
      },
      "verification_method": {
        "type":"hybrid_chamberwise",
        "notes":"Chamberwise classification with explicit obstruction on the alpha=0 boundary.",
        "chambers":[
          {"id":"CH_CONTRACTION","description":"alpha>0 chamber","status":"covered","details":"Contraction certified by C_MIX"},
          {"id":"CH_OG4","description":"alpha=0 chamber","status":"obstruction_found","details":"OG4 witness via idle cycle in C_OG4"}
        ]
      },
      "certificate_index": {
        "C_MIX": {"path":"sources/ru/robust_certificate_fibonacci_realhost_contraction.json"},
        "C_OG4": {"path":"sources/ru/robust_certificate_fibonacci_realhost_og4_idle_avoidable.json"}
      }
    }

    out_path = os.path.join(root,"sources","ru","global_universality_report_fibonacci_alpha_chambers.json")
    dump(out_path, report)
    print("Wrote:", os.path.relpath(out_path, root))
    return 0

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