TNFR Operator: Emission
Emission structural operator (AL) - Foundational activation of nodal resonance.
Physics: See AGENTS.md § Emission Grammar: UNIFIED_GRAMMAR_RULES.md
"""TNFR Operator: Emission
Emission structural operator (AL) - Foundational activation of nodal resonance.
**Physics**: See AGENTS.md § Emission
**Grammar**: UNIFIED_GRAMMAR_RULES.md
""" # flake8: noqa
from __future__ import annotations
import warnings
from typing import Any, ClassVar
from ..alias import get_attr
from ..config.operator_names import EMISSION
from ..constants.aliases import ALIAS_EPI
from ..dynamics.feedback import StructuralFeedbackLoop
from ..types import Glyph, TNFRGraph
from .definitions_base import Operator
class Emission(Operator):
"""Emission structural operator (AL).
Foundational activation of nodal resonance.
Activates structural symbol ``AL`` to initialise outward resonance around a
nascent node, initiating the first phase of structural reorganization.
TNFR Context
------------
In the Resonant Fractal Nature paradigm, Emission (AL) represents
the moment when a latent Primary Information Structure (EPI) begins
to emit coherence toward its surrounding network. This is not passive
information broadcast but active structural reorganization that boosts
the node's EPI (the form) from its latent state. Per the canonical
contract the EPI channel is the direct effect; νf settles at its basal
ν₀⁺ and ΔNFR/phase are left untouched.
**Key Elements:**
- **Coherent Emergence**: Node exists because it resonates;
AL starts resonance
- **Form Activation**: Raises EPI (Primary Information Structure)
- **Structural Frequency**: νf settles at its basal ν₀⁺ (not driven by AL)
- **Network Coupling**: Prepares node for phase alignment
- **Nodal Equation**: Drives ∂EPI/∂t ≥ 0 directly on the EPI channel
**Structural Irreversibility (TNFR.pdf §2.2.1):**
AL is inherently irreversible - once activated, it leaves a persistent
structural trace that cannot be undone. Each emission marks "time
zero" for the node and
establishes genealogical traceability:
- **emission_timestamp**: ISO 8601 UTC timestamp of first activation
- **_emission_activated**: Immutable boolean flag
- **_emission_origin**: Preserved original timestamp (never overwritten)
- **_structural_lineage**: Genealogical record with:
- ``origin``: First emission timestamp
- ``activation_count``: Number of AL applications
- ``derived_nodes``: list for tracking EPI emergence (future use)
- ``parent_emission``: Reference to parent node (future use)
Re-activation increments ``activation_count`` while preserving the
original timestamp.
Use Cases
---------
**Biomedical**: HRV coherence training, neural activation, therapy start
**Cognitive**: Idea germination, learning initiation, creative spark
**Social**: Team activation, community emergence, ritual initiation
Typical Sequences
-----------------
**AL → EN → IL → SHA**: Basic activation with stabilization and silence
**AL → RA**: Emission with immediate propagation
**AL → NAV → IL**: Phased activation with transition
Preconditions
-------------
- EPI < 0.8 (activation threshold)
- Node in latent or low-activation state
- Sufficient network coupling potential
Structural Effects
------------------
**EPI**: Increments (form activation) — the direct AL channel
**νf**: Untouched (settles at basal ν₀⁺)
**ΔNFR**: Untouched (AL does not impose reorganization pressure)
**θ**: Untouched
Examples
--------
>>> from tnfr.constants import DNFR_PRIMARY, EPI_PRIMARY, VF_PRIMARY
>>> from tnfr.dynamics import set_delta_nfr_hook
>>> from tnfr.structural import create_nfr, run_sequence
>>> from tnfr.operators.definitions import (
... Emission, Reception, Coherence, Silence
... )
>>> G, node = create_nfr("seed", epi=0.18, vf=1.0)
>>> run_sequence(
... G,
... node,
... [Emission(), Reception(), Coherence(), Silence()]
... )
>>> # Verify irreversibility
>>> assert G.nodes[node]["_emission_activated"] is True
>>> assert "emission_timestamp" in G.nodes[node]
>>> print(
... f"Activated at: {G.nodes[node]['emission_timestamp']}"
... ) # doctest: +SKIP
Activated at: 2025-11-07T15:47:10.209731+00:00
See Also
--------
Coherence : Stabilizes emitted structures
Resonance : Propagates emitted coherence
Reception : Receives external emissions
"""
__slots__ = ()
name: ClassVar[str] = EMISSION
glyph: ClassVar[Glyph] = Glyph.AL
def __call__(self, G: TNFRGraph, node: Any, **kw: Any) -> None:
"""Apply AL with structural irreversibility tracking.
Marks temporal irreversibility before delegating to grammar execution.
This ensures every emission leaves a persistent structural trace as
required by TNFR.pdf §2.2.1 (AL - Foundational emission).
Parameters
----------
G : TNFRGraph
Graph storing TNFR nodes and structural operator history.
node : Any
Identifier or object representing the target node within ``G``.
**kw : Any
Additional keyword arguments forwarded to the grammar layer.
"""
# Check and clear latency state if reactivating from silence
self._check_reactivation(G, node)
# Mark structural irreversibility BEFORE grammar execution
self._mark_irreversibility(G, node)
# Delegate to parent __call__ which applies grammar
super().__call__(G, node, **kw)
def _check_reactivation(self, G: TNFRGraph, node: Any) -> None:
"""Check and clear latency state when reactivating from silence.
When AL (Emission) is applied to a node in latent state (from SHA),
this validates the reactivation and clears the latency attributes.
Parameters
----------
G : TNFRGraph
Graph containing the node.
node : Any
Target node being reactivated.
Warnings
--------
- Warns if node is reactivated after extended silence (duration check)
- Warns if EPI has drifted from preserved value during silence
"""
if G.nodes[node].get("latent", False):
# Node is in latent state, reactivating from silence
silence_duration = G.nodes[node].get("silence_duration", 0.0)
# Get max silence duration threshold from graph config
max_silence = G.graph.get("MAX_SILENCE_DURATION", float("inf"))
# Validate reactivation timing
if silence_duration > max_silence:
warnings.warn(
f"Node {node} reactivating after extended silence "
f"(duration: {silence_duration:.2f}, "
f"max: {max_silence:.2f})",
stacklevel=3,
)
# Check EPI preservation integrity
preserved_epi = G.nodes[node].get("preserved_epi")
if preserved_epi is not None:
# get_attr already imported at module top
current_epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
epi_drift = abs(current_epi - preserved_epi)
# Enhanced tolerance for initial nodes and dynamic networks
# For initial nodes (preserved_epi ≈ 0), use absolute threshold
# For established nodes, use relative threshold
if abs(preserved_epi) < 1e-6: # Initial node
# Tolerance is an operational value (not derived)
# EPI_THRESHOLD ≈ 0.330 (operational tolerance)
# This respects TNFR nodal dynamics: ∂EPI/∂t = νf · ΔNFR
# Initial nodes can evolve according to canonical limits
tolerance = StructuralFeedbackLoop.EPI_THRESHOLD # ≈ 0.330
should_warn = epi_drift > tolerance
else: # Established node
# Use 1% relative tolerance for established nodes
tolerance = 0.01 * abs(preserved_epi)
should_warn = epi_drift > tolerance
if should_warn:
# Different message based on node type
node_type = (
"initial" if abs(preserved_epi) < 1e-6 else "established"
)
warnings.warn(
f"Node {node} ({node_type}) EPI drifted during silence "
f"(preserved: {preserved_epi:.3f}, "
f"current: {current_epi:.3f}, "
f"drift: {epi_drift:.3f}, tolerance: {tolerance:.3f})",
stacklevel=3,
)
# Clear latency state
del G.nodes[node]["latent"]
if "latency_start_time" in G.nodes[node]:
del G.nodes[node]["latency_start_time"]
if "preserved_epi" in G.nodes[node]:
del G.nodes[node]["preserved_epi"]
if "silence_duration" in G.nodes[node]:
del G.nodes[node]["silence_duration"]
if "was_initial_on_silence" in G.nodes[node]:
del G.nodes[node]["was_initial_on_silence"]
def _mark_irreversibility(self, G: TNFRGraph, node: Any) -> None:
"""Mark structural irreversibility for AL operator.
According to TNFR.pdf §2.2.1, AL (Emission) is structurally
irreversible:
"Una vez activado, AL reorganiza el campo. No puede deshacerse."
This method establishes:
- Temporal marker: ISO timestamp of first emission
- Activation flag: Persistent boolean indicating AL was activated
- Structural lineage: Genealogical record for EPI traceability
Parameters
----------
G : TNFRGraph
Graph containing the node.
node : Any
Target node for emission marking.
Notes
-----
On first activation:
- Sets emission_timestamp (ISO format)
- Sets _emission_activated = True (immutable)
- Sets _emission_origin (timestamp copy for preservation)
- Initializes _structural_lineage dict
On re-activation:
- Preserves original timestamp
- Increments activation_count in lineage
"""
from datetime import datetime, timezone
from ..alias import set_attr_str
from ..constants.aliases import ALIAS_EMISSION_TIMESTAMP
# Check if this is first activation
if "_emission_activated" not in G.nodes[node]:
# Generate UTC timestamp in ISO format
emission_timestamp = datetime.now(timezone.utc).isoformat()
# set canonical timestamp using alias system (string values)
set_attr_str(G.nodes[node], ALIAS_EMISSION_TIMESTAMP, emission_timestamp)
# set persistent activation flag (immutable marker)
G.nodes[node]["_emission_activated"] = True
# Preserve origin timestamp (never overwritten)
G.nodes[node]["_emission_origin"] = emission_timestamp
# Initialize structural lineage for genealogical traceability
G.nodes[node]["_structural_lineage"] = {
"origin": emission_timestamp,
"activation_count": 1,
"derived_nodes": [], # Nodes that emerge from this emission
"parent_emission": None, # If derived from another node
}
else:
# Re-activation: increment counter, keep original timestamp
if "_structural_lineage" in G.nodes[node]:
G.nodes[node]["_structural_lineage"]["activation_count"] += 1
def _validate_preconditions(self, G: TNFRGraph, node: Any) -> None:
"""Validate AL-specific preconditions with strict canonical checks.
Implements TNFR.pdf §2.2.1 precondition validation:
1. EPI < latent threshold (node in nascent/latent state)
2. νf > basal threshold (sufficient structural frequency)
3. Network connectivity check (warning for isolated nodes)
Raises
------
ValueError
If EPI too high or νf too low for emission
"""
from .preconditions.emission import validate_emission_strict
validate_emission_strict(G, node)
def _collect_metrics(
self, G: TNFRGraph, node: Any, state_before: dict[str, Any]
) -> dict[str, Any]:
"""Collect AL-specific metrics."""
from .metrics import emission_metrics
return emission_metrics(
G,
node,
state_before["epi"],
state_before["vf"],
)