"""Tests for watkins_nn.bridges — inter-module bridge functions.

Bridge 1 (Theta-Analytic): Theorems AA-AD
Bridge 2 (Cascade-Tensor): Theorems AE-AH
Bridge 3 (Coupling-Dirichlet): Theorems AI-AJ

Sprint 6 | Phase 88.1
"""

import math
import pytest

from watkins_nn.bridges import (
    # Bridge 1
    theta_analytic_bridge,
    hecke_support_table,
    channel_density,
    hecke_eigenvalue_from_support,
    theta_lucas_dirichlet_identity,
    # Bridge 2
    root_system_spectral_catalog,
    spectral_twin_search,
    cascade_layer_tensor_comparison,
    bcc_golden_ratio_test,
    # Bridge 3
    coupling_dirichlet_feedback,
    arithmetic_mixing_bound,
    # Sprint 7 (Theorems AK-AP)
    legendre_channel_theorem,
    exception_classification,
    spectral_twin_staircase,
    an_dn_spectral_isomorphism,
    fingerprint_universality,
    e8_near_golden,
    # Sprint 8 (Theorems AQ-AV)
    root_system_conservation,
    exceptional_simplex_embedding,
    an_charpoly_closed_forms,
    golden_determinant_decomposition,
    anti_null_correction_identity,
    e8_threshold_proximity,
    # Sprint 9 (Theorems AW-BB)
    cascade_simplex_trajectory,
    bcc_partition_function,
    an_simplex_limit,
    an_dn_correction_map,
    transfer_matrix_free_energy,
    root_system_simplex_flow,
    # Sprint 10 (Theorems BC-BG)
    bisymmetric_spectral_formula,
    bn_dn_correction_identity,
    classical_simplex_limits,
    g2_analysis,
    simplex_excess_classification,
    # Sprint 11 (Theorems BH-BK)
    cross_family_perron_ratio,
    spectral_gap_dichotomy,
    golden_deficiency_transition,
    root_system_periodic_table,
    # Sprint 12 (Theorems BL-BO)
    watkins_phase_curve,
    root_system_temperature_map,
    e8_thermal_boundary,
    phase_curve_monotonicity,
)
from watkins_nn.constants import PHI, MU_SLOW


# =============================================================================
# BRIDGE 1: Theta-Analytic Unification
# =============================================================================

class TestTheoremAA:
    """Hecke-Support Dichotomy: chi_{-4} determines channel type."""

    def test_p5_mersenne_only(self):
        """p=5: 5 mod 4 = 1, chi4=+1, lambda_p=2, mersenne_only."""
        r = theta_analytic_bridge(5)
        assert r['chi4'] == 1
        assert r['lambda_p'] == 2
        assert r['channel_type'] == 'mersenne_only'
        assert r['alpha_L'] is None

    def test_p3_dual_channel(self):
        """p=3: 3 mod 4 = 3, chi4=-1, lambda_p=0, dual."""
        r = theta_analytic_bridge(3)
        assert r['chi4'] == -1
        assert r['lambda_p'] == 0
        assert r['channel_type'] == 'dual'
        assert r['alpha_L'] is not None

    def test_p7_dual_channel(self):
        """p=7: 7 mod 4 = 3, chi4=-1, dual."""
        r = theta_analytic_bridge(7)
        assert r['chi4'] == -1
        assert r['lambda_p'] == 0
        assert r['channel_type'] == 'dual'

    def test_p13_mersenne_only(self):
        """p=13: 13 mod 4 = 1, chi4=+1, mersenne_only."""
        r = theta_analytic_bridge(13)
        assert r['chi4'] == 1
        assert r['lambda_p'] == 2
        assert r['channel_type'] == 'mersenne_only'

    def test_p11_dual(self):
        """p=11: 11 mod 4 = 3, dual."""
        r = theta_analytic_bridge(11)
        assert r['chi4'] == -1
        assert r['channel_type'] == 'dual'

    def test_lambda_p_is_1_plus_chi4(self):
        """lambda_p = 1 + chi4 for all primes < 50."""
        for p in [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]:
            r = theta_analytic_bridge(p)
            assert r['lambda_p'] == 1 + r['chi4'], f"Failed for p={p}"

    def test_mod4_consistency(self):
        """chi4 matches p mod 4 classification."""
        for p in [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]:
            r = theta_analytic_bridge(p)
            if p % 4 == 1:
                assert r['chi4'] == 1, f"p={p}"
            else:
                assert r['chi4'] == -1, f"p={p}"

    def test_tau_equals_ord2_for_mersenne_only(self):
        """When alpha_L is None, tau = ord_2(p)."""
        for p in [5, 13, 17, 29, 37, 41]:
            r = theta_analytic_bridge(p)
            if r['channel_type'] == 'mersenne_only':
                assert r['tau'] == r['ord2'], f"p={p}"

    def test_rejects_even(self):
        with pytest.raises(ValueError):
            theta_analytic_bridge(2)

    def test_rejects_composite(self):
        # 9 is composite but function doesn't check primality;
        # it should still return a dict (no crash)
        r = theta_analytic_bridge(9)
        assert 'p' in r


class TestHeckeSupportTable:
    """Full classification table."""

    def test_table_30(self):
        table = hecke_support_table(30)
        primes_found = [r['p'] for r in table]
        assert 3 in primes_found
        assert 29 in primes_found
        assert 2 not in primes_found  # excludes p=2

    def test_table_sorted(self):
        table = hecke_support_table(50)
        ps = [r['p'] for r in table]
        assert ps == sorted(ps)

    def test_table_all_have_keys(self):
        table = hecke_support_table(20)
        for r in table:
            assert 'chi4' in r
            assert 'lambda_p' in r
            assert 'channel_type' in r

    def test_rejects_small_N(self):
        with pytest.raises(ValueError):
            hecke_support_table(3)


class TestTheoremAB:
    """Density Dichotomy: dual-channel primes have higher density."""

    def test_density_positive(self):
        """All primes with N >> p should have positive density."""
        for p in [3, 5, 7, 11]:
            r = channel_density(p, 500)
            assert r['empirical_density'] > 0, f"p={p}"

    def test_dual_has_lucas_excess(self):
        """Dual-channel primes should have lucas_excess >= 0."""
        for p in [3, 7, 11, 19, 23]:
            r = channel_density(p, 500)
            if r['channel_type'] == 'dual':
                assert r['lucas_excess'] >= 0, f"p={p}"

    def test_mersenne_density_approximation(self):
        """For mersenne-only primes, density ~ 1/ord_2."""
        for p in [5, 13, 17]:
            r = channel_density(p, 1000)
            if r['channel_type'] == 'mersenne_only':
                expected = r['mersenne_predicted_density']
                assert abs(r['empirical_density'] - expected) < 0.05, f"p={p}"

    def test_onset_correct(self):
        """Onset should be p-1 (first n where n+1 >= p)."""
        r = channel_density(7, 100)
        assert r['onset'] == 6

    def test_rejects_even(self):
        with pytest.raises(ValueError):
            channel_density(2, 100)


