@@ -696,6 +696,7 @@ class _SequenceAutomaton:
696696 "_destabilizer_context" ,
697697 "_thol_stack" ,
698698 "_thol_subsequences" ,
699+ "_thol_encapsulated_indices" ,
699700 )
700701
701702 def __init__ (self ) -> None :
@@ -721,6 +722,7 @@ def __init__(self) -> None:
721722 # THOL recursive validation: Track nested THOL blocks and their subsequences
722723 self ._thol_stack : list [int ] = [] # Stack of THOL opening indices
723724 self ._thol_subsequences : dict [int , list [str ]] = {} # Subsequences by opening index
725+ self ._thol_encapsulated_indices : set [int ] = set () # Indices inside THOL windows
724726
725727 def run (self , names : Sequence [str ]) -> None :
726728 if not names :
@@ -815,6 +817,9 @@ def _consume(self, token: str, index: int) -> None:
815817 current_thol = self ._thol_stack [- 1 ]
816818 window_content = self ._thol_subsequences [current_thol ]
817819
820+ # Mark this operator as encapsulated in THOL window
821+ self ._thol_encapsulated_indices .add (index )
822+
818823 # Check if this is the first operator in window
819824 if len (window_content ) == 0 :
820825 # First operator after THOL opening
@@ -825,6 +830,8 @@ def _consume(self, token: str, index: int) -> None:
825830 # Close THOL immediately and process operator in parent context
826831 self ._thol_stack .pop ()
827832 self ._open_thol = bool (self ._thol_stack )
833+ # Unmark as encapsulated since it's part of parent context
834+ self ._thol_encapsulated_indices .discard (index )
828835 # Don't add to window - process normally in parent context
829836 # (will be processed by subsequent validation logic)
830837 return
@@ -1257,12 +1264,23 @@ def _finalize(self, names: Sequence[str]) -> None:
12571264 # Already validated in _accept() for first operator
12581265
12591266 # C1.2: End validation (legacy R3)
1260- if self ._canonical [- 1 ] not in VALID_END_OPERATORS :
1267+ # TNFR Encapsulation: Check last operator NOT inside THOL window
1268+ # Sub-EPIs are independent nodes (operational fractality), so operators
1269+ # inside THOL windows don't count toward main sequence ending.
1270+ last_non_encapsulated_index = len (self ._canonical ) - 1
1271+ for i in range (len (self ._canonical ) - 1 , - 1 , - 1 ):
1272+ if i not in self ._thol_encapsulated_indices :
1273+ last_non_encapsulated_index = i
1274+ break
1275+
1276+ if self ._canonical [last_non_encapsulated_index ] not in VALID_END_OPERATORS :
12611277 cierre = _format_token_group (_CANONICAL_END )
12621278 raise SequenceSyntaxError (
1263- index = len (names ) - 1 ,
1264- token = names [- 1 ],
1265- message = f"C1: sequence must end with { cierre } (EXISTENCE & CLOSURE constraint)" ,
1279+ index = last_non_encapsulated_index ,
1280+ token = names [last_non_encapsulated_index ],
1281+ message = f"C1: sequence must end with { cierre } (EXISTENCE & CLOSURE constraint). "
1282+ f"Operators inside { operator_display_name (SELF_ORGANIZATION )} windows are encapsulated "
1283+ f"(operational fractality) and don't count as sequence ending." ,
12661284 )
12671285
12681286 # NOTE: C1.3 Reception→Coherence segment validation removed
0 commit comments