Skip to content

Implement proposal 0044 (parallel-branches dispatch span)#103

Merged
chris-colinsky merged 3 commits into
mainfrom
feature/0044-parallel-branches-dispatch-span
May 31, 2026
Merged

Implement proposal 0044 (parallel-branches dispatch span)#103
chris-colinsky merged 3 commits into
mainfrom
feature/0044-parallel-branches-dispatch-span

Conversation

@chris-colinsky

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

Copy link
Copy Markdown
Member

Summary

Adds per-branch OTel dispatch spans to ParallelBranchesNode, mirroring the FanOut topology introduced in earlier proposals. Each branch gets its own dispatch span anchored on the parallel-branches node, with inner branch work parented under that span. Augmentation and metadata-update lineage extend through these spans per the ancestor-chain rule.

Bumps the spec pin to v0.36.0 and activates conformance fixture 038.

Changes

  • graph/events.py: new ParallelBranchesEventConfig mirroring FanOutEventConfig; NodeEvent.parallel_branches_config field
  • graph/compiled.py: builds and ships parallel_branches_config on dispatch start/complete from node.branches.keys() and node.error_policy
  • observability/otel/observer.py:
    • opens/closes per-branch dispatch spans driven off the config
    • extends augmentation target collection to walk into per-branch dispatch spans for aug_bn-scoped events
    • renames openarmature.branch_name to openarmature.node.branch_name for namespace alignment
    • adds openarmature.parallel_branches.branch_count and .error_policy attributes
  • Conformance: activates fixture 038 in test_observability.py; defers 039 (PR 11) and 017-031 prompt-management fixtures (PR 12) in test_fixture_parsing.py
  • Unit tests: new coverage for parent-resolution under dispatch span, retry-middleware per-attempt synthesis, nested fan-out topology, and metadata augmentation with sibling-skip semantics
  • Spec submodule pinned to v0.36.0; corresponding bumps in pyproject.toml, __init__.py, test_smoke.py, conformance.toml, AGENTS.md
  • CHANGELOG: 0044 entry and breaking-change note for the attribute rename

Breaking change

openarmature.branch_name is renamed to openarmature.node.branch_name on node spans. Downstream consumers reading this attribute must update their queries.

Test plan

  • Unit tests pass: uv run pytest tests/unit/test_observability_otel.py
  • Conformance tests pass with fixture 038 active: uv run pytest tests/conformance/test_observability.py
  • Span tree visually verified for the four new topology tests (under dispatch span, retry attempt, fan-out + parallel-branches, augmentation lineage)

Adds per-branch OTel dispatch spans to ParallelBranchesNode, mirroring
the FanOut topology. Each branch gets its own dispatch span anchored on
the parallel-branches node, with inner branch work parented under it.
Augmentation and metadata-update lineage extend through these spans per
the ancestor-chain rule (spec 0040 / 0045).

Renames the existing node attribute `openarmature.branch_name` to
`openarmature.node.branch_name` to align with the spec's attribute
namespace conventions. Adds `openarmature.parallel_branches.branch_count`
and `openarmature.parallel_branches.error_policy` to the node span.

Bumps the spec pin to v0.36.0 and activates conformance fixture 038.

Includes regression coverage for parent-resolution under the dispatch
span, retry-middleware per-attempt synthesis, nested fan-out topology,
and metadata augmentation with sibling-skip semantics.
Copilot AI review requested due to automatic review settings May 31, 2026 17:09

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

Implements spec proposal 0044 by adding per-branch OpenTelemetry “dispatch” spans for ParallelBranchesNode, including new event payload (ParallelBranchesEventConfig), observer logic to open/close these spans, and accompanying conformance/unit test updates. It also pins the project’s spec version to v0.36.0 and updates related metadata/documentation.

Changes:

  • Add ParallelBranchesEventConfig to node events and emit it from the engine on parallel-branches node started/completed events.
  • Extend the OTel observer to synthesize per-branch dispatch spans, propagate augmentation lineage through them, and rename openarmature.branch_nameopenarmature.node.branch_name.
  • Activate OTel conformance fixture 038 and add multiple unit/conformance tests for the new topology and attributes.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit/test_observability_otel.py Adds unit tests covering parallel-branches dispatch spans, parenting, retry attempts, nested topology, and augmentation behavior; updates attribute name in assertions.
tests/test_smoke.py Updates pinned spec version assertion to 0.36.0.
tests/conformance/test_observability.py Activates fixture 038 and adds a new runner + span-tree matching helper for proposal 0044.
tests/conformance/test_fixture_parsing.py Defers additional fixtures (038, 039, and prompt-management 017–031) with reasons.
src/openarmature/observability/otel/observer.py Adds per-branch dispatch span state, opening/closing logic, augmentation target traversal, parent-resolution updates, and attribute rename/new attributes.
src/openarmature/graph/events.py Introduces ParallelBranchesEventConfig and wires it into NodeEvent.
src/openarmature/graph/compiled.py Constructs and dispatches parallel_branches_config on parallel-branches node started/completed events.
src/openarmature/AGENTS.md Updates bundled spec version reference to v0.36.0.
src/openarmature/init.py Bumps __spec_version__ to 0.36.0.
pyproject.toml Updates tool.openarmature.spec_version to 0.36.0.
conformance.toml Pins spec to v0.36.0 and marks proposal 0044 implemented.
CHANGELOG.md Documents proposal 0044 and the breaking attribute rename; updates spec pin note.

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