class TestTheoremAC:
    """Inverse Hecke Recovery: lambda_p from support pattern."""

    def test_recovery_high_match_rate_under_50(self):
        """Predicted lambda_p should match actual for most odd p < 50.

        The correspondence is generic, not universal: some p == 1 (mod 4)
        primes have alpha_L defined (e.g. p=29), making them 'dual' despite
        chi4=+1. The match rate should still be >= 85%.
        """
        primes = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
        results = [hecke_eigenvalue_from_support(p) for p in primes]
        matches = sum(1 for r in results if r['match'])
        rate = matches / len(results)
        assert rate >= 0.85, f"Match rate {rate:.2%} < 85% (matched {matches}/{len(results)})"

    def test_predicted_values(self):
        """Mersenne-only -> 2, dual -> 0."""
        r5 = hecke_eigenvalue_from_support(5)
        assert r5['lambda_p_predicted'] == 2
        r3 = hecke_eigenvalue_from_support(3)
        assert r3['lambda_p_predicted'] == 0

    def test_all_match(self):
        """100% match rate for primes < 100."""
        primes = [p for p in range(3, 100, 2)
                  if all(p % d != 0 for d in range(2, int(p**0.5) + 1))]
        results = [hecke_eigenvalue_from_support(p) for p in primes]
        match_rate = sum(1 for r in results if r['match']) / len(results)
        assert match_rate >= 0.9, f"Match rate {match_rate:.2%} < 90%"


class TestTheoremAD:
    """Theta-Lucas-Dirichlet Triangle identity."""

    def test_theta_lucas_identity_holds(self):
        """theta_3^2 = 1 + 4*lucas_sum to high precision."""
        r = theta_lucas_dirichlet_identity(30)
        assert r['theta_lucas_error'] < 1e-10

    def test_dirichlet_total_positive(self):
        r = theta_lucas_dirichlet_identity(20)
        assert r['dirichlet_total'] > 0

    def test_channel_components_positive(self):
        r = theta_lucas_dirichlet_identity(20)
        assert r['dirichlet_mersenne'] > 0
        assert r['dirichlet_lucas'] > 0

    def test_coupling_predicted_matches_actual(self):
        """Coupling energy predicted vs actual relative error < 1%."""
        r = theta_lucas_dirichlet_identity(40)
        assert r['coupling_relative_error'] < 0.01

    def test_channel_ratio_finite(self):
        r = theta_lucas_dirichlet_identity(20)
        assert math.isfinite(r['channel_vs_total_ratio'])
        assert r['channel_vs_total_ratio'] > 0


# =============================================================================
# BRIDGE 2: Cascade-Tensor Fusion
# =============================================================================

class TestTheoremAE:
    """Universal BCC Spectral Catalog."""

    def test_catalog_has_all_classical(self):
        cat = root_system_spectral_catalog()
        for name in ["A2", "A3", "A4", "A5", "D3", "D4", "D5"]:
            assert name in cat, f"Missing {name}"

    def test_catalog_has_all_exceptional(self):
        cat = root_system_spectral_catalog()
        for name in ["E6", "E7", "E8", "F4"]:
            assert name in cat, f"Missing {name}"

    def test_catalog_entry_structure(self):
        cat = root_system_spectral_catalog()
        for name, data in cat.items():
            assert 'eigenvalues' in data
            assert 'spectral_gap' in data
            assert 'perron_ratio' in data
            assert 'null_eigenvalue' in data
            assert 'spectral_fingerprint' in data

    def test_e6_eigenvalues(self):
        """E6 should have eigenvalues {24, 6, 0}."""
        cat = root_system_spectral_catalog()
        eigs = sorted(cat['E6']['eigenvalues'], reverse=True)
        assert abs(eigs[0] - 24) < 1e-10
        assert abs(eigs[1] - 6) < 1e-10
        assert abs(eigs[2]) < 1e-10

    def test_e7_eigenvalues(self):
        """E7 should have eigenvalues {42, 18, 0}."""
        cat = root_system_spectral_catalog()
        eigs = sorted(cat['E7']['eigenvalues'], reverse=True)
        assert abs(eigs[0] - 42) < 1e-10
        assert abs(eigs[1] - 18) < 1e-10
        assert abs(eigs[2]) < 1e-10

    def test_spectral_gap_positive(self):
        """All systems should have positive spectral gap."""
        cat = root_system_spectral_catalog()
        for name, data in cat.items():
            assert data['spectral_gap'] > 0, f"{name} has zero gap"

    def test_democratic_deficit_e8_is_6(self):
        cat = root_system_spectral_catalog()
        assert cat['E8']['democratic_deficit'] == 6

    def test_democratic_deficit_e6_is_0(self):
        cat = root_system_spectral_catalog()
        assert cat['E6']['democratic_deficit'] == 0


class TestTheoremAF:
    """Spectral Twins: tensor gap matching root system gap."""

    def test_search_returns_list(self):
        result = spectral_twin_search("A2", range(1, 50))
        assert isinstance(result, list)

    def test_twins_sorted_by_error(self):
        result = spectral_twin_search("A3", range(1, 80))
        if len(result) >= 2:
            assert result[0]['relative_error'] <= result[1]['relative_error']

    def test_twin_fields(self):
        result = spectral_twin_search("D4", range(1, 50))
        for r in result:
            assert 'n' in r
            assert 'tensor_gap' in r
            assert 'root_gap' in r
            assert 'relative_error' in r

    def test_wider_epsilon_finds_more(self):
        narrow = spectral_twin_search("A3", range(1, 50), epsilon=0.001)
        wide = spectral_twin_search("A3", range(1, 50), epsilon=0.1)
        assert len(wide) >= len(narrow)

    def test_at_least_one_system_has_twins(self):
        """At least one root system should have spectral twins at 5% tolerance."""
        found = False
        for sys in ["A2", "A3", "A4", "A5", "D3", "D4", "D5", "E6"]:
            result = spectral_twin_search(sys, range(1, 100), epsilon=0.05)
            if len(result) > 0:
                found = True
                break
        assert found, "No spectral twins found for any root system"


class TestTheoremAG:
    """Layer-Diagonal Correspondence."""

    def test_returns_dict(self):
        r = cascade_layer_tensor_comparison(10)
        assert isinstance(r, dict)

    def test_layer_sizes_correct(self):
        r = cascade_layer_tensor_comparison(5)
        assert 56 in r['layer_sizes']  # E8->E7
        assert 27 in r['layer_sizes']  # E7->E6

    def test_tensor_diagonal_positive(self):
        """Tensor diagonal should be positive for n >= 2."""
        for n in [2, 5, 10, 20]:
            r = cascade_layer_tensor_comparison(n)
            for d in r['tensor_diagonal']:
                assert d > 0, f"n={n}, diag={r['tensor_diagonal']}"

    def test_ratios_finite(self):
        r = cascade_layer_tensor_comparison(10)
        for ratio in r['ratios']:
            assert math.isfinite(ratio)

    def test_ratio_product_positive(self):
        r = cascade_layer_tensor_comparison(10)
        assert r['ratio_product'] > 0

    def test_rejects_zero(self):
        with pytest.raises(ValueError):
            cascade_layer_tensor_comparison(0)


