Ensure the current context's scope stack is active on the Rust thread-local. Three cases: 1. **ContextVar is set** (normal async tasks, or after ``push_node_scope`` installed a branch stack): always re-sync it to the Rust thread-local. This is critical because concurrent asyn
()
| 41 | |
| 42 | |
| 43 | def _ensure_scope_stack() -> None: |
| 44 | """Ensure the current context's scope stack is active on the Rust thread-local. |
| 45 | |
| 46 | Three cases: |
| 47 | |
| 48 | 1. **ContextVar is set** (normal async tasks, or after ``push_node_scope`` |
| 49 | installed a branch stack): always re-sync it to the Rust thread-local. |
| 50 | This is critical because concurrent async tasks share a single OS thread |
| 51 | and the thread-local may have been overwritten by another task. |
| 52 | 2. **ContextVar is empty but thread-local is set** (worker threads that |
| 53 | called ``set_thread_scope_stack``): keep the thread-local as-is. |
| 54 | 3. **Neither is set**: create a new scope stack via ``get_scope_stack()``. |
| 55 | """ |
| 56 | import nemo_relay |
| 57 | |
| 58 | # Case 1: ContextVar owns a stack — re-sync it to the Rust thread-local. |
| 59 | stack = nemo_relay._scope_stack_var.get(None) |
| 60 | if stack is not None: |
| 61 | nemo_relay._sync_thread_scope_stack(stack) |
| 62 | return |
| 63 | |
| 64 | # Case 2: Worker thread with explicit set_thread_scope_stack — don't clobber. |
| 65 | if nemo_relay._native_scope_stack_active(): |
| 66 | return |
| 67 | |
| 68 | # Case 3: Fresh context — create and register a new stack. |
| 69 | nemo_relay.get_scope_stack() |
| 70 | |
| 71 | |
| 72 | def get_handle() -> ScopeHandle: |