Skip to content

feat: ADCP 3.0.0-rc3 spec + full registry support#165

Merged
bokelley merged 6 commits intomainfrom
bokelley/adcp-rc3-spec
Apr 4, 2026
Merged

feat: ADCP 3.0.0-rc3 spec + full registry support#165
bokelley merged 6 commits intomainfrom
bokelley/adcp-rc3-spec

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented Apr 3, 2026

Summary

  • ADCP 3.0.0-rc3 protocol: TMP (context_match, identity_match), brand rights (get_brand_identity, get_rights, acquire_rights), compliance test controller
  • Full OpenAPI registry parity: 32 new RegistryClient methods covering all 28 endpoints, with codegen and drift detection
  • RegistrySync: cursor-based change feed polling with glob event routing
  • PropertyRegistry: local authorization cache with background sync

Breaking changes

Fields removed from request types (silent drop if passed)

RC3 removed buyer_campaign_ref and buyer_ref from multiple types. Code passing these fields will have them silently ignored:

  • CreateMediaBuyRequest: buyer_campaign_ref, buyer_ref removed (use po_number)
  • UpdateMediaBuyRequest: buyer_ref removed (use media_buy_id)
  • GetMediaBuysRequest: buyer_refs removed (use media_buy_ids)
  • CheckGovernanceRequest: buyer_campaign_ref, binding removed (use media_buy_id + phase)
  • ReportPlanOutcomeRequest: buyer_campaign_ref removed
  • GetPlanAuditLogsRequest: buyer_campaign_ref removed
  • GetSignalsRequest: buyer_campaign_ref removed
  • ActivateSignalRequest: buyer_campaign_ref removed
  • ProvidePerformanceFeedbackRequest: buyer_ref removed
  • GetCreativeDeliveryRequest: media_buy_buyer_refs removed
  • GetMediaBuyDeliveryRequest: buyer_refs removed

Types removed

  • FormatCategory: compat stub added (all 7 values, RC3 agents accept 4)
  • FormatType = FormatCategory alias preserved
  • Format.type field removed (use format_id filtering)
  • Brand schemas (creative-approval, revocation-notification, update-rights) replaced by get_brand_identity, get_rights, acquire_rights
  • A2UI schemas (bound-value, si-catalog, user-action) removed upstream

Test plan

  • 1039 tests passing (199 new)
  • ruff clean, mypy clean
  • Integration tested against prod registry (18/18 GET endpoints)
  • Code review: all Must Fix addressed
  • Security review: no Must Fix, all Should Fix addressed
  • FormatCategory/FormatType compat stub added
  • MCP tool schemas updated to match RC3 models

bokelley and others added 2 commits April 4, 2026 03:35
Protocol (RC3):
- TMP: context_match, identity_match with TmpHandler
- Brand Rights: get_brand_identity, get_rights, acquire_rights with BrandHandler
- Compliance: comply_test_controller with ComplianceHandler (sandbox only)
- Updated all protocol adapters (base, MCP, A2A), MCP tool definitions,
  server handlers, CLI dispatch, and type exports

Registry (full OpenAPI parity):
- 32 new methods on RegistryClient covering all 28 OpenAPI endpoints
- Codegen from registry-openapi.yaml via datamodel-code-generator
- Drift detection tests (schema coverage + endpoint coverage)
- _request/_request_ok helpers with consistent error handling

RegistrySync:
- Cursor-based change feed polling with glob event routing
- Pluggable CursorStore protocol with FileCursorStore default
- 410 cursor expiry handling with automatic resync

PropertyRegistry:
- Local authorization cache (domain <-> agent bidirectional index)
- Instant synchronous queries: is_authorized, get_domains, get_agents
- Background sync via RegistrySync with typed FeedEvent handling
- async context manager support

Tests: 1039 passing (199 new)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The FileCursorStore default path (.adcp-sync-cursor.json) was
committed during integration testing. Remove it and gitignore it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@bokelley bokelley left a comment

Choose a reason for hiding this comment

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

