@@ -1065,7 +1065,26 @@ def validate_mutation(G: "TNFRGraph", node: "NodeId") -> None:
10651065
10661066
10671067def validate_transition (G : "TNFRGraph" , node : "NodeId" ) -> None :
1068- """NAV - Transition requires ΔNFR and vf for controlled handoff.
1068+ """NAV - Comprehensive canonical preconditions for transition.
1069+
1070+ Validates comprehensive preconditions for NAV (Transition) operator according
1071+ to TNFR.pdf §2.3.11:
1072+
1073+ 1. **Minimum νf**: Structural frequency must exceed threshold
1074+ 2. **Controlled ΔNFR**: |ΔNFR| must be below maximum for stable transition
1075+ 3. **Regime validation**: Warns if transitioning from deep latency (EPI < 0.05)
1076+ 4. **Sequence compatibility** (optional): Warns if NAV applied after incompatible operators
1077+
1078+ Configuration Parameters
1079+ ------------------------
1080+ NAV_MIN_VF : float, default 0.01
1081+ Minimum structural frequency for transition
1082+ NAV_MAX_DNFR : float, default 1.0
1083+ Maximum |ΔNFR| for stable transition
1084+ NAV_STRICT_SEQUENCE_CHECK : bool, default False
1085+ Enable strict sequence compatibility checking
1086+ NAV_MIN_EPI_FROM_LATENCY : float, default 0.05
1087+ Minimum EPI for smooth transition from latency
10691088
10701089 Parameters
10711090 ----------
@@ -1077,16 +1096,107 @@ def validate_transition(G: "TNFRGraph", node: "NodeId") -> None:
10771096 Raises
10781097 ------
10791098 OperatorPreconditionError
1080- If node lacks necessary dynamics for transition
1099+ If node lacks necessary dynamics for transition:
1100+ - νf below minimum threshold
1101+ - |ΔNFR| exceeds maximum threshold (unstable state)
1102+
1103+ Warnings
1104+ --------
1105+ UserWarning
1106+ For suboptimal but valid conditions:
1107+ - Transitioning from deep latency (EPI < 0.05)
1108+ - NAV applied after incompatible operator (when strict checking enabled)
1109+
1110+ Notes
1111+ -----
1112+ NAV requires controlled ΔNFR to prevent instability during regime transitions.
1113+ High |ΔNFR| indicates significant reorganization pressure that could cause
1114+ structural disruption during transition. Apply IL (Coherence) first to reduce
1115+ ΔNFR before attempting regime transition.
1116+
1117+ Deep latency transitions (EPI < 0.05 after SHA) benefit from prior AL (Emission)
1118+ to provide smoother reactivation path.
1119+
1120+ Examples
1121+ --------
1122+ >>> from tnfr.structural import create_nfr
1123+ >>> from tnfr.operators.preconditions import validate_transition
1124+ >>>
1125+ >>> # Valid transition - controlled state
1126+ >>> G, node = create_nfr("test", epi=0.5, vf=0.6)
1127+ >>> G.nodes[node]['delta_nfr'] = 0.3 # Controlled ΔNFR
1128+ >>> validate_transition(G, node) # Passes
1129+ >>>
1130+ >>> # Invalid - ΔNFR too high
1131+ >>> G.nodes[node]['delta_nfr'] = 1.5
1132+ >>> validate_transition(G, node) # Raises OperatorPreconditionError
1133+
1134+ See Also
1135+ --------
1136+ Transition : NAV operator implementation
1137+ validate_coherence : IL preconditions for ΔNFR reduction
1138+ TNFR.pdf : §2.3.11 for NAV canonical requirements
10811139 """
1140+ import warnings
1141+
1142+ # 1. νf minimum (existing check - preserved for backward compatibility)
10821143 vf = _get_node_attr (G , node , ALIAS_VF )
10831144 min_vf = float (G .graph .get ("NAV_MIN_VF" , 0.01 ))
10841145 if vf < min_vf :
10851146 raise OperatorPreconditionError (
10861147 "Transition" ,
1087- f"Structural frequency too low for transition (νf={ vf :.3f} < { min_vf :.3f} )" ,
1148+ f"Structural frequency too low (νf={ vf :.3f} < { min_vf :.3f} )" ,
1149+ )
1150+
1151+ # 2. ΔNFR positivity and bounds check (NEW - CRITICAL)
1152+ dnfr = _get_node_attr (G , node , ALIAS_DNFR )
1153+ max_dnfr = float (G .graph .get ("NAV_MAX_DNFR" , 1.0 ))
1154+ if abs (dnfr ) > max_dnfr :
1155+ raise OperatorPreconditionError (
1156+ "Transition" ,
1157+ f"ΔNFR too high for stable transition (|ΔNFR|={ abs (dnfr ):.3f} > { max_dnfr } ). "
1158+ f"Apply IL (Coherence) first to reduce reorganization pressure." ,
1159+ )
1160+
1161+ # 3. Regime origin validation (NEW - WARNING)
1162+ latent = G .nodes [node ].get ("latent" , False )
1163+ epi = _get_node_attr (G , node , ALIAS_EPI )
1164+ min_epi_from_latency = float (G .graph .get ("NAV_MIN_EPI_FROM_LATENCY" , 0.05 ))
1165+
1166+ if latent and epi < min_epi_from_latency :
1167+ # Warning: transitioning from deep latency
1168+ warnings .warn (
1169+ f"Node { node } in deep latency (EPI={ epi :.3f} < { min_epi_from_latency :.3f} ). "
1170+ f"Consider AL (Emission) before NAV for smoother activation." ,
1171+ UserWarning ,
1172+ stacklevel = 2 ,
10881173 )
10891174
1175+ # 4. Sequence compatibility check (NEW - OPTIONAL)
1176+ if G .graph .get ("NAV_STRICT_SEQUENCE_CHECK" , False ):
1177+ history = G .nodes [node ].get ("glyph_history" , [])
1178+ if history :
1179+ from ..grammar import glyph_function_name
1180+
1181+ last_op = glyph_function_name (history [- 1 ]) if history else None
1182+
1183+ # NAV works best after stabilizers or generators
1184+ # Valid predecessors per TNFR.pdf §2.3.11 and AGENTS.md
1185+ valid_predecessors = {
1186+ "emission" , # AL → NAV (activation-transition)
1187+ "coherence" , # IL → NAV (stable-transition)
1188+ "silence" , # SHA → NAV (latency-transition)
1189+ "self_organization" , # THOL → NAV (bifurcation-transition)
1190+ }
1191+
1192+ if last_op and last_op not in valid_predecessors :
1193+ warnings .warn (
1194+ f"NAV applied after { last_op } . "
1195+ f"More coherent after: { ', ' .join (sorted (valid_predecessors ))} " ,
1196+ UserWarning ,
1197+ stacklevel = 2 ,
1198+ )
1199+
10901200
10911201def validate_recursivity (G : "TNFRGraph" , node : "NodeId" ) -> None :
10921202 """REMESH - Recursivity requires global network coherence threshold.
0 commit comments