Skip to content

v9.0.0-beta.1

Pre-release
Pre-release

Choose a tag to compare

@aao-ipr-bot aao-ipr-bot released this 06 Oct 15:12
25b076a

Install the SDK 9 beta

Published on PyPI as adcp==9.0.0b1.

The Python package version is 9.0.0b1; the release tag is v9.0.0-beta.1.

pip install 'adcp==9.0.0b1'

This is a prerelease. Ordinary package resolution continues to select the stable SDK 8 series. Review the breaking changes and migration guidance below before upgrading.

Public ProductFormatDeclaration naming and generated validation remain a pre-GA follow-up (#1401). This beta preserves the existing cross-field and credential validation; a direct export rebind to the generated union would lose those protections.


9.0.0-beta.1 (2026-10-06)

⚠ BREAKING CHANGES

  • types: public canonical creative models are real subclasses of the generated classes they refine, and canonical_creative.pyi is deleted, so mypy now enforces previously hidden required fields (ListCreativesResponse requires query_summary and pagination) and generated validators now apply (CreativeManifest requires format_id or format_kind)
  • types: format_kind and format_kinds are open str on every generated and canonical model and no value is refused; compare with == instead of is CanonicalFormatKind.x and check the vocabulary with adcp.types.is_canonical_format_kind
  • types: adcp_version and adcp_major_version are plain str and int on AcceptProposalRequest, BuyProductsRequest, ControlMediaBuyRequest, DeclineProposalsRequest, ListProductsRequest, RefineProposalsRequest, RequestProposalsRequest and SyncReportingStatusRequest (drop .root), and every task request and response gains AdcpRequest or AdcpResponse as its first base
  • codegen: generated models are defined at adcp.types.domains.., and adcp.types.generated_poc.* is now a deprecated alias of the same module objects (DeprecationWarning, removed in v10); migrate with the prefix rename adcp.types.generated_poc. -> adcp.types.domains.
  • codegen: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
  • types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
  • codegen: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
  • types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. Two consequences for callers.
  • codegen: 42 generated models reject documents they previously accepted. Each rejection is a document the model's own JSON Schema rejects. Code that constructs one of these models without any of its root required groups raises ValidationError where it previously returned a model with every group field None.
  • signing: Webhook verification no longer emits webhook_signature_jwks_unavailable, webhook_signature_jwks_untrusted, webhook_signature_required or webhook_signature_components_unexpected; JWKS discovery failures are now webhook_signature_key_unknown, and an unsigned webhook (or one carrying only Signature or only Signature-Input) or a duplicated covered component is now webhook_signature_header_malformed. adcp.signing.errors no longer defines WEBHOOK_SIGNATURE_JWKS_UNAVAILABLE, WEBHOOK_SIGNATURE_JWKS_UNTRUSTED, WEBHOOK_SIGNATURE_REQUIRED or WEBHOOK_SIGNATURE_COMPONENTS_UNEXPECTED: match WEBHOOK_SIGNATURE_KEY_UNKNOWN / WEBHOOK_SIGNATURE_HEADER_MALFORMED instead, use WEBHOOK_ERROR_CODES for the full list, and to keep retrying a receiver-side JWKS outage read SignatureVerificationError.transient (or WebhookOutcome.transient) rather than the code; the precise request_signature_* cause remains on exc.__cause__ and in the WARNING log.
  • validation: generated models validate boolean, integer and number fields strictly. A payload relying on pydantic's lax coercion — "yes" or 1 for a boolean, "1" or true for an integer, "1" for a number — now raises ValidationError instead of being coerced, matching the bundled JSON Schema for the same tool. An integral float for an integer field (1.0) is still accepted and narrowed to int, because JSON Schema counts it as an integer. The bundled schema validator additionally enforces format: uri and format: hostname, so a response carrying a malformed URL now fails response validation, which defaults to strict outside production.
  • codegen: resolving a pointer ref to its target removes the intermediate class the pointer previously generated, so adcp.types._generated.__all__ goes 3010 -> 2964: 49 names removed, 3 added. The removed names are artifacts of the defect, and the replacement is the shared type the field now points at. No deprecated aliases are provided. See the per-name replacement table above.
  • types: 114 generated classes stop being RootModel subclasses - 107 union roots and 7 single-model roots. A caller that reaches a wrapper's inner model through .root, or calls TypeName.model_validate(...) on a union root, changes at those sites: use TypeAdapter(TypeName).validate_python(payload), which honors the discriminator, and read the inner value directly instead of through .root. A single-model root keeps TypeName.model_validate(...). See the Breaking change section above for the migration.
  • signing: adcp.signing.errors no longer defines WEBHOOK_SIGNATURE_BRAND_JSON_URL_MISSING, WEBHOOK_SIGNATURE_CAPABILITIES_UNREACHABLE, WEBHOOK_SIGNATURE_BRAND_JSON_UNREACHABLE, WEBHOOK_SIGNATURE_BRAND_JSON_MALFORMED, WEBHOOK_SIGNATURE_BRAND_ORIGIN_MISMATCH, WEBHOOK_SIGNATURE_AGENT_NOT_IN_BRAND_JSON, WEBHOOK_SIGNATURE_BRAND_JSON_AMBIGUOUS, WEBHOOK_SIGNATURE_KEY_ORIGIN_MISMATCH or WEBHOOK_SIGNATURE_KEY_ORIGIN_MISSING, so importing any of them raises ImportError; adcp.signing never re-exported them. No verifier emitted those strings and the webhook error taxonomy does not define them: replace each import with WEBHOOK_SIGNATURE_KEY_UNKNOWN ("webhook_signature_key_unknown"), which is the code every webhook key-discovery failure already carried, and read the precise request_signature_* hop from exc.__cause__ or the WARNING log instead of the code. check_key_origin_consistency(..., code_family="webhook") now raises webhook_signature_key_unknown where it raised webhook_signature_key_origin_missing or webhook_signature_key_origin_mismatch; match webhook_signature_key_unknown, or keep the default code_family="request" for the distinct request_signature_key_origin_* codes. Codes emitted by verify_webhook_signature, verify_webhook_from_agent_url and verify_request_signature are unchanged.
  • types: the 224 generated types whose JSON Schema root is a scalar, 18 of them exported from adcp, are str/int/float subclasses instead of RootModel subclasses. issubclass(X, RootModel) is now False for those types, and X.model_dump / X.model_validate / X.model_json_schema no longer exist on them because they are no longer Pydantic models — use TypeAdapter(X) instead. .root reads and X(root=...) construction both still work behind a DeprecationWarning, so no existing call site has to change. See the BREAKING CHANGE section above for the migration steps.
  • signing: allow_private=True now admits only RFC 1918, RFC 4193 unique-local and loopback destinations. The IANA special-use ranges it used to admit — link-local, multicast, the unspecified address, RFC 6598 carrier-grade NAT, documentation and benchmarking space, RFC 6890 protocol assignments, 240.0.0.0/4, 6to4, Teredo, NAT64, the IANA anycast and identifier ranges and unallocated IPv6 — are refused unless the caller also passes the new allow_special_use=True; cloud metadata addresses stay refused under both. Direct callers of validate_resolved_ip, resolve_and_validate_host, validate_jwks_uri, build_ip_pinned_transport, build_async_ip_pinned_transport or the deprecated abuild_ip_pinned_transport that dial those ranges migrate by adding allow_special_use=True next to allow_private=True. The higher-level allow_private_destinations=True surfaces — webhook delivery and WebhookSender, the audit sink, agent and brand.json resolution, and the built-in JWKS and revocation fetchers — forward only allow_private and get no special-use relaxation: deployments that reached a special-use address through them must move the destination into RFC 1918, RFC 4193 or loopback space, or supply their own client or transport built with allow_special_use=True where that surface accepts one. Loopback, RFC 1918 and RFC 4193 destinations, including the DockerLocalhostRewrite targets, are unaffected.
  • auth: Requests that supply different tokens in multiple accepted credential carriers now return HTTP 401 on both MCP and A2A instead of selecting a preferred carrier. Before upgrading, remove stale proxy/client aliases or send the same decoded token in every accepted carrier. This replaces the prior Authorization-wins/first-nonempty migration behavior documented by #720.
  • types: Omitted optional boolean const fields now return None instead of True; callers must handle None and explicitly pass True when intended.
  • server: Public A2A deployments now enforce the SDK Host and Origin policy by default. The default Host allowlist is loopback-only, so deployments serving a public hostname must configure allowed_hosts for their controlled public or proxy Host values before upgrading; otherwise requests including agent-card discovery return HTTP 421. A discovery/public URL does not itself grant Host trust. Configure browser allowed_origins separately when needed. Preserve fail-closed enforcement rather than trusting arbitrary inbound Host values.
  • reporting: Reporting generation APIs and storage require authenticated caller ownership. Stop reporting readers, admission and workers for the documented maintenance migration and authoritative backfill; unmapped state and inherited work remain quarantined without automatic replay.
  • signing: Direct brand.json signing-key resolvers require agent_url and select keys by canonical agent URL.
  • accounts: Account task errors now raise typed buyer-setup exceptions, unknown natural references follow account_policy, and wholesale feed scope is required. ExplicitAccounts.resolve(None) returns None for public discovery. Migration guidance is in docs/account-lifecycle.md.

chore

  • release: start SDK 9 beta series (827d80f)

refactor

  • codegen: generated models are defined at adcp.types.domains.<domain>.<schema>, and adcp.types.generated_poc.* is now a deprecated alias of the same module objects (DeprecationWarning, removed in v10); migrate with the prefix rename adcp.types.generated_poc. -> adcp.types.domains. (3092340)

Features

  • accounts: add provisioning-aware discovery and scoped feeds (#1288) (0499d6b)
  • adagents: expose typed fetch errors and transport options (#1330) (a344195)
  • auth: resolve non-bearer principals on both transports (#1328) (68345b5)
  • decisioning: observe committed task lifecycle transitions (#1323) (9a70217)
  • idempotency: commit business writes and replay in explicit reservations (#1322) (f4525ad)
  • pg: lazily resolve decisioning stores on the serving loop (#1327) (5987c40)
  • server: add explicit unauthenticated operational routes (#1336) (dfeb5f9)
  • server: add typed MCP success text callbacks (#1337) (6e676cd)
  • signing: publish the recovery classification the signing schema mandates (#1403) (86ae412), closes #1400
  • types: adcp_version and adcp_major_version are plain str and int on AcceptProposalRequest, BuyProductsRequest, ControlMediaBuyRequest, DeclineProposalsRequest, ListProductsRequest, RefineProposalsRequest, RequestProposalsRequest and SyncReportingStatusRequest (drop .root), and every task request and response gains AdcpRequest or AdcpResponse as its first base (3092340)
  • types: add statically typed pinned versioned bases (#1340) (8d27463)
  • types: add the AdcpRequest and AdcpResponse markers, AdcpVersionEnvelope on adcp.types.protocol, and the missing Legacy* media-buy response names; LegacyFormatId now resolves to the generated format reference (3092340)
  • types: emit a composing schema root as what it composes (#1353) (e5c2712)
  • types: emit scalar schema roots as plain scalar subclasses (#1286) (9a70503)
  • types: export shared legacy asset coercion helpers (#1334) (4a84082)
  • types: format_kind and format_kinds are open str on every generated and canonical model and no value is refused; compare with == instead of is CanonicalFormatKind.x and check the vocabulary with adcp.types.is_canonical_format_kind (3092340)
  • types: public canonical creative models are real subclasses of the generated classes they refine, and canonical_creative.pyi is deleted, so mypy now enforces previously hidden required fields (ListCreativesResponse requires query_summary and pagination) and generated validators now apply (CreativeManifest requires format_id or format_kind) (3092340)
  • webhooks: add transactional PostgreSQL notification outbox (#1338) (a0fbee3)
  • webhooks: prepare validated non-task notifications (#1335) (3d4df2b)

Bug Fixes

  • accounts: restore 8.0 defaults behind opt-in strict modes for 8.1 (#1348) (3598d09)
  • adagents: follow bounded ads.txt redirects with per-hop pins (#1332) (4c59734)
  • adagents: normalize agent matching and expose listing lookup (#1329) (decbcdf)
  • adagents: remove wall-clock sensitivity from two flaky adagents tests (#1408) (0d2e61d)
  • auth: preserve outer principal on MCP anonymous path (#1326) (6bf9565)
  • auth: unify duplicate credential policy across transports (#1325) (7f9b670)
  • canonical-formats: accept a generated format reference, and name the parameter a refusal is about (#1376) (9c07724)
  • ci: make SDK 14 storyboard lanes pass and gate merges (#1345) (a5d56a6)
  • ci: repair bot credentials and scope release metadata validation (#1390) (d01636c)
  • ci: use cached dependencies for isolated package builds (#1395) (59b4922)
  • codegen: enforce root-level anyOf/oneOf required groups (#1368) (2224c78)
  • codegen: keep the format-reference agent_url as the wire string (#1396) (197bcde)
  • codegen: make a dead post-generation fix and a stale generated tree fail the build (#1374) (a5fe081)
  • codegen: resolve structural pointer refs to the type they select (#1371) (6fa21d2)
  • decisioning: serve account-scoped task polling and listing (#1320) (56fefd2)
  • decisioning: support dict products and platform-owned property filtering (#1324) (3fd42a1)
  • deps: raise dependency floors to the lowest installable working set (#1389) (91b0904), closes #1387
  • idempotency: coalesce local retries before borrowing lock connections (#1317) (a76d81a)
  • idempotency: recognize registered wrappers through outer decorators (#1315) (03da98a)
  • reporting: isolate generations by authenticated caller (#1342) (096a637)
  • reporting: preserve declared capabilities across lifecycle states (#1319) (6e8c3e2)
  • reporting: translate installed service errors by recovery policy (#1316) (9dfc52c)
  • router: advertise only declared optional implementations (#1321) (382954e)
  • router: validate requests against resolved child annotations (#1318) (8a38b64)
  • sdk: restore buyer compatibility and error diagnostics (#1285) (fa4f945)
  • server: bind fresh MCP managers and endpoints for each lifespan (#1333) (a6e7673)
  • server: enforce shared Host and Origin policy across HTTP transports (#1331) (44a07e6)
  • signing: align agent resolution and publisher pins with AdCP 3.3 (#1312) (6677169)
  • signing: close three step-1 header rules and export the precheck (#1369) (8f23329)
  • signing: emit only the webhook taxonomy's codes from webhook verification (#1388) (9219573)
  • signing: emit the spec WWW-Authenticate challenge from one place (#1372) (b4ff04d)
  • signing: fetch resolver capabilities over the agent protocol (#1284) (5e243c9)
  • signing: make agent_url optional with a fail-closed 8.0 fallback (#1350) (a083a19)
  • signing: make REQUEST_TO_WEBHOOK_CODE the only webhook code decider (#1370) (885cbda)
  • signing: report the discovery-chain code the spec assigns each resolver failure (#1373) (d8debc0)
  • signing: ship the IP pin for httpx2 as well as httpx (#1378) (6f88af7)
  • signing: stop allow_private from admitting IANA special-use ranges (#1377) (a287ee2)
  • tests: bound reporting factory work at hour boundaries (#1391) (9ca5a22)
  • tests: isolate caller identity handler registration (#1344) (92b6994)
  • types: defer adapters and prebuild models before freezing time (#1339) (357726e)
  • types: derive the export surface from the generated modules (#1367) (8f989e3)
  • types: name each export once in all (#1393) (d033c36)
  • types: preserve omission of optional boolean constants (#1351) (63bfadb)
  • types: restore opt-in reporting correlation on AdCP 3.2 (#1349) (48b1776)
  • types: restore the composed base dropped from the canonical clone (#1341) (f4bdda7)
  • validation: make the generated models agree with the bundled schema (#1375) (f07db30)
  • validation: preserve wire version envelopes under unknown-field policies (#1314) (07b5d04)