Skip to content

Implement proposal 0045 (nested-lineage augmentation)#104

Merged
chris-colinsky merged 2 commits into
mainfrom
feature/0045-nested-lineage-augmentation
May 31, 2026
Merged

Implement proposal 0045 (nested-lineage augmentation)#104
chris-colinsky merged 2 commits into
mainfrom
feature/0045-nested-lineage-augmentation

Conversation

@chris-colinsky

@chris-colinsky chris-colinsky commented May 31, 2026

Copy link
Copy Markdown
Member

Summary

Implements proposal 0045 (observability §3.4 nested-lineage augmentation containment scope). Rewrites the per-async-context augmentation boundary as three lineage-aware rules: the augmenter's call-stack ancestor chain MUST update, siblings at any depth MUST NOT, and shared parents (fan-out NODE, parallel-branches NODE, invocation span when inside a dispatch boundary) MUST NOT.

Spec pin v0.36.0 → v0.37.0.

Changes

  • Engine (graph/observer.py, graph/parallel_branches.py, graph/compiled.py): per-depth lineage chains (fan_out_index_chain, branch_name_chain) on _InvocationContext. Each descend_into_* extends both chains by one entry. Four leaf-site chain ContextVar sets in compiled.py so set_invocation_metadata reads the full chain.
  • Events (graph/events.py): chain fields on NodeEvent and MetadataAugmentationEvent, populated from context. Scalar fan_out_index / branch_name fields stay as innermost values (backwards-compatible).
  • OTel observer (observability/otel/observer.py): _OpenSpan carries chains; _collect_augmentation_targets rewritten chain-aware against the §3.4 three-step boundary tree; new _span_chain_on_path helper.
  • Langfuse observer (observability/langfuse/observer.py): _OpenObservation carries chains; _handle_metadata_augmentation rewritten; new _observation_chain_on_path helper; parallel_branches_parent_node_name cache added for shared-parent identification.
  • Correlation (observability/correlation.py): chain ContextVars + accessors.
  • Metadata (observability/metadata.py): set_invocation_metadata reads chain vars.
  • Conformance: fixture 039 (observability/039-nested-lineage-augmentation) deferred in the Langfuse harness with an in-source explanation of the two harness primitives needed. Unit-level coverage in test_nested_fan_out_augmentation_reaches_outer_instance_dispatch_span exercises the three boundary rules.

Spec interpretation flag

