From 60bac17f0e695e45aeecccdffa6c0bc7925b1c50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 00:16:02 +0000 Subject: [PATCH 1/2] Initial plan From f9881cfc96bba5393c63e87d4515bee6d6dc6d3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 00:23:06 +0000 Subject: [PATCH 2/2] Refactor canonical_grammar.py to delegate to unified_grammar Co-authored-by: fermga <203334638+fermga@users.noreply.github.com> --- src/tnfr/operators/canonical_grammar.py | 559 +++++++----------- .../test_canonical_grammar_legacy.py | 296 ++++++++++ 2 files changed, 505 insertions(+), 350 deletions(-) create mode 100644 tests/unit/operators/test_canonical_grammar_legacy.py diff --git a/src/tnfr/operators/canonical_grammar.py b/src/tnfr/operators/canonical_grammar.py index 6c3480389..d24c1b5dc 100644 --- a/src/tnfr/operators/canonical_grammar.py +++ b/src/tnfr/operators/canonical_grammar.py @@ -1,83 +1,156 @@ -"""Canonical grammar validator - Pure physics from nodal equation. - -This module implements grammar validation that emerges EXCLUSIVELY from -the nodal equation ∂EPI/∂t = νf · ΔNFR(t), TNFR invariants, and formal contracts. - -Canonical Rules (Inevitable from Physics) ------------------------------------------- -RC1: Initialization - If EPI=0, sequence must start with generator - Reason: ∂EPI/∂t undefined at EPI=0 - -RC2: Convergence - If sequence has destabilizers, must include stabilizer - Reason: ∫νf·ΔNFR dt must converge (convergence theorem) - -RC3: Phase Verification - Coupling/resonance requires phase compatibility - Reason: AGENTS.md Invariant #5 + resonance physics (φᵢ ≈ φⱼ) - -RC4: Bifurcation Limits - If ∂²EPI/∂t² > τ, bifurcation handler required - Reason: AGENTS.md Contract OZ + bifurcation theory (conditional) - -Historical Note ---------------- -Previous versions included RNC1 (Termination requirement), but this was -removed as it does NOT emerge from TNFR physics. It was purely organizational. -The grammar now contains ONLY rules that emerge inevitably from the nodal -equation, invariants, and formal contracts. +"""TNFR Canonical Grammar (LEGACY - Use unified_grammar instead). + +⚠️ DEPRECATION NOTICE +======================= +This module is maintained for backward compatibility only. +All functionality has been consolidated into unified_grammar.py. + +This module will be removed in version 8.0.0. +Please migrate to: + + from tnfr.operators.unified_grammar import UnifiedGrammarValidator + +Old Canonical Grammar (RC1-RC4) → Unified Grammar (U1-U4) +---------------------------------------------------------- +RC1: Initialization → U1a: Initiation +RC2: Convergence → U2: CONVERGENCE & BOUNDEDNESS +RC3: Phase Verification → U3: RESONANT COUPLING +RC4: Bifurcation Limits → U4a: Bifurcation Triggers + +Additional unified constraints: +U1b: Closure (restores physical basis of removed RNC1) +U4b: Transformer Context (graduated destabilization) + +Historical Context +------------------ +Previous versions of this module implemented RC1-RC4 constraints derived from +TNFR physics. These have been consolidated into the unified grammar system +(U1-U4) which provides: +- Single source of truth (no duplication) +- Complete physics derivations in docstrings +- Additional constraints based on structural physics +- Better alignment with TNFR.pdf and AGENTS.md References ---------- -See CANONICAL_GRAMMAR_DERIVATION.md and EMERGENT_GRAMMAR_ANALYSIS.md -for complete mathematical derivations. +- UNIFIED_GRAMMAR_RULES.md: Complete derivations and mappings +- unified_grammar.py: Canonical implementation +- AGENTS.md: Invariants and formal contracts + +Warnings +-------- +Importing from this module will emit DeprecationWarning. +All new code should use unified_grammar.py instead. """ from __future__ import annotations +import warnings from typing import TYPE_CHECKING, List +# Import all exports from unified grammar +from .unified_grammar import ( + UnifiedGrammarValidator, + validate_unified, + GENERATORS, + CLOSURES, + STABILIZERS, + DESTABILIZERS, + COUPLING_RESONANCE, + BIFURCATION_TRIGGERS, + BIFURCATION_HANDLERS, + TRANSFORMERS, +) + if TYPE_CHECKING: from ..types import NodeId from .definitions import Operator -__all__ = [ - "CanonicalGrammarValidator", - "validate_canonical_only", - "validate_with_conventions", -] - - -# Canonical operator sets (derived from physics) -GENERATORS = frozenset({"emission", "transition", "recursivity"}) -STABILIZERS = frozenset({"coherence", "self_organization"}) -DESTABILIZERS = frozenset( - { - "dissonance", - "mutation", - "expansion", - # Note: Some operators have destabilizing components - } +# Emit warning on module import +warnings.warn( + "canonical_grammar is deprecated and will be removed in version 8.0.0. " + "Use unified_grammar instead. See UNIFIED_GRAMMAR_RULES.md for migration guide.", + DeprecationWarning, + stacklevel=2 ) -# RC3: Operators that require phase verification (coupling/resonance) -COUPLING_RESONANCE = frozenset({"coupling", "resonance"}) +__all__ = [ + # Legacy validators (deprecated) + 'CanonicalGrammarValidator', + 'validate_canonical_only', + 'validate_with_conventions', + # Re-exports from unified grammar + 'UnifiedGrammarValidator', + 'validate_unified', + # Legacy operator set names + 'GENERATOR_OPS', + 'STABILIZER_OPS', + 'DESTABILIZER_OPS', + 'COUPLING_OPS', + 'BIFURCATION_TRIGGER_OPS', + 'BIFURCATION_HANDLER_OPS', + # New in unified + 'CLOSURE_OPS', + 'TRANSFORMER_OPS', +] -# RC4: Bifurcation triggers and handlers -BIFURCATION_TRIGGERS = frozenset({"dissonance", "mutation"}) -BIFURCATION_HANDLERS = frozenset({"self_organization", "coherence"}) -# Historical: CONVENTIONAL_TERMINATORS removed - not physics-based -# Previous versions enforced RNC1 (terminator requirement) but this was -# purely organizational convention with no basis in TNFR physics +# ============================================================================= +# MIGRATION GUIDE: canonical_grammar → unified_grammar +# ============================================================================= +# +# Old (canonical_grammar.py): | New (unified_grammar.py): +# -----------------------------------------|---------------------------------- +# from tnfr.operators.canonical_grammar | from tnfr.operators.unified_grammar +# import CanonicalGrammarValidator | import UnifiedGrammarValidator +# | +# valid, msgs = CanonicalGrammarValidator | valid, msgs = UnifiedGrammarValidator +# .validate(seq) | .validate(seq) +# -----------------------------------------|---------------------------------- +# validate_canonical_only(seq) | validate_unified(seq) +# -----------------------------------------|---------------------------------- +# CanonicalGrammarValidator | UnifiedGrammarValidator +# .validate_initialization(seq) | .validate_initiation(seq) +# -----------------------------------------|---------------------------------- +# CanonicalGrammarValidator | UnifiedGrammarValidator +# .validate_convergence(seq) | .validate_convergence(seq) +# -----------------------------------------|---------------------------------- +# CanonicalGrammarValidator | UnifiedGrammarValidator +# .validate_phase_compatibility(seq) | .validate_resonant_coupling(seq) +# -----------------------------------------|---------------------------------- +# CanonicalGrammarValidator | UnifiedGrammarValidator +# .validate_bifurcation_limits(seq) | .validate_bifurcation_triggers(seq) +# -----------------------------------------|---------------------------------- +# +# Benefits of migration: +# 1. Single source of truth (no duplication) +# 2. Complete physics derivations in docstrings +# 3. Detailed validation messages +# 4. Additional constraints (U1b: Closure, U4b: Transformer Context) +# 5. Better alignment with TNFR.pdf and AGENTS.md +# +# See UNIFIED_GRAMMAR_RULES.md for complete migration guide. +# ============================================================================= + + +# Legacy operator set names - map to unified names +GENERATOR_OPS = GENERATORS # RC1 → U1a +STABILIZER_OPS = STABILIZERS # RC2 → U2 +DESTABILIZER_OPS = DESTABILIZERS # RC2 → U2 +COUPLING_OPS = COUPLING_RESONANCE # RC3 → U3 +BIFURCATION_TRIGGER_OPS = BIFURCATION_TRIGGERS # RC4 → U4a +BIFURCATION_HANDLER_OPS = BIFURCATION_HANDLERS # RC4 → U4a + +# NEW in unified grammar (not in original RC system) +CLOSURE_OPS = CLOSURES # U1b +TRANSFORMER_OPS = TRANSFORMERS # U4b class CanonicalGrammarValidator: - """Validates sequences using ONLY physics-derived rules. - - This validator implements RC1, RC2, RC3, and RC4, which emerge inevitably - from the nodal equation ∂EPI/∂t = νf · ΔNFR(t), TNFR invariants, and formal - contracts. - - The grammar is 100% canonical - no organizational conventions are enforced. - All rules derive from TNFR physics. + """DEPRECATED: Use UnifiedGrammarValidator from unified_grammar instead. + + Legacy validator maintained for backward compatibility. + All methods delegate to UnifiedGrammarValidator. """ @staticmethod @@ -85,198 +158,59 @@ def validate_initialization( sequence: List[Operator], epi_initial: float = 0.0, ) -> tuple[bool, str]: - """Validate RC1: Initialization requirement. - - Physical basis: If EPI=0, then ∂EPI/∂t is undefined or zero. - Cannot evolve structure that doesn't exist. - - Parameters - ---------- - sequence : List[Operator] - Sequence of operators to validate - epi_initial : float, optional - Initial EPI value (default: 0.0) - - Returns - ------- - tuple[bool, str] - (is_valid, message) + """DEPRECATED: Use UnifiedGrammarValidator.validate_initiation(). + + RC1 → U1a: Initiation requirement. """ - if epi_initial > 0.0: - # Already initialized, no generator required - return True, "EPI>0: initialization not required" - - if not sequence: - return False, "RC1 violated: Empty sequence with EPI=0" - - first_op = getattr(sequence[0], "canonical_name", sequence[0].name.lower()) - - if first_op not in GENERATORS: - return ( - False, - f"RC1 violated: EPI=0 requires generator (got '{first_op}'). " - f"Valid: {sorted(GENERATORS)}", - ) - - return True, f"RC1 satisfied: starts with generator '{first_op}'" + warnings.warn( + "CanonicalGrammarValidator.validate_initialization is deprecated. " + "Use UnifiedGrammarValidator.validate_initiation().", + DeprecationWarning, + stacklevel=2 + ) + return UnifiedGrammarValidator.validate_initiation(sequence, epi_initial) @staticmethod def validate_convergence(sequence: List[Operator]) -> tuple[bool, str]: - """Validate RC2: Convergence requirement. - - Physical basis: Without stabilizers, ∫νf·ΔNFR dt → ∞ (diverges). - Convergence theorem requires negative feedback. - - Parameters - ---------- - sequence : List[Operator] - Sequence of operators to validate - - Returns - ------- - tuple[bool, str] - (is_valid, message) + """DEPRECATED: Use UnifiedGrammarValidator.validate_convergence(). + + RC2 → U2: Convergence & Boundedness. """ - # Check if sequence contains destabilizers - destabilizers_present = [ - getattr(op, "canonical_name", op.name.lower()) - for op in sequence - if getattr(op, "canonical_name", op.name.lower()) in DESTABILIZERS - ] - - if not destabilizers_present: - # No destabilizers = no divergence risk - return True, "RC2 not applicable: no destabilizers present" - - # Check for stabilizers - stabilizers_present = [ - getattr(op, "canonical_name", op.name.lower()) - for op in sequence - if getattr(op, "canonical_name", op.name.lower()) in STABILIZERS - ] - - if not stabilizers_present: - return ( - False, - f"RC2 violated: destabilizers {destabilizers_present} present " - f"without stabilizer. Integral ∫νf·ΔNFR dt may diverge. " - f"Add: {sorted(STABILIZERS)}", - ) - - return ( - True, - f"RC2 satisfied: stabilizers {stabilizers_present} " - f"bound destabilizers {destabilizers_present}", + warnings.warn( + "CanonicalGrammarValidator.validate_convergence is deprecated. " + "Use UnifiedGrammarValidator.validate_convergence().", + DeprecationWarning, + stacklevel=2 ) + return UnifiedGrammarValidator.validate_convergence(sequence) @staticmethod def validate_phase_compatibility(sequence: List[Operator]) -> tuple[bool, str]: - """Validate RC3: Phase compatibility requirement for coupling/resonance. - - Physical basis: AGENTS.md Invariant #5 states "no coupling is valid - without explicit phase verification (synchrony)". Resonance physics - requires phase compatibility: |φᵢ - φⱼ| ≤ Δφ_max for structural coupling. - - Without phase verification, nodes with incompatible phases (e.g., antiphase) - could attempt coupling, violating resonance physics. - - Parameters - ---------- - sequence : List[Operator] - Sequence of operators to validate - - Returns - ------- - tuple[bool, str] - (is_valid, message) - - Notes - ----- - RC3 is a META-rule: it requires that when UM (Coupling) or RA (Resonance) - operators are used, the implementation MUST verify phase compatibility. - The actual phase check happens in operator preconditions, not in grammar. - - This grammar rule serves to document the requirement and ensure awareness - that phase checks are MANDATORY (Invariant #5), not optional. + """DEPRECATED: Use UnifiedGrammarValidator.validate_resonant_coupling(). + + RC3 → U3: Resonant Coupling (requires phase check per Invariant #5). """ - # Check if sequence contains coupling/resonance operators - coupling_ops = [ - getattr(op, "canonical_name", op.name.lower()) - for op in sequence - if getattr(op, "canonical_name", op.name.lower()) in COUPLING_RESONANCE - ] - - if not coupling_ops: - # No coupling/resonance = RC3 not applicable - return True, "RC3 not applicable: no coupling/resonance operators" - - # RC3 satisfied: Sequence contains coupling/resonance - # Phase verification is MANDATORY per Invariant #5 - # Actual check happens in operator preconditions (validate_coupling, validate_resonance) - return ( - True, - f"RC3 awareness: operators {coupling_ops} require phase verification " - f"(MANDATORY per Invariant #5). Enforced in preconditions.", + warnings.warn( + "CanonicalGrammarValidator.validate_phase_compatibility is deprecated. " + "Use UnifiedGrammarValidator.validate_resonant_coupling().", + DeprecationWarning, + stacklevel=2 ) + return UnifiedGrammarValidator.validate_resonant_coupling(sequence) @staticmethod def validate_bifurcation_limits(sequence: List[Operator]) -> tuple[bool, str]: - """Validate RC4: Bifurcation limits (conditional rule). - - Physical basis: AGENTS.md Contract OZ states that dissonance may trigger - bifurcation if ∂²EPI/∂t² > τ. When bifurcation is triggered, a handler - is required to manage the structural reorganization. - - This is a CONDITIONAL rule: only applies when bifurcation-triggering - operators are present. - - Parameters - ---------- - sequence : List[Operator] - Sequence of operators to validate - - Returns - ------- - tuple[bool, str] - (is_valid, message) - - Notes - ----- - RC4 is enforced at runtime in operator preconditions (validate_dissonance). - This grammar rule documents the requirement for awareness. - Actual bifurcation detection happens via compute_d2epi_dt2(). + """DEPRECATED: Use UnifiedGrammarValidator.validate_bifurcation_triggers(). + + RC4 → U4a: Bifurcation Triggers need handlers. """ - # Check if sequence contains bifurcation triggers - trigger_ops = [ - getattr(op, "canonical_name", op.name.lower()) - for op in sequence - if getattr(op, "canonical_name", op.name.lower()) in BIFURCATION_TRIGGERS - ] - - if not trigger_ops: - # No triggers = RC4 not applicable - return True, "RC4 not applicable: no bifurcation triggers present" - - # Check for handlers - handler_ops = [ - getattr(op, "canonical_name", op.name.lower()) - for op in sequence - if getattr(op, "canonical_name", op.name.lower()) in BIFURCATION_HANDLERS - ] - - if not handler_ops: - return ( - False, - f"RC4 violated: bifurcation triggers {trigger_ops} present " - f"without handler. If ∂²EPI/∂t² > τ, bifurcation may occur unmanaged. " - f"Add: {sorted(BIFURCATION_HANDLERS)}", - ) - - return ( - True, - f"RC4 satisfied: bifurcation triggers {trigger_ops} " - f"have handlers {handler_ops}", + warnings.warn( + "CanonicalGrammarValidator.validate_bifurcation_limits is deprecated. " + "Use UnifiedGrammarValidator.validate_bifurcation_triggers().", + DeprecationWarning, + stacklevel=2 ) + return UnifiedGrammarValidator.validate_bifurcation_triggers(sequence) @classmethod def validate( @@ -284,133 +218,58 @@ def validate( sequence: List[Operator], epi_initial: float = 0.0, ) -> tuple[bool, List[str]]: - """Validate sequence using ONLY canonical rules (RC1, RC2, RC3, RC4). - - This validates 100% pure TNFR physics without organizational conventions. - - Canonical rules validated: - - RC1: Initialization (if EPI=0, use generator) - - RC2: Convergence (if destabilizers, use stabilizer) - - RC3: Phase compatibility (coupling/resonance require phase check) - - RC4: Bifurcation limits (if triggers present, require handlers) - - Parameters - ---------- - sequence : List[Operator] - Sequence to validate - epi_initial : float, optional - Initial EPI value (default: 0.0) - - Returns - ------- - tuple[bool, List[str]] - (is_valid, messages) - is_valid: True if all canonical rules satisfied - messages: List of validation messages + """DEPRECATED: Use UnifiedGrammarValidator.validate(). + + Validates using canonical constraints (RC1-RC4 → U1-U4). + + Note: This now uses the unified grammar which includes U1b (Closure) + and U4b (Transformer Context) constraints that were not in the + original RC1-RC4 system. """ - messages = [] - all_valid = True - - # RC1: Initialization - valid_init, msg_init = cls.validate_initialization(sequence, epi_initial) - messages.append(f"RC1: {msg_init}") - all_valid = all_valid and valid_init - - # RC2: Convergence - valid_conv, msg_conv = cls.validate_convergence(sequence) - messages.append(f"RC2: {msg_conv}") - all_valid = all_valid and valid_conv - - # RC3: Phase compatibility - valid_phase, msg_phase = cls.validate_phase_compatibility(sequence) - messages.append(f"RC3: {msg_phase}") - all_valid = all_valid and valid_phase - - # RC4: Bifurcation limits - valid_bifurc, msg_bifurc = cls.validate_bifurcation_limits(sequence) - messages.append(f"RC4: {msg_bifurc}") - all_valid = all_valid and valid_bifurc - - return all_valid, messages + warnings.warn( + "CanonicalGrammarValidator.validate is deprecated. " + "Use UnifiedGrammarValidator.validate().", + DeprecationWarning, + stacklevel=2 + ) + return UnifiedGrammarValidator.validate(sequence, epi_initial) def validate_canonical_only( sequence: List[Operator], epi_initial: float = 0.0, ) -> bool: - """Validate sequence using only physics-derived canonical rules. - - This function validates ONLY: - - RC1: Initialization (if EPI=0, use generator) - - RC2: Convergence (if destabilizers, use stabilizer) - - RC3: Phase compatibility (coupling/resonance require phase check) - - RC4: Bifurcation limits (if triggers present, require handlers) - - All rules emerge inevitably from TNFR physics. No organizational - conventions are enforced. - - Parameters - ---------- - sequence : List[Operator] - Sequence of operators to validate - epi_initial : float, optional - Initial EPI value (default: 0.0) - - Returns - ------- - bool - True if sequence satisfies canonical physics rules - - Examples - -------- - >>> from tnfr.operators.definitions import Emission, Coherence - >>> ops = [Emission(), Coherence()] - >>> validate_canonical_only(ops, epi_initial=0.0) # doctest: +SKIP - True - - Notes - ----- - This validator is 100% physics-based. All rules emerge inevitably from: - - Nodal equation: ∂EPI/∂t = νf · ΔNFR(t) - - TNFR invariants (especially Invariant #5: phase verification) - - Formal operator contracts (AGENTS.md §4) - - See EMERGENT_GRAMMAR_ANALYSIS.md for complete derivations. + """DEPRECATED: Use validate_unified() from unified_grammar. + + Validates using canonical constraints (RC1-RC4 → U1-U4). + + Note: This now uses the unified grammar which includes U1b (Closure) + and U4b (Transformer Context) constraints that were not in the + original RC1-RC4 system. """ - is_valid, messages = CanonicalGrammarValidator.validate(sequence, epi_initial) - return is_valid + warnings.warn( + "validate_canonical_only is deprecated. Use validate_unified() from unified_grammar.", + DeprecationWarning, + stacklevel=2 + ) + return validate_unified(sequence, epi_initial) def validate_with_conventions( sequence: List[Operator], epi_initial: float = 0.0, ) -> tuple[bool, List[str]]: - """Validate sequence with canonical rules only. - + """DEPRECATED: Use UnifiedGrammarValidator.validate() from unified_grammar. + Historical Note: This function previously enforced RNC1 (terminator - convention), but that has been removed as it does NOT emerge from - TNFR physics. This function now performs the same validation as - validate_canonical_only() but returns detailed messages. - - This validates: - - RC1: Initialization (if EPI=0, use generator) - - RC2: Convergence (if destabilizers, use stabilizer) - - RC3: Phase compatibility (coupling/resonance require phase check) - - RC4: Bifurcation limits (if triggers present, require handlers) - - All rules are 100% physics-based. - - Parameters - ---------- - sequence : List[Operator] - Sequence to validate - epi_initial : float, optional - Initial EPI value (default: 0.0) - - Returns - ------- - tuple[bool, List[str]] - (is_valid, messages) + convention), but that was removed. Now delegates to unified grammar. + + Returns detailed validation messages using unified U1-U4 constraints. """ - # Just use canonical validation - no conventions anymore - return CanonicalGrammarValidator.validate(sequence, epi_initial) + warnings.warn( + "validate_with_conventions is deprecated. " + "Use UnifiedGrammarValidator.validate() from unified_grammar.", + DeprecationWarning, + stacklevel=2 + ) + return UnifiedGrammarValidator.validate(sequence, epi_initial) diff --git a/tests/unit/operators/test_canonical_grammar_legacy.py b/tests/unit/operators/test_canonical_grammar_legacy.py new file mode 100644 index 000000000..19c19275f --- /dev/null +++ b/tests/unit/operators/test_canonical_grammar_legacy.py @@ -0,0 +1,296 @@ +"""Tests for canonical_grammar legacy module (deprecated). + +This module tests the legacy canonical_grammar.py that now delegates +to unified_grammar.py. All tests should pass with DeprecationWarnings. +""" + +import warnings + +import pytest + +from tnfr.operators.definitions import ( + Emission, + Reception, + Coherence, + Dissonance, + Mutation, + Silence, + Coupling, + SelfOrganization, +) + + +class TestLegacyModuleWarnings: + """Test that the legacy module emits proper deprecation warnings.""" + + def test_module_import_emits_warning(self): + """Importing canonical_grammar should emit DeprecationWarning.""" + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + # Re-import to trigger warning + import importlib + import tnfr.operators.canonical_grammar + importlib.reload(tnfr.operators.canonical_grammar) + + # Check that a warning was emitted + deprecation_warnings = [ + warning for warning in w + if issubclass(warning.category, DeprecationWarning) + ] + assert len(deprecation_warnings) > 0 + assert "canonical_grammar is deprecated" in str(deprecation_warnings[0].message) + assert "unified_grammar" in str(deprecation_warnings[0].message) + + +class TestLegacyValidatorMethods: + """Test that legacy CanonicalGrammarValidator methods emit warnings.""" + + def test_validate_initialization_emits_warning(self): + """validate_initialization() should emit DeprecationWarning.""" + # Import with suppressed import warning + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator + + ops = [Emission(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + result = CanonicalGrammarValidator.validate_initialization(ops) + + # Check warning + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_initialization is deprecated" in str(w[0].message) + + # Check functionality still works + assert result[0] is True + assert "U1a" in result[1] + + def test_validate_convergence_emits_warning(self): + """validate_convergence() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator + + ops = [Emission(), Dissonance(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + result = CanonicalGrammarValidator.validate_convergence(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_convergence is deprecated" in str(w[0].message) + + # Check functionality + assert result[0] is True + assert "U2" in result[1] + + def test_validate_phase_compatibility_emits_warning(self): + """validate_phase_compatibility() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator + + ops = [Emission(), Coupling(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + result = CanonicalGrammarValidator.validate_phase_compatibility(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_phase_compatibility is deprecated" in str(w[0].message) + + # Check functionality + assert result[0] is True + assert "U3" in result[1] + + def test_validate_bifurcation_limits_emits_warning(self): + """validate_bifurcation_limits() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator + + ops = [Emission(), Dissonance(), Mutation(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + result = CanonicalGrammarValidator.validate_bifurcation_limits(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_bifurcation_limits is deprecated" in str(w[0].message) + + # Check functionality + assert result[0] is True + assert "U4a" in result[1] + + def test_validate_method_emits_warning(self): + """validate() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator + + ops = [Emission(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + is_valid, messages = CanonicalGrammarValidator.validate(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "CanonicalGrammarValidator.validate is deprecated" in str(w[0].message) + + # Check functionality + assert is_valid is True + assert len(messages) > 0 + + +class TestLegacyFunctions: + """Test that legacy standalone functions emit warnings.""" + + def test_validate_canonical_only_emits_warning(self): + """validate_canonical_only() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import validate_canonical_only + + ops = [Emission(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + result = validate_canonical_only(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_canonical_only is deprecated" in str(w[0].message) + assert "validate_unified" in str(w[0].message) + + # Check functionality + assert result is True + + def test_validate_with_conventions_emits_warning(self): + """validate_with_conventions() should emit DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import validate_with_conventions + + ops = [Emission(), Coherence(), Silence()] + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + is_valid, messages = validate_with_conventions(ops) + + assert len(w) > 0 + assert issubclass(w[0].category, DeprecationWarning) + assert "validate_with_conventions is deprecated" in str(w[0].message) + + # Check functionality + assert is_valid is True + assert len(messages) > 0 + + +class TestLegacyOperatorSets: + """Test that legacy operator set names are available.""" + + def test_legacy_operator_sets_available(self): + """Legacy operator set names should be available.""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import ( + GENERATOR_OPS, + STABILIZER_OPS, + DESTABILIZER_OPS, + COUPLING_OPS, + BIFURCATION_TRIGGER_OPS, + BIFURCATION_HANDLER_OPS, + CLOSURE_OPS, + TRANSFORMER_OPS, + ) + + # Check that all sets are available and contain expected operators + assert 'emission' in GENERATOR_OPS + assert 'coherence' in STABILIZER_OPS + assert 'dissonance' in DESTABILIZER_OPS + assert 'coupling' in COUPLING_OPS + assert 'mutation' in BIFURCATION_TRIGGER_OPS + assert 'coherence' in BIFURCATION_HANDLER_OPS + assert 'silence' in CLOSURE_OPS + assert 'mutation' in TRANSFORMER_OPS + + +class TestBackwardCompatibility: + """Test that the legacy API produces same results as unified grammar.""" + + def test_rc1_maps_to_u1a(self): + """RC1 (initialization) maps to U1a (initiation).""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator as LegacyValidator + from tnfr.operators.unified_grammar import UnifiedGrammarValidator + + ops = [Emission(), Coherence(), Silence()] + + # Get results from both + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + legacy_result = LegacyValidator.validate_initialization(ops) + unified_result = UnifiedGrammarValidator.validate_initiation(ops) + + # Should have same validity + assert legacy_result[0] == unified_result[0] + # Both should mention the rule (legacy uses RC1, unified uses U1a) + assert legacy_result[0] is True + + def test_rc2_maps_to_u2(self): + """RC2 (convergence) maps to U2 (convergence & boundedness).""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator as LegacyValidator + from tnfr.operators.unified_grammar import UnifiedGrammarValidator + + ops = [Emission(), Dissonance(), Coherence(), Silence()] + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + legacy_result = LegacyValidator.validate_convergence(ops) + unified_result = UnifiedGrammarValidator.validate_convergence(ops) + + assert legacy_result[0] == unified_result[0] + assert legacy_result[0] is True + + def test_rc3_maps_to_u3(self): + """RC3 (phase verification) maps to U3 (resonant coupling).""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator as LegacyValidator + from tnfr.operators.unified_grammar import UnifiedGrammarValidator + + ops = [Emission(), Coupling(), Coherence(), Silence()] + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + legacy_result = LegacyValidator.validate_phase_compatibility(ops) + unified_result = UnifiedGrammarValidator.validate_resonant_coupling(ops) + + assert legacy_result[0] == unified_result[0] + assert legacy_result[0] is True + + def test_rc4_maps_to_u4a(self): + """RC4 (bifurcation limits) maps to U4a (bifurcation triggers).""" + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + from tnfr.operators.canonical_grammar import CanonicalGrammarValidator as LegacyValidator + from tnfr.operators.unified_grammar import UnifiedGrammarValidator + + ops = [Emission(), Dissonance(), Mutation(), Coherence(), Silence()] + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + legacy_result = LegacyValidator.validate_bifurcation_limits(ops) + unified_result = UnifiedGrammarValidator.validate_bifurcation_triggers(ops) + + assert legacy_result[0] == unified_result[0] + assert legacy_result[0] is True