Skip to content

fix(version): auto-derive COMPATIBLE_ADCP_VERSIONS from ADCP_VERSION pin#1706

Merged
bokelley merged 2 commits into
mainfrom
bokelley/sync-version-compat-autoderive
May 12, 2026
Merged

fix(version): auto-derive COMPATIBLE_ADCP_VERSIONS from ADCP_VERSION pin#1706
bokelley merged 2 commits into
mainfrom
bokelley/sync-version-compat-autoderive

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 12, 2026

Background

While investigating adcontextprotocol/adcp#4419 (BidMachine reports cite /schemas/3.0.1/ against a 3.0.11 seller), I audited the SDK's AdCP-version surface and found a related drift class: COMPATIBLE_ADCP_VERSIONS caps at 3.0.8 in src/lib/version.ts today, even though ADCP_VERSION = '3.0.11'.

isCompatibleWith('3.0.9') / ('3.0.10') / ('3.0.11') all return false against the SDK's own pin. That's load-bearing for callers using isCompatibleWith() to gate behavior on agent-reported adcp_version.

Root cause

scripts/sync-version.ts generates src/lib/version.ts from a template that embedded COMPATIBLE_ADCP_VERSIONS as a hardcoded array literal. Every AdCP patch bump required someone to remember to manually append the new version to the literal inside the script template.

Audit of the last three patch bumps:

Commit PR Extended compat list?
25af9a01 #1609 (3.0.7→3.0.8) ✓ yes
dc04977f #1641 (3.0.8→3.0.9) ✗ no
126dd1e3 #1655 (3.0.9→3.0.10) ✗ no
ca63b641 #1662 (3.0.10→3.0.11) ✗ no

So the literal hasn't been touched since 3.0.8 even though the pin moved three patches forward. Same root-cause class as the schema URL pinning drift in adcp#4419 — a load-bearing version surface that depends on human discipline at every patch bump.

Fix

  • scripts/sync-version.ts now derives the list dynamically from the current ADCP_VERSION. Enumerates 3.0.0..3.0.<patch> mechanically; the bumper no longer has to remember anything.
  • Fails closed when ADCP_VERSION falls outside the 3.0.x range so a future 3.1.x or 4.x bump forces the script to be extended explicitly. The compat surface for a major/minor move is rarely mechanical — that's the right time to make a human think.
  • Adds test/lib/compatible-versions-self-consistency.test.js asserting (a) the regenerated list contains the current pin and (b) fills 3.0.0..ADCP_VERSION without gaps. Future regressions (someone reverting to hardcoded literals) fail loud at CI.

Regenerated src/lib/version.ts confirms the fix: list now extends '3.0.9', '3.0.10', '3.0.11'.

Out of scope (separate issue forthcoming)

The deeper schema URL pinning drift surfaced by adcp#4419 — validations.ts:354 cites schema URLs using the SDK's build-time ADCP_VERSION regardless of the agent's advertised version — needs its own design pass. The SDK should fetch schemas dynamically from the agent's reported adcp_version. Tracked separately at adcp-client#1707.

Side-finding worth noting

The diff includes a LIBRARY_VERSION bump from 6.19.1 → 7.0.0 in src/lib/version.ts, but package.json on origin/main already says "version": "7.0.0". That means the in-flight "chore: release package #1693" PR bumped package.json and package-lock.json but didn't regenerate src/lib/version.ts. The release pipeline "version": "changeset version && npm run sync-version" script should be running sync-version; this PR's regenerate also catches that up. Worth a separate look at why release-prep didn't include the regen — probably a fresh-clone-vs-committed-output thing.

Test plan

  • npm run build clean
  • npm run format:check clean
  • node --test test/lib/compatible-versions-self-consistency.test.js — 3/3 pass
  • npx tsx scripts/sync-version.ts regenerates src/lib/version.ts with the extended compat list
  • After merge, COMPATIBLE_ADCP_VERSIONS will track ADCP_VERSION automatically across future patch bumps; the new test fails loud if the auto-derive is reverted.

🤖 Generated with Claude Code

The 3.0.x patch enumeration in COMPATIBLE_ADCP_VERSIONS was a hardcoded
array literal inside the scripts/sync-version.ts template. Every AdCP
patch bump needed someone to remember to append the new version. The
3.0.9, 3.0.10, and 3.0.11 chore PRs all forgot — the list capped at
3.0.8 even though ADCP_VERSION moved to 3.0.11. Symptom:
isCompatibleWith('3.0.11') === false against the SDK's own pin.

Same root-cause class as the SDK-build-time schema URL pinning drift
surfaced by adcontextprotocol/adcp#4419 (BidMachine reports cite
"/schemas/3.0.1/" against a 3.0.11 seller): a load-bearing version
surface that depends on human discipline at every patch bump.

scripts/sync-version.ts now derives the list dynamically from the
current ADCP_VERSION. Enumerates 3.0.0..3.0.<patch> mechanically. Fails
closed when the version falls outside 3.0.x so a future 3.1.x or 4.x
bump forces the script to be extended explicitly — the compat surface
for a major/minor move is rarely mechanical.

Adds test/lib/compatible-versions-self-consistency.test.js asserting
the regenerated list contains the current pin and fills the
3.0.0..ADCP_VERSION range without gaps. Future regressions (someone
reverting to hardcoded literals) fail loud at CI.

Out of scope: SDK-build-time schema URL pinning in validations.ts
(cited URLs reflect the SDK's pin, not the agent's advertised version).
Tracked separately.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three nits from code-reviewer + security-reviewer on #1706:

1. Cap patch enumeration at MAX_PATCH_ENUMERATION = 500. A hostile or
   fat-fingered ADCP_VERSION = '3.0.999999999' would have looped ~10⁹
   string allocations and OOM'd the build silently. Bounded build-time
   threat but the fix is one line and the new failure mode is a clean
   error instead of a hang.

2. Refuse prerelease pins (e.g. 3.0.11-rc.1). Enumerating 3.0.0..3.0.11
   from a prerelease pin over-claims GA stability for an unreleased
   patch. Stricter regex; the bumper for a prerelease must land the GA
   pin separately when it stabilizes.

3. Test now asserts the COMPATIBLE_PREFIX legacy aliases (v2.5, v2.6,
   v3, 3.0.0-beta.1, 3.0.0-beta.3) survive — guards against a future
   "clean up legacy aliases" PR silently dropping pinned adopters.

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