Skip to content

Commit a4c5695

Browse files
Clarify terminal-attempt scope, rename reader
Rename current_terminal_attempt_index to the underscore-prefixed _current_terminal_attempt_index (it is internal; only FailureIsolationMiddleware reads it) and move it to the internal __all__ section. Reword the ContextVar + scope comments: a retry recording without an enclosing isolation scope does leave a non-None ambient value, but it is never observed because the sole reader shadows it with None on entry.
1 parent 835bfb9 commit a4c5695

2 files changed

Lines changed: 11 additions & 9 deletions

File tree

src/openarmature/graph/middleware/failure_isolation.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@
4040
from typing import Any
4141

4242
from openarmature.observability.correlation import (
43+
_current_terminal_attempt_index,
4344
_reset_terminal_attempt_index,
4445
_set_terminal_attempt_index,
4546
current_attempt_index,
4647
current_branch_name,
4748
current_dispatch,
4849
current_fan_out_index,
4950
current_namespace_prefix,
50-
current_terminal_attempt_index,
5151
)
5252

5353
from ._core import NextCall
@@ -137,8 +137,9 @@ async def __call__(self, state: Any, next_: NextCall) -> Mapping[str, Any]:
137137
# Establish a clean terminal-attempt scope: an inner
138138
# RetryMiddleware records its final / exhausting attempt here on
139139
# give-up, and _emit_event reports it (proposal 0050 §6.3). The
140-
# ``None`` on entry shadows any stale value from a prior node; the
141-
# finally cleans up so it never leaks to a sibling / next node.
140+
# ``None`` on entry shadows any stale ambient value so this call
141+
# reads correctly; the finally restores the prior value (token
142+
# semantics), and the next isolation call shadows again on entry.
142143
terminal_token = _set_terminal_attempt_index(None)
143144
try:
144145
try:
@@ -218,7 +219,7 @@ def _emit_event(self, state: Any, exc: Exception, degraded: Mapping[str, Any]) -
218219
# already closed by delivery time (their completed event precedes
219220
# this one on the serial queue), so observers parent the marker
220221
# under the invocation span and correlate by ``namespace`` + name.
221-
terminal_attempt = current_terminal_attempt_index()
222+
terminal_attempt = _current_terminal_attempt_index()
222223
attempt_index = terminal_attempt if terminal_attempt is not None else current_attempt_index()
223224
dispatch(
224225
FailureIsolatedEvent(

src/openarmature/observability/correlation.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,10 @@ def _reset_attempt_index(token: Token[int]) -> None:
492492
# rule mandates. On give-up, retry records the final attempt here; the
493493
# enclosing FailureIsolationMiddleware establishes the scope (None on
494494
# entry, reset on exit) and reads it, falling back to ``attempt_index``
495-
# when no retry exhausted. Scoped by the isolation middleware so it never
496-
# leaks across nodes; the sole reader is FailureIsolationMiddleware, which
497-
# always shadows any stale value with its own ``None`` on entry.
495+
# when no retry exhausted. A retry that records without an enclosing
496+
# isolation scope leaves a non-None value in the ambient context, but it
497+
# is never OBSERVED: the sole reader (FailureIsolationMiddleware) shadows
498+
# any such stale value with its own ``None`` on entry before reading.
498499
#
499500
# Two setters by design: ``_set`` / ``_reset`` bracket the isolation SCOPE
500501
# (token-based, mirroring ``_attempt_index``); ``_record`` is retry's
@@ -513,7 +514,7 @@ def _reset_attempt_index(token: Token[int]) -> None:
513514
)
514515

515516

516-
def current_terminal_attempt_index() -> int | None:
517+
def _current_terminal_attempt_index() -> int | None:
517518
"""Return the final / exhausting attempt index recorded by a retry
518519
that gave up within the current FailureIsolationMiddleware scope, or
519520
``None`` when no retry exhausted. Internal."""
@@ -616,12 +617,12 @@ def _reset_active_observer_span(token: Token[object | None]) -> None:
616617
"current_fan_out_index_chain",
617618
"current_invocation_id",
618619
"current_namespace_prefix",
619-
"current_terminal_attempt_index",
620620
"validate_invocation_id",
621621
# Engine-internal lifecycle helpers — exported so the engine in
622622
# ``openarmature.graph.compiled`` can drive set/reset without
623623
# pyright's strict ``reportUnusedFunction`` flagging them as
624624
# dead. Underscore-prefixed; not part of the user-facing API.
625+
"_current_terminal_attempt_index",
625626
"_record_terminal_attempt_index",
626627
"_reset_active_dispatch",
627628
"_reset_active_observer_span",

0 commit comments

Comments
 (0)