Review from salesagent (prebid/salesagent) — largest adcp-client-python consumer

We're on adcp>=3.10.0 and import heavily from adcp.types, adcp.types.generated_poc.*, adcp.types.aliases, adcp.exceptions, adcp.webhooks, adcp.adagents, and adcp.utils. Here's our assessment:


Breaking: FormatCategory removal

FormatCategory (and the FormatType = FormatCategory alias) has been removed from adcp.types and adcp.types.generated_poc.enums.format_category. We use this in 4 source files across creative format tooling, schema definitions, and the creative agent registry. This will be a hard break for us.

Files affected in salesagent:

  • src/core/creative_agent_registry.pyfrom adcp.types import FormatCategory as FormatType (used ~15 times for mock format creation and format filtering)
  • src/core/tools/creative_formats.pyfrom adcp.types.generated_poc.enums.format_category import FormatCategory (used in type annotations, format construction, and string→enum coercion)
  • src/core/schemas/_base.pyFormatCategory as FormatTypeEnum (used in default format construction)

Ask: What replaces FormatCategory? Is the type field on Format now a plain string? If so, we can adapt — but it would help if the migration path were documented in the changelog. If there's a replacement enum, a backward-compat alias FormatCategory = <NewThing> in the interim would save us a coordinated version bump.


New capabilities look great

TMP (context_match / identity_match): The privacy-by-design separation of context and identity is well architected. The constraint that package_ids in context_match "MUST NOT vary by user" and that identity_match request_id "MUST NOT correlate with any context_match request_id" are exactly right for publisher trust.

Brand rights: The 4-way discriminated union on AcquireRightsResponse (acquired/pending_approval/rejected/error) is a good pattern. The generation_credentials + rights_constraint flow for scoping creative generation to acquired brand rights is solid.

Compliance test controller: This is extremely useful for us. We already have integration tests that manually force state transitions — being able to use a standard test controller protocol instead would let us validate our implementation against the spec automatically. The simulate_delivery and simulate_budget_spend scenarios are exactly what we need.

Registry + PropertyRegistry: The local authorization cache with background sync via cursor-based change feed is a good design. We currently poll properties ad-hoc — this would give us much better latency for property authorization checks.


Questions / concerns for our integration

  1. BrandReference changes? We use BrandReference from adcp.types.generated_poc.core.brand_ref extensively (DB models, schema helpers, MCP tools). The brand type additions (house, keller_type, visual_guidelines, voice_synthesis) are on the response side so shouldn't break our request usage — but please confirm BrandReference itself (domain + optional brand_id) is unchanged.

  2. generated_poc stability. We have 80+ imports from adcp.types.generated_poc.* paths. The PR regenerated all schemas from rc3. Are there field renames, type changes, or removed fields in the core types we should be aware of beyond FormatCategory? Specifically:

    • ContextObject (core/context.py)
    • CreativeAsset (core/creative_asset.py)
    • PackageRequest / PackageUpdate (media_buy/)
    • TargetingOverlay (core/targeting.py)
    • MediaBuyFeatures (core/media_buy_features.py)
    • PaginationRequest / PaginationResponse
  3. Error type aliasing. We see Error is now re-exported from _ErrorFromError. Our code imports from adcp import Error and from adcp.types.generated_poc.core.error import Error. Will both paths still work identically?

  4. Deleted brand schemas. creative-approval-request.json, creative-approval-response.json, revocation-notification.json, update-rights-request.json, update-rights-response.json were deleted. We don't currently use these, but if any downstream tooling references them, that's a break.

  5. Deleted a2ui schemas. bound-value.json, si-catalog.json, user-action.json were deleted. We don't use a2ui currently, but worth noting in the changelog.


