Implement 0040 open-span metadata update#96
Merged
Conversation
Mid-invocation set_invocation_metadata now emits a MetadataAugmentationEvent on the engine's serial observer queue. Both observers match the augmenter's lineage tuple (namespace, attempt_index, fan_out_index, branch_name) against their open observations and apply the entries in place: span.set_attribute on OTel, observation.update(metadata=...) on Langfuse. Outermost-serial also fires trace.update so the augmented keys land at trace.metadata.<key>. Sibling instances and ancestors above the innermost containment are skipped per spec sec 3.4. OTel's open-span _StackKey widened to include branch_name so concurrent same-named inner nodes across sibling parallel-branches branches no longer collide. Same widening on the Langfuse observer plus the LLM event payload's calling_branch_name field. Shared tuple-prefix helpers extracted to observability/lineage.py. Conformance: activate 028's mid-invocation rejection case (helper raises at the call site on a reserved key) and 034 outermost-serial fixture via the Langfuse harness. Fix the pre-existing 005 flake by resetting the OTel global tracer Once primitive before set_tracer_provider. 029 and 030 stay deferred with documented fixture-shape gaps; the augmentation mechanism itself is covered end-to-end by new unit tests in test_observability_otel and test_observability_langfuse. Two coord threads opened for follow-up: nested fan-out lineage scope and parallel-branches per-branch dispatch span shape.
There was a problem hiding this comment.
Pull request overview
Implements proposal 0040 mid-invocation metadata augmentation. set_invocation_metadata now emits a new MetadataAugmentationEvent through the engine's serial observer queue; the OTel and Langfuse observers apply the augmented entries in place to open spans/observations whose lineage covers the calling context (per spec §3.4 scoping). The observer _StackKey is widened with branch_name to disambiguate concurrent same-named inner nodes across sibling parallel branches.
Changes:
- New
MetadataAugmentationEvent(frozen dataclass, exported fromopenarmature.graph) + delivery plumbing in the observer worker that bypasses the phase filter for augmentation events. - OTel and Langfuse observers gain
_handle_metadata_augmentation, a sharedlineage.pyprefix-helpers module, branch-aware_StackKey, andcalling_branch_nameinLlmEventPayload. - Conformance: activate fixture 028 mid-invocation rejection case and 034 outermost-serial via the Langfuse harness; fixtures 029/030 stay deferred with documented reasons; pre-existing fixture 005 flake fixed via direct reset of the OTel
_TRACER_PROVIDER_SET_ONCEprimitive.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/openarmature/graph/events.py | Defines MetadataAugmentationEvent; adds to __all__. |
| src/openarmature/graph/init.py | Re-exports MetadataAugmentationEvent. |
| src/openarmature/graph/observer.py | Updates Observer protocol/_QueuedItem to event union; routes augmentation events past phase filter and prepare_sync. |
| src/openarmature/observability/correlation.py | Widens dispatch ContextVar typing to the event union. |
| src/openarmature/observability/metadata.py | Emits MetadataAugmentationEvent through current dispatch after merging entries. |
| src/openarmature/observability/lineage.py | New shared tuple-prefix helpers. |
| src/openarmature/observability/llm_event.py | Adds calling_branch_name to LLM event payload. |
| src/openarmature/llm/providers/openai.py | Populates calling_branch_name on the LLM event. |
| src/openarmature/observability/otel/observer.py | Widens _StackKey with branch_name; adds augmentation-target collection and in-place set_attribute. |
| src/openarmature/observability/langfuse/observer.py | Mirrors OTel: branch-aware key, update_trace/observation.update augmentation. |
| examples/* | Examples updated to accept the union and isinstance-narrow. |
| tests/unit/test_observer.py, test_drain.py, test_runtime_errors.py | Observer signatures updated to the union. |
| tests/unit/test_observability_otel.py | New outermost-serial / fan-out / parallel-branches / no-op / outside-invocation tests. |
| tests/unit/test_observability_langfuse.py | New trace+node-update, fan-out per-instance, no-op, outside-invocation tests. |
| tests/conformance/test_observability.py | Activates 028 augment-rejection case; adds OTel _TRACER_PROVIDER_SET_ONCE reset before set_tracer_provider. |
| tests/conformance/test_observability_langfuse.py | Activates 034; adds augment-middleware builders for fan-out / parallel branches; subgraph-key normalization; fixture-level subgraph folding into cases. |
| tests/conformance/test_fixture_parsing.py | Updates 029/030/034 deferral notes. |
| tests/conformance/test_conformance.py, tests/conformance/adapter.py | Adapter observer ignores MetadataAugmentationEvent. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
6 tasks
chris-colinsky
added a commit
that referenced
this pull request
May 30, 2026
Extends the observability spec.4 reserved exact-key-name set from 21 to 24 entries with `branch_name`, `detached`, and `detached_from_invocation_id`. These three are top-level Langfuse metadata keys the observer mapping already writes; without reservation a caller key matching one would silently shadow the OA-emitted field at the boundary, the same hazard 0041 closed for its 20 names. Also relocates `observation.metadata.detached: true` from the detached-side dispatch observation onto the parent-side dispatching observation in the main trace (link observation for detached subgraphs; parent fan-out node observation for detached fan-outs), matching the .4.2 row 0042 added and the corresponding fixture 033 assertions. Bumps the spec pin from v0.31.0 to v0.34.0, absorbing 0042 plus the two textual additions in v0.32.0 (Gemini wire-format mapping, 0038, not yet implemented) and v0.33.0 (sessions capability, 0020, not yet implemented). Updates `conformance.toml` accordingly: 0040 flipped not-yet to implemented (shipped in PR #96); 0042 added as implemented; 0020 and 0038 added as not-yet. Defers the 10 new Gemini conformance fixtures in both the cross-capability parser and the LLM-provider harness to match the not-yet status.
6 tasks
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
set_invocation_metadatanow emits aMetadataAugmentationEventon the engine's serial observer queue; both OTel and Langfuse observers match the augmenter's lineage tuple(namespace, attempt_index, fan_out_index, branch_name)against their open observations and apply the entries in place (span.set_attribute/observation.update(metadata=...)). Outermost-serial also firestrace.update. Sibling instances and ancestors above the innermost containment are skipped per spec sec 3.4._StackKeywidened to includebranch_namein both observers so concurrent same-named inner nodes across sibling parallel-branches branches no longer collide; LLM event payload picks upcalling_branch_name.src/openarmature/observability/lineage.py.set_tracer_provider.discuss-augmentation-nested-lineage-scope(nested fan-out / parallel-branch lineage chain shape) anddiscuss-otel-parallel-branches-dispatch-span(per-branch dispatch span on the OTel mapping).Test plan
uv run pyrightcleanuv run pytest tests/unit/ tests/conformance/ -q(948 pass, 81 skipped)