feat: ADCP 3.0.0-rc3 spec + full registry support#165
Conversation
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>
bokelley
left a comment
There was a problem hiding this comment.
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.py—from adcp.types import FormatCategory as FormatType(used ~15 times for mock format creation and format filtering)src/core/tools/creative_formats.py—from adcp.types.generated_poc.enums.format_category import FormatCategory(used in type annotations, format construction, and string→enum coercion)src/core/schemas/_base.py—FormatCategory 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
-
BrandReferencechanges? We useBrandReferencefromadcp.types.generated_poc.core.brand_refextensively (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 confirmBrandReferenceitself (domain + optional brand_id) is unchanged. -
generated_pocstability. We have 80+ imports fromadcp.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 beyondFormatCategory? 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
-
Errortype aliasing. We seeErroris now re-exported from_ErrorFromError. Our code importsfrom adcp import Errorandfrom adcp.types.generated_poc.core.error import Error. Will both paths still work identically? -
Deleted brand schemas.
creative-approval-request.json,creative-approval-response.json,revocation-notification.json,update-rights-request.json,update-rights-response.jsonwere deleted. We don't currently use these, but if any downstream tooling references them, that's a break. -
Deleted a2ui schemas.
bound-value.json,si-catalog.json,user-action.jsonwere deleted. We don't use a2ui currently, but worth noting in the changelog.
Suggestions
- Add a BREAKING CHANGES section to the PR description listing
FormatCategoryremoval and any other type removals, with migration guidance. - Consider a backward-compat shim for
FormatCategory(even if deprecated) to allow consumers to upgrade incrementally. - Add a migration guide for the rc2 → rc3 transition, especially for the generated type changes.
- 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.
- 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>
bokelley
left a comment
There was a problem hiding this comment.
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:
-
BrandReference: Unchanged — still
brand_id+domain. The new brand types (house,keller_type,visual_guidelines, etc.) are on the response-sideGetBrandIdentityResponse, not onBrandReference. -
generated_poc stability:
ContextObject,CreativeAsset,PackageRequest,TargetingOverlay,MediaBuyFeatures,PaginationRequest/Response— all field names and types preserved. The main structural changes in RC3 are:GetProductsRequestflattened from a union to a single class,FormatCategoryremoved (now fixed with compat stub), andFormat.typefield removed. -
Error type aliasing: Both
from adcp import Errorandfrom adcp.types.generated_poc.core.error import Errorresolve to the same class. The_ErrorFromErrorqualified name is an internal alias in_generated.pyto handle the collision with the compliance test controller'sErrorenum — the publicErroris always the core Pydantic model. -
Deleted brand schemas: Correct —
creative-approval,revocation-notification,update-rightsare 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. -
Deleted a2ui schemas: Will note in changelog.
Suggestions taken:
- Will add a BREAKING CHANGES section to the PR description.
- FormatCategory compat shim is now in place.
- Migration guide — will add to the PR description.
- Compliance test controller — it's a standard ADCP tool that sellers expose. The
ComplianceHandleris a separate handler class, so it's opt-in: only servers that subclassComplianceHandlerexpose the tool. The description explicitly says "Sandbox only, not for production use."
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>
Summary
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:
Types removed
Test plan