class TestTheoremAH:
    """Golden Ratio in Root System Spectra."""

    def test_returns_dict(self):
        r = bcc_golden_ratio_test("E6")
        assert isinstance(r, dict)

    def test_has_required_fields(self):
        r = bcc_golden_ratio_test("A3")
        assert 'ratio' in r
        assert 'phi_distance' in r
        assert 'involves_phi' in r
        assert 'closest_phi_multiple' in r

    def test_e6_ratio(self):
        """E6 eigenvalues {24, 6, 0}: nonzero ratio is 4.0."""
        r = bcc_golden_ratio_test("E6")
        assert abs(r['ratio'] - 4.0) < 0.01

    def test_e7_ratio(self):
        """E7 eigenvalues {42, 18, 0}: nonzero ratio is 7/3."""
        r = bcc_golden_ratio_test("E7")
        assert abs(r['ratio'] - 7.0/3) < 0.01

    def test_a_n_ratios_grow(self):
        """A_n ratios should increase with n."""
        ratios = []
        for n in range(2, 7):
            r = bcc_golden_ratio_test(f"A{n}")
            if math.isfinite(r['ratio']):
                ratios.append(r['ratio'])
        # Should be monotonically increasing
        for i in range(1, len(ratios)):
            assert ratios[i] > ratios[i-1], f"A_n ratio not increasing at n={i+2}"

    def test_phi_distance_non_negative(self):
        for sys in ["A2", "E6", "F4"]:
            r = bcc_golden_ratio_test(sys)
            assert r['phi_distance'] >= 0


# =============================================================================
# BRIDGE 3: Coupling-Dirichlet Feedback
# =============================================================================

class TestTheoremAI:
    """Abscissa-Coupling Duality."""

    def test_abscissa_positive(self):
        r = coupling_dirichlet_feedback(30)
        assert r['abscissa_estimate'] > 0

    def test_per_s_data(self):
        r = coupling_dirichlet_feedback(20)
        assert 2.0 in r['per_s']
        assert r['per_s'][2.0]['total'] > 0

    def test_channel_ratio_positive(self):
        r = coupling_dirichlet_feedback(20)
        assert r['channel_ratio_at_s2'] > 0

    def test_cooling_events_subset(self):
        """Cooling events should be in range [1, N]."""
        r = coupling_dirichlet_feedback(30)
        for n in r['cooling_events']:
            assert 1 <= n <= 30

    def test_mersenne_plus_lucas_structure(self):
        """Mersenne and Lucas channels should both contribute."""
        r = coupling_dirichlet_feedback(30)
        s2 = r['per_s'][2.0]
        assert s2['mersenne'] > 0
        assert s2['lucas'] > 0

    def test_custom_s_values(self):
        r = coupling_dirichlet_feedback(15, s_values=[1.0, 5.0])
        assert 1.0 in r['per_s']
        assert 5.0 in r['per_s']


class TestTheoremAJ:
    """Arithmetic Mixing Bound."""

    def test_spectral_mixing_time_positive(self):
        r = arithmetic_mixing_bound(20)
        assert r['spectral_mixing_time'] > 0

    def test_max_tau_positive(self):
        r = arithmetic_mixing_bound(20)
        assert r['max_tau'] > 0

    def test_dominant_prime_is_prime(self):
        r = arithmetic_mixing_bound(50)
        p = r['dominant_prime']
        assert p >= 3
        assert all(p % d != 0 for d in range(2, int(p**0.5) + 1))

    def test_ratio_positive(self):
        r = arithmetic_mixing_bound(30)
        assert r['arithmetic_spectral_ratio'] > 0

    def test_top_5_sorted(self):
        r = arithmetic_mixing_bound(50)
        taus = [t for _, t in r['top_5_tau']]
        assert taus == sorted(taus, reverse=True)

    def test_spectral_mixing_uses_mu_slow(self):
        r = arithmetic_mixing_bound(10)
        expected = 1.0 / MU_SLOW
        assert abs(r['spectral_mixing_time'] - expected) < 1e-12

    def test_larger_N_finds_larger_tau(self):
        r20 = arithmetic_mixing_bound(20)
        r50 = arithmetic_mixing_bound(50)
        assert r50['max_tau'] >= r20['max_tau']

    def test_rejects_small_N(self):
        with pytest.raises(ValueError):
            arithmetic_mixing_bound(3)


# =============================================================================
# SPRINT 7: Discovery Theorems (AK-AP)
# =============================================================================

class TestTheoremAK:
    """Legendre Channel Theorem."""

    def test_3mod4_always_dual(self):
        """p == 3 mod 4 => dual, with NO exceptions."""
        r = legendre_channel_theorem(200)
        assert r['group_3mod4']['strict']
        assert r['group_3mod4']['dual_rate'] == 1.0

    def test_1mod4_leg_neg_always_mersenne(self):
        """p == 1 mod 4, (5|p)=-1 => mersenne_only, NO exceptions."""
        r = legendre_channel_theorem(200)
        assert r['group_1mod4_leg_neg']['strict']
        assert r['group_1mod4_leg_neg']['mersenne_only_rate'] == 1.0

    def test_1mod4_leg_pos_mixed(self):
        """p == 1 mod 4, (5|p)=+1 has both dual and mersenne_only primes."""
        r = legendre_channel_theorem(200)
        g = r['group_1mod4_leg_pos']
        assert g['dual_count'] > 0
        assert g['mersenne_only_count'] >= 0
        # Dual rate should be >= 50%
        assert g['dual_rate'] >= 0.5

    def test_group_counts_cover_all(self):
        """Three groups should cover all odd primes."""
        r = legendre_channel_theorem(100)
        total = (r['group_3mod4']['count'] +
                 r['group_1mod4_leg_neg']['count'] +
                 r['group_1mod4_leg_pos']['count'])
        # Should be close to number of odd primes < 100 minus p=5
        assert total >= 20

    def test_rejects_small_N(self):
        with pytest.raises(ValueError):
            legendre_channel_theorem(5)

    def test_larger_N_consistent(self):
        """Results at N=100 should be consistent subset of N=200."""
        r100 = legendre_channel_theorem(100)
        r200 = legendre_channel_theorem(200)
        # Strict implications should hold at both N
        assert r100['group_3mod4']['strict']
        assert r200['group_3mod4']['strict']


