Skip to content

feat(protocol)!: adopt the signed AdCP 3.3.0-beta.0 bundle - #1662

Merged
bokelley merged 1 commit into
nextfrom
claude/sdk10-adopt-adcp-3-3-beta-0
Oct 27, 2026
Merged

bokelley merged 1 commit into
nextfrom
claude/sdk10-adopt-adcp-3-3-beta-0

Conversation

@bokelley

@bokelley bokelley commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1560. Follows the main → next sync (#1578) and the inventory (#1660). Squash-merge, keeping the ! and the BREAKING CHANGE: footer from the commit message (below).

The bundle

  • schemas/releases/3.3.0-beta.0.json pins the signed release: source commit a2d7eac350f0325331ae544bc071301afe01d2f2, identity release.yml@refs/heads/main, four artifacts with sizes and sha256. Verified locally as the release notes prescribe: sha256sum -c OK and cosign verify-blob "Verified OK" against that identity; scripts/sync_schemas.py --require-signed-release re-verifies the same four artifacts and the signature on every sync.
  • src/adcp/ADCP_VERSION is 3.3.0-beta.0; the bundle key keeps the full identifier (schemas/cache/3.3.0-beta.0, src/adcp/_schemas/3.3.0-beta.0, src/adcp/_compliance/3.3.0-beta.0: 4443 manifest files, 242 provenance files), with MANIFEST.in and package-data entries, so the protocol repo's "Generate Python SDK" check finds the pinned key. The signed 3.2.4 bytes stay installed under schemas/cache/3.2 as a preview bundle (PREVIEW_VERSIONS = ("3.2.4", "3.1.27")) for negotiation and translation with 3.2 peers.
  • Regeneration: 181 generated files change and 44 are added (1135 total). The delta is semantic (SCHEMA_DELTAS.md); the numbered-class churn in it is a consequence of new sibling schemas and cannot be discarded. No hand-written module referenced a removed numbered name. make validate-generated is deterministic on the new tree.
  • From the bundle: skills/adcp-media-buy/SKILL.md, the request-signing conformance vectors (130 files, manifest pinned), the 3.3 compliance package.

Version negotiation and translation

  • COMPATIBLE_ADCP_VERSIONS adds 3.3; get_supported_adcp_versions() advertises the exact pre-release 3.3-beta.0 (never a stable 3.3): 3.0, 3.1, 3.2, 3.3-beta.0, 3.2-rc.7.
  • adcp.compat.versions converts the 3.3 line: the SDK's served pre-release is its line's representative (_wire_for_line), so 3.3-beta.0 ↔ 3.2 ↔ 3.1 ↔ 3.0 step through the bundled schemas; any other pre-release keeps its own contract (is_convertible_version). Downgrades still go through _require_target_valid (3.2 to 3.1 conversion emits payloads 3.1 refuses: empty notification event_types, and geo_regions as {} #1621 / fix(compat): never downgrade into a payload the older schema refuses #1630): a converted payload the older schema refuses fails as ADCPVersionConversionError. The version envelope is stamped only where the target contract admits it: 3.3 added adcp_version to list_products responses, whose 3.2 schema forbids it.
  • The client negotiates from the served pre-release (_convert_outgoing_request no longer treats it as a historical pin), and a server_version pin keeps wire precision ("3.1.0-beta.1" → "3.1-beta.1"), so a pre-release pin is never echoed as its bundle key.
  • A server that restricts supported_versions without adcp_version pins to its newest listed release (version_policy.default_adcp_version) instead of refusing because the SDK default moved past it. The decisioning capabilities gate (startswith("3.2")) is now "3.2 or later".
  • Signing: the 3.3 line maps to the 3.2 RFC 9421 profile; rfc9421_deprecation_active() is now true by default, so legacy SigningConfig / RequestSignatureVerification construction warns, as 3.3 deprecates those profiles.

Forward-compat patches retired (each verified against the 3.3 schema)

  • reporting_webhook.operation_id (adcp#7895): core/reporting-webhook.json declares it with minLength 1, maxLength 255 and the same pattern, optional, never null. The _forward_compat.py runtime patch and _ReportingOperationId are deleted; ReportingWebhook and the request facades bind the generated classes. tests/test_reporting_webhook_operation_id.py passes unchanged.
  • list_creatives creatives[].platform_id (adcp#8175): native in 3.3 (Creative.platform_id). This SDK carried no forward-compat patch for it, so there was nothing to retire.
  • Still needed: the canonical_creatives capability patch (3.3 does not declare it), the targeting-overlay rc.3 bridge and the readback manifest patches.

Identity preview retired

The vendored identity schemas (src/adcp/signing/_identity_schemas/, adcp main 277e0a5) are semantically identical to the bundle's (only $ref prefixes differ), so adcp.types._identity_preview, the vendored tree and scripts/generate_identity_preview.py are deleted. adcp.types.experimental_identity keeps every exported name on the generated 3.3 types; AgentOnboardingRequirement.kind stays open (enum | str, the schema enum is x-extensible) through inherit_field redeclarations down the capabilities tree, with one exemption recorded in tests/test_redeclared_fields_inherit.py. adcp.signing.trust validates trust records and requirement kinds against the bundle through get_named_validator / get_named_schema_document; identity_schema_bundle() is gone.

3.3 task surface

list_collections and list_proposals are wired through ADCPClient, ADCPMultiAgentClient, ADCPHandler (not-supported defaults), the MCP and A2A adapters, the CLI dispatch and the MCP tool definitions, the way list_products is. The test controller gains the 3.3 simulate_delivery params (property_delivery, installment_delivery, installment_property_delivery) and the four new scenarios, raising NotImplementedError like every other unimplemented scenario. sales-fixed-rate joins the specialism enum and maps.

Generator

  • Scalar roots whose pattern needs lookaround are generated with model_config = ConfigDict(regex_engine="python-re"); _scalar_root_spec now keeps that engine as a constraint, so PositiveDuration and Domain become ScalarStr subclasses like every other scalar root.
  • UniversalMacro is a RootModel union in 3.3 (enum | GDPR_CONSENT_<gvl_id> pattern); the canonical direct scan reads scalar-root and root-model values as the dump would instead of falling back to a full dump.

Reporting

The production and feed code derived wire versions correctly once the client stopped echoing bundle keys; feed/snapshot.py's unversioned-walk branch accepts any served release at or above 3.2-rc.6 instead of a literal 3.2 set. The production reporting mount still advertises exactly its pin, so an SDK 10 mount on the default pin refuses 3.2 buyers unless constructed with adcp_version="3.2" (flagged for workstream 3 in the inventory). The receipt-submission plan stays tagged 3.2 (frozen bytes).

Breaking changes (see MIGRATION_v9_to_v10.md)

Wire pin 3.3.0-beta.0 and default adcp_version: "3.3-beta.0"; UniversalMacro union (UniversalMacro3 is the enum); the identity preview modules removed and experimental_identity bound to generated types (RequestSigning.profiles: list[Profile], PrincipalChangedWebhook.reason is the generated enum); identity_schema_bundle() removed; RFC 9421 construction warns; evaluator_id gone from evaluator specs; server_version pins keep wire precision; schema defaults appear in dumps for the new 3.3 fields (include_collections, hold_extension); delivery rows may omit impressions.

For workstream 2 (first items)

  • Schema defaults materialized on dump (model_dump emits schema defaults the wire document omitted (143 fields in 60 schemas), which changes digested and echoed bytes #1613) now have user-visible cost: every get_products request carries include_collections: false, which a 3.3 → 3.2 downgrade drops with a recorded loss and a buyer-side warning per request, and criteria.product_ids_exclusive: false had to be special-cased on the legacy catalog route. Dumping outgoing requests with "what the caller set" semantics would remove the class.
  • x-extensible enums generate closed (agent-onboarding-requirement-kind, advertiser-industry, media-buy-action-mode); the identity facade widens one by hand.
  • No v33 versioned view modules yet (scripts/generate_versioned_stubs.VERSIONS).

Validation (local, Python 3.12)

make lint, make typecheck-all, make validate-generated: pass. Full suite (pytest tests/ -n auto): 19073 passed, 2730 skipped; the 12 failures and 1 error of the parallel run (a2a context id, freezegun fresh process, versioned-bases mypy subprocess, two staging-reuse writer tests, a notification-outbox import test, plus the four fixed here) all pass serially, as they did on #1578. Postgres lanes are skipped locally.

BREAKING CHANGE: the wire pin is AdCP 3.3.0-beta.0 and the default adcp_version is "3.3-beta.0" (pin adcp_version="3.2" for a 3.2 contract); adcp.types.UniversalMacro is a RootModel union whose closed enum is UniversalMacro3; the identity preview modules (adcp.types._identity_preview, adcp.signing._identity_schemas, scripts/generate_identity_preview.py) are removed and adcp.types.experimental_identity binds the generated 3.3 types (RequestSigning.profiles is list[Profile], PrincipalChangedWebhook.reason is the generated enum); adcp.signing.identity_schema_bundle is removed; legacy RFC 9421 SigningConfig and RequestSignatureVerification construction emits a DeprecationWarning; evaluator_id is gone from evaluator specs; server_version pins keep wire precision; schema defaults for the new 3.3 fields appear in dumps. See MIGRATION_v9_to_v10.md.

🤖 Generated with Claude Code

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon is not auto-reviewing this PR because it modifies the review system itself (LADON.md). A human reviewer should review and merge this PR; Ladon resumes on subsequent PRs once these changes land on main.

@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch 2 times, most recently from 66bbc41 to 8967f6b Compare October 27, 2026 02:36

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — packaging/docs/schema-bundle pass with no blocking findings.

This pass is confined to docs, packaging (MANIFEST.in, pyproject.toml), auto-generated shared-type-names.md, and the pinned signed AdCP 3.3.0-beta.0 bundle bytes. No hand-written source changed; the source wiring was prior-reviewed. Packaging is complete and consistent: the new 3.3.0-beta.0 cache/_schemas/_compliance trees are added to both MANIFEST.in and package-data, and retired _identity_schemas/_identity_preview entries are removed from both package-data and the ruff exclude.

Decision-table walk: the high_risk flag is true only because many new schemas/** files are added (plus three renames) — all (added)/(renamed), no (deleted) and no modified high-risk file carrying a medium finding, so rows 3 and 5 do not fire. gated_paths is false and no no-auto-approve team matches. No critical/high/medium findings. Only two Low doc-accuracy nits recorded, which are omitted from blocking but noted below. Falls through to row 9 → approve.

Nits (non-blocking):

  • docs/adcp-3.3-sdk-inventory.md:143 — inventory status for list_collections/list_proposals contradicts PR body's "wired" claim.
  • MIGRATION_v9_to_v10.md:53 — PositiveDuration/Domain RootModel→ScalarStr (.root removed) shape change not mentioned in the migration note (semver signal otherwise present via feat!/BREAKING CHANGE).

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — AdCP 3.3.0-beta.0 bundle adoption, subsequent pass with no actionable findings.

The delta is overwhelmingly generated artifacts (schema cache under schemas/cache/3.3.0-beta.0/**, domain types, conformance vectors). The reviewer verified the hand-written layer:

  • New list_collections/list_proposals wiring across client/base/mcp/a2a/builder/mcp_tools/types — consistent and complete.
  • compat/versions.py translation (_admits_version_envelope safe; is_convertible_version matches documented prerelease design).
  • _forward_compat.py operation_id retirement verified against 3.3 schema constraints.
  • decisioning/accounts.py loader fail-closes on id mismatch with multi-tenant scoping documented.
  • post_generate_fixes.py regex_engine preservation intact.
  • Semver signal present (feat(protocol)! + BREAKING CHANGE footer + MIGRATION_v9_to_v10.md); pathway-back rule satisfied (product_ids_exclusive refused, dropped default recorded as loss).

Decision-table walk: no critical/high/medium findings (row 1 no). gated_paths=false (row 2 no) and review_decision is APPROVED regardless. High-risk flag is true but all reasons are (added) scaffolding or (renamed) codegen churn — no (deleted) (row 3 no), no medium findings to pair with (rows 4/5 no). Prior decision was approve, not escalate (row 6 no). No no-auto-approve team match (row 7 no). Zero medium findings (row 8 no). Falls through to row 9 — approve. Clean net-improvement iteration on top of a prior clean approve.

@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch from 8967f6b to 0d27045 Compare October 27, 2026 03:56
@aao-secretariat

Copy link
Copy Markdown

Ladon cannot review this PR until merge conflicts are resolved.

@bokelley bokelley closed this Oct 27, 2026
@bokelley bokelley reopened this Oct 27, 2026
@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch from 0d27045 to 2ade6f8 Compare October 27, 2026 04:18

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — AdCP 3.3.0-beta.0 migration delta, clean pass.

The reviewer found no critical/high/medium findings. Checked:

  • Walked the decision table top-down. No critical/high findings (row 1 no), gated_paths is false (row 2 no), no (deleted) entries in high_risk_reasons — only (added) and (renamed) (rows 3 no). No medium findings at all, so rows 4/5/8 don't fire. Prior decision was approve, not escalate, so row 6 doesn't apply. No no-auto-approve team match (row 7 no). Falls through to row 9 → approve.
  • high_risk: true is driven entirely by added/renamed schemas/cache/** codegen artifacts — new-file scaffolding and traversal-order renumbering, which the rules explicitly treat as normal non-escalation-worthy churn when the reviewer surfaces no medium-or-higher concerns.
  • Hand-written logic (version-line translation, brand_jwks bounds/timeouts, JSON bounds scanner, webhook_receiver, forward-compat retirement, pixel_tracker) all verified clean; breaking public-surface changes carry the feat!/BREAKING CHANGE semver signal; video_brief routes correctly in both asset unions and vocabularies.

No blocking findings, no medium findings, no escalation trigger.

@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch from 2ade6f8 to 7b9a89f Compare October 27, 2026 05:14

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — clean pass on PR #1662.

No critical/high/medium findings. Walking the decision table top-down:

  • Row 1 (critical/high): no findings — skip.
  • Row 2 (gated_paths unsatisfied): gated_paths is false, and review_decision is APPROVED anyway — skip.
  • Row 3 (high-risk deleted): high_risk is true, but all high_risk_reasons entries are (added) or (renamed); no (deleted) — skip. The renamed core/agent-onboarding* entries are treated as modifications, not deletions, and carried no findings.
  • Row 4 (medium data-loss/schema/infra): no findings — skip.
  • Row 5 (high-risk modified + medium): no medium findings — skip.
  • Row 6 (sticky escalate): prior decision was approve, not escalate — skip.
  • Row 7 (no-auto-approve team): no team match — skip.
  • Row 8 (≥3 medium): zero medium — skip.
  • Row 9: approve.

The high_risk flag fires only because the diff adds the 3.3.0-beta.0 schema cache tree (schemas/**), which is normal scaffolding/regeneration output — not an escalation trigger. The reviewer verified the hand-written delta: the ADCP_VERSION 3.2.4 → 3.3.0-beta.0 bump carries the correct feat(protocol)!: breaking marker plus MIGRATION_v9_to_v10.md; new list_collections/list_proposals tasks are fully wired and snapshot-tested; cross-version translation helpers are covered at both transport boundaries down to 3.0/3.1; _forward_compat.py changes and the open asset-union vocabulary check out. Prior pass was clean and remains so.

@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch from 7b9a89f to aa56bf1 Compare October 27, 2026 05:46

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — clean 3.3.0-beta.0 adoption with no findings.

No critical/high/medium findings surfaced. The delta since the prior approve is a rebase + full regeneration (gen date 2026-10-26); the ClassNameN renumber churn is codegen, not a schema delta.

Checks verified by the reviewer:

  • Load-bearing version-translation logic (compat/versions.py _wire_for_line/is_convertible_version/_admits_version_envelope) correctly steps 3.3-beta.0↔3.2↔3.1↔3.0 and drops adcp_version only where the target contract forbids it (list_products), with matching cross-version + logging tests — DR-0032/DR-0033 pathway coverage present.
  • signing/autosign.py clamps 3.3 to the 3.2 RFC 9421 profile.
  • reporting_webhook.operation_id / identity-preview forward-compat retirements are backed by the generated 3.3 class carrying the same constraints + NoExplicitNull — no fallback arm lost.
  • Semver signal present (feat!: + BREAKING CHANGE squash, MIGRATION_v9_to_v10.md).
  • No generated-tree hand-edits, no credentials in ctx_metadata, import layering intact, CI gates armed.

Gating posture: high_risk is true, but all schema matches are (added) or (renamed) (treated as modification) scaffolding/regeneration with no medium-or-higher finding on them, so rows 3–5 do not fire. gated_paths is false and review_decision is APPROVED. No no-auto-approve team match. Prior decision was approve, so sticky escalation (row 6) does not apply. No findings → rows 1, 8 do not fire. Falls through to row 9 = approve.

Pin src/adcp/ADCP_VERSION to 3.3.0-beta.0 (schemas/releases/3.3.0-beta.0.json:
source a2d7eac3, release.yml@refs/heads/main, sha256 and cosign verified),
regenerate the types from its schemas, package the 3.3.0-beta.0 schema cache
and compliance bundle, and keep the signed 3.2.4 bytes installed as the 3.2
contract (PREVIEW_VERSIONS) beside 3.1.27.

Advertise 3.3 as the exact pre-release (3.3-beta.0), negotiate and translate
the 3.3 line through the bundled schemas (3.3-beta.0 <-> 3.2 <-> 3.1 <-> 3.0),
and let a server restricted to older supported_versions pin to its newest
listed release. Map the 3.3 line to the 3.2 RFC 9421 signing profile; the
profile's 3.3 deprecation warns by default.

Retire the identity preview (adcp.types._identity_preview, the vendored
_identity_schemas tree and scripts/generate_identity_preview.py): the bundle
declares those schemas, so adcp.types.experimental_identity binds the generated
3.3 types and adcp.signing.trust validates against the bundle. Retire the
reporting_webhook.operation_id runtime patch (native since 3.3, adcp#7895).
Wire list_collections and list_proposals through the client, handler, adapters,
CLI and MCP tool definitions; add the 3.3 test-controller params and scenarios.

Generator: scalar roots whose pattern needs lookaround keep the python-re
engine (PositiveDuration, Domain); the canonical direct scan reads scalar and
root-model values as the dump would.

BREAKING CHANGE: the wire pin is AdCP 3.3.0-beta.0 (adcp_version "3.3-beta.0"
by default; pin adcp_version="3.2" for a 3.2 contract). adcp.types.UniversalMacro
is a RootModel union; the closed enum is UniversalMacro3. The identity preview
modules are removed and adcp.types.experimental_identity binds the generated
3.3 types (RequestSigning.profiles is list[Profile], PrincipalChangedWebhook.reason
is the generated enum). adcp.signing.identity_schema_bundle is removed. Legacy
RFC 9421 SigningConfig / RequestSignatureVerification construction emits a
DeprecationWarning. evaluator_id is gone from evaluator specs. See
MIGRATION_v9_to_v10.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bokelley
bokelley force-pushed the claude/sdk10-adopt-adcp-3-3-beta-0 branch from 2bcd3a4 to f701081 Compare October 27, 2026 06:55

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — subsequent clean pass on the AdCP 3.3 upgrade.

No critical/high/medium findings. Walking the decision table top-down:

  • Row 1 (critical/high): no such findings.
  • Row 2 (gated_paths): gated_paths is false; also review_decision is APPROVED. Not triggered.
  • Row 3 (high_risk + deleted): high_risk is true, but the high_risk_reasons entries are all (added) or (renamed) — no (deleted). Renames of a few core schema files are codegen churn, not destructive. Not triggered.
  • Row 4 (medium + data-loss/schema/infra): no medium findings.
  • Row 5 (high_risk modified + medium): no (modified) entries carry a medium finding (no mediums at all). Not triggered.
  • Row 6 (sticky escalate): prior decision was approve, not escalate. Not triggered.
  • Row 7 (no-auto-approve team): no team match.
  • Row 8 (≥3 mediums): zero mediums.
  • Row 9: approve.

The high-risk flag fires only because the diff touches schemas/** cache files — these are added/renamed generated schema cache artifacts (AdCP 3.3.0-beta.0), normal scaffolding/regeneration output, not escalation-worthy on the flag alone.

Reviewer verified the load-bearing contracts: semver signal (9→10 major carries ! + BREAKING CHANGE + MIGRATION note), forward-compat unions (no fallback arm removed, discriminator intact), the version-translation pathway (droppable/refused/moves handled with tests), and A2A fail-closed hardening. One Low nit in scripts/post_generate_fixes.py (unused extra_constraints) is non-blocking and omitted from the gate.

@bokelley
bokelley merged commit 7472aae into next Oct 27, 2026
41 checks passed
@bokelley
bokelley deleted the claude/sdk10-adopt-adcp-3-3-beta-0 branch October 27, 2026 07:56
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