Skip to content

Fix failure-isolation event attempt_index#155

Merged
chris-colinsky merged 2 commits into
mainfrom
fix/failure-isolation-attempt-index
Jun 12, 2026
Merged

Fix failure-isolation event attempt_index#155
chris-colinsky merged 2 commits into
mainfrom
fix/failure-isolation-attempt-index

Conversation

@chris-colinsky

Copy link
Copy Markdown
Member

Summary

Fix FailureIsolatedEvent.attempt_index to report the wrapped node's final / exhausting attempt when FailureIsolationMiddleware wraps RetryMiddleware, per spec's ruling on the attempt-index reconciliation. Previously it reported the post-reset baseline (0), because RetryMiddleware resets the attempt-index ContextVar in its per-iteration finally as the exhausted exception unwinds, before the outer isolation middleware catches it.

This is the last v0.14.0 build piece tied to the failure-isolation conformance work; it un-defers fixture 061.

How

An isolation-scoped _terminal_attempt_index ContextVar carries the final attempt past retry's reset:

  • FailureIsolationMiddleware.__call__ establishes a fresh scope (None on entry, reset in a finally).
  • RetryMiddleware, on give-up (exhaustion or a non-transient error), records the final attempt into that scope before re-raising.
  • _emit_event reads the recorded terminal index, falling back to the live attempt index when no retry exhausted (so the no-retry fixtures stay at 0).

The blast radius is limited to isolation's attempt sourcing: retry's control flow, the live per-attempt scoping, and the nested-retry token stack are all unchanged.

Spec

The contract was already in the spec (§6.3 lineage correlation + fixture 061); the prior impl comment claiming the baseline was "spec-confirmed" was unsubstantiated and is removed. No spec change or proposal was needed.

Validation

  • Fixture 061 now passes; the three-piece unit test asserts attempt_index == 2 (final of attempts 0/1/2); the no-retry fixtures (058-063) confirm the fallback to 0.
  • Full unit + conformance suite: 1252 passed, 0 failed; ruff + pyright clean; conformance-manifest guard OK.
  • No CHANGELOG entry: this corrects unreleased 0050 behavior, and the existing FailureIsolationMiddleware entry already describes the event carrying the wrapped node's lineage.

FailureIsolatedEvent.attempt_index now reports the wrapped node's final
/ exhausting attempt (spec ruling), not the post-reset baseline. An
isolation-scoped terminal-attempt ContextVar carries it: RetryMiddleware
records the final attempt on give-up, and FailureIsolationMiddleware
reads it (falling back to the live attempt index when no retry
exhausted). Un-defers conformance fixture 061.
Copilot AI review requested due to automatic review settings June 12, 2026 16:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes FailureIsolatedEvent.attempt_index so that when FailureIsolationMiddleware wraps RetryMiddleware, the event reports the wrapped node’s final/exhausting retry attempt index (per proposal 0050 §6.3), rather than the post-reset baseline.

Changes:

  • Add an isolation-scoped “terminal attempt index” ContextVar in correlation primitives and plumb it through failure isolation event emission.
  • Record the terminal attempt in RetryMiddleware on give-up so outer failure isolation can read it after retry resets attempt_index.
  • Un-defer and extend tests to assert the corrected attempt_index behavior (including conformance fixture coverage).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/test_failure_isolation_middleware.py Adds an observer capture and assertion that the failure-isolation event reports the exhausting attempt index.
tests/conformance/test_pipeline_utilities.py Removes the deferral for the failure-isolation three-piece composition fixture.
src/openarmature/observability/correlation.py Introduces terminal-attempt ContextVar helpers and exports them for use by retry/isolation middleware.
src/openarmature/graph/middleware/retry.py Records the terminal attempt index on give-up before re-raising.
src/openarmature/graph/middleware/failure_isolation.py Establishes/reset terminal-attempt scope and uses it when emitting FailureIsolatedEvent.
conformance.toml Updates proposal 0050 “partial” commentary to reflect passing failure-isolation fixtures and the new attempt-index behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/openarmature/observability/correlation.py Outdated
Comment thread src/openarmature/observability/correlation.py Outdated
Comment thread src/openarmature/graph/middleware/failure_isolation.py Outdated
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.
@chris-colinsky chris-colinsky merged commit 272b0dd into main Jun 12, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the fix/failure-isolation-attempt-index branch June 12, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants