Module adcp.validation.version
Bundle-key resolution for per-version schema validation.
The schema cache is laid out as schemas/cache/{bundle_key}/ so multiple
AdCP spec versions can coexist on disk and at runtime. bundle_key is
derived from a version string with these rules:
- Stable releases collapse to
MAJOR.MINORso3.0.0/3.0.7/3.0.42all resolve to3.0. Adopter pins to patch granularity inside a minor pick up patch fixes without a cache reshuffle. - Prereleases keep their full identifier —
3.1.0-beta.1resolves to3.1.0-beta.1(not3.1). Prereleases ship with breaking changes vs. the matching stable, so each one is its own cache bucket. - Release-precision prereleases from the wire —
3.1-beta.1resolves to3.1.0-beta.1. Percore/version-envelope.jsonthe wire'sadcp_versionis release-precision only, so v3.1+ sellers emit the patchless form (3.1-beta.1, not3.1.0-beta.1); the SDK injects.0to find the cache directory.
Mirrors resolveBundleKey() in the TypeScript SDK
(src/lib/validation/schema-loader.ts).
Functions
def resolve_bundle_key(version: str) ‑> str-
Expand source code
def resolve_bundle_key(version: str) -> str: """Collapse a version string to its on-disk cache key. Accepts: * ``MAJOR.MINOR.PATCH`` — collapsed to ``MAJOR.MINOR``. * ``MAJOR.MINOR.PATCH-PRERELEASE`` — kept exact; prereleases ship with breaking changes vs. the matching stable, so each one is its own bucket. * ``MAJOR.MINOR`` — passed through as-is (already a bundle key; matches the wire-level ``adcp_version`` field's release-precision shape). * ``MAJOR.MINOR-PRERELEASE`` — release-precision prerelease wire shape (e.g. ``"3.1-beta.1"`` from a v3.1 seller's response envelope). The ``.0`` patch component is injected to match the cache directory (``schemas/cache/3.1.0-beta.1/``). Per ``core/version-envelope.json`` this is the canonical wire form — adding the SDK's recognition is what makes validator routing actually find the 3.1 bundle when an agent emits ``adcp_version: "3.1-beta.1"``. Raises ``ValueError`` for anything else — adopters pin on real release identifiers, so a malformed version is a real bug. """ stripped = version.strip() full = _FULL_SEMVER_RE.match(stripped) if full is not None: if full.group("prerelease"): return stripped return f"{full.group('major')}.{full.group('minor')}" mm_pre = _MAJOR_MINOR_PRERELEASE_RE.match(stripped) if mm_pre is not None: # Inject ``.0`` patch so the wire shape ``3.1-beta.1`` lines up # with the on-disk directory ``3.1.0-beta.1``. return f"{mm_pre.group('major')}.{mm_pre.group('minor')}.0-{mm_pre.group('prerelease')}" mm = _MAJOR_MINOR_RE.match(stripped) if mm is not None: return stripped raise ValueError( f"resolve_bundle_key: {version!r} is not a valid version " "(expected MAJOR.MINOR, MAJOR.MINOR.PATCH, " "MAJOR.MINOR-PRERELEASE, or MAJOR.MINOR.PATCH-PRERELEASE)" )Collapse a version string to its on-disk cache key.
Accepts:
MAJOR.MINOR.PATCH— collapsed toMAJOR.MINOR.MAJOR.MINOR.PATCH-PRERELEASE— kept exact; prereleases ship with breaking changes vs. the matching stable, so each one is its own bucket.MAJOR.MINOR— passed through as-is (already a bundle key; matches the wire-leveladcp_versionfield's release-precision shape).MAJOR.MINOR-PRERELEASE— release-precision prerelease wire shape (e.g."3.1-beta.1"from a v3.1 seller's response envelope). The.0patch component is injected to match the cache directory (schemas/cache/3.1.0-beta.1/). Percore/version-envelope.jsonthis is the canonical wire form — adding the SDK's recognition is what makes validator routing actually find the 3.1 bundle when an agent emitsadcp_version: "3.1-beta.1".
Raises
ValueErrorfor anything else — adopters pin on real release identifiers, so a malformed version is a real bug.