Skip to content

Commit 30ca885

Browse files
Copilotfermga
andcommitted
Add U2-REMESH grammar rule: Recursive amplification control
Implement physics-derived grammar limitation for REMESH operator: Physical basis: - REMESH temporal coupling (1-α)·EPI_now + α·EPI_past creates feedback - Amplifies structural changes through recursive propagation - REMESH + destabilizers → unbounded growth without stabilizers - ∫ νf · ΔNFR dt → ∞ (divergence) requires control Grammar rule U2-REMESH: - If sequence contains BOTH REMESH AND destabilizers {VAL, OZ, ZHIR} - Then MUST contain stabilizers {IL, THOL} - Prevents: Recursive expansion, recursive bifurcation, replicative mutation Specific combinations: - REMESH + VAL: Recursive expansion needs coherence stabilization - REMESH + OZ: Recursive bifurcation needs self-organization handlers - REMESH + ZHIR: Replicative mutation needs coherence consolidation Implementation: - GrammarValidator.validate_remesh_amplification() in grammar.py - Called in unified validation pipeline - 6 comprehensive tests validating physics-based constraints - All 80 tests passing (40 canonical + 17 existing + 17 integration + 6 grammar) Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 7382c1a commit 30ca885

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

src/tnfr/operators/grammar.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,96 @@ def validate_transformer_context(sequence: List[Operator]) -> tuple[bool, str]:
804804

805805
return (True, f"U4b satisfied: transformers have proper context")
806806