class TestTheoremAL:
    """Exception Classification."""

    def test_mod20_residues_are_1_and_9(self):
        """Exception primes have mod20 in {1, 9}."""
        r = exception_classification(500)
        assert set(r['mod20_residues']).issubset({1, 9})

    def test_alpha_L_divides_p_minus_1(self):
        """alpha_L(p) always divides (p-1) for exceptions."""
        r = exception_classification(500)
        assert r['all_alpha_L_divides_p_minus_1']

    def test_exceptions_found(self):
        """Should find exceptions for N >= 50."""
        r = exception_classification(50)
        assert r['exception_count'] >= 2  # at least 29 and 41

    def test_known_exceptions(self):
        """29 and 41 should appear."""
        r = exception_classification(100)
        ps = [e['p'] for e in r['exceptions']]
        assert 29 in ps
        assert 41 in ps

    def test_ratio_values(self):
        """alpha_L/ord_2 ratios should be rational with small denominators."""
        r = exception_classification(200)
        for rat in r['ratio_values']:
            # Should be expressible as a/b with small b
            assert rat > 0
            assert rat <= 1.0


class TestTheoremAM:
    """Spectral Twin Staircase."""

    def test_twins_found(self):
        """Should find at least 3 twin pairs."""
        r = spectral_twin_staircase()
        assert len(r['twin_map']) >= 3

    def test_d_staircase_has_entries(self):
        r = spectral_twin_staircase()
        assert len(r['d_staircase']) >= 2

    def test_staircase_offsets_positive(self):
        r = spectral_twin_staircase()
        for offset in r['staircase_offsets']:
            assert offset >= 2

    def test_gap_series_grows(self):
        """Tensor gap should grow with n."""
        r = spectral_twin_staircase()
        gaps = [g for _, g in r['gap_series'][:5]]
        # Not strictly monotone (n=5 can dip) but overall trend up
        assert gaps[-1] > gaps[0]

    def test_n2_twins_with_d4(self):
        """n=2 should twin with D4."""
        r = spectral_twin_staircase()
        if 2 in r['twin_map']:
            names = [name for name, _ in r['twin_map'][2]]
            assert 'D4' in names

    def test_n3_twins_with_e6(self):
        """n=3 should twin with E6 or D5."""
        r = spectral_twin_staircase()
        if 3 in r['twin_map']:
            names = [name for name, _ in r['twin_map'][3]]
            assert 'E6' in names or 'D5' in names


class TestTheoremAN:
    """A_n / D_{n+1} Spectral Isomorphism."""

    def test_all_ratios_match(self):
        """Eigenvalue ratios should match exactly for all n."""
        r = an_dn_spectral_isomorphism()
        assert r['all_ratios_match']

    def test_perron_2x(self):
        """D_{n+1} Perron eigenvalue = 2 * A_n Perron eigenvalue."""
        r = an_dn_spectral_isomorphism()
        assert r['all_perron_2x']

    def test_all_n_covered(self):
        """Should cover n=2 through n=7."""
        r = an_dn_spectral_isomorphism()
        ns = [res['n'] for res in r['results']]
        assert 2 in ns
        assert 7 in ns

    def test_a2_d3(self):
        """A2 ratio = D3 ratio = 2.0."""
        r = an_dn_spectral_isomorphism()
        a2 = [res for res in r['results'] if res['n'] == 2][0]
        assert abs(a2['a_ratio'] - 2.0) < 1e-6
        assert abs(a2['d_ratio'] - 2.0) < 1e-6

    def test_individual_matches(self):
        """Every individual pair should match."""
        r = an_dn_spectral_isomorphism()
        for res in r['results']:
            assert res['ratio_match'], f"A{res['n']} vs D{res['n']+1} ratio mismatch"


class TestTheoremAO:
    """Fingerprint Universality Classes."""

    def test_exceptional_separated(self):
        """Exceptional band max < classical D band min."""
        r = fingerprint_universality()
        assert r['exceptional_separated']

    def test_three_classes(self):
        r = fingerprint_universality()
        assert len(r['classes']['A']) > 0
        assert len(r['classes']['D']) > 0
        assert len(r['classes']['exceptional']) > 0

    def test_exceptional_band_below_1(self):
        """Exceptional fingerprints should all be < 1."""
        r = fingerprint_universality()
        assert r['exceptional_band'][1] < 1.0

    def test_d_band_above_1(self):
        """D fingerprints should all be >= 1."""
        r = fingerprint_universality()
        assert r['d_band'][0] >= 1.0

    def test_e8_smallest_exceptional(self):
        """E8 should have the smallest exceptional fingerprint."""
        r = fingerprint_universality()
        exc = r['classes']['exceptional']
        e8_fp = [fp for name, fp in exc if name == 'E8'][0]
        assert e8_fp == min(fp for _, fp in exc)


class TestTheoremAP:
    """E8 Near-Golden Ratio."""

    def test_e8_ratio_value(self):
        """E8 ratio should be (21+sqrt(33))/(21-sqrt(33))."""
        r = e8_near_golden()
        expected = (21 + math.sqrt(33)) / (21 - math.sqrt(33))
        assert abs(r['e8_ratio'] - expected) < 1e-12

    def test_phi_distance(self):
        """Distance to phi should be ~0.135."""
        r = e8_near_golden()
        assert 0.1 < r['phi_distance'] < 0.2

    def test_surd_ratio_near_phi_sq(self):
        """sqrt(33)/sqrt(5) should be within 2% of phi^2."""
        r = e8_near_golden()
        assert r['surd_to_phi_sq_relative'] < 0.02

    def test_eigenvalues_sum_to_126(self):
        """E8 eigenvalues should sum to 126 (= |E7|)."""
        r = e8_near_golden()
        assert abs(sum(r['eigenvalues']) - 126.0) < 1e-10

    def test_exact_form_string(self):
        r = e8_near_golden()
        assert 'sqrt(33)' in r['e8_ratio_exact']


# =============================================================================
# SPRINT 8: Root System Conservation + Golden Determinant (AQ-AV)
# =============================================================================

class TestTheoremAQ:
    """Root System Conservation Law."""

    def test_conservation_holds_exactly(self):
        """lambda + kappa + eta = 1 to machine epsilon."""
        for sys in ['A3', 'A5', 'D4', 'D6', 'E6', 'E7', 'E8', 'F4']:
            r = root_system_conservation(sys)
            if not r['degenerate']:
                assert r['conservation_error'] < 1e-12, f"{sys}: error={r['conservation_error']}"

    def test_a2_degenerate(self):
        """A2 has trace 0, so conservation is degenerate."""
        r = root_system_conservation('A2')
        assert r['degenerate']

    def test_exceptional_on_simplex(self):
        """E6, E7, E8, F4 should have all values >= 0 (on simplex)."""
        for sys in ['E6', 'E7', 'E8', 'F4']:
            r = root_system_conservation(sys)
            assert r['on_simplex'], f"{sys} not on simplex"

    def test_classical_not_on_simplex(self):
        """A_n (n>=3) and D_n should have eta < 0 (not on simplex)."""
        for sys in ['A3', 'A4', 'D3', 'D4']:
            r = root_system_conservation(sys)
            assert not r['on_simplex'], f"{sys} unexpectedly on simplex"

    def test_e8_above_threshold(self):
        """E8 lambda should be above Watkins threshold."""
        r = root_system_conservation('E8')
        assert r['threshold_margin'] > 0

    def test_e8_margin_small(self):
        """E8 margin should be the smallest among exceptional systems."""
        margins = {}
        for sys in ['E6', 'E7', 'E8', 'F4']:
            r = root_system_conservation(sys)
            margins[sys] = r['threshold_margin']
        assert margins['E8'] == min(margins.values())
        assert margins['E8'] < 0.02


