Skip to content

feat(plugin): add execution_arn to OperationInfo hooks - #684

Closed
wangyb-A wants to merge 1 commit into
mainfrom
feat/plugin-operation-info-execution-arn
Closed

feat(plugin): add execution_arn to OperationInfo hooks#684
wangyb-A wants to merge 1 commit into
mainfrom
feat/plugin-operation-info-execution-arn

Conversation

@wangyb-A

Copy link
Copy Markdown
Contributor

Summary

Adds an additive execution_arn: str | None field to the shared OperationInfo
dataclass so every operation and user-function plugin hook, and the operation
maps/snapshots on the invocation hooks, can attribute an operation to its
enclosing durable execution without relying on dictionary insertion order.

This is a prerequisite API improvement for the Python Workflow Insight plugin
(PR #632), which needs a reliable per-operation execution ARN.

Design & compatibility

  • New field is keyword-only, default=None, repr=False, compare=False,
    hash=False, experimental metadata
    — mirroring the additive-field pattern
    established in merged PR feat(plugin): operation maps on invocation hooks #629. Existing infos keep comparing, hashing, and
    reprinting exactly as before, and callers constructing OperationInfo without
    an ARN are unchanged.
  • Inherited by OperationStartInfo, OperationEndInfo, UserFunctionStartInfo,
    and UserFunctionEndInfo.
  • PluginExecutor stamps the active invocation's ARN (from the captured
    InvocationStartInfo) onto every direct hook: on_operation_action (START),
    on_operation_replay, terminal on_operation_update, on_child_context_end,
    on_user_function_start, and the derived user-function end
    (UserFunctionEndInfo.from_start_info preserves it).
  • The OperationInfo entries in InvocationInfo.operations,
    InvocationStartInfo.updated_operations, and OperationChangeInfo
    operations/updated_operations carry the ARN too. It is threaded explicitly
    through OperationInfo.from_operation and _to_operation_info_map — never
    inferred from map ordering.
  • Before an invocation starts, the ARN is None (no active invocation to
    attribute to).

Tests

Added focused unit tests in plugin_test.py:

  • field is keyword-only, experimental, and excluded from repr/eq/hash on the base
    class and all subclasses;
  • repr/equality/hash are unchanged by the ARN;
  • from_operation accepts and propagates the ARN (and defaults to None);
  • every direct hook (on_operation_action, on_operation_replay,
    on_operation_update, on_child_context_end, on_user_function_start,
    user-function end) receives the active ARN;
  • an A/B/A regression proving hooks follow whichever invocation is currently
    active;
  • invocation start/end and OperationChangeInfo map entries all carry the ARN;
  • legacy constructors without an ARN still work.

Validation

  • hatch run dev-core:test — 1640 passed
  • hatch run dev-core:typecheck (mypy) — Success, no issues in 77 source files
  • hatch fmt --check (ruff check + format) — all checks passed, 77 files formatted

Draft — prerequisite for Workflow Insight PR #632. Not for merge until reviewed.

Add an additive, keyword-only execution_arn: str | None field to the shared
OperationInfo dataclass (repr=False, compare=False, hash=False, experimental
metadata) so it is inherited by OperationStartInfo, OperationEndInfo,
UserFunctionStartInfo, and UserFunctionEndInfo.

PluginExecutor stamps the active invocation's ARN onto every direct
operation/user-function lifecycle hook (on_operation_action, on_operation_replay,
terminal on_operation_update, on_child_context_end, on_user_function_start, and
the derived user-function end) and onto the OperationInfo entries of the maps
exposed by InvocationInfo.operations, InvocationStartInfo.updated_operations, and
OperationChangeInfo. The ARN is threaded explicitly through from_operation and
the conversion helpers rather than inferred from map ordering.

Fully backward compatible: the field defaults to None, callers building
OperationInfo without an ARN are unchanged, and equality/hash/repr are
unaffected.
@wangyb-A
wangyb-A deployed to ai-pr-review August 26, 2026 22:18 — with GitHub Actions Active
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 26, 2026 22:21 — with GitHub Actions Inactive
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 26, 2026 22:21 — with GitHub Actions Inactive
)


class TestPluginExecutorStampsExecutionArn(unittest.TestCase):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex AI review

[P2] Add end-to-end coverage for ARN propagation

These tests call PluginExecutor directly, so they do not verify propagation through durable_execution, ExecutionState, background checkpointing, and replay. Repository rules require e2e tests for public API and cross-component changes. Add a tests/e2e/ suspend/replay test asserting the invocation ARN on lifecycle hooks and operation-map entries.

@github-actions

Copy link
Copy Markdown
Contributor

Codex AI review

The implementation is internally consistent, but the new public plugin field lacks required end-to-end coverage.

Reviewed commit 22f5fb059f1f5d799263dde82077acc86d54d069. Workflow run

@github-actions

Copy link
Copy Markdown
Contributor

Claude AI review

No actionable findings. This is a clean, well-scoped additive change that adds an experimental execution_arn: str | None field to OperationInfo and threads it through PluginExecutor's hooks and operation-map snapshots.

Correctness verified:

  • The field is kw_only=True, default=None, repr=False, compare=False, hash=False, so equality, hashing, repr, and all existing positional/keyword construction are unchanged. Pre-existing field-enumeration tests match on input/output/result/error name substrings, which execution_arn does not, so they remain green.
  • Subclass dataclass ordering stays valid: UserFunctionEndInfo's non-defaulted fields still follow only the parent's non-defaulted positional fields because every defaulted parent field (including the new one) is kw_only.
  • Every OperationInfo/subclass emission site is covered — on_operation_action (START), on_operation_replay, terminal on_operation_update end, on_child_context_end, on_user_function_start, UserFunctionEndInfo.from_start_info, and the maps on on_invocation_start/on_invocation_end/OperationChangeInfo. No site was missed.
  • _active_execution_arn correctly returns None before an invocation and follows re-entrant on_invocation_start (validated by the A/B/A test). Where OperationChangeInfo reads self._invocation_status.execution_arn directly, the preceding None guard makes it equivalent to _active_execution_arn, so stamping is consistent within a single on_operation_update call.
  • No cross-package compatibility risk: only plugin.py constructs these infos; the OTel/testing/examples packages consume them, and a defaulted keyword-only field cannot break existing construction.

The added unit tests are comprehensive (field additivity/experimental metadata, keyword-only enforcement, per-hook ARN stamping, A/B/A regression, and operation-map coverage).

Residual test risk (minor, non-blocking): coverage is unit-level only. Since this adds a public API field, an e2e test in tests/e2e/ asserting the ARN propagates end-to-end through a real durable_execution() run would harden the guarantee, but the existing focused unit tests adequately cover the changed behavior for a draft/experimental field.

Reviewed commit 22f5fb059f1f5d799263dde82077acc86d54d069. Workflow run

@wangyb-A wangyb-A closed this Aug 26, 2026
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.

1 participant