feat(compat): AdapterPair pattern + v2.5 sync_creatives (stage 4)#665
Merged
Conversation
``get_validator``, ``validate_request``, and ``validate_response`` now accept an optional ``version=`` kwarg. ``None`` defaults to the SDK's compile-time pin (existing behaviour, byte-identical for current call sites). A wire-version string (``"3.0.7"``, ``"2.5"``, ``"3.1.0-beta.1"``) routes to the per-bundle-key cache laid down by Stage 1 — each version's file index, compiled validators, and core registry live in their own ``_LoaderState`` so cross-version traffic doesn't share compilation state. The dispatcher call sites are unchanged today; Stage 3 will detect the buyer's ``adcp_major_version`` off the wire and thread it through. Also widens ``resolve_bundle_key`` to accept bare ``MAJOR.MINOR`` (already a bundle key — matches the wire envelope's release-precision ``adcp_version`` field, so the dispatcher can pass it straight through). Tests: * ``test_schema_loader_per_version`` lays down a synthetic ``schemas/cache/2.5/`` fixture, asserts validators for the synthetic legacy tool and the real SDK-pin tools coexist independently, and pins ``version=None`` behaviour to the SDK pin. * ``test_validation_version`` extended with the new pass-through and rejection cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…g tree Review feedback on PR #659 (Stage 2). Two nits: * Fixture used to write into the repo's real ``schemas/cache/2.5/``, which means CI runs against an installed wheel would silently miss the synthetic bundle (packaged ``_schemas/`` wins) and the assertions would be vacuous. Move to ``tmp_path`` + ``monkeypatch.setattr`` on the loader's resolver instead. * Teardown used a sequence of ``rmdir`` calls that fail if anything else lands in the directories mid-run. ``shutil.rmtree(..., ignore_errors= True)`` is robust. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stage 3 of the versioned-schema-validation port. ``create_tool_caller`` now detects the buyer's claimed version off the request envelope and threads it through to the per-version validator added in Stage 2. Detection order (mirrors the TS SDK's ``applyVersionEnvelope`` and the spec text on every ``*-request`` schema): 1. ``adcp_version`` (3.1+ release-precision string) — normalized to release precision (``"3.0.7"`` → ``"3.0"``); must be in ``COMPATIBLE_ADCP_VERSIONS`` or ``VERSION_UNSUPPORTED`` is raised. 2. ``adcp_major_version`` (legacy integer) — maps to the highest supported minor for that major. Unknown major raises ``VERSION_UNSUPPORTED`` with structured details. 3. Neither field set — falls through to the SDK pin (existing behaviour). New module ``adcp.validation.envelope`` owns the detection logic; ``UnsupportedVersionError`` carries the wire value and supported set so the dispatcher can echo both into the error envelope's ``details``. Existing ``test_spec_compat_hooks`` payloads used ``adcp_major_version=4`` as a wire-shape placeholder — updated to ``3`` now that the dispatcher actually validates the field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… echo Review feedback on PR #660. * String ``adcp_major_version`` (e.g. ``"3"``) used to fall through to ``None`` and silently get SDK-pin validation. A buyer that JSON-stringified the field deserves a loud ``VERSION_UNSUPPORTED``, not a quiet behaviour swap. Same for ``< 1`` values (below the spec's ``minimum: 1`` bound). * ``claimed_version`` in error details used to be ``str(exc.wire_value)``, which converted the int field to ``"4"``. Pass through verbatim so buyer telemetry sees the same type they sent. * Rename ``test_no_version_field_validator_uses_sdk_pin`` to actually test that claim — pass a ``ValidationHookConfig`` so the validator fires, and assert ``version=None`` is threaded. Split the original test's "no validation config means no validator runs" assertion into its own regression test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…T_VERSION_ENVELOPE) Downstream-impact audit on PR #660 flagged that switching from "wire schema accepts adcp_major_version 1-99" to "dispatcher rejects unknown versions" in one release would break test fixtures using ``4`` as a sentinel and any buyer claiming an unsupported version that happened to pass schema validation. Decouple legacy adapter routing (additive, ships now) from version-envelope strictness (subtractive, ships under a gate). * Default (``ADCP_STRICT_VERSION_ENVELOPE`` unset or ``"0"``): an unsupported wire version is logged at WARNING with a migration hint pointing at the env var. The dispatcher falls through to SDK-pin validation — same as 5.1.0 behaviour for that payload. * Strict (``ADCP_STRICT_VERSION_ENVELOPE=1``): raise the ``VERSION_UNSUPPORTED`` envelope the spec prescribes, before any handler dispatch. This becomes the default in 5.3. Existing strict-mode tests gain a ``strict_version_envelope`` fixture so the spec-prescribed behaviour stays covered. New ``test_unsupported_version_permissive_falls_through`` exercises the default-permissive path and asserts the migration hint shows up in logs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stage 4 of the versioned-schema-validation port. Replaces the heuristic ``spec_compat_hooks()`` model with a typed per-tool adapter registry. What changed: * New package ``adcp.compat.legacy`` with the ``AdapterPair`` dataclass, registry (``get_legacy_adapter`` / ``list_legacy_adapter_tools``), and the ``LEGACY_ADAPTER_VERSIONS`` constant. Mirrors the TS SDK's ``src/lib/adapters/legacy/v2-5/``. * First concrete adapter: ``adcp.compat.legacy.v2_5.sync_creatives``. Three wire-shape coercions (bare-string ``format_id`` → structured, ``asset_type`` inference, ``image``-without-dims → ``url`` demotion). * ``validation.envelope.SUPPORTED_WIRE_VERSIONS`` now includes legacy versions, so ``detect_wire_version`` accepts both native and legacy claims. * ``create_tool_caller`` routes legacy-versioned requests through the adapter: ``adapt_request`` runs *after* version detection and *before* current-schema validation, so a buggy translator surfaces as ``INVALID_REQUEST`` with a field-level pointer. A legacy version with no adapter for the requested tool raises ``INVALID_REQUEST``. * Response side: optional ``normalize_response`` callable runs after current-schema validation. ``sync_creatives`` has the same response shape across v2.5/v3 so leaves it ``None``. Deferred (Stage 4b): real v2.5 schema bundle. Upstream CDN doesn't ship v2.5 tarballs; the JS SDK pins a GitHub commit SHA. Wire that fetch in a follow-up. Today the adapter validates against the v3 output only. Tests (25 new): registry contract, every v2.5 sync_creatives coercion via the public adapter surface, end-to-end dispatcher routing including missing-adapter and adapter-raises cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ader Review feedback on Stage 4. * AdapterPair docstring states the contract: sync + pure (no mutation), no I/O, request raise → INVALID_REQUEST, response raise → INTERNAL_ERROR. * _ensure_loaded reads its work from _VERSION_MODULES dict — adding a tool to a version is a one-line append, not a control-flow change. * Dispatcher renames effective_version → post_adapter_validator_version with a comment explaining how Stage 4b (real v2.5 schema bundle) extends the variable's role. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ec3de0f to
859626d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-opened with main as base after #659 (Stage 2) and #664 (Stage 3) merged — the original #661 auto-closed on base-branch deletion.
Summary
Stage 4 of the versioned-schema-validation port. Replaces the heuristic
spec_compat_hooks()model with a typed per-tool adapter registry.adcp.compat.legacywith theAdapterPairdataclass, registry (get_legacy_adapter/list_legacy_adapter_tools), and theLEGACY_ADAPTER_VERSIONSconstant. Mirrors the TS SDK'ssrc/lib/adapters/legacy/v2-5/.adcp.compat.legacy.v2_5.sync_creatives. Three wire-shape coercions (bare-stringformat_id→ structured,asset_typeinference,image-without-dims →urldemotion).validation.envelope.SUPPORTED_WIRE_VERSIONSextendsCOMPATIBLE_ADCP_VERSIONSwith legacy versions, sodetect_wire_versionaccepts both shapes.create_tool_callerroutes legacy-versioned requests through the adapter:adapt_requestruns after version detection and before current-schema validation. A legacy version with no adapter for the requested tool raisesINVALID_REQUEST.Review applied
AdapterPairdocstring now states the contract (sync + pure, no mutation, no I/O, request/response exception mapping)._ensure_loadedreads from data-driven_VERSION_MODULESdict (one-line append to add a tool in Stage 5).effective_version→post_adapter_validator_versionand documented the Stage 4b extension point.Deferred to Stage 4b
Real v2.5 schema bundle. Upstream CDN doesn't ship v2.5 tarballs; the JS SDK pins to a GitHub commit SHA. Wire that fetch in a follow-up. Today the adapter validates against v3 output only.
Stage 5 will
Port the remaining v2.5 adapters (
get_products,create_media_buy,update_media_buy,list_creative_formats,preview_creative) and add aDeprecationWarningonspec_compat_hooks().🤖 Generated with Claude Code