Skip to content

fix(webhooks): correct type annotations for extract_webhook_result_data and payload builders#600

Merged
bokelley merged 3 commits intomainfrom
claude/issue-598-webhook-type-annotation-fixes
May 9, 2026
Merged

fix(webhooks): correct type annotations for extract_webhook_result_data and payload builders#600
bokelley merged 3 commits intomainfrom
claude/issue-598-webhook-type-annotation-fixes

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 8, 2026

Closes #598

Summary

Two webhook helpers in src/adcp/webhooks.py declared type annotations that didn't match runtime behavior, forcing adopters to cast or add # type: ignore comments.

extract_webhook_result_data — declared return type was AdcpAsyncResponseData | None but every code path returns dict[str, Any] | None. The cast() calls inside the body were lies to mypy; callers that did result.get(...) correctly got a type error. Return type corrected to dict[str, Any] | None; docstring updated accordingly.

create_mcp_webhook_payload and create_a2a_webhook_payloadresult parameter was typed as AdcpAsyncResponseData | dict[str, Any] (narrow discriminated union), but both functions already called hasattr(result, "model_dump") at runtime and accepted any Pydantic model. Parameter widened to PydanticBaseModel | dict[str, Any]; docstrings updated.

Also removes the direct import from adcp/types/generated_poc/ in webhooks.py (a CLAUDE.md layering violation — that import path is for stable.py / aliases.py / _ergonomic.py only). The import is now unused after the above fixes.

Fixes bogus message= kwarg in the create_a2a_webhook_payload docstring example, which would raise TypeError if copied verbatim.

Not in scope / noted for follow-up: WebhookSender.send_mcp in webhook_sender.py:525 has the same narrow AdcpAsyncResponseData | dict[str, Any] | None annotation and the same generated_poc/ import. That file is separate from the callsites named in #598 — addressed in a follow-up.

What tested

  • pytest tests/test_webhook_handling.py tests/test_webhooks_deliver.py tests/conformance/signing/164 passed, 15 skipped
  • Added TestWebhookPayloadBuilderPydanticModel (4 tests) exercising the model_dump path in both builders via a plain BaseModel subclass — previously untested code path
  • mypy src/adcp/webhooks.pyclean
  • ruff check src/adcp/webhooks.pyclean

Pre-PR review

  • code-reviewer: approved — all blockers resolved, no new issues (round 2)
  • dx-expert: approved — all blockers resolved (round 2)

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_013oiysa4CAeiSFFdnvFTHqh


Generated by Claude Code

@bokelley
Copy link
Copy Markdown
Contributor Author

bokelley commented May 8, 2026

Fold opportunity from #601: Issue #601 proposes adding to_wire_dict — a public wrapper around the same Task | TaskStatusUpdateEvent | Pydantic | dict dispatch that _payload_to_dict (private) already implements in this file — plus an optional return-type change to create_mcp_webhook_payload that directly overlaps this PR's annotation work.

If you want to ship them together, consider folding before merge: expose _payload_to_dict as to_wire_dict, re-export it from adcp.webhooks and the package root, and add the two roundtrip tests from #601's acceptance criteria. The implementation is small given _payload_to_dict already exists. If you prefer to keep this PR scoped to annotations, #601 will resurface on merge automatically.


Generated by Claude Code

claude added 2 commits May 9, 2026 04:32
extract_webhook_result_data declared AdcpAsyncResponseData | None but
every code path returned dict[str, Any] | None, forcing adopters to
cast before using .get(). Return type corrected to dict[str, Any] | None
and internal cast calls updated accordingly.

create_mcp_webhook_payload and create_a2a_webhook_payload typed result
narrowly as AdcpAsyncResponseData but accepted any BaseModel via
hasattr check at runtime. Parameter widened to PydanticBaseModel |
dict[str, Any] so callers pass any Pydantic model without type: ignore.

Also drops the direct generated_poc import (CLAUDE.md layering rule)
since AdcpAsyncResponseData is no longer referenced in this module,
and fixes a bogus message= kwarg in the create_a2a_webhook_payload
docstring example.

https://claude.ai/code/session_013oiysa4CAeiSFFdnvFTHqh
…builders

Adds TestWebhookPayloadBuilderPydanticModel covering the model_dump path
in create_mcp_webhook_payload and create_a2a_webhook_payload (both
completed and working status paths). Also fixes the result param
docstring in create_mcp_webhook_payload to match the widened type.

https://claude.ai/code/session_013oiysa4CAeiSFFdnvFTHqh
@bokelley bokelley force-pushed the claude/issue-598-webhook-type-annotation-fixes branch from 3cb642e to 00d93db Compare May 9, 2026 08:32
@bokelley bokelley marked this pull request as ready for review May 9, 2026 08:33
The fix removed the generated_poc/ import from webhooks.py, so the entry
in _KNOWN_VIOLATIONS is now stale and the layering test fails on the
"stale entries" branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit e624b5c into main May 9, 2026
16 checks passed
@bokelley bokelley deleted the claude/issue-598-webhook-type-annotation-fixes branch May 9, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type-annotation fixes for webhook helpers

2 participants