@@ -225,6 +225,8 @@ def __init__(
225225 # === Flags (kept for batch operations) ===
226226 self ._in_reset = False
227227 self ._block_cross_window_updates = False
228+ self ._forwarding_to_parent = False
229+ self ._parent_field_name : Optional [str ] = None
228230
229231 # === State Change Callbacks ===
230232 # Callbacks notified when materialized state changes (dirty/signature diffs)
@@ -340,6 +342,12 @@ def _check_and_sync_delegate(self) -> bool:
340342
341343 return True
342344
345+ @property
346+ def has_delegate (self ) -> bool :
347+ """Return whether this state extracts parameters through an object delegate."""
348+
349+ return self ._delegate_attr is not None
350+
343351 @property
344352 def saved_object (self ) -> Any :
345353 """Get the saved baseline object with the correct type.
@@ -437,15 +445,15 @@ def on_child_changed(changed_paths):
437445 )
438446
439447 # Reentrancy guard (pattern from ObjectState architectural fixes)
440- if getattr ( self , ' _forwarding_to_parent' , False ) :
448+ if self . _forwarding_to_parent :
441449 logger .debug (f"[ObjectState] Reentrancy guard blocked for { self .scope_id } " )
442450 return
443451
444452 self ._forwarding_to_parent = True
445453 try :
446454 # Determine which parent field changed
447455 # Priority: explicit field_path arg > _parent_field_name > auto-detect
448- parent_field = field_path or getattr ( self , ' _parent_field_name' , None )
456+ parent_field = field_path or self . _parent_field_name
449457 if parent_field is None :
450458 # Auto-detect from scope: step::function_0 → 'function'
451459 parts = self .scope_id .split ('::' )
@@ -1258,8 +1266,6 @@ def reset_parameter(self, param_name: str) -> None:
12581266 default_value = self ._signature_defaults .get (param_name )
12591267 self .update_parameter (param_name , default_value )
12601268
1261-
1262-
12631269 def get_current_values (self ) -> Dict [str , Any ]:
12641270 """
12651271 Get current parameter values from state.
0 commit comments