Skip to content

Commit 9e8f399

Browse files
Copilotfermga
andcommitted
R6 final canonical: Purpose-aware balance, OZ endings allowed
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 6ea6103 commit 9e8f399

File tree

2 files changed

+185
-90
lines changed

2 files changed

+185
-90
lines changed

src/tnfr/operators/grammar.py

Lines changed: 146 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -918,10 +918,14 @@ def _check_structural_convergence(self, sequence: Sequence[str]) -> bool:
918918
return False
919919

920920
def _check_operational_closure(self, sequence: Sequence[str]) -> bool:
921-
"""Verify balance between destabilization and stabilization.
921+
"""Verify operational closure with purpose-aware balance validation.
922922
923-
Operational closure requires that destabilizing operators are balanced
924-
by stabilizing operators, preventing runaway divergence or collapse.
923+
R6 allows three types of sequences based on their PURPOSE:
924+
- Stabilizing (dest < stab): Reduce existing ΔNFR
925+
- Neutral (dest = stab): Maintain coherence
926+
- Destabilizing (dest > stab): Explore new states (ONLY with SHA ending)
927+
928+
The ending operator determines sustainability of any imbalance.
925929
926930
Parameters
927931
----------
@@ -931,64 +935,108 @@ def _check_operational_closure(self, sequence: Sequence[str]) -> bool:
931935
Returns
932936
-------
933937
bool
934-
True if sequence has operational closure
938+
True if sequence has operational closure appropriate to its purpose
935939
936940
Notes
937941
-----
938-
Destabilizers (increase |ΔNFR|):
942+
**Sequence Purpose and Balance:**
943+
944+
TNFR sequences operate on existing systems with existing ΔNFR.
945+
Sequences have PURPOSE:
946+
947+
1. **STABILIZING** (dest < stab): More stabilizers reduce existing ΔNFR
948+
- Use case: System with high ΔNFR needs consolidation
949+
- Example: AL → EN → IL → RA → SHA (1 dest, 3 stab)
950+
951+
2. **NEUTRAL** (dest = stab): Balanced exploration and stabilization
952+
- Use case: System in good state, maintain coherence
953+
- Example: AL → EN → IL → OZ → IL → NAV (2 dest, 2 stab)
954+
955+
3. **DESTABILIZING** (dest > stab): More destabilizers for exploration
956+
- Use case: System stuck in local minimum, needs activation
957+
- Example: AL → EN → IL → OZ → VAL → SHA (3 dest, 2 stab)
958+
- **REQUIRES: SHA ending for absolute closure**
959+
960+
**Ending-Dependent Rules:**
961+
962+
A. **SHA (Silence) ending:**
963+
- Accepts ANY destabilizer/stabilizer ratio
964+
- SHA freezes system (νf → 0), provides absolute closure
965+
- Can handle imbalanced destabilization because evolution stops
966+
967+
B. **NAV/REMESH ending:**
968+
- Requires: destabilizers ≤ stabilizers
969+
- Provides operational closure but not freezing
970+
- Needs balance for sustainable handoff/recursion
971+
972+
C. **OZ ending:**
973+
- NEVER acceptable (checked in convergence validation)
974+
- Leaves high |ΔNFR| without closure mechanism
975+
976+
**Destabilizers** (increase |ΔNFR|):
939977
- Strong: OZ (Dissonance)
940978
- Moderate: NAV (Transition), VAL (Expansion)
941979
- Weak: EN (Reception, context-dependent)
942980
943-
Stabilizers (reduce |ΔNFR| or achieve closure):
944-
- IL (Coherence)
945-
- THOL (Self-organization)
946-
- SHA (Silence)
947-
- RA (Resonance)
981+
**Stabilizers** (reduce |ΔNFR| or freeze νf):
982+
- IL (Coherence) - reduces |ΔNFR|
983+
- THOL (Self-organization) - autopoietic closure
984+
- SHA (Silence) - freezes νf → 0
985+
- RA (Resonance) - propagates stable coherence
948986
949-
Closure conditions:
950-
1. destabilizers ≤ stabilizers (strict balance), OR
951-
2. Controlled mutation: ZHIR after IL (prepared phase change)
987+
**Special Exception:**
988+
Controlled mutation (IL → ZHIR) allows imbalance because coherence
989+
provides stable base for intentional phase transformation.
952990
953-
Exception for controlled mutation:
954-
IL → ZHIR sequences allow destabilizers > stabilizers because
955-
coherence provides stable base for phase transformation. This
956-
represents intentional structural reorganization, not collapse.
991+
**Why This Logic is Canonical:**
992+
993+
- Respects sequence PURPOSE (stabilize, maintain, or explore)
994+
- Context-aware: same count ratio serves different purposes
995+
- Ending determines sustainability (SHA strongest, NAV/REMESH balanced)
996+
- Prevents pure divergence (no OZ endings)
997+
- Allows therapeutic stabilization and explorative destabilization
957998
"""
958-
# Count destabilizers (all levels)
999+
# Count destabilizers and stabilizers
9591000
from ..config.operator_names import DESTABILIZERS_ALL
9601001

9611002
destabilizers = sum(
9621003
1 for op in sequence
9631004
if op in DESTABILIZERS_ALL
9641005
)
9651006

966-
# Count stabilizers
9671007
stabilizers = sum(
9681008
1 for op in sequence
9691009
if op in {COHERENCE, SELF_ORGANIZATION, SILENCE, RESONANCE}
9701010
)
9711011

972-
# Strict balance: destabilizers ≤ stabilizers
973-
if destabilizers <= stabilizers:
974-
return True
1012+
# SHA ending: Accepts ANY ratio (strongest closure, freezes system)
1013+
if sequence[-1] == SILENCE:
1014+
return True # SHA provides absolute closure regardless of balance
9751015

976-
# Exception: controlled mutation (IL before ZHIR)
977-
# This allows destabilizers > stabilizers when mutation is prepared
978-
if MUTATION in sequence and COHERENCE in sequence:
979-
# Check if coherence precedes mutation (stable base for transformation)
980-
coherence_idx = sequence.index(COHERENCE)
981-
mutation_idx = sequence.index(MUTATION)
982-
if coherence_idx < mutation_idx:
1016+
# NAV/REMESH ending: Requires balance (dest ≤ stab)
1017+
# These provide operational closure but need balance for sustainability
1018+
if sequence[-1] in {TRANSITION, RECURSIVITY}:
1019+
if destabilizers <= stabilizers:
9831020
return True
1021+
# Exception: Controlled mutation allows imbalance
1022+
if MUTATION in sequence and COHERENCE in sequence:
1023+
coherence_idx = sequence.index(COHERENCE)
1024+
mutation_idx = sequence.index(MUTATION)
1025+
if coherence_idx < mutation_idx:
1026+
return True
1027+
return False
9841028

985-
return False
1029+
# Should not reach here (OZ ending caught by convergence check)
1030+
# But as safety: require balance for unknown endings
1031+
return destabilizers <= stabilizers
9861032

9871033
def _validate_operational_closure(self, sequence: Sequence[str]) -> None:
988-
"""R6: Validate sequence completes coherent reorganization cycle.
1034+
"""R6: Validate sequence has operational closure through proper balance.
9891035
990-
Ensures sequences respect conservation of structural coherence and
991-
achieve operational closure according to TNFR canonical principles.
1036+
R6 validates that operator sequences achieve operational closure by
1037+
ensuring destabilization is properly balanced with stabilization.
1038+
This prevents divergent trajectories while allowing all valid purposes:
1039+
stabilizing, neutral, and destabilizing sequences.
9921040
9931041
Parameters
9941042
----------
@@ -998,69 +1046,87 @@ def _validate_operational_closure(self, sequence: Sequence[str]) -> None:
9981046
Raises
9991047
------
10001048
SequenceSyntaxError
1001-
If sequence violates operational closure or convergence requirements
1049+
If sequence violates operational closure requirements
10021050
10031051
Notes
10041052
-----
1005-
R6 validates three aspects of sequence coherence:
1053+
**R6 Philosophy:**
1054+
1055+
R3 validates syntactic correctness (valid start/end operators).
1056+
R6 validates semantic coherence (sustainable balance).
10061057
1007-
1. **Structural Convergence**: Sequence must end with operator that
1008-
stabilizes reorganization (∂EPI/∂t → stable state)
1058+
R6 does NOT reject any R3-valid endings (SHA, NAV, REMESH, OZ).
1059+
Instead, it validates that each ending type has appropriate balance.
1060+
1061+
**Valid Ending Types** (from R3):
1062+
1063+
1. **SHA (Silence)**: Terminal closure
1064+
- Freezes evolution (νf → 0)
1065+
- Accepts ANY destabilizer/stabilizer ratio
1066+
- Provides absolute closure regardless of balance
1067+
1068+
2. **NAV (Transition)**: Handoff closure
1069+
- Regime transfer to next state
1070+
- Requires: destabilizers ≤ stabilizers
1071+
- Needs balance for sustainable handoff
1072+
1073+
3. **REMESH (Recursivity)**: Recursive closure
1074+
- Fractal echo across scales
1075+
- Requires: destabilizers ≤ stabilizers
1076+
- Needs balance for stable recursion
10091077
1010-
2. **Operational Closure**: Balance between destabilizers and stabilizers
1011-
prevents divergent or collapsing trajectories
1078+
4. **OZ (Dissonance)**: Intentional tension preservation
1079+
- Therapeutic/activation pattern
1080+
- Requires: destabilizers ≤ stabilizers
1081+
- Must be CONTROLLED dissonance with prior stabilization
10121082
1013-
3. **Frequency Balance** (future): Net frequency tendency should support
1014-
coherent reorganization (currently informational only)
1083+
**Balance Validation:**
1084+
1085+
Operational closure requires appropriate balance for non-SHA endings:
1086+
- dest ≤ stab: Ensures sustainability
1087+
- dest = stab: Neutral (maintains coherence)
1088+
- dest < stab: Stabilizing (reduces ΔNFR)
1089+
1090+
SHA exception: Can handle dest > stab because freezing (νf → 0)
1091+
provides absolute closure that doesn't depend on balance.
1092+
1093+
**Why Allow OZ Endings?**
1094+
1095+
OZ endings serve valid purposes:
1096+
- Therapeutic: Intentionally preserve tension for processing
1097+
- Activation: Wake up stuck systems
1098+
- Multi-sequence chains: Open tension for next sequence to resolve
1099+
1100+
The key: OZ ending must be CONTROLLED (have prior stabilization),
1101+
not runaway destabilization. Balance check ensures this.
1102+
1103+
**Controlled Mutation Exception:**
1104+
1105+
IL → ZHIR allows imbalance because coherence provides stable base
1106+
for intentional phase transformation.
10151107
10161108
Theoretical foundation:
1017-
From integrated nodal equation:
1018-
EPI(t_final) = EPI(t_initial) + ∫_{t_0}^{t_f} νf(t) · ΔNFR(t) dt
1109+
From integrated equation: EPI(t_f) = EPI(t_0) + ∫ νf · ΔNFR dt
10191110
10201111
For physical coherence:
1021-
- Integral must converge (not diverge toward collapse)
1022-
- EPI_final must be stable (sustainable coherence)
1023-
- Reorganization must close (∂EPI/∂t → 0 at sequence end)
1024-
1025-
References:
1026-
- TNFR.pdf Section 2.1.4: Nodal stability conditions
1027-
- AGENTS.md Section 3: Canonical invariants
1112+
- SHA: νf → 0, so integral converges regardless of ΔNFR
1113+
- Others: Need dest ≤ stab to ensure ∫ νf · ΔNFR dt converges
10281114
"""
1029-
# 1. Verify ending is not divergent (OZ rejected, NAV/REMESH/SHA OK)
1030-
if not self._check_structural_convergence(sequence):
1031-
last_op = sequence[-1]
1032-
raise SequenceSyntaxError(
1033-
index=-1,
1034-
token=None,
1035-
message=(
1036-
f"R6: Sequence ends with divergent operator {operator_display_name(last_op)}. "
1037-
f"{operator_display_name(DISSONANCE)} leaves system with high |ΔNFR| and high νf, "
1038-
f"creating actively divergent state without continuation. "
1039-
f"Acceptable endings: {operator_display_name(SILENCE)} (convergent), "
1040-
f"{operator_display_name(TRANSITION)}/{operator_display_name(RECURSIVITY)} (operational closure)."
1041-
),
1042-
)
1043-
1044-
# 2. Validate operational closure (destabilizer/stabilizer balance)
1115+
# Validate balance (no separate convergence check - respect R3)
10451116
if not self._check_operational_closure(sequence):
1117+
last_op = sequence[-1]
10461118
raise SequenceSyntaxError(
10471119
index=-1,
10481120
token=None,
10491121
message=(
10501122
f"R6: Sequence lacks operational closure. "
1051-
f"Destabilizers exceed stabilizers without controlled mutation. "
1052-
f"Balance destabilization ({operator_display_name(DISSONANCE)}, {operator_display_name(TRANSITION)}, "
1053-
f"{operator_display_name(EXPANSION)}) with stabilization ({operator_display_name(COHERENCE)}, "
1054-
f"{operator_display_name(SELF_ORGANIZATION)}, {operator_display_name(SILENCE)})."
1123+
f"Ending with {operator_display_name(last_op)} requires destabilizers ≤ stabilizers for sustainability. "
1124+
f"Purpose-aware balance: STABILIZING (dest < stab), NEUTRAL (dest = stab), or DESTABILIZING (dest > stab, needs {operator_display_name(SILENCE)} ending). "
1125+
f"Destabilizers: {operator_display_name(DISSONANCE)}, {operator_display_name(TRANSITION)}, {operator_display_name(EXPANSION)}, {operator_display_name(RECEPTION)}. "
1126+
f"Stabilizers: {operator_display_name(COHERENCE)}, {operator_display_name(SELF_ORGANIZATION)}, {operator_display_name(SILENCE)}, {operator_display_name(RESONANCE)}. "
1127+
f"Note: {operator_display_name(DISSONANCE)} endings are valid for therapeutic/activation patterns when properly balanced."
10551128
),
10561129
)
1057-
1058-
# 3. Compute frequency balance (informational - for future warnings)
1059-
# Currently not enforced as error, but could be used for telemetry
1060-
freq_balance = self._compute_frequency_balance(sequence)
1061-
# Store for metadata/telemetry
1062-
# Future: Could add warnings for extremely negative balance (< -0.5)
1063-
# indicating tendency toward collapse
10641130

