refactor(schemas): per-bundle-key schema cache layout (stage 1 of versioned validation)#658
Merged
Merged
Conversation
Move the schema cache from ``schemas/cache/...`` to
``schemas/cache/{bundle_key}/...`` so multiple AdCP spec versions can
coexist on disk. ``bundle_key`` is derived from a version string via
``resolve_bundle_key()``: stable releases collapse to ``MAJOR.MINOR``
(``3.0.7`` → ``3.0``); prereleases keep their full identifier
(``3.1.0-beta.1``). Mirrors ``resolveBundleKey()`` in the TypeScript SDK.
Stage 1 of the versioned-schema-validation port. Zero behavior change:
the loader and every script derive the bundle key from the SDK-pinned
``ADCP_VERSION`` so today's single-version flow resolves
``schemas/cache/3.0/`` exactly the same way the old code resolved
``schemas/cache/``.
Per-version arg on the loader, wire-level version detection, and the
legacy v2.5 adapter registry land in subsequent stages.
Changes:
* Move every file under ``schemas/cache/*`` into ``schemas/cache/3.0/*``
(git mv so history follows).
* New ``adcp.validation.version.resolve_bundle_key()`` with tests.
* ``adcp.validation.schema_loader._resolve_schema_root`` now takes an
optional ``bundle_key`` (defaults to the SDK pin) and walks
``schemas/cache/{bundle_key}/`` plus the packaged copy at
``_schemas/{bundle_key}/``.
* ``scripts/sync_schemas.py`` writes to
``schemas/cache/{bundle_key}/``.
* ``scripts/generate_types.py``, ``scripts/fix_schema_refs.py``,
``scripts/post_generate_fixes.py`` read from the per-bundle-key
subdirectory.
* Tests with hardcoded ``schemas/cache/...`` paths updated to derive
the bundle key the same way the production code does.
* ``test_sync_schemas`` updated for ``replace_cache_from_bundle``'s new
``bundle_key`` arg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review feedback on PR #658. When ``fetch_bundle_with_fallback`` 404s on the pinned bundle and falls back to ``latest.tgz``, ``effective_version`` is the literal string ``"latest"`` — ``resolve_bundle_key("latest")`` would crash. Use ``target_version`` (the SDK pin) as the bundle-key input. The cache is keyed by what the loader looks up, not by what the server happened to return — writing latest's contents under the target's bundle key is the behaviour adopters rely on (a pre-release dev snapshot still validates under the SDK's pinned version). Adds a regression test on the call site so a future refactor that re-introduces ``resolve_bundle_key(effective_version)`` fails loudly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Stage 1 commit added ``from adcp.validation.version import resolve_bundle_key`` to four codegen/sync scripts. That triggers ``adcp/__init__.py``, which eagerly imports the generated Pydantic models. ``post_generate_fixes.py`` runs *during* regeneration — at that point the models are freshly generated but not yet post-fixed, so importing them raises ``TypeError: Value 'reuse' for discriminator 'source' mapped to multiple choices`` and exits 1. CI caught this on the ``Validate schemas are up-to-date`` job. Load ``version.py`` directly via ``importlib.util.spec_from_file_location`` in all four scripts — no package init, no chicken-and-egg with mid-regeneration models. The single source of truth for the helper stays in ``src/adcp/validation/version.py``; unit tests at ``tests/test_validation_version.py`` exercise it through the normal package path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Stage 1 of porting the JS SDK's versioned-schema-validation model to Python (replacing the heuristic
spec_compat_hooks()approach). The on-disk cache moves fromschemas/cache/...toschemas/cache/{bundle_key}/...so multiple AdCP spec versions can coexist.bundle_keycollapses stable releases toMAJOR.MINOR(3.0.7→3.0) and keeps prereleases exact (3.1.0-beta.1). MirrorsresolveBundleKey()in the TypeScript SDK.Zero behavior change — the loader and every script derive the bundle key from the SDK-pinned
ADCP_VERSION, so today's single-version flow resolvesschemas/cache/3.0/exactly the same way the old code resolvedschemas/cache/.For reviewers pulling this branch locally
Stale unversioned files from the old layout could coexist with the new
3.0/subdir on an existing dev checkout. Clean first:rm -rf schemas/cache/ && python scripts/sync_schemas.py(or just delete the unversioned siblings; the moved files arrived via
git mvand are at the right paths after checkout.)Subsequent stages (separate PRs)
get_validator(tool, direction, version=None)per-version arg + per-bundle-key state map.adcp_major_version/adcp_version) +VERSION_UNSUPPORTEDenvelope.v2.5.sync_creatives) wired through the dispatcher.spec_compat_hooks()deprecation.What changed in code
adcp.validation.version.resolve_bundle_key()with tests._resolve_schema_roottakes an optionalbundle_key(defaults to SDK pin).scripts/sync_schemas.pywrites toschemas/cache/{bundle_key}/, deriving the key fromtarget_version(the SDK pin) so thelatest.tgzfallback path stays valid.scripts/generate_types.py,fix_schema_refs.py,post_generate_fixes.pyread from the per-bundle-key subdirectory.schemas/cache/...paths updated to derive the bundle key the same way production code does.Review notes addressed
latest.tgzfallback (resolve_bundle_key("latest")rejection). Fixed by usingtarget_versionfor the bundle key, with a regression test pinning the call site.Test plan
pytest tests/ -q --ignore=tests/integration— 4397 passedpytest tests/test_validation_version.py tests/test_sync_schemas.py— 26 tests including the fallback regressionruff check+mypy src/adcp/schemas/cache/3.0/(git mv preserves history)🤖 Generated with Claude Code