Skip to content

Commit 888d69c

Browse files
Copilotfermga
andcommitted
Add THOL recursive subsequence validation structure
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 8777417 commit 888d69c

File tree

2 files changed

+643
-2
lines changed

2 files changed

+643
-2
lines changed

src/tnfr/operators/grammar.py

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,8 @@ class _SequenceAutomaton:
694694
"_detected_pattern",
695695
"_bifurcation_context",
696696
"_destabilizer_context",
697+
"_thol_stack",
698+
"_thol_subsequences",
697699
)
698700

699701
def __init__(self) -> None:
@@ -716,6 +718,9 @@ def __init__(self) -> None:
716718
"moderate": deque(maxlen=BIFURCATION_WINDOWS["moderate"]),
717719
"weak": deque(maxlen=BIFURCATION_WINDOWS["weak"]),
718720
}
721+
# THOL recursive validation: Track nested THOL blocks and their subsequences
722+
self._thol_stack: list[int] = [] # Stack of THOL opening indices
723+
self._thol_subsequences: dict[int, list[str]] = {} # Subsequences by opening index
719724

720725
def run(self, names: Sequence[str]) -> None:
721726
if not names:
@@ -788,11 +793,35 @@ def _consume(self, token: str, index: int) -> None:
788793
if canonical == DISSONANCE:
789794
self._found_dissonance = True
790795

791-
# Track THOL state
796+
# Track THOL state with recursive support
792797
if canonical == SELF_ORGANIZATION:
798+
# THOL opening: push to stack and initialize subsequence
799+
self._thol_stack.append(index)
800+
self._thol_subsequences[index] = []
793801
self._open_thol = True
794802
elif self._open_thol and canonical in SELF_ORGANIZATION_CLOSURES:
795-
self._open_thol = False
803+
# THOL closure: validate subsequence recursively
804+
if not self._thol_stack:
805+
raise SequenceSyntaxError(
806+
index=index,
807+
token=token,
808+
message=f"{operator_display_name(canonical)} closure without corresponding {operator_display_name(SELF_ORGANIZATION)} opening"
809+
)
810+
811+
thol_start = self._thol_stack.pop()
812+
thol_subseq = self._thol_subsequences[thol_start]
813+
814+
# Validate THOL subsequence recursively
815+
self._validate_thol_subsequence(thol_subseq, thol_start, index, token)
816+
817+
# Update _open_thol based on stack state (supports nested THOL)
818+
self._open_thol = bool(self._thol_stack)
819+
elif self._open_thol and self._thol_stack:
820+
# Track operators within THOL block (excluding nested THOL openings)
821+
# Nested THOL openings are handled separately, closures are part of inner subsequence
822+
if canonical != SELF_ORGANIZATION:
823+
current_thol = self._thol_stack[-1]
824+
self._thol_subsequences[current_thol].append(canonical)
796825

797826
# Validate sequential compatibility if not first token
798827
# Only validate if both prev and current are known operators
@@ -999,6 +1028,76 @@ def _has_graduated_destabilizer(self, current_index: int) -> bool:
9991028

10001029
return False
10011030

1031+
def _validate_thol_subsequence(
1032+
self,
1033+
subsequence: list[str],
1034+
start_index: int,
1035+
end_index: int,
1036+
end_token: str
1037+
) -> None:
1038+
"""Validate recursively the subsequence within THOL block.
1039+
1040+
TNFR Fractal Principle: THOL (self-organization) is a fractal operator
1041+
that encapsulates autonomous reorganization. The subsequence must:
1042+
1. Be non-empty (THOL without content is meaningless)
1043+
2. Respect all grammar rules R1-R6 (recursive coherence)
1044+
1045+
Parameters
1046+
----------
1047+
subsequence : list[str]
1048+
Operators within THOL block (between opening and closure)
1049+
start_index : int
1050+
Index of THOL opening in parent sequence
1051+
end_index : int
1052+
Index of THOL closure in parent sequence
1053+
end_token : str
1054+
Token used for closure (for error messages)
1055+
1056+
Raises
1057+
------
1058+
SequenceSyntaxError
1059+
If subsequence is empty or invalid
1060+
1061+
Notes
1062+
-----
1063+
From TNFR Manual §3.2.2 (Ontología fractal resonante):
1064+
"Los NFRs pueden anidarse jerárquicamente: un nodo puede contener
1065+
nodos internos coherentes, dando lugar a una estructura fractal."
1066+
1067+
This validation ensures THOL maintains operational fractality:
1068+
structures are coherent at all scales.
1069+
1070+
Autonomy is implicit: if the subsequence passes all grammar rules,
1071+
it is by definition autonomous (can function independently).
1072+
"""
1073+
# Validation 1: Non-empty subsequence
1074+
if not subsequence:
1075+
raise SequenceSyntaxError(
1076+
index=end_index,
1077+
token=end_token,
1078+
message=(
1079+
f"{operator_display_name(SELF_ORGANIZATION)} block is empty "
1080+
f"(opened at position {start_index}). Subsequence must contain "
1081+
f"at least one operator for autonomous reorganization."
1082+
)
1083+
)
1084+
1085+
# Validation 2: Recursive grammar validation
1086+
# Create new automaton to validate subsequence independently
1087+
try:
1088+
nested_automaton = _SequenceAutomaton()
1089+
nested_automaton.run(subsequence)
1090+
except SequenceSyntaxError as e:
1091+
# Re-raise with THOL context
1092+
raise SequenceSyntaxError(
1093+
index=start_index + e.index + 1, # Offset by THOL position
1094+
token=e.token,
1095+
message=(
1096+
f"Invalid subsequence within {operator_display_name(SELF_ORGANIZATION)} "
1097+
f"block (opened at position {start_index}): {e.message}"
1098+
)
1099+
) from e
1100+
10021101
def _validate_threshold_physics(self, sequence: Sequence[str]) -> None:
10031102
"""C4: Validate threshold physics - transformations require context.
10041103

0 commit comments

Comments
 (0)