@@ -775,10 +775,11 @@ def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
775775 According to TNFR theory, RA creates "resonant cascades" where coherence
776776 amplifies across the network, increasing collective νf and global C(t).
777777
778- **Canonical Effects:**
778+ **Canonical Effects (always active) :**
779779
780780 - **EPI Propagation**: Diffuses EPI to neighbors (identity-preserving)
781781 - **νf Amplification**: Increases structural frequency when propagating coherence
782+ - **Phase Alignment**: Strengthens phase synchrony across propagation path
782783 - **Network C(t)**: Contributes to global coherence increase
783784 - **Identity Preservation**: Maintains structural identity during propagation
784785
@@ -787,21 +788,29 @@ def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
787788 node : NodeProtocol
788789 Node harmonising with its neighbourhood.
789790 gf : GlyphFactors
790- Provides ``RA_epi_diff`` (mixing coefficient, default 0.15) and
791- ``RA_vf_amplification`` (νf boost factor, default 0.05).
791+ Provides ``RA_epi_diff`` (mixing coefficient, default 0.15),
792+ ``RA_vf_amplification`` (νf boost factor, default 0.05), and
793+ ``RA_phase_coupling`` (phase alignment factor, default 0.10).
792794
793795 Notes
794796 -----
795- **νf Amplification**: When neighbors have coherence (|epi_bar| > 1e-9),
797+ **νf Amplification (Canonical) **: When neighbors have coherence (|epi_bar| > 1e-9),
796798 node.vf is multiplied by (1.0 + RA_vf_amplification). This reflects
797799 the canonical TNFR property that resonance amplifies collective νf.
800+ This is NOT optional - it is a fundamental property of resonance per TNFR theory.
798801
799- **Network Coherence Tracking**: If ``TRACK_NETWORK_COHERENCE`` is enabled,
802+ **Phase Alignment Strengthening (Canonical)**: RA strengthens phase alignment
803+ with neighbors by applying a small phase correction toward the network mean.
804+ This ensures that "Phase alignment: Strengthens across propagation path" as
805+ stated in the theoretical foundations. Uses existing phase utility functions
806+ to avoid code duplication.
807+
808+ **Network Coherence Tracking (Optional)**: If ``TRACK_NETWORK_COHERENCE`` is enabled,
800809 global C(t) is measured before/after RA application to quantify network-level
801810 coherence increase.
802811
803- **Identity Preservation**: EPI structure (kind and sign) are preserved during
804- propagation to ensure structural identity is maintained as required by theory.
812+ **Identity Preservation (Canonical) **: EPI structure (kind and sign) are preserved
813+ during propagation to ensure structural identity is maintained as required by theory.
805814
806815 Examples
807816 --------
@@ -810,23 +819,26 @@ def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
810819 ... self.EPI = epi
811820 ... self.epi_kind = "seed"
812821 ... self.vf = 1.0
822+ ... self.theta = 0.0
813823 ... self.graph = {}
814824 ... self._neighbors = neighbors
815825 ... def neighbors(self):
816826 ... return self._neighbors
817827 >>> neighbor = MockNode(1.0, [])
828+ >>> neighbor.theta = 0.1
818829 >>> node = MockNode(0.2, [neighbor])
819830 >>> _op_RA(node, {"RA_epi_diff": 0.25, "RA_vf_amplification": 0.05})
820831 >>> round(node.EPI, 2)
821832 0.4
822- >>> node.vf # Amplified due to neighbor coherence
833+ >>> node.vf # Amplified due to neighbor coherence (canonical effect)
823834 1.05
824835 """
825836 # Get configuration factors
826837 diff = get_factor (gf , "RA_epi_diff" , 0.15 )
827838 vf_boost = get_factor (gf , "RA_vf_amplification" , 0.05 )
839+ phase_coupling = get_factor (gf , "RA_phase_coupling" , 0.10 ) # Canonical phase strengthening
828840
829- # Track network C(t) before RA if enabled
841+ # Track network C(t) before RA if enabled (optional telemetry)
830842 track_coherence = bool (node .graph .get ("TRACK_NETWORK_COHERENCE" , False ))
831843 c_before = None
832844 if track_coherence and hasattr (node , "G" ):
@@ -842,23 +854,75 @@ def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
842854 vf_before = node .vf
843855 epi_before = node .EPI
844856 kind_before = node .epi_kind
857+ theta_before = node .theta if hasattr (node , "theta" ) else None
845858
846859 # EPI diffusion (existing behavior)
847860 neigh , epi_bar = get_neighbor_epi (node )
848861 epi_bar_result , kind_result = _mix_epi_with_neighbors (node , diff , Glyph .RA )
849862
850- # νf amplification through resonance (NEW)
863+ # CANONICAL EFFECT 1: νf amplification through resonance
864+ # This is always active - it's a fundamental property of resonance per TNFR theory
851865 # Only amplify if neighbors have coherence to propagate
852866 if abs (epi_bar_result ) > 1e-9 and len (neigh ) > 0 :
853867 node .vf *= (1.0 + vf_boost )
854868
855- # Track identity preservation
869+ # CANONICAL EFFECT 2: Phase alignment strengthening
870+ # Per theory: "Phase alignment: Strengthens across propagation path"
871+ # Uses existing phase locking logic from IL operator (avoid duplication)
872+ phase_strengthened = False
873+ if len (neigh ) > 0 and hasattr (node , "theta" ) and hasattr (node , "G" ):
874+ try :
875+ # Use existing phase locking utility from IL operator
876+ from ..alias import get_attr
877+ from ..constants .aliases import ALIAS_THETA
878+ import cmath
879+ import math
880+
881+ # Get neighbor phases using existing utilities
882+ neighbor_phases = []
883+ for n in neigh :
884+ try :
885+ theta_n = float (get_attr (n , ALIAS_THETA , 0.0 ))
886+ neighbor_phases .append (theta_n )
887+ except (KeyError , ValueError , TypeError ):
888+ continue
889+
890+ if neighbor_phases :
891+ # Circular mean using the same method as in phase_coherence.py
892+ complex_phases = [cmath .exp (1j * theta ) for theta in neighbor_phases ]
893+ mean_real = sum (z .real for z in complex_phases ) / len (complex_phases )
894+ mean_imag = sum (z .imag for z in complex_phases ) / len (complex_phases )
895+ mean_complex = complex (mean_real , mean_imag )
896+ mean_phase = cmath .phase (mean_complex )
897+
898+ # Ensure positive phase [0, 2π]
899+ if mean_phase < 0 :
900+ mean_phase += 2 * math .pi
901+
902+ # Calculate phase difference (shortest arc)
903+ delta_theta = mean_phase - node .theta
904+ if delta_theta > math .pi :
905+ delta_theta -= 2 * math .pi
906+ elif delta_theta < - math .pi :
907+ delta_theta += 2 * math .pi
908+
909+ # Apply phase strengthening (move toward network mean)
910+ # Same approach as IL operator phase locking
911+ node .theta = node .theta + phase_coupling * delta_theta
912+
913+ # Normalize to [0, 2π]
914+ node .theta = node .theta % (2 * math .pi )
915+ phase_strengthened = True
916+ except (AttributeError , ImportError ):
917+ pass # Phase alignment not possible in this context
918+
919+ # Track identity preservation (canonical validation)
856920 identity_preserved = (
857921 (kind_result == kind_before or kind_result == Glyph .RA .value )
858922 and (float (epi_before ) * float (node .EPI ) >= 0 ) # Sign preserved
859923 )
860924
861- # Collect propagation metrics if enabled
925+ # Collect propagation metrics if enabled (optional telemetry)
862926 collect_metrics = bool (node .graph .get ("COLLECT_RA_METRICS" , False ))
863927 if collect_metrics :
864928 metrics = {
@@ -871,12 +935,15 @@ def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
871935 "epi_after" : float (node .EPI ),
872936 "vf_before" : vf_before ,
873937 "vf_after" : node .vf ,
938+ "phase_before" : theta_before ,
939+ "phase_after" : node .theta if hasattr (node , "theta" ) else None ,
940+ "phase_alignment_strengthened" : phase_strengthened ,
874941 }
875942 if "ra_metrics" not in node .graph :
876943 node .graph ["ra_metrics" ] = []
877944 node .graph ["ra_metrics" ].append (metrics )
878945
879- # Track network C(t) after RA if enabled
946+ # Track network C(t) after RA if enabled (optional telemetry)
880947 if track_coherence and c_before is not None and hasattr (node , "G" ):
881948 try :
882949 from ..metrics .coherence import compute_network_coherence
0 commit comments