Skip to content

feat: support AdCP 3.1 Beta 4#872

Merged
bokelley merged 5 commits into
mainfrom
bokelley/adcp-3-1-beta-4
May 26, 2026
Merged

feat: support AdCP 3.1 Beta 4#872
bokelley merged 5 commits into
mainfrom
bokelley/adcp-3-1-beta-4

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 26, 2026

Summary

  • bump generated protocol/schema surface to AdCP 3.1.0-beta.4 and expose the new placement, format option, signal targeting, and webhook challenge types
  • update schema generation/post-generation fixes for Beta 4 unions and generated model edge cases
  • make the example seller and MCP output schemas backward-compatible with current 3.0 storyboards while passing the 3.1 beta storyboard runner
  • matrix the reference seller storyboard CI job across sticky @adcp/sdk adcp-3.0 and adcp-3.1 dist-tags

Validation

  • PYTHONPATH=src uv run pytest tests/ -q - 5422 passed, 30 skipped, 10 deselected, 1 xfailed
  • PYTHONPATH=src uv run ruff check src/adcp/server/mcp_tools.py src/adcp/server/responses.py examples/seller_agent.py tests/test_server_dx.py
  • ADCP_SDK_VERSION=adcp-3.0 STORYBOARD_RESULT_PATH=.context/storyboard-result-adcp-3.0.json bash scripts/ci/run_storyboard_reference_seller.sh - 59 passed, 0 failed
  • ADCP_SDK_VERSION=adcp-3.1 ADCP_PORT=3002 STORYBOARD_RESULT_PATH=.context/storyboard-result-adcp-3.1-retry.json SELLER_LOG_PATH=/tmp/adcp-reference-seller-3002.log bash scripts/ci/run_storyboard_reference_seller.sh - 90 passed, 0 failed
  • npm view @adcp/sdk dist-tags --json - confirmed adcp-3.0 -> 7.11.0 and adcp-3.1 -> 8.1.0-beta.12
  • pre-commit on commit: Black, Ruff, mypy, Bandit, YAML/JSON, and safety checks passed

@bokelley bokelley marked this pull request as ready for review May 26, 2026 10:23
@bokelley bokelley changed the title [codex] Support AdCP 3.1 Beta 4 feat: support AdCP 3.1 Beta 4 May 26, 2026
@bokelley bokelley force-pushed the bokelley/adcp-3-1-beta-4 branch from 37c539f to 4d6f0cd Compare May 26, 2026 10:24
aao-ipr-bot[bot]
aao-ipr-bot Bot previously approved these changes May 26, 2026
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.

Approving. Schema regen to 3.1.0-beta.4 with the public-API surface kept additive and the wire-shape fix on Pagination going in the right direction.

