Skip to content

Commit 6c56085

Browse files
Copilotfermga
andcommitted
Implement RC3 (Phase Verification) as canonical grammar rule
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent b019481 commit 6c56085

File tree

2 files changed

+108
-23
lines changed

2 files changed

+108
-23
lines changed

src/tnfr/operators/canonical_grammar.py

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Canonical grammar validator - Pure physics from nodal equation.
22
33
This module implements grammar validation that emerges EXCLUSIVELY from
4-
the nodal equation ∂EPI/∂t = νf · ΔNFR(t), without organizational conventions.
4+
the nodal equation ∂EPI/∂t = νf · ΔNFR(t), TNFR invariants, and formal contracts.
55
66
Canonical Rules (Inevitable from Physics)
77
------------------------------------------
@@ -11,6 +11,12 @@
1111
RC2: Convergence - If sequence has destabilizers, must include stabilizer
1212
Reason: ∫νf·ΔNFR dt must converge (convergence theorem)
1313
14+
RC3: Phase Verification - Coupling/resonance requires phase compatibility
15+
Reason: AGENTS.md Invariant #5 + resonance physics (φᵢ ≈ φⱼ)
16+
17+
RC4: Bifurcation Limits - If ∂²EPI/∂t² > τ, bifurcation handler required
18+
Reason: AGENTS.md Contract OZ + bifurcation theory (conditional)
19+
1420
Non-Canonical Rules (Organizational Conventions)
1521
-------------------------------------------------
1622
RNC1: Termination - Sequence must end with specific terminators
@@ -21,7 +27,8 @@
2127
2228
References
2329
----------
24-
See CANONICAL_GRAMMAR_DERIVATION.md for complete mathematical derivation.
30+
See CANONICAL_GRAMMAR_DERIVATION.md and EMERGENT_GRAMMAR_ANALYSIS.md
31+
for complete mathematical derivations.
2532
"""
2633

2734
from __future__ import annotations
@@ -49,6 +56,13 @@
4956
# Note: Some operators have destabilizing components
5057
})
5158

59+
# RC3: Operators that require phase verification (coupling/resonance)
60+
COUPLING_RESONANCE = frozenset({'coupling', 'resonance'})
61+
62+
# RC4: Bifurcation triggers and handlers
63+
BIFURCATION_TRIGGERS = frozenset({'dissonance', 'mutation'})
64+
BIFURCATION_HANDLERS = frozenset({'self_organization', 'coherence'})
65+
5266
# Conventional terminators (NOT canonical - organizational only)
5367
CONVENTIONAL_TERMINATORS = frozenset({
5468
'silence',
@@ -61,9 +75,9 @@
6175
class CanonicalGrammarValidator:
6276
"""Validates sequences using ONLY physics-derived rules.
6377
64-
This validator implements RC1 and RC2, which emerge inevitably from
65-
the nodal equation ∂EPI/∂t = νf · ΔNFR(t). It does NOT enforce
66-
organizational conventions like required terminators.
78+
This validator implements RC1, RC2, and RC3, which emerge inevitably from
79+
the nodal equation ∂EPI/∂t = νf · ΔNFR(t), TNFR invariants, and formal
80+
contracts. It does NOT enforce organizational conventions like required terminators.
6781
6882
Use this for testing algebraic properties where you want to validate
6983
pure physics without implementation conventions.
@@ -158,16 +172,71 @@ def validate_convergence(sequence: List[Operator]) -> tuple[bool, str]:
158172
f"bound destabilizers {destabilizers_present}"
159173
)
160174