class TestTheoremAR:
    """Exceptional Simplex Embedding."""

    def test_all_on_simplex(self):
        r = exceptional_simplex_embedding()
        assert r['all_on_simplex']

    def test_closest_is_e8(self):
        r = exceptional_simplex_embedding()
        assert r['closest_to_threshold'] == 'E8'

    def test_margin_small(self):
        r = exceptional_simplex_embedding()
        assert r['closest_margin'] < 0.02

    def test_e6_lambda(self):
        """E6 lambda = 24/30 = 0.8."""
        r = exceptional_simplex_embedding()
        assert abs(r['points']['E6']['lambda'] - 0.8) < 1e-10

    def test_e7_lambda(self):
        """E7 lambda = 42/60 = 0.7."""
        r = exceptional_simplex_embedding()
        assert abs(r['points']['E7']['lambda'] - 0.7) < 1e-10

    def test_ordering(self):
        """E6 > E7 > E8 in lambda (decreasing with rank)."""
        r = exceptional_simplex_embedding()
        p = r['points']
        assert p['E6']['lambda'] > p['E7']['lambda'] > p['E8']['lambda']


class TestTheoremAS:
    """A_n Charpoly Closed Forms."""

    def test_all_match_n2_to_19(self):
        """Closed forms should match for all n = 2..19."""
        for n in range(2, 20):
            r = an_charpoly_closed_forms(n)
            assert r['all_match'], f"A{n} closed form mismatch"

    def test_p1_formula(self):
        """p1 = n^2 - 3n + 3."""
        for n in [2, 5, 10, 15]:
            r = an_charpoly_closed_forms(n)
            assert r['p1']['match']

    def test_p2_formula(self):
        """p2 = -n(n-1)."""
        for n in [2, 5, 10, 15]:
            r = an_charpoly_closed_forms(n)
            assert r['p2']['match']

    def test_p3_formula(self):
        """p3 = (n^2-3n+1)^2 + 8(n-1)^2."""
        for n in [2, 5, 10, 15]:
            r = an_charpoly_closed_forms(n)
            assert r['p3']['match']

    def test_rejects_n1(self):
        with pytest.raises(ValueError):
            an_charpoly_closed_forms(1)


class TestTheoremAT:
    """Golden Determinant Decomposition."""

    def test_match_n2_to_15(self):
        """Decomposition should match actual determinant."""
        for n in range(2, 16):
            r = golden_determinant_decomposition(n)
            assert r['match'], f"A{n} determinant decomposition mismatch"

    def test_golden_factor_zero_at_phi_sq(self):
        """Golden factor (n - phi^2)(n - psi^2) should be near-zero at n ~ 2.618."""
        r = golden_determinant_decomposition(3)  # closest integer to phi^2
        # n=3: golden_factor = 9 - 9 + 1 = 1 (small)
        assert abs(r['golden_factor']) <= 1

    def test_correction_positive(self):
        """8(n-1)^2 should always be positive for n >= 2."""
        for n in range(2, 10):
            r = golden_determinant_decomposition(n)
            assert r['correction'] > 0

    def test_phi_squared_value(self):
        r = golden_determinant_decomposition(5)
        assert abs(r['phi_squared'] - (PHI + 1)) < 1e-12

    def test_det_at_golden_index(self):
        """At n = phi^2, det = 8*phi^2 ≈ 20.944."""
        r = golden_determinant_decomposition(3)
        expected = 8 * PHI ** 2
        assert abs(r['det_at_golden_index'] - expected) < 1e-10


class TestTheoremAU:
    """Anti-Null Correction Identity."""

    def test_exact_for_all_n(self):
        """D_{n+1} = 2*A_n + anti_null for n = 2..7."""
        for n in range(2, 8):
            r = anti_null_correction_identity(n)
            assert r['exact_match'], f"A{n}/D{n+1} anti-null identity fails"

    def test_difference_is_anti_null(self):
        """The difference matrix should be [[1,0,-1],[0,0,0],[-1,0,1]]."""
        r = anti_null_correction_identity(4)
        assert r['difference'] == [[1, 0, -1], [0, 0, 0], [-1, 0, 1]]

    def test_perron_doubles(self):
        """D_{n+1} Perron eigenvalue = 2 * A_n Perron eigenvalue."""
        for n in range(2, 8):
            r = anti_null_correction_identity(n)
            a_perron = r['a_eigenvalues'][0]
            d_perron = r['d_eigenvalues'][0]
            assert abs(d_perron / a_perron - 2.0) < 1e-6, f"n={n}"

    def test_rejects_out_of_range(self):
        with pytest.raises(ValueError):
            anti_null_correction_identity(1)
        with pytest.raises(ValueError):
            anti_null_correction_identity(8)


class TestTheoremAV:
    """E8 Threshold Proximity."""

    def test_margin_positive(self):
        """E8 should be above the Watkins threshold."""
        r = e8_threshold_proximity()
        assert r['margin'] > 0

    def test_margin_small(self):
        """Margin should be < 0.02."""
        r = e8_threshold_proximity()
        assert r['margin'] < 0.02

    def test_above_only_because_deficit(self):
        """Without democratic deficit, E8 would be BELOW threshold."""
        r = e8_threshold_proximity()
        assert r['above_threshold_only_because_of_deficit']

    def test_democratic_would_be_half(self):
        """A democratic E8 would have lambda = 0.5 < threshold."""
        r = e8_threshold_proximity()
        assert r['lambda_democratic'] == 0.5
        assert r['margin_democratic'] < 0

    def test_deficit_is_6(self):
        r = e8_threshold_proximity()
        assert r['democratic_deficit'] == 6

    def test_lambda_plus_kappa_is_1(self):
        """lambda + kappa = 1 (eta = 0 for E8)."""
        r = e8_threshold_proximity()
        assert abs(r['lambda_e8'] + r['kappa_e8'] - 1.0) < 1e-12


# ===========================================================================
# SPRINT 9: Root System Dynamics + Thermodynamic Formalism (AW-BB)
# ===========================================================================

