feat(plugin): report incomplete user function outcomes - #661
Conversation
| if ( | ||
| info.operation_type is OperationType.STEP | ||
| and info.outcome is not UserFunctionOutcome.INCOMPLETE |
There was a problem hiding this comment.
Codex AI review
[P1] Preserve the OTel package's declared core compatibility
The OTel package still permits core >=1.8.0, where UserFunctionOutcome.INCOMPLETE does not exist. With that supported combination, every normal STEP end raises AttributeError here before ending the span or detaching its context; plugin dispatch swallows the error, leaving stale trace context for subsequent work. Apply the same fix to invocation_plugin.py: compare the outcome value or feature-detect the member, or raise the core dependency minimum to the version introducing it.
| def test_wrap_user_function_reports_incomplete_when_no_outcome(raised): | ||
| """A user function that reports no outcome notifies plugins instead.""" |
There was a problem hiding this comment.
Codex AI review
[P2] Add end-to-end coverage for the public lifecycle change
These tests call wrap_user_function directly, while the OTel tests synthesize hooks directly, so none covers the actual executor, invocation, suspension, replay, and plugin integration. Repository rules require e2e tests for public cross-component behavior. Add a tests/e2e/ case that suspends inside a child context and verifies one INCOMPLETE end for the first start, followed by a new start and eventual SUCCEEDED end on replay, including thread pairing.
Codex AI reviewThe lifecycle logic is coherent for matched versions, but package/API version skew can corrupt telemetry. Required end-to-end coverage is also missing. Reviewed commit |
Summary
UserFunctionOutcome.INCOMPLETEwithout adding a new plugin hook or info typeon_user_function_startis paired with exactly one existingon_user_function_end, including suspension and otherBaseExceptionexitsSemantics
INCOMPLETEmeans the current user-function execution left without producing a success or failure outcome. It covers suspension, orphaned branches, background checkpoint failures, and interpreter-exit control flow. Plugins receive it on the thread that executed the user function, allowing thread-bound state to be released. A suspended operation may resume later and report another start/end pair with its eventual outcome.No new
DurableInstrumentationPlugincallback or payload type is introduced.SUCCEEDEDandFAILEDbehavior is unchanged.Validation
hatch run test:all— 3253 passed, 2 skipped, 5 subtests passedhatch run types:check— cleanhatch run dev-core:typecheck— cleanhatch run dev-otel:typecheck— cleanhatch run dev-otel:test— 146 passedhatch fmt --check— cleanResolves #658