@@ -2720,6 +2720,13 @@ def __call__(self, G: TNFRGraph, node: Any, **kw: Any) -> None:
27202720 if d2_epi > tau :
27212721 self ._spawn_sub_epi (G , node , d2_epi = d2_epi , tau = tau )
27222722
2723+ # CANONICAL VALIDATION: Verify collective coherence of sub-EPIs
2724+ # When THOL creates multiple sub-EPIs, they must form a coherent ensemble
2725+ # that preserves the structural identity of the parent node (TNFR Manual §2.2.10)
2726+ # Always validate if node has sub-EPIs (whether created now or previously)
2727+ if G .nodes [node ].get ("sub_epis" ):
2728+ self ._validate_collective_coherence (G , node )
2729+
27232730 def _compute_epi_acceleration (self , G : TNFRGraph , node : Any ) -> float :
27242731 """Calculate ∂²EPI/∂t² from node's EPI history.
27252732
@@ -2947,6 +2954,71 @@ def _create_sub_node(
29472954
29482955 return sub_node_id
29492956
2957+ def _validate_collective_coherence (self , G : TNFRGraph , node : Any ) -> None :
2958+ """Validate collective coherence of sub-EPI ensemble after bifurcation.
2959+
2960+ When THOL creates multiple sub-EPIs, they must form a coherent ensemble
2961+ that preserves the structural identity of the parent node. This validation
2962+ ensures the emergent sub-structures maintain structural alignment.
2963+
2964+ Parameters
2965+ ----------
2966+ G : TNFRGraph
2967+ Graph containing the node
2968+ node : Any
2969+ Node that underwent bifurcation
2970+
2971+ Notes
2972+ -----
2973+ TNFR Canonical Principle (TNFR Manual §2.2.10):
2974+ "THOL reorganiza la forma desde dentro, en respuesta a la coherencia
2975+ vibracional del campo. La autoorganización es resonancia estructurada
2976+ desde el interior del nodo."
2977+
2978+ Implication: Sub-EPIs are not random fragments but coherent structures
2979+ that emerge from internal resonance.
2980+
2981+ This method:
2982+ 1. Computes collective coherence of sub-EPI ensemble
2983+ 2. Stores coherence value for telemetry
2984+ 3. Logs warning if coherence < threshold
2985+ 4. Records event for analysis
2986+
2987+ Does NOT fail the operation - allows monitoring and analysis of
2988+ low-coherence bifurcations for research purposes.
2989+ """
2990+ import logging
2991+ from .metabolism import compute_subepi_collective_coherence
2992+
2993+ # Compute collective coherence
2994+ coherence = compute_subepi_collective_coherence (G , node )
2995+
2996+ # Store for telemetry (always store, even if 0.0 for single/no sub-EPIs)
2997+ G .nodes [node ]["_thol_collective_coherence" ] = coherence
2998+
2999+ # Get threshold from graph config
3000+ min_coherence = float (G .graph .get ("THOL_MIN_COLLECTIVE_COHERENCE" , 0.3 ))
3001+
3002+ # Validate against threshold (only warn if we have multiple sub-EPIs)
3003+ sub_epis = G .nodes [node ].get ("sub_epis" , [])
3004+ if len (sub_epis ) >= 2 and coherence < min_coherence :
3005+ # Log warning (but don't fail - allow monitoring)
3006+ logger = logging .getLogger (__name__ )
3007+ logger .warning (
3008+ f"Node { node } : THOL collective coherence ({ coherence :.3f} ) < "
3009+ f"threshold ({ min_coherence } ). Sub-EPIs may be fragmenting. "
3010+ f"Sub-EPI count: { len (sub_epis )} ."
3011+ )
3012+
3013+ # Record event for analysis
3014+ events = G .graph .setdefault ("thol_coherence_warnings" , [])
3015+ events .append ({
3016+ "node" : node ,
3017+ "coherence" : coherence ,
3018+ "threshold" : min_coherence ,
3019+ "sub_epi_count" : len (sub_epis ),
3020+ })
3021+
29503022 def _validate_preconditions (self , G : TNFRGraph , node : Any ) -> None :
29513023 """Validate THOL-specific preconditions."""
29523024 from .preconditions import validate_self_organization
0 commit comments