Skip to content

Commit 19119d2

Browse files
Copilotfermga
andcommitted
Implement U4b validation: strict IL precedence + destabilizer checks for ZHIR
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent b83d387 commit 19119d2

File tree

4 files changed

+646
-4
lines changed

4 files changed

+646
-4
lines changed

src/tnfr/operators/grammar.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,43 @@ def glyph_function_name(
9797
Parameters
9898
----------
9999
val : Glyph | str | None
100-
Glyph or string to convert
100+
Glyph enum, glyph string value ('IL', 'OZ'), or function name to convert
101101
default : str | None, optional
102102
Default value if conversion fails
103103
104104
Returns
105105
-------
106106
str | None
107107
Canonical function name or default
108+
109+
Notes
110+
-----
111+
Glyph enum inherits from str, so we must check for Enum type
112+
BEFORE checking isinstance(val, str), otherwise Glyph instances
113+
will be returned unchanged instead of being converted.
114+
115+
The function handles three input types:
116+
1. Glyph enum (e.g., Glyph.IL) → function name (e.g., 'coherence')
117+
2. Glyph string value (e.g., 'IL') → function name (e.g., 'coherence')
118+
3. Function name (e.g., 'coherence') → returned as-is
108119
"""
109120
if val is None:
110121
return default
122+
# Check for Glyph/Enum BEFORE str (Glyph inherits from str)
123+
if isinstance(val, Enum):
124+
return GLYPH_TO_FUNCTION.get(val, default)
111125
if isinstance(val, str):
126+
# Check if it's a glyph string value ('IL', 'OZ', etc)
127+
# Build reverse lookup on first use
128+
if not hasattr(glyph_function_name, '_glyph_value_map'):
129+
glyph_function_name._glyph_value_map = {
130+
g.value: func for g, func in GLYPH_TO_FUNCTION.items()
131+
}
132+
# Try to convert glyph value to function name
133+
func_name = glyph_function_name._glyph_value_map.get(val)
134+
if func_name:
135+
return func_name
136+
# Otherwise assume it's already a function name
112137
return val
113138
return GLYPH_TO_FUNCTION.get(val, default)
114139

src/tnfr/operators/preconditions/__init__.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,8 @@ def validate_mutation(G: "TNFRGraph", node: "NodeId") -> None:
994994
995995
1. Minimum νf for phase transformation capacity
996996
2. **∂EPI/∂t > ξ: Structural change velocity exceeds threshold**
997-
3. Stable base (IL precedence validated by grammar U4b)
997+
3. **U4b Part 1: Prior IL (Coherence) for stable transformation base**
998+
4. **U4b Part 2: Recent destabilizer (~3 ops) for threshold energy**
998999
9991000
Also detects and records the destabilizer type that enabled this mutation
10001001
for telemetry and structural tracing purposes.
@@ -1009,7 +1010,20 @@ def validate_mutation(G: "TNFRGraph", node: "NodeId") -> None:
10091010
Raises
10101011
------
10111012
OperatorPreconditionError
1012-
If node state is unsuitable for mutation
1013+
If node state is unsuitable for mutation or U4b requirements not met
1014+
1015+
Configuration Parameters
1016+
------------------------
1017+
ZHIR_MIN_VF : float, default 0.05
1018+
Minimum structural frequency for phase transformation
1019+
ZHIR_THRESHOLD_XI : float, default 0.1
1020+
Threshold for ∂EPI/∂t velocity check
1021+
VALIDATE_OPERATOR_PRECONDITIONS : bool, default False
1022+
Enable strict U4b validation (IL precedence + destabilizer requirement)
1023+
ZHIR_REQUIRE_IL_PRECEDENCE : bool, default False
1024+
Require prior IL even if VALIDATE_OPERATOR_PRECONDITIONS=False
1025+
ZHIR_REQUIRE_DESTABILIZER : bool, default False
1026+
Require recent destabilizer even if VALIDATE_OPERATOR_PRECONDITIONS=False
10131027
10141028
Notes
10151029
-----
@@ -1023,6 +1037,14 @@ def validate_mutation(G: "TNFRGraph", node: "NodeId") -> None:
10231037
- If ∂EPI/∂t ≥ ξ: Logs success, sets validation flag
10241038
- If insufficient history: Logs warning, cannot verify
10251039
1040+
**U4b Validation (Grammar Rule)**:
1041+
1042+
When strict validation enabled (VALIDATE_OPERATOR_PRECONDITIONS=True):
1043+
- **Part 1**: Prior IL (Coherence) required for stable base
1044+
- **Part 2**: Recent destabilizer (OZ/VAL/etc) required within ~3 ops
1045+
1046+
Without strict validation: Only telemetry/warnings logged.
1047+
10261048
This function implements R4 Extended telemetry by analyzing the glyph_history
10271049
to determine which destabilizer (strong/moderate/weak) enabled the mutation.
10281050
The destabilizer context is stored in node metadata for structural tracing.
@@ -1075,9 +1097,53 @@ def validate_mutation(G: "TNFRGraph", node: "NodeId") -> None:
10751097
)
10761098
G.nodes[node]["_zhir_threshold_unknown"] = True
10771099

1100+
# U4b Part 1: IL Precedence Check (stable base for transformation)
1101+
# Check if strict validation enabled
1102+
strict_validation = bool(G.graph.get("VALIDATE_OPERATOR_PRECONDITIONS", False))
1103+
require_il = strict_validation or bool(G.graph.get("ZHIR_REQUIRE_IL_PRECEDENCE", False))
1104+
1105+
if require_il:
1106+
# Get glyph history
1107+
glyph_history = G.nodes[node].get("glyph_history", [])
1108+
1109+
# Import glyph_function_name to convert glyphs to operator names
1110+
from ..grammar import glyph_function_name
1111+
1112+
# Convert history to operator names
1113+
history_names = [glyph_function_name(g) for g in glyph_history]
1114+
1115+
# Check for prior IL (coherence)
1116+
il_found = "coherence" in history_names
1117+
1118+
if not il_found:
1119+
raise OperatorPreconditionError(
1120+
"Mutation",
1121+
"U4b violation: ZHIR requires prior IL (Coherence) for stable transformation base. "
1122+
"Apply Coherence before mutation sequence. "
1123+
f"Recent history: {history_names[-5:] if len(history_names) > 5 else history_names}"
1124+
)
1125+
1126+
logger.debug(f"Node {node}: ZHIR IL precedence satisfied (prior Coherence found)")
1127+
1128+
# U4b Part 2: Recent Destabilizer Check (threshold energy for bifurcation)
10781129
# R4 Extended: Detect and record destabilizer type for telemetry
1079-
# This provides structural traceability for bifurcation events
10801130
_record_destabilizer_context(G, node, logger)
1131+
1132+
# If strict validation enabled, enforce destabilizer requirement
1133+
require_destabilizer = strict_validation or bool(G.graph.get("ZHIR_REQUIRE_DESTABILIZER", False))
1134+
1135+
if require_destabilizer:
1136+
context = G.nodes[node].get("_mutation_context", {})
1137+
destabilizer_found = context.get("destabilizer_operator")
1138+
1139+
if destabilizer_found is None:
1140+
recent_history = context.get("recent_history", [])
1141+
raise OperatorPreconditionError(
1142+
"Mutation",
1143+
"U4b violation: ZHIR requires recent destabilizer (OZ/VAL/etc) within ~3 ops. "
1144+
f"Recent history: {recent_history}. "
1145+
"Apply Dissonance or Expansion to elevate ΔNFR first."
1146+
)
10811147

10821148

10831149
def validate_transition(G: "TNFRGraph", node: "NodeId") -> None:
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""Unified TNFR Grammar - Facade to GrammarValidator.
2+
3+
This module provides a clean facade to the canonical grammar validation
4+
implemented in grammar.py. It exports the unified grammar constraints (U1-U4)
5+
and the validator for use in tests and applications.
6+
7+
All grammar rules derive inevitably from TNFR physics:
8+
- U1: STRUCTURAL INITIATION & CLOSURE
9+
- U2: CONVERGENCE & BOUNDEDNESS
10+
- U3: RESONANT COUPLING
11+
- U4: BIFURCATION DYNAMICS (U4a: triggers, U4b: transformers)
12+
13+
References
14+
----------
15+
- UNIFIED_GRAMMAR_RULES.md: Complete physics derivations
16+
- AGENTS.md: Canonical invariants and formal contracts
17+
- TNFR.pdf: Nodal equation and bifurcation theory
18+
19+
Notes
20+
-----
21+
This is a facade module that re-exports from grammar.py for clean imports.
22+
The actual implementation is in grammar.py::GrammarValidator.
23+
"""
24+
25+
from __future__ import annotations
26+
27+
from typing import TYPE_CHECKING, List
28+
29+
if TYPE_CHECKING:
30+
from .definitions import Operator
31+
32+
# Import validator class and rename for clarity
33+
from .grammar import GrammarValidator as UnifiedGrammarValidator
34+
35+
# Import operator sets (canonical definitions from grammar.py)
36+
from .grammar import (
37+
BIFURCATION_HANDLERS,
38+
BIFURCATION_TRIGGERS,
39+
CLOSURES,
40+
COUPLING_RESONANCE,
41+
DESTABILIZERS,
42+
GENERATORS,
43+
STABILIZERS,
44+
TRANSFORMERS,
45+
)
46+
47+
# Import validation functions
48+
from .grammar import validate_grammar
49+
50+
__all__ = [
51+
# Validator class
52+
"UnifiedGrammarValidator",
53+
# Convenience function
54+
"validate_unified",
55+
# Operator sets (U1-U4 categories)
56+
"GENERATORS",
57+
"CLOSURES",
58+
"STABILIZERS",
59+
"DESTABILIZERS",
60+
"COUPLING_RESONANCE",
61+
"BIFURCATION_TRIGGERS",
62+
"BIFURCATION_HANDLERS",
63+
"TRANSFORMERS",
64+
]
65+
66+
67+
def validate_unified(
68+
sequence: List["Operator"],
69+
epi_initial: float = 0.0,
70+
) -> bool:
71+
"""Validate sequence using unified TNFR grammar (U1-U4).
72+
73+
Convenience function that returns only boolean result.
74+
For detailed messages, use UnifiedGrammarValidator.validate().
75+
76+
Parameters
77+
----------
78+
sequence : List[Operator]
79+
Sequence of operators to validate
80+
epi_initial : float, optional
81+
Initial EPI value (default: 0.0)
82+
83+
Returns
84+
-------
85+
bool
86+
True if sequence satisfies all U1-U4 constraints
87+
88+
Examples
89+
--------
90+
>>> from tnfr.operators.definitions import Emission, Coherence, Silence
91+
>>> from tnfr.operators.unified_grammar import validate_unified
92+
>>> ops = [Emission(), Coherence(), Silence()]
93+
>>> validate_unified(ops, epi_initial=0.0) # doctest: +SKIP
94+
True
95+
96+
Notes
97+
-----
98+
This validator is 100% physics-based. All constraints emerge from:
99+
- Nodal equation: ∂EPI/∂t = νf · ΔNFR(t)
100+
- TNFR invariants (AGENTS.md)
101+
- Formal operator contracts
102+
103+
See UNIFIED_GRAMMAR_RULES.md for complete derivations.
104+
"""
105+
return validate_grammar(sequence, epi_initial)

0 commit comments

Comments
 (0)