The invocation span update behavior is preserved per fixture 034 (outermost-serial: no fan-out and no pb dispatch on the augmenter's chain). A strict reading of §3.4 would treat the invocation span as ALWAYS a shared parent regardless of cardinality, but that would break fixture 034 which 0045 explicitly says stays unchanged. Reconciliation predicate is all(fi is None for fi in aug_fi_chain) and all(bn is None for bn in aug_bn_chain) — invocation updates only when no dispatch boundary sits on the augmenter's path. Flagged on the coord thread (discuss-augmentation-nested-lineage-scope msg-04) for spec confirmation before the v0.11.0 release.

Test plan

  • Unit tests pass: uv run pytest tests/unit/test_observability_otel.py tests/unit/test_observability_langfuse.py
  • Full suite: uv run pytest tests/ — 1010 passed, 208 skipped, 3 deselected
  • New regression test: test_nested_fan_out_augmentation_reaches_outer_instance_dispatch_span covers two-instance fan-out + nested subgraph wrapper + lineage-aware boundary application
  • Span-tree visual verification for the new test (optional)

Spec proposal 0045 (observability §3.4) rewrites the per-async-context
augmentation boundary as three lineage-aware rules: the augmenter's
call-stack ancestor chain MUST update (every strict dispatch ancestor
on the augmenter's specific path); siblings at any depth MUST NOT;
shared parents (fan-out NODE, parallel-branches NODE, invocation
span when inside a dispatch boundary) MUST NOT.

Engine: tracks per-depth lineage chains parallel to namespace_prefix.
descend_into_subgraph extends both chains by None; fan-out instance
descent extends fan_out_index_chain with the instance index; pb branch
descent extends branch_name_chain with the branch name. Chain
ContextVars driven at every leaf-node execution site so
set_invocation_metadata sees the full chain.

Events: NodeEvent and MetadataAugmentationEvent grow
fan_out_index_chain and branch_name_chain fields populated from
context. Backwards-compatible — scalar fan_out_index and branch_name
fields stay as innermost values.

OTel and Langfuse observers: _collect_augmentation_targets and
_handle_metadata_augmentation rewrite against the three-step boundary
decision tree. Both observers store the chain on _OpenSpan /
_OpenObservation so the comparison is local rather than re-derived
per event. Shared-parent identification uses the parent_node_name
caches structurally — pb cache mirror added to the Langfuse observer.

Invocation span update: preserved per fixture 034 (outermost-serial
case where the augmenter has no fan-out or pb dispatch on its
call-stack path). When inside any dispatch boundary, the invocation
span MUST NOT update per §3.4's shared-parent rule.

Spec pin v0.36.0 → v0.37.0. Conformance fixture 039 stays deferred
in the Langfuse harness — needs runtime-state item-list lookup for
nested fan-outs plus a new augment_metadata_from_outer_item directive
for case 2. Behavioral contract verified at unit level via
test_nested_fan_out_augmentation_reaches_outer_instance_dispatch_span.
Copilot AI review requested due to automatic review settings May 31, 2026 20:30

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

This PR implements spec proposal 0045 (observability §3.4 nested-lineage augmentation containment scope), rewriting the per-async-context augmentation boundary as three lineage-aware rules so that nested fan-outs / parallel-branches correctly route augmentation only to the augmenter's call-stack ancestor chain (skipping siblings and structural shared parents like fan-out / pb NODE spans and the invocation span when inside a dispatch boundary). The spec pin bumps v0.36.0 → v0.37.0.

Changes:

  • Engine: tracks per-depth fan_out_index_chain / branch_name_chain on _InvocationContext, extended at each descend_into_*, surfaced on NodeEvent / MetadataAugmentationEvent, and driven through new ContextVars at each leaf execution site so set_invocation_metadata reads the full chain.
  • Observers: _OpenSpan / _OpenObservation carry their own chains; _collect_augmentation_targets (OTel) and _handle_metadata_augmentation (Langfuse) rewrite against §3.4's three-step decision tree with chain-prefix matching and structural shared-parent skipping via parent_node_name caches.
  • Tests / version: new unit test covering nested fan-out + subgraph wrapper + leaf augmentation; conformance fixture 039 deferred in the Langfuse harness with an in-source rationale; spec pin & package metadata bumped to 0.37.0.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/openarmature/graph/observer.py Adds per-depth lineage chain fields to _InvocationContext and extends them in each descend_into_*.
src/openarmature/graph/parallel_branches.py Threads branch_name keyword into descend_into_parallel_branch so the branch chain advances.
src/openarmature/graph/compiled.py Imports the new chain ContextVar accessors and sets/resets them around every node execution site; propagates chains onto dispatch events.
src/openarmature/graph/events.py Adds fan_out_index_chain / branch_name_chain to NodeEvent and MetadataAugmentationEvent.
src/openarmature/observability/correlation.py Introduces chain ContextVars + internal setters/resetters + public current_*_chain accessors.
src/openarmature/observability/metadata.py Populates the new chain fields when emitting MetadataAugmentationEvent.
src/openarmature/observability/otel/observer.py Carries chains on _OpenSpan, rewrites _collect_augmentation_targets as a chain-aware §3.4 walk, adds _span_chain_on_path.
src/openarmature/observability/langfuse/observer.py Mirrors the OTel rewrite for Langfuse, adds parallel_branches_parent_node_name cache and _observation_chain_on_path.
tests/unit/test_observability_otel.py New regression test exercising nested fan-out + subgraph + leaf augmentation against §3.4.
tests/conformance/test_observability_langfuse.py Documents why fixture 039 is deferred (two missing harness primitives).
tests/test_smoke.py Updates the asserted spec version.
CHANGELOG.md, conformance.toml, pyproject.toml, src/openarmature/init.py, src/openarmature/AGENTS.md Spec pin and changelog updates to 0.37.0.

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

CI check_conformance_manifest.py flagged that proposal 0045
(accepted in spec v0.37.0) had no entry in conformance.toml. Add
the entry alongside 0044 with status=implemented and the same
v0.11.0 ``since`` as the other proposals in the batch.
@chris-colinsky chris-colinsky merged commit fb1ef70 into main May 31, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the feature/0045-nested-lineage-augmentation branch May 31, 2026 23:11
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