Comment thread src/openarmature/observability/otel/observer.py Outdated
Comment thread src/openarmature/observability/otel/observer.py
Comment thread src/openarmature/observability/otel/observer.py
Comment thread tests/conformance/test_observability.py
CoPilot's PR 103 review flagged three correctness issues for
parallel-branches nodes nested deeper than depth 1; addressing them
fully also required extending the analogous fan-out machinery and
fixing two latent bugs the campsite test exposed.

Resolver: replaces the four hard-coded namespace[:1] / depth-1 dispatch
lookups (1a, 1a', 1c) with one prefix walk longest-to-shortest that
checks per-branch, detached fan-out instance, and non-detached fan-out
instance dispatch at every depth. The innermost matching dispatch span
wins regardless of which type, which gives the right answer for
parallel-branches nested inside a fan-out instance and the inverse.

Synthesis: drops the depth == 1 gate from non-detached fan-out instance
synthesis and from its companion dedup guard; the parent_node_name
cache match already self-gates to the correct depth. Updates the
detached-subgraph and detached-fan-out checks to match on prefix[-1]
(the node-name segment) at any depth instead of prefix[0]; behavior at
depth 1 is unchanged. _open_detached_subgraph_root now walks
prefix-by-prefix to find its dispatch span's parent instead of
hardcoding the invocation span.

Scans: _find_fan_out_node_span and the parallel-branches NODE scan in
_open_parallel_branches_branch_dispatch_span both relax to match by
namespace only; the NODE span may legitimately carry an outer
fan_out_index or branch_name when nested.

Cache filter: drops the secondary branch_name is None / fan_out_index
is None predicates from both cache-update gates. The *_config field is
itself only populated on a NODE's own events, so the secondary check
was redundant; in practice it skipped caching whenever a pb or fan-out
node sat inside another pb's branch or fan-out's instance, breaking
synthesis for the inner node.

Branch-name validation: caches branch_names from
ParallelBranchesEventConfig alongside parent_node_name; per-branch
synthesis now requires event.branch_name to be in this pb's actual
branch set. Prevents an inner pb's branch event from synthesizing a
phantom dispatch span at an outer pb that doesn't declare that
branch.

NODE-ancestor guard: when the synthesis loop reaches an ancestor
prefix that is already known to be a pb or fan-out NODE (via either
cache), don't open a synthetic subgraph-wrapper span; the NODE's own
span via _open_started_span is the correct ancestor.

Conformance fixture 038 harness: the per-subgraph closure documented
binding messages from the fixture but only bound stores_in. Now parses
calls_llm.messages.

Tests:
- test_parallel_branches_inside_subgraph_wrapper_parent_topology
- extends test_parallel_branches_inside_fan_out_instance to assert
  per-branch dispatch parents the leaf and itself parents under the
  parallel-branches NODE at the fan-out instance's namespace
- test_fan_out_inside_subgraph_wrapper_emits_per_instance_dispatch_span
- test_detached_subgraph_at_depth_two_mints_fresh_trace
- test_three_deep_mixed_pb_fan_out_pb_composition

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

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

Comment thread src/openarmature/observability/otel/observer.py Outdated
Comment thread tests/unit/test_observability_otel.py Outdated
Comment thread tests/conformance/test_observability.py Outdated
CoPilot's second review caught a symmetric mirror of the cache-update
filter bug fixed in the previous commit. The completion handlers
gated on ``branch_name is None and parallel_branches_config is not
None`` (pb) and ``fan_out_index is None and fan_out_config is not
None`` (fan-out). The ``*_config`` field is only populated on a NODE's
own events, so the secondary predicate was redundant; in practice it
skipped close for nested pb/fan-out and leaked the per-branch /
per-instance dispatch span caches.

Fix both close handlers symmetrically (CoPilot flagged the pb side
only; same latent bug on the fan-out side). Add a regression test
exercising pb-completion-inside-outer-pb-branch.

Also fix two stale doc comments PR 9 left behind:
- test_observability_otel.py: claim that fixture 038 activation is
  deferred is outdated; PR 9 activated it in the conformance harness.
- test_observability.py: claim that the mock LLM matches by user-
  message content is outdated; the _handler is FIFO (its own docstring
  three lines down already says so).
@chris-colinsky chris-colinsky merged commit 74c6719 into main May 31, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the feature/0044-parallel-branches-dispatch-span branch May 31, 2026 19:00
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