807+
@staticmethod
808+
def validate_remesh_amplification(sequence: List[Operator]) -> tuple[bool, str]:
809+
"""Validate U2-REMESH: Recursive amplification control.
810+
811+
Physical basis: REMESH implements temporal coupling EPI(t) ↔ EPI(t-τ)
812+
which creates feedback that amplifies structural changes. When combined
813+
with destabilizers, this can cause unbounded growth.
814+
815+
From integrated nodal equation:
816+
EPI(t_f) = EPI(t_0) + ∫_{t_0}^{t_f} νf·ΔNFR dτ
817+
818+
REMESH temporal mixing:
819+
EPI_mixed = (1-α)·EPI_now + α·EPI_past
820+
821+
Without stabilizers:
822+
REMESH + destabilizers → recursive amplification
823+
→ ∫ νf·ΔNFR dt → ∞ (feedback loop)
824+
→ System fragments
825+
826+
With stabilizers:
827+
IL or THOL provides negative feedback
828+
→ Bounded recursive evolution
829+
→ ∫ νf·ΔNFR dt < ∞
830+
831+
Specific combinations requiring stabilizers:
832+
- REMESH + VAL: Recursive expansion needs coherence stabilization
833+
- REMESH + OZ: Recursive bifurcation needs self-organization handlers
834+
- REMESH + ZHIR: Replicative mutation needs coherence consolidation
835+
836+
Parameters
837+
----------
838+
sequence : List[Operator]
839+
Sequence of operators to validate
840+
841+
Returns
842+
-------
843+
tuple[bool, str]
844+
(is_valid, message)
845+
846+
Notes
847+
-----
848+
This rule is DISTINCT from general U2 (convergence). While U2 checks
849+
for destabilizers needing stabilizers, U2-REMESH specifically addresses
850+
REMESH's amplification property: it multiplies the effect of destabilizers
851+
through recursive feedback across temporal/spatial scales.
852+
853+
Physical derivation: See src/tnfr/operators/remesh.py module docstring,
854+
section "Grammar Implications from Physical Analysis" → U2: CONVERGENCE.
855+
"""
856+
# Check if sequence contains REMESH
857+
has_remesh = any(
858+
getattr(op, "canonical_name", op.name.lower()) == "recursivity"
859+
for op in sequence
860+
)
861+
862+
if not has_remesh:
863+
return True, "U2-REMESH: not applicable (no recursivity present)"
864+
865+
# Check for destabilizers
866+
destabilizers_present = [
867+
getattr(op, "canonical_name", op.name.lower())
868+
for op in sequence
869+
if getattr(op, "canonical_name", op.name.lower()) in DESTABILIZERS
870+
]
871+
872+
if not destabilizers_present:
873+
return True, "U2-REMESH: satisfied (no destabilizers to amplify)"
874+
875+
# Check for stabilizers
876+
stabilizers_present = [
877+
getattr(op, "canonical_name", op.name.lower())
878+
for op in sequence
879+
if getattr(op, "canonical_name", op.name.lower()) in STABILIZERS
880+
]
881+
882+
if not stabilizers_present:
883+
return (
884+
False,
885+
f"U2-REMESH violated: recursivity amplifies destabilizers "
886+
f"{destabilizers_present} via recursive feedback. "
887+
f"Integral ∫νf·ΔNFR dt may diverge (unbounded growth). "
888+
f"Required: {sorted(STABILIZERS)} to bound recursive amplification",
889+
)
890+
891+
return (
892+
True,
893+
f"U2-REMESH satisfied: stabilizers {stabilizers_present} "
894+
f"bound recursive amplification of {destabilizers_present}",
895+
)
896+
807897
@classmethod
808898
def validate(
809899
cls,
@@ -865,6 +955,11 @@ def validate(
865955
messages.append(f"U4b: {msg_context}")
866956
all_valid = all_valid and valid_context
867957

958+
# U2-REMESH: Recursive amplification control
959+
valid_remesh, msg_remesh = cls.validate_remesh_amplification(sequence)
960+
messages.append(f"U2-REMESH: {msg_remesh}")
961+
all_valid = all_valid and valid_remesh
962+
868963
return all_valid, messages
869964

870965

tests/unit/operators/test_remesh_operator_integration.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,106 @@ def test_similar_patterns_after_same_sequence(self):
369369

370370
similarity = structural_similarity(epi1, epi2)
371371
assert similarity > 0.8 # Should remain similar
372+
373+
374+
class TestREMESHGrammarLimitations:
375+
"""Test REMESH-specific grammar limitations derived from physics."""
376+
377+
def test_remesh_amplification_requires_stabilizer_with_VAL(self):
378+
"""U2-REMESH: REMESH + VAL requires stabilizer (recursive expansion)."""
379+
from tnfr.operators.grammar import GrammarValidator
380+
381+
# REMESH + VAL without stabilizer should violate U2-REMESH
382+
seq_invalid = [Emission(), Recursivity(), Expansion(), Silence()]
383+
valid, msgs = GrammarValidator.validate(seq_invalid)
384+
385+
# Should fail
386+
assert not valid
387+
388+
# Should mention U2-REMESH violation
389+
u2_remesh_msg = [m for m in msgs if "U2-REMESH" in m and "violated" in m]
390+
assert len(u2_remesh_msg) > 0
391+
assert "recursive amplification" in u2_remesh_msg[0].lower()
392+
393+
def test_remesh_amplification_satisfied_with_stabilizer(self):
394+
"""U2-REMESH: REMESH + VAL + IL satisfies grammar."""
395+
from tnfr.operators.grammar import GrammarValidator
396+
397+
# REMESH + VAL + IL should satisfy U2-REMESH
398+
seq_valid = [Emission(), Recursivity(), Expansion(), Coherence(), Silence()]
399+
valid, msgs = GrammarValidator.validate(seq_valid)
400+
401+
# Should pass
402+
assert valid
403+
404+
# U2-REMESH should be satisfied
405+
u2_remesh_msg = [m for m in msgs if "U2-REMESH" in m and "satisfied" in m]
406+
assert len(u2_remesh_msg) > 0
407+
408+
def test_remesh_amplification_requires_stabilizer_with_OZ(self):
409+
"""U2-REMESH: REMESH + OZ requires stabilizer (recursive bifurcation)."""
410+
from tnfr.operators.grammar import GrammarValidator
411+
412+
# REMESH + OZ without stabilizer should violate U2-REMESH
413+
seq_invalid = [Emission(), Recursivity(), Dissonance(), Silence()]
414+
valid, msgs = GrammarValidator.validate(seq_invalid)
415+
416+
# Should fail
417+
assert not valid
418+
419+
# Should mention dissonance amplification
420+
u2_remesh_msg = [m for m in msgs if "U2-REMESH" in m and "violated" in m]
421+
assert len(u2_remesh_msg) > 0
422+
assert "dissonance" in u2_remesh_msg[0].lower()
423+
424+
def test_remesh_without_destabilizer_not_applicable(self):
425+
"""U2-REMESH: Not applicable when REMESH has no destabilizers."""
426+
from tnfr.operators.grammar import GrammarValidator
427+
428+
# REMESH without destabilizers - U2-REMESH not applicable
429+
seq = [Emission(), Recursivity(), Coherence(), Silence()]
430+
valid, msgs = GrammarValidator.validate(seq)
431+
432+
# Should pass
433+
assert valid
434+
435+
# U2-REMESH should indicate not applicable or satisfied
436+
u2_remesh_msg = [m for m in msgs if "U2-REMESH" in m]
437+
assert len(u2_remesh_msg) > 0
438+
assert ("not applicable" in u2_remesh_msg[0].lower() or
439+
"satisfied" in u2_remesh_msg[0].lower())
440+
441+
def test_destabilizer_without_remesh_uses_general_U2(self):
442+
"""General U2 applies when destabilizers present without REMESH."""
443+
from tnfr.operators.grammar import GrammarValidator
444+
445+
# VAL without REMESH - general U2 applies, not U2-REMESH
446+
seq = [Emission(), Expansion(), Silence()]
447+
valid, msgs = GrammarValidator.validate(seq)
448+
449+
# Should fail on general U2
450+
assert not valid
451+
452+
# U2 should be violated
453+
u2_msg = [m for m in msgs if m.startswith("U2:") and "violated" in m]
454+
assert len(u2_msg) > 0
455+
456+
# U2-REMESH should not be applicable
457+
u2_remesh_msg = [m for m in msgs if "U2-REMESH" in m]
458+
assert len(u2_remesh_msg) > 0
459+
assert "not applicable" in u2_remesh_msg[0].lower()
460+
461+
def test_physical_rationale_documented(self):
462+
"""Verify U2-REMESH has physical derivation from nodal equation."""
463+
from tnfr.operators.grammar import GrammarValidator
464+
import inspect
465+
466+
# Check that validate_remesh_amplification has proper documentation
467+
method = GrammarValidator.validate_remesh_amplification
468+
docstring = inspect.getdoc(method)
469+
470+
# Should mention key physical concepts
471+
assert "temporal coupling" in docstring.lower()
472+
assert "recursive" in docstring.lower() or "amplif" in docstring.lower()
473+
assert "nodal equation" in docstring.lower()
474+
assert "∫" in docstring or "integral" in docstring.lower()

0 commit comments

Comments
 (0)