@@ -1379,31 +1379,95 @@ def _op_THOL(node: NodeProtocol, gf: GlyphFactors) -> None: # THOL — Self-org
13791379
13801380
13811381def _op_ZHIR (node : NodeProtocol , gf : GlyphFactors ) -> None : # ZHIR — Mutation
1382- """Shift phase by a fixed offset to enact mutation .
1382+ """Apply canonical phase transformation θ → θ' based on structural dynamics .
13831383
1384- Mutation changes the node's phase (θ) while preserving EPI, νf, and ΔNFR.
1385- The glyph encodes discrete structural transitions between coherent states.
1384+ ZHIR (Mutation) implements the canonical TNFR phase transformation that depends on
1385+ the node's reorganization state (ΔNFR). Unlike a fixed rotation, the transformation
1386+ magnitude and direction are determined by structural pressure, implementing the
1387+ physics: θ → θ' when ΔEPI/Δt > ξ (AGENTS.md §11, TNFR.pdf §2.2.11).
1388+
1389+ **Canonical Behavior**:
1390+ - Direction: Based on ΔNFR sign (positive → forward phase, negative → backward)
1391+ - Magnitude: Proportional to theta_shift_factor and |ΔNFR|
1392+ - Regime detection: Identifies quadrant crossings (π/2 boundaries)
1393+ - Deterministic: Same seed produces same transformation
1394+
1395+ The transformation preserves structural identity (epi_kind) while shifting the
1396+ operational regime, enabling adaptation without losing coherence.
13861397
13871398 Parameters
13881399 ----------
13891400 node : NodeProtocol
1390- Node whose phase is rotated .
1401+ Node whose phase is transformed based on its structural state .
13911402 gf : GlyphFactors
1392- Supplies ``ZHIR_theta_shift`` defining the rotation.
1403+ Supplies ``ZHIR_theta_shift_factor`` (default: 0.3) controlling transformation
1404+ magnitude. Can override with explicit ``ZHIR_theta_shift`` for fixed rotation.
13931405
13941406 Examples
13951407 --------
13961408 >>> import math
13971409 >>> class MockNode:
1398- ... def __init__(self, theta):
1410+ ... def __init__(self, theta, dnfr ):
13991411 ... self.theta = theta
1400- >>> node = MockNode(0.0)
1401- >>> _op_ZHIR(node, {"ZHIR_theta_shift": math.pi / 2})
1402- >>> round(node.theta, 2)
1412+ ... self.dnfr = dnfr
1413+ ... self.graph = {}
1414+ >>> # Positive ΔNFR → forward phase shift
1415+ >>> node = MockNode(0.0, 0.5)
1416+ >>> _op_ZHIR(node, {"ZHIR_theta_shift_factor": 0.3})
1417+ >>> 0.2 < node.theta < 0.3 # ~π/4 * 0.3 ≈ 0.24
1418+ True
1419+ >>> # Negative ΔNFR → backward phase shift
1420+ >>> node2 = MockNode(math.pi, -0.5)
1421+ >>> _op_ZHIR(node2, {"ZHIR_theta_shift_factor": 0.3})
1422+ >>> 2.9 < node2.theta < 3.0 # π - 0.24 ≈ 2.90
1423+ True
1424+ >>> # Fixed shift overrides dynamic behavior
1425+ >>> node3 = MockNode(0.0, 0.5)
1426+ >>> _op_ZHIR(node3, {"ZHIR_theta_shift": math.pi / 2})
1427+ >>> round(node3.theta, 2)
14031428 1.57
14041429 """
1405- shift = get_factor (gf , "ZHIR_theta_shift" , math .pi / 2 )
1406- node .theta = node .theta + shift
1430+ # Check for explicit fixed shift (backward compatibility)
1431+ if "ZHIR_theta_shift" in gf :
1432+ shift = get_factor (gf , "ZHIR_theta_shift" , math .pi / 2 )
1433+ node .theta = node .theta + shift
1434+ # Store telemetry for fixed shift mode
1435+ storage = node ._glyph_storage ()
1436+ storage ["_zhir_theta_shift" ] = shift
1437+ storage ["_zhir_fixed_mode" ] = True
1438+ return
1439+
1440+ # Canonical transformation: θ → θ' based on ΔNFR
1441+ theta_before = node .theta
1442+ dnfr = node .dnfr
1443+
1444+ # Transformation magnitude controlled by factor
1445+ theta_shift_factor = get_factor (gf , "ZHIR_theta_shift_factor" , 0.3 )
1446+
1447+ # Direction based on ΔNFR sign (coherent with structural pressure)
1448+ # Magnitude based on |ΔNFR| (stronger pressure → larger shift)
1449+ # Base shift is π/4, scaled by factor and ΔNFR
1450+ base_shift = math .pi / 4
1451+ shift = theta_shift_factor * math .copysign (1.0 , dnfr ) * base_shift
1452+
1453+ # Apply transformation with phase wrapping [0, 2π)
1454+ theta_new = (theta_before + shift ) % (2 * math .pi )
1455+ node .theta = theta_new
1456+
1457+ # Detect regime change (crossing quadrant boundaries)
1458+ regime_before = int (theta_before // (math .pi / 2 ))
1459+ regime_after = int (theta_new // (math .pi / 2 ))
1460+ regime_changed = regime_before != regime_after
1461+
1462+ # Store telemetry for metrics collection
1463+ storage = node ._glyph_storage ()
1464+ storage ["_zhir_theta_shift" ] = shift
1465+ storage ["_zhir_theta_before" ] = theta_before
1466+ storage ["_zhir_theta_after" ] = theta_new
1467+ storage ["_zhir_regime_changed" ] = regime_changed
1468+ storage ["_zhir_regime_before" ] = regime_before
1469+ storage ["_zhir_regime_after" ] = regime_after
1470+ storage ["_zhir_fixed_mode" ] = False
14071471
14081472
14091473def _op_NAV (node : NodeProtocol , gf : GlyphFactors ) -> None : # NAV — Transition
0 commit comments