Suggestions

  1. Add a BREAKING CHANGES section to the PR description listing FormatCategory removal and any other type removals, with migration guidance.
  2. Consider a backward-compat shim for FormatCategory (even if deprecated) to allow consumers to upgrade incrementally.
  3. Add a migration guide for the rc2 → rc3 transition, especially for the generated type changes.
  4. Document the compliance test controller opt-in mechanism — should sellers expose it unconditionally, or behind a flag/env var? (We'd want it in test/staging only.)

Overall this is a strong release. The TMP + brand + compliance trifecta gives us a clear path to automated conformance testing. The FormatCategory break is the only blocker for us.

bokelley and others added 2 commits April 3, 2026 22:34
- Add blank line after TYPE_CHECKING block in registry_sync.py
- Remove unnecessary parens in except clause in property_registry.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FormatCategory was removed in RC3 (inlined as Type enum on
ListCreativeFormatsRequest). Add a backward-compat stub enum
with all 7 original values so existing consumers don't break.

FormatType = FormatCategory alias preserved.

Addresses salesagent team review feedback on PR #165.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@bokelley bokelley left a comment

Choose a reason for hiding this comment

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

Thanks for the thorough review from the salesagent perspective — exactly the feedback we needed.

FormatCategory: Fixed

Added a backward-compat enum stub in 756ed50c. Both import paths work:

from adcp import FormatCategory  # works
from adcp.types import FormatCategory  # works
from adcp import FormatType  # works (alias)

The stub has all 7 original values (audio, video, display, native, dooh, rich_media, universal). Note that the RC3 spec only defines 4 values (audio, video, display, dooh) in the inline Type enum on ListCreativeFormatsRequest — the other 3 are preserved for backward compat but may not be accepted by RC3 agents.

Answers to your questions:

  1. BrandReference: Unchanged — still brand_id + domain. The new brand types (house, keller_type, visual_guidelines, etc.) are on the response-side GetBrandIdentityResponse, not on BrandReference.

  2. generated_poc stability: ContextObject, CreativeAsset, PackageRequest, TargetingOverlay, MediaBuyFeatures, PaginationRequest/Response — all field names and types preserved. The main structural changes in RC3 are: GetProductsRequest flattened from a union to a single class, FormatCategory removed (now fixed with compat stub), and Format.type field removed.

  3. Error type aliasing: Both from adcp import Error and from adcp.types.generated_poc.core.error import Error resolve to the same class. The _ErrorFromError qualified name is an internal alias in _generated.py to handle the collision with the compliance test controller's Error enum — the public Error is always the core Pydantic model.

  4. Deleted brand schemas: Correct — creative-approval, revocation-notification, update-rights are replaced by the new rights management protocol (get_brand_identity, get_rights, acquire_rights). No backward compat stubs since you confirmed you don't use them.

  5. Deleted a2ui schemas: Will note in changelog.

Suggestions taken:

  1. Will add a BREAKING CHANGES section to the PR description.
  2. FormatCategory compat shim is now in place.
  3. Migration guide — will add to the PR description.
  4. Compliance test controller — it's a standard ADCP tool that sellers expose. The ComplianceHandler is a separate handler class, so it's opt-in: only servers that subclass ComplianceHandler expose the tool. The description explicitly says "Sandbox only, not for production use."

bokelley and others added 2 commits April 3, 2026 23:03
RC3 removed buyer_campaign_ref and buyer_ref from:
- check_governance (replaced by media_buy_id + phase)
- report_plan_outcome
- get_plan_audit_logs
- get_media_buys (buyer_refs removed, use media_buy_ids)

Updated MCP tool inputSchemas to match actual RC3 Pydantic models.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop compat stubs for types removed in prior spec versions:
BrandManifest, PromotedOfferings, PromotedOfferingsAssetRequirements,
PromotedOfferingsRequirement, PromotedProducts, AssetSelectors,
DeliverTo, DeliverTo1, Pricing, Measurement, PackageStatus,
ListAuthorizedPropertiesRequest, ListAuthorizedPropertiesResponse,
FormatCategory, FormatType.

The 3.0.0-rc3 SDK surface now matches the 3.0.0-rc3 spec exactly.
Consumers on older types must update to RC3 equivalents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit c3f6937 into main Apr 4, 2026
8 checks passed
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