Skip to content

Commit d9b2521

Browse files
authored
Merge pull request #2870 from fermga/copilot/validate-bifurcation-threshold
Validate THOL bifurcation threshold (∂²EPI/∂t² > τ) in preconditions
2 parents 5ab48f9 + e88e52d commit d9b2521

File tree

2 files changed

+411
-0
lines changed

2 files changed

+411
-0
lines changed

src/tnfr/operators/preconditions/__init__.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,23 @@ def validate_self_organization(G: "TNFRGraph", node: "NodeId") -> None:
714714
3. Structural reorganization capacity (νf > 0)
715715
4. Network connectivity for metabolism (degree ≥ 1)
716716
5. EPI history for acceleration computation (≥3 points)
717+
6. **NEW**: Bifurcation threshold check (∂²EPI/∂t² vs τ) with telemetry
717718
718719
Also detects and records the destabilizer type that enabled this self-organization
719720
for telemetry and structural tracing purposes.
720721
722+
**Bifurcation Threshold Validation (∂²EPI/∂t² > τ):**
723+
724+
According to TNFR.pdf §2.2.10, THOL bifurcation occurs only when structural
725+
acceleration exceeds threshold τ. This function now explicitly validates this
726+
condition and sets telemetry flags:
727+
728+
- If ∂²EPI/∂t² > τ: Bifurcation will occur (normal THOL behavior)
729+
- If ∂²EPI/∂t² ≤ τ: THOL executes but no sub-EPIs generated (warning logged)
730+
731+
The validation is NON-BLOCKING (warning only) because THOL can meaningfully
732+
execute without bifurcation - it still applies coherence and metabolic effects.
733+
721734
Parameters
722735
----------
723736
G : TNFRGraph
@@ -749,6 +762,10 @@ def validate_self_organization(G: "TNFRGraph", node: "NodeId") -> None:
749762
Allow isolated nodes for internal-only bifurcation
750763
THOL_METABOLIC_ENABLED : bool, default True
751764
Require metabolic network context
765+
BIFURCATION_THRESHOLD_TAU : float, default 0.1
766+
Bifurcation threshold for ∂²EPI/∂t² (see THOL_BIFURCATION_THRESHOLD)
767+
THOL_BIFURCATION_THRESHOLD : float, default 0.1
768+
Alias for BIFURCATION_THRESHOLD_TAU (operator-specific config)
752769
"""
753770
import logging
754771

@@ -821,6 +838,53 @@ def validate_self_organization(G: "TNFRGraph", node: "NodeId") -> None:
821838
# R4 Extended: Detect and record destabilizer type for telemetry
822839
_record_destabilizer_context(G, node, logger)
823840

841+
# NEW: Bifurcation threshold validation (∂²EPI/∂t² > τ)
842+
# This is NON-BLOCKING - THOL can execute without bifurcation
843+
# Note: SelfOrganization uses its own _compute_epi_acceleration which looks at 'epi_history'
844+
# while compute_d2epi_dt2 looks at '_epi_history'. We check both for compatibility.
845+
846+
# Get EPI history from node (try both keys for compatibility)
847+
history = G.nodes[node].get("_epi_history") or G.nodes[node].get("epi_history", [])
848+
849+
# Compute d²EPI/dt² directly from history (same logic as both functions)
850+
if len(history) >= 3:
851+
epi_t = float(history[-1])
852+
epi_t1 = float(history[-2])
853+
epi_t2 = float(history[-3])
854+
d2_epi_signed = epi_t - 2.0 * epi_t1 + epi_t2
855+
d2_epi = abs(d2_epi_signed)
856+
else:
857+
# Insufficient history - should have been caught earlier, but handle gracefully
858+
d2_epi = 0.0
859+
860+
# Get bifurcation threshold from graph configuration
861+
# Try BIFURCATION_THRESHOLD_TAU first (canonical), then THOL_BIFURCATION_THRESHOLD
862+
tau = G.graph.get("BIFURCATION_THRESHOLD_TAU")
863+
if tau is None:
864+
tau = float(G.graph.get("THOL_BIFURCATION_THRESHOLD", 0.1))
865+
else:
866+
tau = float(tau)
867+
868+
# Check if bifurcation threshold will be exceeded
869+
if d2_epi <= tau:
870+
# Log warning but allow execution - THOL can be meaningful without bifurcation
871+
logger.warning(
872+
f"Node {node}: THOL applied with ∂²EPI/∂t²={d2_epi:.3f} ≤ τ={tau:.3f}. "
873+
f"No bifurcation will occur (empty THOL window expected). "
874+
f"Sub-EPIs will not be generated. "
875+
f"Consider stronger destabilizer (OZ, VAL) to increase acceleration."
876+
)
877+
# Set telemetry flag for post-hoc analysis
878+
G.nodes[node]["_thol_no_bifurcation_expected"] = True
879+
else:
880+
# Clear flag if previously set
881+
G.nodes[node]["_thol_no_bifurcation_expected"] = False
882+
logger.debug(
883+
f"Node {node}: THOL bifurcation threshold exceeded "
884+
f"(∂²EPI/∂t²={d2_epi:.3f} > τ={tau:.3f}). "
885+
f"Sub-EPI generation expected."
886+
)
887+
824888

825889
def _record_destabilizer_context(
826890
G: "TNFRGraph", node: "NodeId", logger: "logging.Logger"

0 commit comments

Comments
 (0)