Add cause chain to failure-isolation event (0068)#162
Merged
Conversation
FailureIsolatedEvent.caught_exception gains a structured chain: an ordered list of CauseLink records (category, message, and a carrier flag) from the caught exception to the originating raise, with engine node_exception wrappers flagged. The single category and message are retained and redefined as a derivation over the chain, reproducing the prior 0065 values, so the change is additive: existing consumers and the bundled OTel and Langfuse observers are unaffected. This supersedes 0065's single originating-cause representation, which was ambiguous when the post-carrier chain held more than one non-carrier link. Advance the pinned spec to v0.57.0 with conformance fixture 066 plus unit tests for the carrier, nested-carrier, and re-categorization cases.
There was a problem hiding this comment.
Pull request overview
Implements spec proposal 0068 (spec v0.57.0) by extending failure-isolation telemetry so FailureIsolatedEvent.caught_exception includes a structured, ordered cause chain, while preserving the previously exposed derived category/message behavior for existing consumers.
Changes:
- Added
CauseLinkand extendedCaughtExceptionwith achainrepresenting the full__cause__chain with engine carrier wrappers flagged. - Updated
FailureIsolationMiddlewareto build the chain and derive the legacycategory/messagefrom it. - Bumped spec pin/versioning and updated conformance harness + unit tests + docs/changelog accordingly.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_failure_isolation_middleware.py | Adds unit tests validating chain construction and derivation behavior (carrier, nested carriers, recategorization). |
| tests/test_smoke.py | Updates asserted __spec_version__ to 0.57.0. |
| tests/conformance/test_pipeline_utilities.py | Extends conformance runner to translate node-nested middleware and asserts expected cause chains. |
| src/openarmature/graph/middleware/failure_isolation.py | Builds cause chain and derives single category/message from it when emitting events. |
| src/openarmature/graph/events.py | Introduces CauseLink; extends CaughtException with chain; updates event docs/exports. |
| src/openarmature/graph/init.py | Re-exports CauseLink from openarmature.graph. |
| src/openarmature/init.py | Bumps __spec_version__ to 0.57.0. |
| pyproject.toml | Bumps [tool.openarmature].spec_version to 0.57.0. |
| docs/concepts/middleware.md | Updates failure-isolation documentation to describe the derived fields plus full chain. |
| conformance.toml | Advances spec_pin to v0.57.0 and records proposal 0068 as implemented. |
| CHANGELOG.md | Adds changelog entry for proposal 0068 and updates spec-pin advancement narrative. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The bundled agent guide embeds the spec-pin version stamps, which the test_agents_md_drift check verifies against a fresh regeneration. The v0.57.0 submodule bump left them reading v0.56.0; regenerate via scripts/build_agents_md.py. Generated artifact only, no behavior change.
`_build_cause_chain` recorded an empty-string `category` verbatim, but `CauseLink.category` is documented as a non-empty string or None and `_derive_cause` already treats an empty string as no-category. Coerce it to None so the chain representation matches. No exception carries an empty-string category in practice; addresses PR review feedback.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When
FailureIsolationMiddlewarecatches an error and degrades a node, theFailureIsolatedEventit emits now carries the full structured cause chain alongside the existing single category and message.CaughtExceptiongains achain: an ordered list ofCauseLinkrecords (category,message, and acarrierflag) from the caught exception down to the originating raise, with the engine'snode_exceptionwrapper layers flagged so consumers can skip them.The single
category/messageare retained and redefined as a derivation over the chain (the outermost non-carrier link carrying a category). The derivation reproduces the prior 0065 values exactly, so the change is additive: existing consumers and the bundled OTel and Langfuse observers are unaffected. This supersedes proposal 0065's single "originating cause" representation, which was ambiguous once the post-carrier chain held more than one non-carrier link.Adopts proposal 0068 (spec v0.57.0). First of four PRs folding the v0.14.0 consolidated spec-review findings (0068 through 0071) into the release.
Changes
CauseLinkdataclass andCaughtException.chainfield, exported fromopenarmature.graph.FailureIsolationMiddlewarebuilds the chain on catch and derives the single category / message from it.Testing
uv run pytest tests/unit tests/conformance: 1269 passed, 280 skipped.ruff,pyright, andmkdocs build --strictall clean.