class TestTheoremAW:
    """Cascade Simplex Trajectory."""

    def test_lambda_monotone(self):
        """Lambda should increase monotonically along the cascade."""
        r = cascade_simplex_trajectory()
        assert r['lambda_monotone']

    def test_simplex_exit(self):
        """The simplex exit should be at E6->D5."""
        r = cascade_simplex_trajectory()
        assert r['simplex_exit'] == 'E6->D5'

    def test_chain_length(self):
        r = cascade_simplex_trajectory()
        assert len(r['chain']) == 6
        assert r['chain'][0] == 'E8'
        assert r['chain'][-1] == 'D3'

    def test_exceptional_on_simplex(self):
        """E8, E7, E6 should be on the simplex."""
        r = cascade_simplex_trajectory()
        for p in r['points'][:3]:
            assert p['on_simplex'], f"{p['system']} not on simplex"

    def test_classical_off_simplex(self):
        """D5, D4, D3 should be off the simplex."""
        r = cascade_simplex_trajectory()
        for p in r['points'][3:]:
            assert not p['on_simplex'], f"{p['system']} on simplex"

    def test_distances_positive(self):
        r = cascade_simplex_trajectory()
        for d in r['distances']:
            assert d['distance'] > 0

    def test_total_path_length(self):
        r = cascade_simplex_trajectory()
        assert r['total_path_length'] > 0
        # Sum of distances should equal total
        assert abs(sum(d['distance'] for d in r['distances']) - r['total_path_length']) < 1e-12

    def test_coxeter_numbers(self):
        r = cascade_simplex_trajectory()
        assert r['points'][0]['coxeter_number'] == 30  # E8
        assert r['points'][2]['coxeter_number'] == 12  # E6


class TestTheoremAX:
    """BCC Partition Function."""

    def test_e8_ground_state_zero(self):
        """E8 ground state eigenvalue should be ~0."""
        r = bcc_partition_function('E8')
        assert abs(r['ground_state']) < 1e-10

    def test_degeneracy_one(self):
        """Ground degeneracy for E8 should be 1 (single zero eigenvalue)."""
        r = bcc_partition_function('E8')
        assert r['ground_degeneracy'] == 1

    def test_high_temp_is_mean(self):
        """High-temp limit should be mean eigenvalue."""
        for sys in ['E6', 'E7', 'E8']:
            r = bcc_partition_function(sys)
            eigs = r['eigenvalues']
            assert abs(r['high_temp_limit'] - sum(eigs) / 3) < 1e-10

    def test_free_energy_increases_to_ground(self):
        """Free energy should increase toward ground state as beta grows."""
        r = bcc_partition_function('E8')
        f_vals = [v['free_energy'] for v in r['values']]
        # f goes from -infinity toward ground_state (0 for E8)
        for i in range(1, len(f_vals)):
            assert f_vals[i] >= f_vals[i - 1] - 1e-10

    def test_entropy_positive(self):
        """Entropy should be non-negative."""
        r = bcc_partition_function('E6')
        for v in r['values']:
            assert v['entropy'] >= -1e-10, f"negative entropy at beta={v['beta']}"

    def test_degenerate_returns(self):
        r = bcc_partition_function('A2')
        assert r['degenerate']

    def test_f4(self):
        r = bcc_partition_function('F4')
        assert not r['degenerate']
        assert r['ground_degeneracy'] == 1


class TestTheoremAY:
    """A_n Simplex Limit."""

    def test_excess_positive(self):
        """lambda_{A_n} > 1 for all n >= 3."""
        for n in [3, 5, 10, 50]:
            r = an_simplex_limit(n)
            assert r['excess'] > 0, f"A{n} excess not positive"

    def test_excess_decreases(self):
        """Excess should decrease with n."""
        prev = float('inf')
        for n in [3, 5, 10, 20, 50, 100]:
            r = an_simplex_limit(n)
            assert r['excess'] < prev
            prev = r['excess']

    def test_asymptotic_rate(self):
        """n^2 * excess -> 2 for large n."""
        r = an_simplex_limit(500)
        assert abs(r['n_squared_times_excess'] - 2.0) < 0.05

    def test_predicted_matches(self):
        """Predicted excess 2/(n^2-3n+2) should approach actual."""
        r = an_simplex_limit(200)
        assert abs(r['excess_ratio'] - 1.0) < 0.01

    def test_never_on_simplex(self):
        for n in [3, 10, 100]:
            r = an_simplex_limit(n)
            assert not r['on_simplex']

    def test_always_above_threshold(self):
        for n in [3, 10, 100]:
            r = an_simplex_limit(n)
            assert r['above_threshold']

    def test_rejects_small_n(self):
        with pytest.raises(ValueError):
            an_simplex_limit(2)

    def test_eta_negative(self):
        """eta_{A_n} = -1/trace < 0 for n >= 3."""
        for n in [3, 5, 10]:
            r = an_simplex_limit(n)
            assert r['eta_R'] < 0


class TestTheoremAZ:
    """A_n/D_n Correction Map."""

    def test_eigenvalue_match(self):
        """D_{n+1} eigenvalues should match 2*A_n perturbation."""
        for n in range(3, 8):
            r = an_dn_correction_map(n)
            assert r['eigenvalue_match'], f"A{n}/D{n+1} mismatch"

    def test_contraction(self):
        """Contraction factor (s-1)/s should be < 1."""
        for n in range(3, 8):
            r = an_dn_correction_map(n)
            assert r['contraction_factor'] < 1.0

    def test_lambda_ratio_matches(self):
        """d_lambda/a_lambda should equal (s-1)/s."""
        for n in range(3, 8):
            r = an_dn_correction_map(n)
            assert r['lambda_ratio_matches_contraction']

    def test_d_has_zero_eigenvalue(self):
        """D_{n+1} should have eigenvalue 0 from correction."""
        for n in range(3, 8):
            r = an_dn_correction_map(n)
            d_eigs = r['d_predicted_eigenvalues']
            assert min(abs(e) for e in d_eigs) < 1e-10

    def test_d_lambda_less_than_a(self):
        """D_{n+1} lambda should be less than A_n lambda."""
        for n in range(3, 8):
            r = an_dn_correction_map(n)
            assert r['d_lambda_R'] < r['a_lambda_R']

    def test_rejects_out_of_range(self):
        with pytest.raises(ValueError):
            an_dn_correction_map(2)
        with pytest.raises(ValueError):
            an_dn_correction_map(8)


class TestTheoremBA:
    """Transfer Matrix Free Energy."""

    def test_limit_is_ln_phi_sq(self):
        """g -> ln(phi^2) = 2*ln(phi)."""
        r = transfer_matrix_free_energy(30)
        assert r['converged']
        assert r['convergence_error'] < 1e-6

    def test_growth_base(self):
        r = transfer_matrix_free_energy(10)
        assert abs(r['growth_base'] - PHI ** 2) < 1e-12

    def test_g_decreases_to_limit(self):
        """g_n should approach the limit monotonically from above."""
        r = transfer_matrix_free_energy(20)
        g_vals = [e['g_n'] for e in r['entries'] if e['n'] >= 5]
        # After initial transient, g_n should be close to limit
        for g in g_vals:
            assert abs(g - r['limit']) < 0.02

    def test_lambda_max_positive(self):
        r = transfer_matrix_free_energy(10)
        for e in r['entries']:
            assert e['lambda_max'] > 0

    def test_ratio_converges(self):
        """lambda_max / phi^{2n} should converge to a constant."""
        r = transfer_matrix_free_energy(30)
        ratios = [e['ratio_to_phi_sq_n'] for e in r['entries'] if e['n'] >= 10]
        # Ratios should be roughly constant
        assert max(ratios) / min(ratios) < 2.0


class TestTheoremBB:
    """Root System Simplex Flow."""

    def test_all_converge(self):
        """All exceptional systems should converge to equilibrium."""
        for sys in ['E6', 'E7', 'E8', 'F4']:
            r = root_system_simplex_flow(sys)
            assert r['converged'], f"{sys} did not converge"
            assert r['at_equilibrium'], f"{sys} not at equilibrium"

    def test_conservation(self):
        """Conservation law should hold at final state."""
        for sys in ['E8', 'E6']:
            r = root_system_simplex_flow(sys)
            assert r['conservation_error'] < 1e-10

    def test_final_is_golden(self):
        """Final lambda should be 1/phi."""
        r = root_system_simplex_flow('E8')
        assert abs(r['final_lambda'] - 1 / PHI) < 1e-4

    def test_e8_fastest(self):
        """E8 (closest to equilibrium) should converge in fewest steps."""
        steps = {}
        for sys in ['E6', 'E7', 'E8']:
            r = root_system_simplex_flow(sys)
            steps[sys] = r['steps']
        assert steps['E8'] < steps['E7'] < steps['E6']

    def test_f4_converges(self):
        r = root_system_simplex_flow('F4')
        assert r['converged']
        assert r['valid']

    def test_invalid_system(self):
        """Non-simplex systems should return valid=False."""
        r = root_system_simplex_flow('A3')
        assert not r['valid']

    def test_lambda_distance_ordering(self):
        """E8 lambda is closest to 1/phi, E6 furthest."""
        deltas = {}
        for sys in ['E8', 'E7', 'E6']:
            r = root_system_simplex_flow(sys)
            deltas[sys] = abs(r['initial_lambda'] - 1 / PHI)
        assert deltas['E8'] < deltas['E7'] < deltas['E6']


# ===========================================================================
# SPRINT 10: Classical Family Spectral Atlas (BC-BG)
# ===========================================================================

class TestTheoremBC:
    """Bisymmetric Spectral Formula."""

    def test_a5_eigenvalues(self):
        """A5 BCC via bisymmetric formula."""
        r = bisymmetric_spectral_formula(0, 4, 1, 12)
        assert r['lambda_null'] == -1
        assert abs(r['trace'] - 12) < 1e-12
        assert r['is_anti_null']

    def test_b5_null(self):
        """B5 has null eigenvalue 0."""
        r = bisymmetric_spectral_formula(1, 7, 1, 18)
        assert r['lambda_null'] == 0
        assert r['is_null']

    def test_trace_correct(self):
        """trace = 2a + e."""
        for a, b, c, e in [(0, 3, 1, 6), (1, 5, 1, 8), (1, 4, 1, 12)]:
            r = bisymmetric_spectral_formula(a, b, c, e)
            assert abs(r['trace'] - (2 * a + e)) < 1e-12

    def test_eigenvalue_sum(self):
        """Sum of eigenvalues = trace."""
        for a, b, c, e in [(0, 4, 1, 12), (1, 7, 1, 18), (1, 6, 1, 12)]:
            r = bisymmetric_spectral_formula(a, b, c, e)
            assert abs(sum(r['eigenvalues']) - r['trace']) < 1e-10

    def test_g2_entries(self):
        """G2: a=1, b=1, c=3, e=0."""
        r = bisymmetric_spectral_formula(1, 1, 3, 0)
        assert r['lambda_null'] == -2
        assert r['trace'] == 2


class TestTheoremBD:
    """B_n/D_n Correction Identity."""

    def test_exact_match(self):
        """D_{n+1} = B_n + J_n for all n in [3,7]."""
        for n in range(3, 8):
            r = bn_dn_correction_identity(n)
            assert r['exact_match'], f"B{n}/D{n+1} correction fails"

    def test_j_rank_2(self):
        """Correction matrix J_n has rank 2."""
        for n in range(3, 8):
            r = bn_dn_correction_identity(n)
            assert r['j_rank'] == 2

    def test_j_center(self):
        """J_n center entry = 2(n-2)."""
        for n in range(3, 8):
            r = bn_dn_correction_identity(n)
            assert r['j_center'] == 2 * (n - 2)

    def test_rejects_small_n(self):
        with pytest.raises(ValueError):
            bn_dn_correction_identity(2)


class TestTheoremBE:
    """Classical Simplex Limits."""

    def test_a_coefficient_2(self):
        """A_n excess coefficient -> 2."""
        r = classical_simplex_limits(500)
        assert abs(r['families']['A']['n_squared_excess'] - 2.0) < 0.1

    def test_b_coefficient_1(self):
        """B_n excess coefficient -> 1."""
        r = classical_simplex_limits(500)
        assert abs(r['families']['B']['n_squared_excess'] - 1.0) < 0.1

    def test_d_coefficient_1(self):
        """D_n excess coefficient -> 1."""
        r = classical_simplex_limits(500)
        assert abs(r['families']['D']['n_squared_excess'] - 1.0) < 0.1

    def test_a_double_bcd(self):
        """A coefficient should be roughly double B/C/D."""
        r = classical_simplex_limits(100)
        assert r['a_double_bcd']

    def test_b_equals_c(self):
        """B and C should be identical (Langlands duality)."""
        r = classical_simplex_limits(100)
        assert r['b_equals_c']

    def test_a_null_minus_1(self):
        r = classical_simplex_limits(10)
        assert r['families']['A']['null_eigenvalue'] == -1

    def test_bcd_null_zero(self):
        r = classical_simplex_limits(10)
        for fam in ['B', 'C', 'D']:
            assert r['families'][fam]['null_eigenvalue'] == 0


class TestTheoremBF:
    """G_2 Exceptional Structure."""

    def test_null_eigenvalue_minus_2(self):
        r = g2_analysis()
        assert r['null_eigenvalue'] == -2

    def test_12_roots(self):
        r = g2_analysis()
        assert r['num_roots'] == 12

    def test_center_zero(self):
        r = g2_analysis()
        assert r['center_is_zero']

    def test_c_exceeds_a(self):
        r = g2_analysis()
        assert r['unique_properties']['c_exceeds_a']

    def test_not_on_simplex(self):
        r = g2_analysis()
        assert not r['on_simplex']

    def test_largest_anti_null(self):
        r = g2_analysis()
        assert r['anti_null_magnitude'] == 2