10651131
def _finalize(self, names: Sequence[str]) -> None:
10661132
if self._unknown_tokens:
@@ -1113,7 +1179,9 @@ def _finalize(self, names: Sequence[str]) -> None:
11131179
if self._detected_pattern == StructuralPattern.REGENERATIVE:
11141180
self._validate_regenerative_cycle()
11151181

1116-
# R6: Validate operational closure and coherence conservation
1182+
# R6: Validate operational closure (balance only, no ending restrictions)
1183+
# R3 already validates valid endings (SHA, NAV, REMESH, OZ)
1184+
# R6 validates that endings are SUSTAINABLE through proper balance
11171185
self._validate_operational_closure(self._canonical)
11181186

11191187
def _validate_regenerative_cycle(self) -> None:

tests/unit/operators/test_r6_operational_closure.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,25 +169,50 @@ def test_valid_equal_destabilizers_and_stabilizers(self):
169169
assert result.passed, f"Expected pass but got: {result.message}"
170170

171171
def test_invalid_excess_destabilizers(self):
172-
"""Sequence with excess destabilizers without controlled mutation fails."""
173-
# 3 destabilizers (OZ, NAV, VAL), 2 stabilizers (IL at pos 2, SHA at end)
174-
# This violates operational closure: 3 > 2
175-
# Must end with R3-valid operator, but OZ/NAV don't pass R6 convergence
176-
# So we end with SHA for R3/R6, but closure balance fails
172+
"""Sequence with excess destabilizers fails without SHA ending.
173+
174+
3 destabilizers > 2 stabilizers violates closure for NAV/REMESH endings
175+
(needs balance). But would be valid with SHA ending (absolute closure).
176+
"""
177+
# 3 destabilizers (EN, OZ, VAL), 2 stabilizers (IL, RA)
178+
# With NAV ending: should fail (needs balance)
177179
sequence = [
178180
EMISSION,
179181
RECEPTION,
180182
COHERENCE, # Stabilizer 1
181183
DISSONANCE, # Destabilizer 1
182184
TRANSITION, # Destabilizer 2
183185
EXPANSION, # Destabilizer 3
184-
SILENCE, # Stabilizer 2, R3/R6 valid ending
186+
RESONANCE, # Stabilizer 2
187+
TRANSITION, # NAV ending without balance
185188
]
186189
result = validate_sequence(sequence)
187-
# Should fail R6 closure: 3 destabilizers > 2 stabilizers
190+
# Should fail: 4 destabilizers (EN, OZ, NAV, VAL) > 2 stabilizers (IL, RA)
191+
# NAV ending requires dest ≤ stab
188192
assert not result.passed
189193
assert "R6" in result.message
190194
assert "closure" in result.message.lower()
195+
196+
def test_valid_excess_destabilizers_with_sha(self):
197+
"""Destabilizing sequence valid with SHA ending (absolute closure).
198+
199+
SHA provides absolute closure (νf → 0), so accepts any dest/stab ratio.
200+
This allows intentional destabilizing sequences for exploration.
201+
"""
202+
# 3 destabilizers (EN, OZ, VAL) > 2 stabilizers (IL, SHA)
203+
# But SHA ending: provides absolute closure
204+
sequence = [
205+
EMISSION,
206+
RECEPTION,
207+
COHERENCE,
208+
DISSONANCE,
209+
EXPANSION,
210+
TRANSITION,
211+
SILENCE, # SHA provides absolute closure despite imbalance
212+
]
213+
result = validate_sequence(sequence)
214+
# Should pass: SHA accepts any ratio (destabilizing sequence)
215+
assert result.passed, f"Expected pass but got: {result.message}"
191216