175+
@staticmethod
176+
def validate_phase_compatibility(sequence: List[Operator]) -> tuple[bool, str]:
177+
"""Validate RC3: Phase compatibility requirement for coupling/resonance.
178+
179+
Physical basis: AGENTS.md Invariant #5 states "no coupling is valid
180+
without explicit phase verification (synchrony)". Resonance physics
181+
requires phase compatibility: |φᵢ - φⱼ| ≤ Δφ_max for structural coupling.
182+
183+
Without phase verification, nodes with incompatible phases (e.g., antiphase)
184+
could attempt coupling, violating resonance physics.
185+
186+
Parameters
187+
----------
188+
sequence : List[Operator]
189+
Sequence of operators to validate
190+
191+
Returns
192+
-------
193+
tuple[bool, str]
194+
(is_valid, message)
195+
196+
Notes
197+
-----
198+
RC3 is a META-rule: it requires that when UM (Coupling) or RA (Resonance)
199+
operators are used, the implementation MUST verify phase compatibility.
200+
The actual phase check happens in operator preconditions, not in grammar.
201+
202+
This grammar rule serves to document the requirement and ensure awareness
203+
that phase checks are MANDATORY (Invariant #5), not optional.
204+
"""
205+
# Check if sequence contains coupling/resonance operators
206+
coupling_ops = [
207+
getattr(op, 'canonical_name', op.name.lower())
208+
for op in sequence
209+
if getattr(op, 'canonical_name', op.name.lower()) in COUPLING_RESONANCE
210+
]
211+
212+
if not coupling_ops:
213+
# No coupling/resonance = RC3 not applicable
214+
return True, "RC3 not applicable: no coupling/resonance operators"
215+
216+
# RC3 satisfied: Sequence contains coupling/resonance
217+
# Phase verification is MANDATORY per Invariant #5
218+
# Actual check happens in operator preconditions (validate_coupling, validate_resonance)
219+
return (
220+
True,
221+
f"RC3 awareness: operators {coupling_ops} require phase verification "
222+
f"(MANDATORY per Invariant #5). Enforced in preconditions."
223+
)
224+
161225
@classmethod
162226
def validate(
163227
cls,
164228
sequence: List[Operator],
165229
epi_initial: float = 0.0,
166230
) -> tuple[bool, List[str]]:
167-
"""Validate sequence using ONLY canonical rules (RC1, RC2).
231+
"""Validate sequence using ONLY canonical rules (RC1, RC2, RC3).
168232
169233
This validates pure physics without organizational conventions.
170234
235+
Canonical rules validated:
236+
- RC1: Initialization (if EPI=0, use generator)
237+
- RC2: Convergence (if destabilizers, use stabilizer)
238+
- RC3: Phase compatibility (coupling/resonance require phase check)
239+
171240
Parameters
172241
----------
173242
sequence : List[Operator]
@@ -195,6 +264,11 @@ def validate(
195264
messages.append(f"RC2: {msg_conv}")
196265
all_valid = all_valid and valid_conv
197266

267+
# RC3: Phase compatibility
268+
valid_phase, msg_phase = cls.validate_phase_compatibility(sequence)
269+
messages.append(f"RC3: {msg_phase}")
270+
all_valid = all_valid and valid_phase
271+
198272
return all_valid, messages
199273

200274

@@ -207,10 +281,11 @@ def validate_canonical_only(
207281
This function validates ONLY:
208282
- RC1: Initialization (if EPI=0, use generator)
209283
- RC2: Convergence (if destabilizers, use stabilizer)
284+
- RC3: Phase compatibility (coupling/resonance require phase check)
210285
211286
It does NOT validate:
212-
- Terminator requirements (organizational convention)
213-
- Specific composition restrictions (high-level semantics)
287+
- RNC1: Terminator requirements (organizational convention)
288+
- RNC2: Specific composition restrictions (high-level semantics)
214289
215290
Use this when testing algebraic properties where you want pure physics
216291
validation without implementation conventions.
@@ -236,8 +311,12 @@ def validate_canonical_only(
236311
237312
Notes
238313
-----
239-
This validator is 100% physics-based. All rules emerge inevitably from
240-
the nodal equation ∂EPI/∂t = νf · ΔNFR(t).
314+
This validator is 100% physics-based. All rules emerge inevitably from:
315+
- Nodal equation: ∂EPI/∂t = νf · ΔNFR(t)
316+
- TNFR invariants (especially Invariant #5: phase verification)
317+
- Formal operator contracts (AGENTS.md §4)
318+
319+
See EMERGENT_GRAMMAR_ANALYSIS.md for complete derivations.
241320
"""
242321
is_valid, messages = CanonicalGrammarValidator.validate(sequence, epi_initial)
243322
return is_valid
@@ -250,7 +329,7 @@ def validate_with_conventions(
250329
"""Validate sequence with both canonical rules and conventions.
251330
252331
This validates:
253-
- RC1, RC2: Canonical physics rules
332+
- RC1, RC2, RC3: Canonical physics rules
254333
- RNC1: Terminator convention (organizational, NOT physics)
255334
256335
Parameters
@@ -268,14 +347,14 @@ def validate_with_conventions(
268347
messages = []
269348
all_valid = True
270349

271-
# First validate canonical rules
350+
# First validate canonical rules (RC1, RC2, RC3)
272351
valid_canonical, canonical_msgs = CanonicalGrammarValidator.validate(
273352
sequence, epi_initial
274353
)
275354
messages.extend(canonical_msgs)
276355
all_valid = all_valid and valid_canonical
277356

278-
# Then check conventions
357+
# Then check conventions (RNC1)
279358
if sequence:
280359
last_op = getattr(sequence[-1], 'canonical_name', sequence[-1].name.lower())
281360
if last_op not in CONVENTIONAL_TERMINATORS:

src/tnfr/operators/preconditions/__init__.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,18 @@ def validate_coupling(G: "TNFRGraph", node: "NodeId") -> None:
277277
1. **Graph connectivity**: At least one other node exists for coupling
278278
2. **Active EPI**: Node has sufficient structural form (EPI > threshold)
279279
3. **Structural frequency**: Node has capacity for synchronization (νf > threshold)
280-
4. **Phase compatibility** (optional): At least one neighbor within phase range
280+
4. **Phase compatibility** (MANDATORY per Invariant #5): At least one neighbor within phase range
281281
282282
Configuration Parameters
283283
------------------------
284284
UM_MIN_EPI : float, default 0.05
285285
Minimum EPI magnitude required for coupling
286286
UM_MIN_VF : float, default 0.01
287287
Minimum structural frequency required for coupling
288-
UM_STRICT_PHASE_CHECK : bool, default False
289-
Enable strict phase compatibility checking with existing neighbors
288+
UM_STRICT_PHASE_CHECK : bool, default True (changed from False per RC3)
289+
Enable strict phase compatibility checking with existing neighbors.
290+
**MANDATORY per AGENTS.md Invariant #5**: "no coupling is valid without
291+
explicit phase verification (synchrony)"
290292
UM_MAX_PHASE_DIFF : float, default π/2
291293
Maximum phase difference for compatible coupling (radians)
292294
@@ -308,9 +310,11 @@ def validate_coupling(G: "TNFRGraph", node: "NodeId") -> None:
308310
309311
Notes
310312
-----
311-
Phase compatibility check is soft by default (UM_STRICT_PHASE_CHECK=False)
312-
since UM can create new links via UM_FUNCTIONAL_LINKS mechanism. Enable
313-
strict checking when coupling should only work with existing neighbors.
313+
**IMPORTANT**: Phase compatibility check is now MANDATORY by default
314+
(UM_STRICT_PHASE_CHECK=True) to align with AGENTS.md Invariant #5 and RC3.
315+
316+
Set UM_STRICT_PHASE_CHECK=False to disable (NOT RECOMMENDED - violates
317+
canonical physics requirements).
314318
315319
Examples
316320
--------
@@ -328,6 +332,8 @@ def validate_coupling(G: "TNFRGraph", node: "NodeId") -> None:
328332
See Also
329333
--------
330334
Coupling : UM operator that uses this validation
335+
AGENTS.md : Invariant #5 (phase check mandatory)
336+
EMERGENT_GRAMMAR_ANALYSIS.md : RC3 derivation
331337
"""
332338
import math
333339

@@ -354,10 +360,10 @@ def validate_coupling(G: "TNFRGraph", node: "NodeId") -> None:
354360
"Coupling", f"Structural frequency too low (νf={vf:.3f} < {min_vf:.3f})"
355361
)
356362

357-
# Optional: Check if at least some neighbors are phase-compatible
358-
# This is a soft check - we don't fail if no neighbors exist yet
359-
# since UM can create new links with UM_FUNCTIONAL_LINKS
360-
strict_phase = bool(G.graph.get("UM_STRICT_PHASE_CHECK", False))
363+
# RC3: Phase compatibility check
364+
# Per AGENTS.md Invariant #5: "no coupling is valid without explicit phase verification"
365+
# Changed from False to True to align with canonical physics requirements
366+
strict_phase = bool(G.graph.get("UM_STRICT_PHASE_CHECK", True))
361367
if strict_phase:
362368
neighbors = list(G.neighbors(node))
363369
if neighbors:

0 commit comments

Comments
 (0)