Things I checked

  • Public-API additivity. src/adcp/__init__.py and src/adcp/types/__init__.py add 14 names (FormatOptionReference, PackageSignalTargeting{,Group,Groups}, Placement, PlacementReference, ProductSignalTargetingOption, SignalListing, SignalRef, SignalTargeting{,Expression,Rules}, WebhookChallenge, WebhookChallengeResponse). No removals, no renames. tests/fixtures/public_api_snapshot.json confirms diff is purely additive. feat: (not feat!:) is the right semver signal.
  • responses.py:614 totaltotal_count. The Pagination model carries extra='forbid'; the upstream field has been total_count since beta.3. The previous default emitted an unknown field that any conformance-checking adopter rejected. Fix, not regression. ad-tech-protocol-expert verified against schemas/cache/3.1.0-beta.4/core/pagination-response.json.
  • _widen_media_buy_output_schema_for_version_compat at src/adcp/server/mcp_tools.py:1690-1735. Variant-match predicate (media_buy_id in required AND status.const == "completed") targets only the sync-success arms of create_media_buy / update_media_buy. The errors arm has no status const; the submitted task-envelope arm lacks media_buy_id — both untouched. ad-tech-protocol-expert confirms the upstream oneOf discriminates branches via required-set + the submitted branch's not(required: media_buy_id|packages), so widening status does not collide with the envelope discriminator.
  • Generated-type regeneration audit. src/adcp/types/generated_poc/** and src/adcp/types/_generated.py are the output of running the codegen against schemas/cache/3.1.0-beta.4/. ADCP_VERSION is bumped in lockstep. The PricingOption13/14/15/16 → 141/142/... and similar renumber churn in SCHEMA_DELTAS.md is expected codegen behavior per the project README.
  • Type-layering preserved. New exports reach the surface through _generated__init__ only — no source file outside the allowlist imports from generated_poc/.
  • signal_targeting_allowed projection move. The field moved from _get_products_helpers.py's non-enum pass-through set into the GetProductsField enum, matching the upstream 3.1 product-projection contract. Test added at tests/test_get_products_projection.py:174-189 asserts buyers must explicitly request it.
  • Test-plan honesty. PR description's validation is all checked: 5422/5422 pass, both storyboard matrix rows pass (59/59 latest, 90/90 beta), pre-commit passes. No unchecked boxes.

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

  • PackageSignalTargeting{Groups,Group}.operator is a two-tier enum. Outer (Groups) is ["all"] only; inner (Group) is ["any","none"] only. Worth a one-line note in the public docstring so adopters don't pass "all" on an inner group and get rejected by the seller validator. (ad-tech-protocol-expert flag.)
  • MCP outputSchema widening has no regression test. tests/test_server_dx.py:957-987 exercises the post-widen shape, but nothing asserts the variant-match predicate stays narrow if Pydantic's union arm ordering reshuffles. Add a test that the errors and submitted variants are not mutated.
  • Typed-Pydantic path for sync create_media_buy is stricter than upstream. src/adcp/types/generated_poc/media_buy/create_media_buy_response.py:32 pins status: Literal["completed"], but the upstream schema makes status optional and references MediaBuyStatus. The widening covers the MCP-advertisement layer; confirm the per-version response validator path actually short-circuits Pydantic.parse for 3.0 buyers, or 3.0 sellers' payloads will round-trip-fail through the typed path. (ad-tech-protocol-expert caveat.)

Minor nits (non-blocking)

  1. fix_deprecated_rootmodel_fields line-blanking is brittle. scripts/post_generate_fixes.py:1483-1487 clears the entire line whenever it contains deprecated=True. Today datamodel-code-generator emits deprecated=True on its own line for RootModel root fields, so it works. If a future emission packs Field(deprecated=True, description=…, ge=…) onto one line (see bundled/signals/get_signals_request.py:813 for an example of that layout elsewhere in the tree), the fix erases the whole Field(...) call and produces a syntax error. A targeted re.sub(r",?\s*deprecated\s*=\s*True\s*,?", "", lines[index]) would be safer.
  2. CI cache key is now a moving label. .github/workflows/ci.yml:12 switched ADCP_SDK_VERSION from pinned 8.1.0-beta.7 to the beta dist-tag, and the npm cache key uses the tag directly. Cache contents will drift relative to the installed package over time. Not blocking — npm install -g still runs every job — but a deterministic-version recording step would make storyboard reruns reproducible. The docstring you added already calls out the long-term solution (sticky per-minor tags upstream).
  3. _is_adcp_31_or_newer exception list. src/adcp/server/mcp_tools.py:52-60 catches AttributeError/TypeError; the only branch into the body operates on a string, so narrowing to ValueError would be tighter.

Safe to merge.

@bokelley bokelley enabled auto-merge (squash) May 26, 2026 10:39
@bokelley
Copy link
Copy Markdown
Contributor Author

Nudging GitHub Actions after workflow-only CI gate fix did not create a run for the new head.

@bokelley bokelley closed this May 26, 2026
auto-merge was automatically disabled May 26, 2026 10:44

Pull request was closed

@bokelley bokelley reopened this May 26, 2026
@bokelley
Copy link
Copy Markdown
Contributor Author

Nudging GitHub Actions again after resolving the main-branch conflict; prior pushes only attached GitGuardian, not the required Actions suite.

@bokelley bokelley closed this May 26, 2026
@bokelley bokelley reopened this May 26, 2026
@bokelley bokelley added the v3.1 Blocked on AdCP spec v3.1 — needs spec changes before SDK can land label May 26, 2026
# Conflicts:
#	src/adcp/server/mcp_tools.py
#	tests/test_server_dx.py
@bokelley bokelley force-pushed the bokelley/adcp-3-1-beta-4 branch from 33ef86e to 74e5529 Compare May 26, 2026 10:49
@bokelley bokelley merged commit 1bae6e8 into main May 26, 2026
1 check passed
@bokelley bokelley deleted the bokelley/adcp-3-1-beta-4 branch May 26, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v3.1 Blocked on AdCP spec v3.1 — needs spec changes before SDK can land

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant