@@ -530,10 +530,14 @@ def validate_contraction(G: "TNFRGraph", node: "NodeId") -> None:
530530
531531
532532def validate_self_organization (G : "TNFRGraph" , node : "NodeId" ) -> None :
533- """THOL - Self-organization requires minimum EPI, positive ΔNFR, and connectivity .
533+ """THOL - Enhanced validation: connectivity, metabolic context, acceleration .
534534
535- T'HOL implements structural metabolism and bifurcation. Preconditions ensure
536- sufficient structure and reorganization pressure for self-organization.
535+ Self-organization requires:
536+ 1. Sufficient EPI for bifurcation
537+ 2. Positive reorganization pressure (ΔNFR > 0)
538+ 3. Structural reorganization capacity (νf > 0)
539+ 4. Network connectivity for metabolism (degree ≥ 1)
540+ 5. EPI history for acceleration computation (≥3 points)
537541
538542 Also detects and records the destabilizer type that enabled this self-organization
539543 for telemetry and structural tracing purposes.
@@ -548,47 +552,96 @@ def validate_self_organization(G: "TNFRGraph", node: "NodeId") -> None:
548552 Raises
549553 ------
550554 OperatorPreconditionError
551- If EPI is too low for bifurcation, or if ΔNFR is non-positive
552-
553- Warnings
554- --------
555- Warns if node is isolated - bifurcation may not propagate through network
555+ If any structural requirement is not met
556556
557557 Notes
558558 -----
559559 This function implements R4 Extended telemetry by analyzing the glyph_history
560560 to determine which destabilizer (strong/moderate/weak) enabled the self-organization.
561+
562+ Configuration Parameters
563+ ------------------------
564+ THOL_MIN_EPI : float, default 0.2
565+ Minimum EPI for bifurcation
566+ THOL_MIN_VF : float, default 0.1
567+ Minimum structural frequency for reorganization
568+ THOL_MIN_DEGREE : int, default 1
569+ Minimum network connectivity
570+ THOL_MIN_HISTORY_LENGTH : int, default 3
571+ Minimum EPI history for acceleration computation
572+ THOL_ALLOW_ISOLATED : bool, default False
573+ Allow isolated nodes for internal-only bifurcation
574+ THOL_METABOLIC_ENABLED : bool, default True
575+ Require metabolic network context
561576 """
562577 import logging
563- import warnings
564578
565579 logger = logging .getLogger (__name__ )
566580
567581 epi = _get_node_attr (G , node , ALIAS_EPI )
568582 dnfr = _get_node_attr (G , node , ALIAS_DNFR )
583+ vf = _get_node_attr (G , node , ALIAS_VF )
569584
570- # EPI must be sufficient for bifurcation
585+ # 1. EPI sufficiency
571586 min_epi = float (G .graph .get ("THOL_MIN_EPI" , 0.2 ))
572587 if epi < min_epi :
573588 raise OperatorPreconditionError (
574589 "Self-organization" ,
575590 f"EPI too low for bifurcation (EPI={ epi :.3f} < { min_epi :.3f} )" ,
576591 )
577592
578- # ΔNFR must be positive (reorganization pressure required)
593+ # 2. Reorganization pressure
579594 if dnfr <= 0 :
580595 raise OperatorPreconditionError (
581596 "Self-organization" ,
582597 f"ΔNFR non-positive, no reorganization pressure (ΔNFR={ dnfr :.3f} )" ,
583598 )
584599
585- # Warn if node is isolated (bifurcation won't propagate)
586- if G .degree (node ) == 0 :
587- warnings .warn (
588- f"Node { node } is isolated - bifurcation may not propagate through network" ,
589- stacklevel = 3 ,
600+ # 3. Structural frequency validation
601+ min_vf = float (G .graph .get ("THOL_MIN_VF" , 0.1 ))
602+ if vf < min_vf :
603+ raise OperatorPreconditionError (
604+ "Self-organization" ,
605+ f"Structural frequency too low for reorganization (νf={ vf :.3f} < { min_vf :.3f} )" ,
606+ )
607+
608+ # 4. Connectivity requirement (ELEVATED FROM WARNING)
609+ min_degree = int (G .graph .get ("THOL_MIN_DEGREE" , 1 ))
610+ node_degree = G .degree (node )
611+
612+ # Allow isolated THOL if explicitly enabled
613+ allow_isolated = bool (G .graph .get ("THOL_ALLOW_ISOLATED" , False ))
614+
615+ if node_degree < min_degree and not allow_isolated :
616+ raise OperatorPreconditionError (
617+ "Self-organization" ,
618+ f"Node insufficiently connected for network metabolism "
619+ f"(degree={ node_degree } < { min_degree } ). "
620+ f"Set THOL_ALLOW_ISOLATED=True to enable internal-only bifurcation." ,
590621 )
591622
623+ # 5. EPI history validation (for d²EPI/dt² computation)
624+ epi_history = G .nodes [node ].get ("epi_history" , [])
625+ min_history_length = int (G .graph .get ("THOL_MIN_HISTORY_LENGTH" , 3 ))
626+
627+ if len (epi_history ) < min_history_length :
628+ raise OperatorPreconditionError (
629+ "Self-organization" ,
630+ f"Insufficient EPI history for acceleration computation "
631+ f"(have { len (epi_history )} , need ≥{ min_history_length } ). "
632+ f"Apply operators to build history before THOL." ,
633+ )
634+
635+ # 6. Metabolic context validation (if metabolism enabled)
636+ if G .graph .get ("THOL_METABOLIC_ENABLED" , True ):
637+ # If network metabolism is expected, verify neighbors exist
638+ if node_degree == 0 :
639+ raise OperatorPreconditionError (
640+ "Self-organization" ,
641+ "Metabolic mode enabled but node is isolated. "
642+ "Disable THOL_METABOLIC_ENABLED or add network connections." ,
643+ )
644+
592645 # R4 Extended: Detect and record destabilizer type for telemetry
593646 _record_destabilizer_context (G , node , logger )
594647
0 commit comments