Skip to content

fix(version): keep protocol envelope fields when converting responses down - #3594

Merged
bokelley merged 1 commit into
mainfrom
bokelley/projection-keeps-envelope
Nov 2, 2026
Merged

bokelley merged 1 commit into
mainfrom
bokelley/projection-keeps-envelope

Conversation

@bokelley

@bokelley bokelley commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Generating the 3.3 ↔ 3.2 conformance vectors (adcontextprotocol/adcp#8433) turned up a bug in version translation: converting a response down to an older release stripped protocol envelope fields (status, message, context and the rest) when that release's task schema didn't compose the protocol envelope.

That's the case for the 3.2 proposal-flow responses, which DR-0036 correction (b) fixes in 3.3 and a 3.2.x patch. A 3.3 server's list_products response reached a 3.2 buyer without status. The envelope applies to every task payload regardless of the task schema, so the projection now keeps every root-level property the release's protocol and version envelopes declare.

The released 16.x line (3.2 → 3.1) isn't affected on the common tasks: their 3.1 schemas compose the envelope.

Tests

  • A new regression test in test/server-version-translation.test.js covers the stripped-envelope case.
  • test/lib/version-translation-vectors.test.js now runs both shared vector files, 3.2-3.1.json and the new 3.3-3.2.json, each with the pair's own client release (40 cases).
  • Local results:
    • typecheck clean;
    • slow suite: 996 tests, 0 failures;
    • targeted files: 437 pass, plus 1 PostgreSQL test that can't connect here.

Separate gap (not fixed here): SDK 17 (main) still bundles 3.2.7 for its maintained 3.2 line, while 16.x moved to 3.2.8 (#3484). 3.2.8 carries the DR-0036 proposal-flow reopening. A 17.x client validating against 3.2 therefore uses the pre-correction schemas.

🤖 Generated with Claude Code


Open workspace in Conductor

… down

The schema projection removed `status`, `message`, `context` and the other
envelope fields when converting a response down to a release whose task
schema didn't compose the protocol envelope (the 3.2 proposal-flow
responses; DR-0036 correction b), so a 3.2 buyer could get a 3.3 server's
list_products response without its status. Root-level envelope fields are
now never projected away.

Also runs both shared vector files (3.2-3.1 and the new 3.3-3.2 set from
adcontextprotocol/adcp#8433), using each pair's client release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
const sourceSchemas = schemasForKey(sourceIndex, key) ?? nonEmpty(sourceIndex.additional);
const targetSchemas = schemasForKey(targetIndex, key) ?? nonEmpty(targetIndex.additional);
const entryPath = joinPath(path, key);
if (protectedKeys.has(key)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: The protection is unconditional — it continues before recursing, so structured envelope keys (context, governance_context, push_notification_config, payload) are kept wholesale even when the target release composes the envelope and could project their contents. For a 3.3 → 3.2.8 down-conversion (DR-0036 correction (b) backports the envelope into 3.2.8, so 3.2.8 declares these keys), a newer-only sub-field of context/governance_context now leaks unprojected and, because this path skips dropped.push, unreported. The witness-not-translator contract requires every removed-or-undeliverable field to surface as drift; this short-circuit silently keeps them instead. The surgical shape protects a key only when the target does not declare it — when the target declares the envelope, normal projection already keeps the key and still reports nested drift. Same set is also applied to request projection (translate.ts:179), so envelope-keyed request fields bypass the mutating-refusal gate; that's benign for the current field set but widens the blast radius. No test covers nested envelope-field drift.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — schema projection now preserves protocol-envelope fields (status/message/context) during version down-conversion instead of stripping them, a correct witness-not-translator fix grounded in DR-0036 correction (b), with a changeset and top-level test coverage.

Medium findings

  • src/lib/adapters/version/schema-projection.ts:327 — Unconditional envelope-key protection skips nested projection and drift reporting: newer sub-fields of structured envelope objects (context, governance_context, payload) may leak unprojected/unreported when the target composes the envelope; same set applied to request projection bypasses the mutating-refusal gate (benign for current fields).

Only 1 medium finding, not in {data-loss, schema, infra}; no critical/high; high_risk false; gated_paths false; no author team gate; no prior decision. Rows 1–8 do not fire — row 9 applies. Note: review_decision is REVIEW_REQUIRED but gated_paths is false, so row 2 does not apply.

Medium findings

  • src/lib/adapters/version/schema-projection.ts:327 — Unconditional envelope-key protection skips nested projection and drift reporting

@bokelley
bokelley merged commit 0bf2bcc into main Nov 2, 2026
46 checks passed
@bokelley
bokelley deleted the bokelley/projection-keeps-envelope branch November 2, 2026 17:15
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