Skip to content

fix(types): add UpdateMediaBuyResponse1 ergonomic coercion#864

Merged
bokelley merged 1 commit into
mainfrom
bokelley/update-media-buy-response-coercion
May 26, 2026
Merged

fix(types): add UpdateMediaBuyResponse1 ergonomic coercion#864
bokelley merged 1 commit into
mainfrom
bokelley/update-media-buy-response-coercion

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Summary

Replaces #857 on a repo-owned branch so required base-repo checks can run normally.

Follow-up to #854.

This extends the generated ergonomic coercion pass to include the update-media-buy success response arm. UpdateMediaBuySuccessResponse / UpdateMediaBuyResponse1 now gets the same package-subclass and media_buy_status string coercion treatment that CreateMediaBuyResponse1 already had.

What changed

  • Added UpdateMediaBuyResponse1 to scripts/generate_ergonomic_coercion.py response analysis.
  • Regenerated src/adcp/types/_ergonomic.py so affected_packages, packages, and media_buy_status are patched at import time.
  • Added regression coverage for package subclass inputs on both update response package fields and string media_buy_status coercion.

Local validation

  • PYTHONPATH=src pytest tests/test_type_coercion.py tests/test_code_generation.py -q --tb=short
  • PYTHONPATH=src pytest tests/test_type_aliases.py tests/test_public_api.py tests/type_checks -q --tb=short
  • PYTHONPATH=src ruff check scripts/generate_ergonomic_coercion.py src/adcp/types/_ergonomic.py tests/test_type_coercion.py

Copy link
Copy Markdown

@aao-ipr-bot aao-ipr-bot Bot left a comment

Choose a reason for hiding this comment

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

LGTM. Follow-ups noted below. Right call to mirror the CreateMediaBuyResponse1 coercion shape on the update-side success arm — the _find_media_buy_success_variant(module) refactor generalizes cleanly and _ergonomic.py:505-528 matches the upstream field declarations exactly (Sequence[Package] for affected_packages, list[Package] for packages, MediaBuyStatus for media_buy_status).

Things I checked

  • Patch annotations mirror the generated source: update_media_buy_response.py:31-34 declares affected_packages: Sequence[Package] | None, packages: list[Package] | None, media_buy_status: MediaBuyStatus | None_ergonomic.py:509-528 preserves the Sequence vs list distinction, which is load-bearing per the file preamble.
  • _find_media_buy_success_variant cannot false-positive: only *Response1 in either module carries media_buy_id (verified across both create_media_buy_response.py and update_media_buy_response.py).
  • Container detection in the comment generator (get_origin(base_ann) is AbcSequence) tracks post_generate_fixes.rewrite_response_list_to_sequence/widen_extension_point_lists_to_sequence outputs — the four list[X] → Sequence[X] comment churn sites at PackageRequest.creatives, CreateMediaBuyRequest.packages, ListCreativesResponse.creatives, GetMediaBuyDeliveryResponse.media_buy_deliveries are correctness, not cosmetic.
  • Legacy status → media_buy_status bridging (media_buy_status_helpers.MEDIA_BUY_LEGACY_STATUS_VALUES) is preserved: the @model_validator(mode='before') at update_media_buy_response.py:37-57 runs ahead of the new field-level BeforeValidator, so the normalizer fires first.
  • Conventional-commit prefix is right: fix(types): is non-breaking and additive. No public-API removal.
  • Public surface unchanged: UpdateMediaBuyResponse1 / UpdateMediaBuySuccessResponse were already exported (__init__.py:613,616, aliases.py:214,607); this PR only loosens input validation, no JSON-schema export change.

Follow-ups (non-blocking — file as issues)

  • UpdateMediaBuyResponse1.packages patches a codegen artifact, not a wire field. Per ad-tech-protocol-expert: the 3.1.0-beta.3, 3.0, and 2.5 update-media-buy-response schemas define only affected_packages on the success arm — packages at update_media_buy_response.py:32 has no upstream basis. The patch is harmless (extra='allow' already accepts it, no wire round-trip change) but advertises a field the spec doesn't define. Either fix the codegen to drop the spurious packages, or drop the patch + the corresponding test assertion. Cross-refs: adcontextprotocol/adcp#4906, #4895.
  • Document the exclude=True discipline for subclass-list coercion. coerce_subclass_list widens input variance, but model_config = ConfigDict(extra='allow') on the response means subclass fields without Field(..., exclude=True) will leak into model_dump(). The new tests use it correctly; the docstring on coerce_subclass_list could note it. Same risk already exists on CreateMediaBuyResponse1.packages — not introduced here.

Minor nits (non-blocking)

  1. Sequence coverage in the new test. tests/test_type_coercion.py:454-468 exercises affected_packages with a plain list, which already worked under the old list[Package] annotation. Passing a tuple (or any non-list Sequence) would actually prove the covariant-Sequence intent of the patch.
  2. Hoist _find_media_buy_success_variant. It's a closure inside generate_code() (scripts/generate_ergonomic_coercion.py:267). Promoting it to module scope alongside get_base_type would make it independently testable. Cosmetic.

Approving on the strength of the protocol-shape check plus the Sequence/list parity with the generated source.

@bokelley bokelley merged commit c111ba6 into main May 26, 2026
23 checks passed
@bokelley bokelley deleted the bokelley/update-media-buy-response-coercion branch May 26, 2026 02:37
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