Skip to content

chore(types): pin AdCP spec to 3.0.1 and regenerate#292

Open
bokelley wants to merge 2 commits intomainfrom
bokelley/sdk-release-prep
Open

chore(types): pin AdCP spec to 3.0.1 and regenerate#292
bokelley wants to merge 2 commits intomainfrom
bokelley/sdk-release-prep

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented Apr 29, 2026

Summary

Pin the SDK to AdCP 3.0.1 (released 2026-04-28). Per the 3.0.1 release notes, it's a stable-surface no-op for handlers — adopter action is just bumping `ADCP_VERSION`. This PR also picks up:

  • Regenerated schema cache + Pydantic types (700+ files)
  • 7 new canonical skill bundles that 3.0.1 ships in the protocol tarball (the original driver for cutting 3.0.1): `adcp-brand`, `adcp-creative`, `adcp-governance`, `adcp-media-buy`, `adcp-si`, `adcp-signals`, `call-adcp-agent`
  • Seven new top-level enums + one new core type (`seller-agent-ref`, exported as `SellerAgentReference`) — all additive

Compatibility note (4.1.0-bound, not 4.0.x)

This naturally rides into the 4.1.0 release that #257 already stages, not a 4.0.1 patch. The schema title polish on `core/format-id.json` ("Format ID" → "Format Reference (Structured Object)") changes the canonical class's `name` and `qualname`. That's invisible for typical user code (you construct via dict or via the public `FormatId` alias and don't notice), but it crosses the SemVer line for two niche cases:

  • Pickled instances. A pickle written under 4.0.0 embeds qualname `FormatId`; loading it under this PR fails because `core.format_id` no longer defines that symbol.
  • Reflection on `name`. Anyone scraping logs or snapshotting type names will see the rename.

Public `FormatId` keeps working (re-bound in `aliases.py` to the canonical class), and `isinstance` checks against the public alias on either version are consistent. Just not 4.0.1 territory.

Why so many files changed

Most churn is mechanical:

  • Every schema now carries a `$id` pointing at `/schemas/3.0.1/...`
  • Internal `$ref` paths went from relative to absolute
  • Net deletion (~28k lines) is real — schemas got more compact

Review additions (commit 707cdb1)

After python-expert + dx-expert review:

  • `consolidate_exports.py`: `FormatId` is now in `known_collisions` keyed to all 25 bundled-message modules that inline a stale per-message duplicate, so `_generated.py` stops re-exporting the stale class under the bare name. Fixed a structural bug in the qualified-name generator (`Bundled`) so duplicates that exist under both `bundled/creative/` and `bundled/media_buy/` produce distinct mypy-compatible aliases.
  • `tests/test_import_layering.py`: new test that enforces the CLAUDE.md import layering rule (only `aliases.py` / `_ergonomic.py` / `_generated.py` / the public composer may reach into `generated_poc/`). Frozen baseline of 9 pre-existing violators in `_KNOWN_VIOLATIONS`; new violations trip the test, and stale entries trip it too so cleanups have a forcing function.
  • Public surface: export `SellerAgentReference` from both `adcp` and `adcp.types` — was generated by codegen but not re-exported.
  • `.pre-commit-config.yaml`: add the same `^src/adcp/types/generated_poc/` exclude to black that was already on ruff. Without it every regen reformats ~200 codegen files for no benefit, hiding real diffs.
  • `tests/fixtures/public_api_snapshot.json`: regenerated to capture `SellerAgentReference`.

What was tested

  • Full unit suite: 1854 passed, 15 skipped (excluding integration / conformance)
  • `mypy src/adcp`: clean (703 files)
  • `ruff check src/ tests/`: clean
  • `pytest tests/test_import_layering.py tests/test_public_api.py`: 21 passed
  • Verified `Format(format_id=FormatId(...))` constructs successfully with the public alias
  • Verified `_generated.py` no longer exports a bare `FormatId` (only qualified `_FormatIdFromBundled` aliases)

Out of scope

🤖 Generated with Claude Code

3.0.1 is a stable-surface no-op for handlers — no new fields, no
renamed fields, no new enum values on stable schemas. Adopter action
per the 3.0.1 release notes is just to bump ADCP_VERSION; this commit
also ships the regenerated cache, types, and the new canonical skill
bundles that 3.0.1 ships in the protocol tarball (the original driver
for cutting 3.0.1).

Schema deltas worth knowing:

- Every schema now carries a $id pointing at /schemas/3.0.1/... and
  internal $refs are absolute. Source of the large file churn.
- Seven new top-level enums + one new core type (seller-agent-ref).
  All additive.
- core/format-id.json's title was polished from "Format ID" to
  "Format Reference (Structured Object)". The generator picks up the
  new class name (FormatReferenceStructuredObject), but the public
  surface keeps `FormatId` — re-bound in aliases.py to the canonical
  core class. Before this change, public FormatId resolved to a stale
  bundled-content-standards per-message duplicate that didn't match
  what Format.format_id actually expected, so user code constructing
  Format(format_id=FormatId(...)) would have raised at validation.

Tests previously importing FormatId from adcp.types._generated are
moved to the public adcp.types path (the layering rule documented in
CLAUDE.md).

New canonical skills bundled by 3.0.1: adcp-brand, adcp-creative,
adcp-governance, adcp-media-buy, adcp-si, adcp-signals,
call-adcp-agent. Tracked alongside the existing build-* SDK-local
skills.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Acting on python-expert + dx-expert review of this PR:

- ``scripts/consolidate_exports.py``: list ``FormatId`` in
  ``known_collisions`` keyed to all 25 bundled-message modules that inline
  a stale per-message duplicate. ``_generated.py`` no longer re-exports
  the bare ``FormatId`` name; the canonical class is exposed only through
  ``aliases.py``'s rebind. Fix the qualified-name generator to include
  the bundled subdir (``Bundled<Subdir><Stem>``) so duplicates that exist
  under both ``bundled/creative/`` and ``bundled/media_buy/`` produce
  distinct mypy-compatible aliases.
- ``tests/test_import_layering.py``: enforce CLAUDE.md's layering rule
  (only ``aliases.py`` / ``_ergonomic.py`` / ``_generated.py`` / the
  public composer ``adcp.types/__init__.py`` may import from
  ``generated_poc/``). Frozen baseline of 9 pre-existing violators is
  listed in ``_KNOWN_VIOLATIONS``; new files or new imports trip the
  test, stale entries also trip it. Pre-existing violators get cleaned
  up in follow-up PRs without blocking this release.
- ``adcp/__init__.py`` + ``adcp/types/__init__.py``: export
  ``SellerAgentReference`` (new core type added by AdCP 3.0.1) on the
  public surface — was generated but not re-exported.
- ``.pre-commit-config.yaml``: add the same
  ``^src/adcp/types/generated_poc/`` exclude to black that was already
  on ruff. Without it every regen reformats ~200 codegen files for no
  benefit, masking real changes in the diff.
- ``tests/fixtures/public_api_snapshot.json``: regenerate to capture
  ``SellerAgentReference``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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