From e26221ede4dc0069c7346768c32074a1f3cad14e Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 13 Aug 2026 10:05:40 +0200 Subject: [PATCH 1/2] fix(compliance): correct stripped-field notice --- .changeset/fix-input-schema-strip-notice.md | 5 ++++ .../universal/runner-output-contract.yaml | 15 ++++++------ tests/lint-storyboard-check-enum.test.cjs | 23 +++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 .changeset/fix-input-schema-strip-notice.md diff --git a/.changeset/fix-input-schema-strip-notice.md b/.changeset/fix-input-schema-strip-notice.md new file mode 100644 index 0000000000..c400c21d08 --- /dev/null +++ b/.changeset/fix-input-schema-strip-notice.md @@ -0,0 +1,5 @@ +--- +"adcontextprotocol": patch +--- + +Correct the `input_schema_field_stripped` compliance notice so it identifies request payload drift without blaming agents for omitting fields that are not part of the canonical task schema. diff --git a/static/compliance/source/universal/runner-output-contract.yaml b/static/compliance/source/universal/runner-output-contract.yaml index 95f20d753d..d7dca555cb 100644 --- a/static/compliance/source/universal/runner-output-contract.yaml +++ b/static/compliance/source/universal/runner-output-contract.yaml @@ -26,7 +26,7 @@ # --- Schema definition --- id: runner_output_contract -version: "2.9.0" +version: "2.9.1" title: "Runner output contract" summary: "Required failure-detail shape that AdCP storyboard runners MUST emit so implementors can self-diagnose validation failures." @@ -1232,14 +1232,13 @@ notice: receivers SHOULD migrate to RFC 9421 signatures only. input_schema_field_stripped: severity: info - spec_source: creative/list-creative-formats-request.json message_template: | - Runner stripped spec-defined request field(s) {stripped_fields} - from {task} because the agent's MCP inputSchema does not declare - them. The step's validations may pass vacuously if the stripped - field was material to the scenario's intent. Agents should - declare all spec-defined fields they support in their - inputSchema. + Runner stripped request field(s) {stripped_fields} from {task} + because neither the agent's MCP inputSchema nor the canonical + AdCP request schema for the negotiated version declares them. + The step's validations may pass vacuously if a stripped field was + material to the scenario's intent. Check the caller or runner + payload and version adaptation before changing the agent schema. capabilities_response_schema_invalid: severity: info spec_source: protocol/get-adcp-capabilities-response.json diff --git a/tests/lint-storyboard-check-enum.test.cjs b/tests/lint-storyboard-check-enum.test.cjs index c806128dcd..3307645a11 100644 --- a/tests/lint-storyboard-check-enum.test.cjs +++ b/tests/lint-storyboard-check-enum.test.cjs @@ -17,6 +17,7 @@ const os = require('node:os'); const path = require('node:path'); const test = require('node:test'); const assert = require('node:assert/strict'); +const yaml = require('js-yaml'); const { lint, @@ -51,6 +52,28 @@ test('authored_check_kinds enum loads from runner-output-contract.yaml', () => { } }); +test('field-strip notice attributes noncanonical fields to the request payload', () => { + const contractPath = path.join( + __dirname, + '..', + 'static', + 'compliance', + 'source', + 'universal', + 'runner-output-contract.yaml', + ); + const contract = yaml.load(fs.readFileSync(contractPath, 'utf8')); + const notice = contract.notice.canonical_codes.input_schema_field_stripped; + + assert.equal(contract.version, '2.9.1'); + assert.equal(notice.severity, 'info'); + assert.equal('spec_source' in notice, false, 'the notice is task-neutral and must not cite one creative schema'); + assert.match(notice.message_template, /neither the agent's MCP inputSchema nor the canonical/); + assert.match(notice.message_template, /Check the caller or runner\s+payload/); + assert.doesNotMatch(notice.message_template, /spec-defined/); + assert.doesNotMatch(notice.message_template, /Agents should declare/); +}); + function withTempStoryboardDir(name, doc, fn) { const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'check-enum-lint-')); const file = path.join(tmp, name); From ffc0c3757f23d2b48ce4f0e049a8693f24683c3a Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 13 Aug 2026 10:34:31 +0200 Subject: [PATCH 2/2] fix(compliance): consume corrected SDK runner --- .agents/sdk-shim-ledger.json | 2 +- .changeset/fix-input-schema-strip-notice.md | 2 +- .../verification/validate-your-agent.mdx | 6 +++--- package-lock.json | 8 ++++---- package.json | 2 +- scripts/patch-sdk-rc15.mjs | 2 +- tests/patch-sdk-rc15.test.cjs | 16 ++++++++-------- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.agents/sdk-shim-ledger.json b/.agents/sdk-shim-ledger.json index 2b74c04b7f..94a869ba55 100644 --- a/.agents/sdk-shim-ledger.json +++ b/.agents/sdk-shim-ledger.json @@ -46,7 +46,7 @@ "status": "temporary", "owner": "training-agent", "upstream": "adcontextprotocol/adcp-client#2495, adcontextprotocol/adcp-client#2527", - "problem": "The rc.17 storyboard task map forces get_products onto a legacy-only wire, and scoped transports discover capabilities without carrying them into request adaptation. The latter makes 3.1 sellers look pre-3.1 and strips filters.pricing_currencies.", + "problem": "The rc.18 storyboard task map forces get_products onto a legacy-only wire, and scoped transports discover capabilities without carrying them into request adaptation. The latter makes 3.1 sellers look pre-3.1 and strips filters.pricing_currencies.", "localBehavior": "Patch both compiled SDK module formats after installation so the storyboard runner leaves get_products wire selection unspecified and request-local capabilities drive version adaptation without cross-tenant caching.", "removalCondition": "Remove the patch script, Docker invocations, and ledger entry after an SDK release fixes storyboard get_products routing and carries scoped capabilities into request adaptation, and both current and released-3.0 storyboard matrices pass without the patch.", "paths": [ diff --git a/.changeset/fix-input-schema-strip-notice.md b/.changeset/fix-input-schema-strip-notice.md index c400c21d08..951950147a 100644 --- a/.changeset/fix-input-schema-strip-notice.md +++ b/.changeset/fix-input-schema-strip-notice.md @@ -2,4 +2,4 @@ "adcontextprotocol": patch --- -Correct the `input_schema_field_stripped` compliance notice so it identifies request payload drift without blaming agents for omitting fields that are not part of the canonical task schema. +Correct the `input_schema_field_stripped` compliance notice so it identifies request payload drift without blaming agents for omitting fields that are not part of the canonical task schema, and consume the SDK release that keeps broad `list_accounts` discovery requests unscoped. diff --git a/docs/building/verification/validate-your-agent.mdx b/docs/building/verification/validate-your-agent.mdx index 0690e929e7..3004cbbb9b 100644 --- a/docs/building/verification/validate-your-agent.mdx +++ b/docs/building/verification/validate-your-agent.mdx @@ -112,16 +112,16 @@ Add `--json` for structured output. ### Select a compliance cache and test kit -`--compliance-version` selects a cache bundled with the SDK. For an extracted cache, pass its versioned directory to `--compliance-dir`; `--test-kit` takes a YAML file from the `test-kits/` directory below that same cache root. After extracting the `@adcp/sdk` 13.0.0-rc.17 npm tarball in the current directory, use its versioned cache root like this: +`--compliance-version` selects a cache bundled with the SDK. For an extracted cache, pass its versioned directory to `--compliance-dir`; `--test-kit` takes a YAML file from the `test-kits/` directory below that same cache root. After extracting the `@adcp/sdk` 13.0.0-rc.18 npm tarball in the current directory, use its versioned cache root like this: ```bash -npx @adcp/sdk@13.0.0-rc.17 storyboard run my-agent \ +npx @adcp/sdk@13.0.0-rc.18 storyboard run my-agent \ --compliance-dir ./package/compliance/cache/3.1.13 \ --test-kit ./package/compliance/cache/3.1.13/test-kits/acme-outdoor.yaml ``` -`@adcp/sdk` 13.0.0-rc.17 infers the compliance line from test-kit metadata and rejects mixed or ambiguous `--test-kit`, `--compliance-version`, and `--compliance-dir` selections before contacting the agent. Keep the test kit and storyboard files under the same versioned cache root. +`@adcp/sdk` 13.0.0-rc.18 infers the compliance line from test-kit metadata and rejects mixed or ambiguous `--test-kit`, `--compliance-version`, and `--compliance-dir` selections before contacting the agent. Keep the test kit and storyboard files under the same versioned cache root. The storyboard runner operates in two modes depending on whether your agent implements the optional [compliance test controller](/docs/building/by-layer/L3/comply-test-controller): diff --git a/package-lock.json b/package-lock.json index 9c02292eda..6d3202514b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "3.1.1", "hasInstallScript": true, "dependencies": { - "@adcp/sdk": "13.0.0-rc.17", + "@adcp/sdk": "13.0.0-rc.18", "@anthropic-ai/sdk": "^0.115.0", "@asteasolutions/zod-to-openapi": "^8.5.0", "@contentauth/c2pa-node": "^0.8.3", @@ -132,9 +132,9 @@ } }, "node_modules/@adcp/sdk": { - "version": "13.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@adcp/sdk/-/sdk-13.0.0-rc.17.tgz", - "integrity": "sha512-okG288htgo8oeZOpv79oahezXWGQD0jI847MUhDZz9TOhE0jm70HuyatX9GZkJ/4uBs3dhMe3L5GTTj4MOIj6Q==", + "version": "13.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@adcp/sdk/-/sdk-13.0.0-rc.18.tgz", + "integrity": "sha512-SbLflNxWmYWSguvMDGWW4ssHIpfO67ZlLBvLtb1vqf1PZMi6n6Vz9VJijCIAzFajUJWbZ24LVWwTlasyVgOrhw==", "license": "Apache-2.0", "workspaces": [ ".", diff --git a/package.json b/package.json index 6e4b8b0568..0ab21131bd 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "docs:json-field-audit": "node scripts/docs-json-field-audit.cjs" }, "dependencies": { - "@adcp/sdk": "13.0.0-rc.17", + "@adcp/sdk": "13.0.0-rc.18", "@anthropic-ai/sdk": "^0.115.0", "@asteasolutions/zod-to-openapi": "^8.5.0", "@contentauth/c2pa-node": "^0.8.3", diff --git a/scripts/patch-sdk-rc15.mjs b/scripts/patch-sdk-rc15.mjs index b2ec2c99cf..59fd0eb17d 100644 --- a/scripts/patch-sdk-rc15.mjs +++ b/scripts/patch-sdk-rc15.mjs @@ -6,7 +6,7 @@ import path from 'node:path'; // This temporary patch remains version-locked even though its filename dates // from the release where it was introduced. Remove it when the upstream // get_products routing and scoped capability propagation fixes ship. -const EXPECTED_VERSION = '13.0.0-rc.17'; +const EXPECTED_VERSION = '13.0.0-rc.18'; const packageJson = JSON.parse(fs.readFileSync(path.resolve('node_modules/@adcp/sdk/package.json'), 'utf8')); if (packageJson.version !== EXPECTED_VERSION) { diff --git a/tests/patch-sdk-rc15.test.cjs b/tests/patch-sdk-rc15.test.cjs index 02d80088e8..8dcc3de026 100644 --- a/tests/patch-sdk-rc15.test.cjs +++ b/tests/patch-sdk-rc15.test.cjs @@ -52,7 +52,7 @@ class SingleAgentClient { module.exports = { SingleAgentClient }; `; -function writeFixture(version = '13.0.0-rc.17') { +function writeFixture(version = '13.0.0-rc.18') { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sdk-rc15-patch-')); const sdkRoot = path.join(root, 'node_modules', '@adcp', 'sdk'); fs.mkdirSync(sdkRoot, { recursive: true }); @@ -134,11 +134,11 @@ test('hosted SDK patch fixes get_products routing in CJS and ESM idempotently', }); test('hosted SDK patch refuses an unreviewed SDK version before modifying artifacts', (t) => { - const root = writeFixture('13.0.0-rc.18'); + const root = writeFixture('13.0.0-rc.19'); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Refusing to patch @adcp\/sdk 13\.0\.0-rc\.18/); + assert.match(result.stderr, /Refusing to patch @adcp\/sdk 13\.0\.0-rc\.19/); }); test('hosted SDK patch rejects an unexpected task-map source shape', (t) => { @@ -155,7 +155,7 @@ test('hosted SDK patch rejects an unexpected task-map source shape', (t) => { const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.17 SDK shape/); + assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.18 SDK shape/); }); test('hosted SDK patch rejects mixed original and patched call sites before writing either format', (t) => { @@ -170,7 +170,7 @@ test('hosted SDK patch rejects mixed original and patched call sites before writ const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.17 SDK shape/); + assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.18 SDK shape/); assert.equal(fs.readFileSync(cjsFile, 'utf8'), cjsBefore); }); @@ -185,7 +185,7 @@ test('hosted SDK patch rejects duplicate original call sites before writing eith const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.17 SDK shape/); + assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.18 SDK shape/); assert.equal(fs.readFileSync(cjsFile, 'utf8'), cjsBefore); }); @@ -205,7 +205,7 @@ test('hosted SDK patch preflights both module formats before writing either one' const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.17 SDK shape/); + assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.18 SDK shape/); assert.equal(fs.readFileSync(cjsFile, 'utf8'), cjsBefore); }); @@ -225,7 +225,7 @@ test('hosted SDK patch preflights core clients before writing any artifact', (t) const result = runPatcher(root); assert.notEqual(result.status, 0); - assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.17 SDK shape/); + assert.match(result.stderr, /Unexpected 13\.0\.0-rc\.18 SDK shape/); assert.equal(fs.readFileSync(taskMapFile, 'utf8'), taskMapBefore); });