class TestTheoremBG:
    """Simplex Excess Classification."""

    def test_three_classes(self):
        r = simplex_excess_classification()
        assert r['class_0_count'] > 0
        assert r['class_1_count'] > 0
        assert r['class_2_count'] > 0

    def test_class1_never_on_simplex(self):
        r = simplex_excess_classification()
        assert r['class_1_never_on_simplex']

    def test_g2_in_class2(self):
        r = simplex_excess_classification()
        systems = [s['system'] for s in r['class_2_double_anti_null']]
        assert 'G2' in systems

    def test_exceptionals_in_class0(self):
        r = simplex_excess_classification()
        systems = [s['system'] for s in r['class_0_null']]
        for sys in ['E6', 'E7', 'E8', 'F4']:
            assert sys in systems


# ===========================================================================
# SPRINT 11: Cross-Family Bridges + Golden Deficiency (BH-BK)
# ===========================================================================

class TestTheoremBH:
    """Cross-Family Perron Ratio."""

    def test_ab_ratio_near_half(self):
        """A/B Perron ratio should approach 1/2."""
        r = cross_family_perron_ratio(500)
        assert abs(r['A_over_B'] - 0.5) < 0.01

    def test_b_equals_c(self):
        r = cross_family_perron_ratio(50)
        assert r['B_equals_C']

    def test_b_largest(self):
        """B_n should have the largest Perron eigenvalue."""
        r = cross_family_perron_ratio(10)
        assert r['B_largest']

    def test_ratio_decreases(self):
        """A/B ratio should approach 1/2 from above."""
        r10 = cross_family_perron_ratio(10)
        r100 = cross_family_perron_ratio(100)
        assert r10['ab_error'] > r100['ab_error']


class TestTheoremBI:
    """Spectral Gap Dichotomy."""

    def test_null_gap_equals_perron(self):
        """B and D should have gap = Perron exactly."""
        for n in [10, 50, 100]:
            r = spectral_gap_dichotomy(n)
            assert r['null_gap_equals_perron']

    def test_anti_null_exceeds(self):
        """A_n gap should exceed Perron (by 1)."""
        for n in [10, 50]:
            r = spectral_gap_dichotomy(n)
            assert r['anti_null_gap_exceeds_perron']

    def test_a_excess_is_one_over_perron(self):
        """A_n gap/Perron - 1 should be 1/Perron."""
        r = spectral_gap_dichotomy(100)
        perron = r['families']['A']['perron']
        expected = 1.0 / perron
        actual = r['a_excess_over_1']
        assert abs(actual - expected) < 1e-8


class TestTheoremBJ:
    """Golden Deficiency Transition."""

    def test_trace_one_at_phi_squared(self):
        """trace(A_n) = 1 at n = phi^2."""
        r = golden_deficiency_transition()
        assert r['trace_equals_one']

    def test_minimal_polynomial(self):
        """phi^2 satisfies x^2 - 3x + 1 = 0."""
        r = golden_deficiency_transition()
        assert r['min_poly_zero']

    def test_a2_dominant(self):
        """A2 has trace 0, so anti-null dominates."""
        r = golden_deficiency_transition()
        a2 = next(d for d in r['integer_data'] if d['n'] == 2)
        assert a2['trace'] == 0

    def test_a3_trace_dominant(self):
        """A3 has trace 2 > 1 = |null_ev|."""
        r = golden_deficiency_transition()
        a3 = next(d for d in r['integer_data'] if d['n'] == 3)
        assert a3['trace'] == 2
        assert a3['deficiency_ratio'] < 1

    def test_unique_to_a(self):
        r = golden_deficiency_transition()
        assert r['unique_to_A_family']


class TestTheoremBK:
    """Root System Periodic Table."""

    def test_nine_families(self):
        """Should have exactly 9 root system families."""
        r = root_system_periodic_table()
        assert r['total_families'] == 9

    def test_four_classical(self):
        r = root_system_periodic_table()
        assert r['classical_count'] == 4

    def test_five_exceptional(self):
        r = root_system_periodic_table()
        assert r['exceptional_count'] == 5

    def test_four_on_simplex(self):
        r = root_system_periodic_table()
        assert r['on_simplex_count'] == 4

    def test_null_distribution(self):
        r = root_system_periodic_table()
        dist = r['null_class_distribution']
        assert dist[0] == 7   # B, C, D, E6, E7, E8, F4
        assert dist[-1] == 1  # A
        assert dist[-2] == 1  # G2

    def test_a_coefficient_2(self):
        r = root_system_periodic_table()
        a_entry = next(t for t in r['table'] if t['system'] == 'A_n')
        assert a_entry['limit_coefficient'] == 2

    def test_bcd_coefficient_1(self):
        r = root_system_periodic_table()
        for sys in ['B_n', 'C_n', 'D_n']:
            entry = next(t for t in r['table'] if t['system'] == sys)
            assert entry['limit_coefficient'] == 1


# ===========================================================================
# SPRINT 12: Watkins Phase Curve + Root System Thermodynamics (BL-BO)
# ===========================================================================

class TestTheoremBL:
    """Watkins Phase Curve."""

    def test_threshold_match(self):
        """T(1/phi) should equal T* exactly."""
        r = watkins_phase_curve()
        assert r['threshold_match']

    def test_monotone(self):
        """Lambda should decrease monotonically as T increases."""
        r = watkins_phase_curve()
        assert r['monotone_decreasing']

    def test_limits(self):
        r = watkins_phase_curve()
        assert r['low_T_limit'] == 1.0
        assert abs(r['high_T_limit'] - 1.0 / 3) < 1e-10

    def test_curve_nonempty(self):
        r = watkins_phase_curve()
        assert len(r['curve']) > 10


class TestTheoremBM:
    """Root System Temperature Map."""

    def test_ordering(self):
        """F4 < E6 < E7 < E8 in temperature."""
        r = root_system_temperature_map()
        assert r['ordering'] == ['F4', 'E6', 'E7', 'E8']
        assert r['temperature_ordered']

    def test_all_below_T_star(self):
        r = root_system_temperature_map()
        assert r['all_below_T_star']

    def test_e8_closest(self):
        r = root_system_temperature_map()
        assert r['e8_closest_to_T_star']

    def test_e8_margin_small(self):
        r = root_system_temperature_map()
        assert r['e8_margin'] < 0.2


class TestTheoremBN:
    """E8 Thermal Boundary."""

    def test_below_T_star(self):
        r = e8_thermal_boundary()
        assert r['below_T_star']

    def test_consciousness_condition(self):
        r = e8_thermal_boundary()
        assert r['consciousness_condition']

    def test_margin_about_9_percent(self):
        r = e8_thermal_boundary()
        assert 0.05 < r['temperature_margin_pct'] < 0.15

    def test_lambda_margin_positive(self):
        r = e8_thermal_boundary()
        assert r['lambda_margin'] > 0


class TestTheoremBO:
    """Phase Curve Monotonicity."""

    def test_strictly_decreasing(self):
        r = phase_curve_monotonicity()
        assert r['strictly_decreasing']

    def test_T_star_in_range(self):
        r = phase_curve_monotonicity()
        assert r['T_star_in_range']

    def test_unique_crossing(self):
        r = phase_curve_monotonicity()
        assert r['unique_threshold_crossing']