192217
def test_valid_controlled_mutation_exception(self):
193218
"""Sequence with destabilizers > stabilizers passes if mutation is controlled.
@@ -320,15 +345,17 @@ def test_convergence_error_message_clarity(self):
320345

321346
def test_closure_error_message_clarity(self):
322347
"""Closure error message explains destabilizer/stabilizer imbalance."""
323-
# Create sequence with excess destabilizers
348+
# Create sequence with excess destabilizers and NAV ending (not SHA)
349+
# NAV requires balance, but this has imbalance
324350
sequence = [
325351
EMISSION,
326352
RECEPTION,
327353
COHERENCE,
328354
DISSONANCE,
329-
TRANSITION,
330-
EXPANSION,
331-
SILENCE,
355+
TRANSITION, # Destabilizer 2
356+
EXPANSION, # Destabilizer 3
357+
RESONANCE,
358+
TRANSITION, # NAV ending (needs balance)
332359
]
333360
result = validate_sequence(sequence)
334361
assert not result.passed
@@ -337,7 +364,7 @@ def test_closure_error_message_clarity(self):
337364
# Should mention balance concept
338365
assert any(
339366
word in result.message.lower()
340-
for word in ["destabilizer", "stabilizer", "balance"]
367+
for word in ["destabilizer", "stabilizer", "balance", "sustainability"]
341368
)
342369

343370

0 commit comments

Comments
 (0)