@adcp/sdk 15.9.4 → 15.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/lib/core/AgentClient.d.mts +4 -2
  2. package/dist/lib/core/AgentClient.d.ts +4 -2
  3. package/dist/lib/core/AgentClient.js +4 -2
  4. package/dist/lib/core/AgentClient.mjs +4 -2
  5. package/dist/lib/core/SingleAgentClient.d.mts +7 -3
  6. package/dist/lib/core/SingleAgentClient.d.ts +7 -3
  7. package/dist/lib/core/SingleAgentClient.js +204 -13
  8. package/dist/lib/core/SingleAgentClient.mjs +209 -13
  9. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  10. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  11. package/dist/lib/core/TaskExecutor.js +48 -34
  12. package/dist/lib/core/TaskExecutor.mjs +49 -35
  13. package/dist/lib/core/product-cache.d.mts +3 -1
  14. package/dist/lib/core/product-cache.d.ts +3 -1
  15. package/dist/lib/core/product-cache.js +2 -1
  16. package/dist/lib/core/product-cache.mjs +2 -1
  17. package/dist/lib/registry/types.d.mts +3 -2
  18. package/dist/lib/registry/types.d.ts +3 -2
  19. package/dist/lib/registry/types.generated.d.mts +21 -9
  20. package/dist/lib/registry/types.generated.d.ts +21 -9
  21. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  22. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  23. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  24. package/dist/lib/testing/client.js +3 -5
  25. package/dist/lib/testing/client.mjs +4 -6
  26. package/dist/lib/testing/compliance/comply.js +7 -2
  27. package/dist/lib/testing/compliance/comply.mjs +8 -3
  28. package/dist/lib/testing/index.d.mts +1 -1
  29. package/dist/lib/testing/index.d.ts +1 -1
  30. package/dist/lib/testing/index.js +4 -2
  31. package/dist/lib/testing/index.mjs +8 -2
  32. package/dist/lib/testing/storyboard/runner.js +12 -12
  33. package/dist/lib/testing/storyboard/runner.mjs +14 -13
  34. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  35. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  36. package/dist/lib/testing/storyboard/validations.js +23 -1
  37. package/dist/lib/testing/storyboard/validations.mjs +28 -2
  38. package/dist/lib/testing/types.d.mts +39 -0
  39. package/dist/lib/testing/types.d.ts +39 -0
  40. package/dist/lib/v2/projection/augment-response.js +6 -3
  41. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  42. package/dist/lib/v2/projection/creative-delivery.d.mts +2 -0
  43. package/dist/lib/v2/projection/creative-delivery.d.ts +2 -0
  44. package/dist/lib/v2/projection/creative-delivery.js +36 -17
  45. package/dist/lib/v2/projection/creative-delivery.mjs +37 -18
  46. package/dist/lib/v2/projection/legacy-metadata.d.mts +12 -0
  47. package/dist/lib/v2/projection/legacy-metadata.d.ts +12 -0
  48. package/dist/lib/v2/projection/legacy-metadata.js +41 -1
  49. package/dist/lib/v2/projection/legacy-metadata.mjs +37 -1
  50. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  51. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  52. package/dist/lib/v2/projection/v1-to-v2.js +83 -2
  53. package/dist/lib/v2/projection/v1-to-v2.mjs +86 -1
  54. package/dist/lib/validation/index.d.mts +1 -1
  55. package/dist/lib/validation/index.d.ts +1 -1
  56. package/dist/lib/validation/index.js +4 -2
  57. package/dist/lib/validation/index.mjs +4 -2
  58. package/dist/lib/validation/schema-loader.d.mts +26 -0
  59. package/dist/lib/validation/schema-loader.d.ts +26 -0
  60. package/dist/lib/validation/schema-loader.js +98 -14
  61. package/dist/lib/validation/schema-loader.mjs +95 -13
  62. package/dist/lib/version.d.mts +3 -3
  63. package/dist/lib/version.d.ts +3 -3
  64. package/dist/lib/version.js +3 -3
  65. package/dist/lib/version.mjs +3 -3
  66. package/docs/TYPE-SUMMARY.md +2 -2
  67. package/docs/guides/CREATIVE-DELIVERY.md +45 -6
  68. package/docs/guides/VALIDATE-YOUR-AGENT.md +34 -0
  69. package/docs/llms.txt +2 -2
  70. package/docs/migration-14.x-rc-worksheet.md +4 -4
  71. package/package.json +1 -1
@@ -144,9 +144,10 @@ export type SavePropertyRequest = Omit<RegistrySavePropertyRequest, 'authorized_
144
144
  /** Response from POST /api/properties/save (200) */
145
145
  export type SavePropertyResponse = operations['saveProperty']['responses']['200']['content']['application/json'];
146
146
  type RegistryResolveIdentifiersRequest = NonNullable<operations['resolveIdentifiers']['requestBody']>['content']['application/json'];
147
- /** Request body for POST /api/registry/resolve. `mode` defaults to `resolve` server-side. */
148
- export type ResolveIdentifiersRequest = Omit<RegistryResolveIdentifiersRequest, 'mode'> & {
147
+ /** Request body for POST /api/registry/resolve. Mode and sandbox use the registry's defaults when omitted. */
148
+ export type ResolveIdentifiersRequest = Omit<RegistryResolveIdentifiersRequest, 'mode' | 'sandbox'> & {
149
149
  mode?: RegistryResolveIdentifiersRequest['mode'];
150
+ sandbox?: RegistryResolveIdentifiersRequest['sandbox'];
150
151
  };
151
152
  /** Response from POST /api/registry/resolve (200) */
152
153
  export type ResolveIdentifiersResponse = operations['resolveIdentifiers']['responses']['200']['content']['application/json'];
@@ -283,7 +283,7 @@ export interface paths {
283
283
  put?: never;
284
284
  /**
285
285
  * Save property
286
- * @description Save or update a hosted property in the registry. Requires authentication. For existing properties, creates a revision-tracked edit. For new properties, creates the property directly. Cannot edit authoritative properties managed via adagents.json.
286
+ * @description Save or update a hosted property in the registry. Requires authentication. For bulk identifier contributions use resolveIdentifiers instead (up to 10,000 identifiers per request). This endpoint is limited to 60 requests/hour per user/IP. publisher_domain must be a lowercase hostname without a URL, port, whitespace, wildcard, or trailing dot. Reserved test domains are rejected unless sandbox is true. With sandbox: true the request is validated and a simulated result is returned without reading or writing a hosted property; the ID is ephemeral. For existing properties, creates a revision-tracked edit. For new properties, creates the property directly. Cannot edit authoritative properties managed via adagents.json.
287
287
  *
288
288
  * This is an identity-only write surface: the stored document always carries `authorized_agents: []`. Sales authorization lives solely in the publisher's own origin `adagents.json`; the community registry cannot mint or carry it. Any `authorized_agents` sent in the request body is ignored.
289
289
  */
@@ -4892,6 +4892,11 @@ export interface components {
4892
4892
  */
4893
4893
  OrganizationRevenueTier: "under_1m" | "1m_5m" | "5m_50m" | "50m_250m" | "250m_1b" | "1b_plus";
4894
4894
  ResolveResponse: {
4895
+ /**
4896
+ * @description Present for a non-persistent sandbox simulation. New property handles are ephemeral.
4897
+ * @enum {boolean}
4898
+ */
4899
+ sandbox?: true;
4895
4900
  resolved: components["schemas"]["ResolvedEntry"][];
4896
4901
  summary: {
4897
4902
  total: number;
@@ -4915,30 +4920,30 @@ export interface components {
4915
4920
  CatalogIdentifier: {
4916
4921
  /** @example domain */
4917
4922
  type: string;
4918
- /** @example nytimes.com */
4923
+ /** @example streamhaus.com */
4919
4924
  value: string;
4920
4925
  };
4926
+ /** @description Up to 10,000 identifiers plus provenance. resolve requires authentication and contributes unknown identifiers; lookup is read-only. Domain/subdomain values must follow core/identifier.json; production rejects reserved test domains. sandbox: true simulates contributions without writes. */
4921
4927
  ResolveRequest: {
4922
4928
  /** @description Identifiers to resolve (and, in resolve mode, contribute). Max 10,000 per call for all callers. */
4923
4929
  identifiers: components["schemas"]["CatalogIdentifier"][];
4924
4930
  provenance: components["schemas"]["FactProvenance"];
4925
4931
  /**
4926
- * @description `resolve` (default) contributes the identifiers, auto-creates missing catalog entries, logs demand activity, and returns rids — requires authentication. `lookup` is a pure read: no write, no activity log, no auth.
4932
+ * @description resolve (default) contributes identifiers, creates missing catalog entries, and logs activity; authentication is required. lookup is a public read with no writes or activity logging.
4927
4933
  * @default resolve
4928
4934
  * @enum {string}
4929
4935
  */
4930
4936
  mode: "resolve" | "lookup";
4937
+ /** @description Simulate contributions without storing properties, identifiers, facts, or activity. Reads existing catalog data; new handles are ephemeral. Reserved test domains are allowed only in sandbox mode. Defaults to false when omitted. */
4938
+ sandbox?: boolean;
4931
4939
  };
4932
4940
  FactProvenance: {
4933
4941
  /**
4934
- * @description How the caller knows these identifiers — the trust/audit envelope on the fact. Determines the confidence the catalog assigns. `crawl` is reserved for server-side pipelines; callers use the others.
4942
+ * @description How the caller knows these identifiers — the trust/audit envelope on the fact. Determines the confidence the catalog assigns. crawl is reserved for server-side pipelines; callers use the others.
4935
4943
  * @enum {string}
4936
4944
  */
4937
4945
  type: "agency_allowlist" | "publisher_declaration" | "impression_log" | "ssp_inventory" | "deal_history" | "crawl" | "data_partner" | "member_assertion";
4938
- /**
4939
- * @description Optional free-text annotation (campaign, dataset).
4940
- * @example unilever_q3
4941
- */
4946
+ /** @description Optional free-text annotation (campaign, dataset). */
4942
4947
  context?: string;
4943
4948
  };
4944
4949
  CatalogDisputeTriageResult: {
@@ -5731,6 +5736,11 @@ export interface operations {
5731
5736
  "application/json": {
5732
5737
  /** @example examplepub.com */
5733
5738
  publisher_domain: string;
5739
+ /**
5740
+ * @description Validate and simulate a save without persisting it. Allows reserved test hostnames.
5741
+ * @default false
5742
+ */
5743
+ sandbox?: boolean;
5734
5744
  /**
5735
5745
  * @description Ignored. Community-registry rows never assert sales authorization — the owner's origin adagents.json is the sole authorization source — so any value here is dropped and the stored document carries authorized_agents:[].
5736
5746
  * @example []
@@ -5770,6 +5780,8 @@ export interface operations {
5770
5780
  success: true;
5771
5781
  message: string;
5772
5782
  id: string;
5783
+ /** @enum {boolean} */
5784
+ sandbox?: true;
5773
5785
  revision_number?: number;
5774
5786
  };
5775
5787
  };
@@ -8475,7 +8487,7 @@ export interface operations {
8475
8487
  getAgentAuthorizations: {
8476
8488
  parameters: {
8477
8489
  query: {
8478
- /** @description Agent URL to look up. Canonicalized server-side (lowercased, trailing slashes trimmed). */
8490
+ /** @description Agent URL to look up. Canonicalized server-side per AdCP URL canonicalization: the scheme and host fold, the path does not. */
8479
8491
  agent_url: string;
8480
8492
  /** @description `effective` (default) applies override layer; `raw` reads base table. */
8481
8493
  include?: "raw" | "effective";
@@ -283,7 +283,7 @@ export interface paths {
283
283
  put?: never;
284
284
  /**
285
285
  * Save property
286
- * @description Save or update a hosted property in the registry. Requires authentication. For existing properties, creates a revision-tracked edit. For new properties, creates the property directly. Cannot edit authoritative properties managed via adagents.json.
286
+ * @description Save or update a hosted property in the registry. Requires authentication. For bulk identifier contributions use resolveIdentifiers instead (up to 10,000 identifiers per request). This endpoint is limited to 60 requests/hour per user/IP. publisher_domain must be a lowercase hostname without a URL, port, whitespace, wildcard, or trailing dot. Reserved test domains are rejected unless sandbox is true. With sandbox: true the request is validated and a simulated result is returned without reading or writing a hosted property; the ID is ephemeral. For existing properties, creates a revision-tracked edit. For new properties, creates the property directly. Cannot edit authoritative properties managed via adagents.json.
287
287
  *
288
288
  * This is an identity-only write surface: the stored document always carries `authorized_agents: []`. Sales authorization lives solely in the publisher's own origin `adagents.json`; the community registry cannot mint or carry it. Any `authorized_agents` sent in the request body is ignored.
289
289
  */
@@ -4892,6 +4892,11 @@ export interface components {
4892
4892
  */
4893
4893
  OrganizationRevenueTier: "under_1m" | "1m_5m" | "5m_50m" | "50m_250m" | "250m_1b" | "1b_plus";
4894
4894
  ResolveResponse: {
4895
+ /**
4896
+ * @description Present for a non-persistent sandbox simulation. New property handles are ephemeral.
4897
+ * @enum {boolean}
4898
+ */
4899
+ sandbox?: true;
4895
4900
  resolved: components["schemas"]["ResolvedEntry"][];
4896
4901
  summary: {
4897
4902
  total: number;
@@ -4915,30 +4920,30 @@ export interface components {
4915
4920
  CatalogIdentifier: {
4916
4921
  /** @example domain */
4917
4922
  type: string;
4918
- /** @example nytimes.com */
4923
+ /** @example streamhaus.com */
4919
4924
  value: string;
4920
4925
  };
4926
+ /** @description Up to 10,000 identifiers plus provenance. resolve requires authentication and contributes unknown identifiers; lookup is read-only. Domain/subdomain values must follow core/identifier.json; production rejects reserved test domains. sandbox: true simulates contributions without writes. */
4921
4927
  ResolveRequest: {
4922
4928
  /** @description Identifiers to resolve (and, in resolve mode, contribute). Max 10,000 per call for all callers. */
4923
4929
  identifiers: components["schemas"]["CatalogIdentifier"][];
4924
4930
  provenance: components["schemas"]["FactProvenance"];
4925
4931
  /**
4926
- * @description `resolve` (default) contributes the identifiers, auto-creates missing catalog entries, logs demand activity, and returns rids — requires authentication. `lookup` is a pure read: no write, no activity log, no auth.
4932
+ * @description resolve (default) contributes identifiers, creates missing catalog entries, and logs activity; authentication is required. lookup is a public read with no writes or activity logging.
4927
4933
  * @default resolve
4928
4934
  * @enum {string}
4929
4935
  */
4930
4936
  mode: "resolve" | "lookup";
4937
+ /** @description Simulate contributions without storing properties, identifiers, facts, or activity. Reads existing catalog data; new handles are ephemeral. Reserved test domains are allowed only in sandbox mode. Defaults to false when omitted. */
4938
+ sandbox?: boolean;
4931
4939
  };
4932
4940
  FactProvenance: {
4933
4941
  /**
4934
- * @description How the caller knows these identifiers — the trust/audit envelope on the fact. Determines the confidence the catalog assigns. `crawl` is reserved for server-side pipelines; callers use the others.
4942
+ * @description How the caller knows these identifiers — the trust/audit envelope on the fact. Determines the confidence the catalog assigns. crawl is reserved for server-side pipelines; callers use the others.
4935
4943
  * @enum {string}
4936
4944
  */
4937
4945
  type: "agency_allowlist" | "publisher_declaration" | "impression_log" | "ssp_inventory" | "deal_history" | "crawl" | "data_partner" | "member_assertion";
4938
- /**
4939
- * @description Optional free-text annotation (campaign, dataset).
4940
- * @example unilever_q3
4941
- */
4946
+ /** @description Optional free-text annotation (campaign, dataset). */
4942
4947
  context?: string;
4943
4948
  };
4944
4949
  CatalogDisputeTriageResult: {
@@ -5731,6 +5736,11 @@ export interface operations {
5731
5736
  "application/json": {
5732
5737
  /** @example examplepub.com */
5733
5738
  publisher_domain: string;
5739
+ /**
5740
+ * @description Validate and simulate a save without persisting it. Allows reserved test hostnames.
5741
+ * @default false
5742
+ */
5743
+ sandbox?: boolean;
5734
5744
  /**
5735
5745
  * @description Ignored. Community-registry rows never assert sales authorization — the owner's origin adagents.json is the sole authorization source — so any value here is dropped and the stored document carries authorized_agents:[].
5736
5746
  * @example []
@@ -5770,6 +5780,8 @@ export interface operations {
5770
5780
  success: true;
5771
5781
  message: string;
5772
5782
  id: string;
5783
+ /** @enum {boolean} */
5784
+ sandbox?: true;
5773
5785
  revision_number?: number;
5774
5786
  };
5775
5787
  };
@@ -8475,7 +8487,7 @@ export interface operations {
8475
8487
  getAgentAuthorizations: {
8476
8488
  parameters: {
8477
8489
  query: {
8478
- /** @description Agent URL to look up. Canonicalized server-side (lowercased, trailing slashes trimmed). */
8490
+ /** @description Agent URL to look up. Canonicalized server-side per AdCP URL canonicalization: the scheme and host fold, the path does not. */
8479
8491
  agent_url: string;
8480
8492
  /** @description `effective` (default) applies override layer; `raw` reads base table. */
8481
8493
  include?: "raw" | "effective";
@@ -4,5 +4,5 @@
4
4
  "source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
5
5
  "source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
6
6
  "upstream_adcp_version": "2.5.3",
7
- "synced_at": "2026-10-16T23:43:47.149Z"
7
+ "synced_at": "2026-10-19T00:55:30.097Z"
8
8
  }
@@ -309,7 +309,10 @@ function projectResponseCreativeIdentities(value, operation, legacyFormatConvert
309
309
  let projected = dataRecord;
310
310
  if ((0, import_types2.isProjectionProductInput)(projected)) {
311
311
  if (wireMode === "canonical") {
312
- const canonical = (0, import_augment_response.toCanonicalOnlyResponse)({ products: [projected] }, { legacyFormatConverter });
312
+ const canonical = (0, import_augment_response.toCanonicalOnlyResponse)(
313
+ { products: [projected] },
314
+ { legacyFormatConverter, _inferDualEmissionLegacyRefs: false }
315
+ );
313
316
  if (canonical.diagnostics.length > 0 || canonical.response.products.length !== 1) {
314
317
  throw new import_creative_delivery.CreativeFormatProjectionError(
315
318
  operation,
@@ -548,7 +551,8 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
548
551
  assertSafeGetProductsResponse(response);
549
552
  validateDualProductFormatDeclarations(response, legacyFormatConverter);
550
553
  const projected = (0, import_augment_response.toCanonicalOnlyResponse)(response, {
551
- legacyFormatConverter
554
+ legacyFormatConverter,
555
+ _inferDualEmissionLegacyRefs: false
552
556
  });
553
557
  const blockingDiagnostics = projected.diagnostics.filter(
554
558
  (diagnostic) => diagnostic.code !== "LEGACY_FORMAT_ID_DROPPED_UNMAPPED"
@@ -338,7 +338,10 @@ function projectResponseCreativeIdentities(value, operation, legacyFormatConvert
338
338
  let projected = dataRecord;
339
339
  if (isProjectionProductInput(projected)) {
340
340
  if (wireMode === "canonical") {
341
- const canonical = toCanonicalOnlyResponse({ products: [projected] }, { legacyFormatConverter });
341
+ const canonical = toCanonicalOnlyResponse(
342
+ { products: [projected] },
343
+ { legacyFormatConverter, _inferDualEmissionLegacyRefs: false }
344
+ );
342
345
  if (canonical.diagnostics.length > 0 || canonical.response.products.length !== 1) {
343
346
  throw new CreativeFormatProjectionError(
344
347
  operation,
@@ -577,7 +580,8 @@ function asCanonicalProductResponse(response, legacyFormatConverter) {
577
580
  assertSafeGetProductsResponse(response);
578
581
  validateDualProductFormatDeclarations(response, legacyFormatConverter);
579
582
  const projected = toCanonicalOnlyResponse(response, {
580
- legacyFormatConverter
583
+ legacyFormatConverter,
584
+ _inferDualEmissionLegacyRefs: false
581
585
  });
582
586
  const blockingDiagnostics = projected.diagnostics.filter(
583
587
  (diagnostic) => diagnostic.code !== "LEGACY_FORMAT_ID_DROPPED_UNMAPPED"
@@ -414,12 +414,10 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
414
414
  step.error = versionUnsupported;
415
415
  } else if (caps?.data) {
416
416
  profile.raw_capabilities = caps.data;
417
- const validation = (0, import_client_hooks.validateIncomingResponse)(
418
- "get_adcp_capabilities",
417
+ const validation = (0, import_schema_loader.withServedValidationVersion)(
419
418
  caps.data,
420
- "strict",
421
- void 0,
422
- (0, import_schema_loader.resolveServedValidationVersion)(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
419
+ schemaAdcpVersion ?? client.getAdcpVersion(),
420
+ (validationVersion) => (0, import_client_hooks.validateIncomingResponse)("get_adcp_capabilities", caps.data, "strict", void 0, validationVersion)
423
421
  );
424
422
  if (!validation.valid) {
425
423
  profile.capabilities_schema_issues = validation.issues.map((issue) => ({
@@ -10,7 +10,7 @@ import { SsrfRefusedError } from "../net/ssrf-fetch.mjs";
10
10
  import { ADCP_VERSION, toReleasePrecisionVersion } from "../version.mjs";
11
11
  import { createHmac, hkdfSync, randomBytes } from "node:crypto";
12
12
  import { validateIncomingResponse } from "../validation/client-hooks.mjs";
13
- import { resolveServedValidationVersion } from "../validation/schema-loader.mjs";
13
+ import { withServedValidationVersion } from "../validation/schema-loader.mjs";
14
14
  import { extractVersionUnsupportedDetails } from "../utils/error-extraction.mjs";
15
15
  import { buildAgentSigningContext } from "../signing/client.mjs";
16
16
  import { bindAgentStorage } from "../auth/oauth/storage-registry.mjs";
@@ -374,12 +374,10 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
374
374
  step.error = versionUnsupported;
375
375
  } else if (caps?.data) {
376
376
  profile.raw_capabilities = caps.data;
377
- const validation = validateIncomingResponse(
378
- "get_adcp_capabilities",
377
+ const validation = withServedValidationVersion(
379
378
  caps.data,
380
- "strict",
381
- void 0,
382
- resolveServedValidationVersion(caps.data, schemaAdcpVersion ?? client.getAdcpVersion())
379
+ schemaAdcpVersion ?? client.getAdcpVersion(),
380
+ (validationVersion) => validateIncomingResponse("get_adcp_capabilities", caps.data, "strict", void 0, validationVersion)
383
381
  );
384
382
  if (!validation.valid) {
385
383
  profile.capabilities_schema_issues = validation.issues.map((issue) => ({
@@ -1344,7 +1344,12 @@ async function complyImpl(agentUrl, options) {
1344
1344
  }
1345
1345
  (0, import_test_kit.validateTestKit)(testOptions.test_kit);
1346
1346
  const signal = externalSignal;
1347
- return await (0, import_schema_loader.withExternalSchemaRoot)(complianceIndex.adcp_version, scopedSchemaRoot, async () => {
1347
+ return await (0, import_schema_loader.withExternalSchemaRoot)(
1348
+ complianceIndex.adcp_version,
1349
+ scopedSchemaRoot,
1350
+ () => (0, import_schema_loader.withServedReleaseSchemaRoots)(testOptions.servedReleaseSchemaRoots, () => complyInSchemaScope())
1351
+ );
1352
+ async function complyInSchemaScope() {
1348
1353
  let effectiveOptions = (0, import_runner.applyAdcpVersionRunOptions)(complianceIndex.adcp_version, {
1349
1354
  ...testOptions,
1350
1355
  // `comply()` has always defaulted an unset transport to MCP when it built
@@ -1648,7 +1653,7 @@ async function complyImpl(agentUrl, options) {
1648
1653
  total_duration_ms: Date.now() - start,
1649
1654
  notices: noticesDedup
1650
1655
  };
1651
- });
1656
+ }
1652
1657
  }
1653
1658
  function hasComplyTimeoutBudgetExpired(start, timeout_ms, now = Date.now()) {
1654
1659
  return timeout_ms !== void 0 && now - start >= timeout_ms;
@@ -28,7 +28,7 @@ import { closeScopedConnections, withMCPConnectionScope } from "../../protocols/
28
28
  import { detectController, hasTestController } from "../test-controller.mjs";
29
29
  import { randomBytes } from "crypto";
30
30
  import { isPre31AdcpVersion } from "../../utils/adcp-version-config.mjs";
31
- import { withExternalSchemaRoot } from "../../validation/schema-loader.mjs";
31
+ import { withExternalSchemaRoot, withServedReleaseSchemaRoots } from "../../validation/schema-loader.mjs";
32
32
  import { redactOAuthUrlForOutput, redactOAuthUrlsInText } from "../storyboard/oauth-metadata-graph/index.mjs";
33
33
  import { LIBRARY_VERSION } from "../../version.mjs";
34
34
  import { validationFailsStep } from "../storyboard/validations.mjs";
@@ -1327,7 +1327,12 @@ async function complyImpl(agentUrl, options) {
1327
1327
  }
1328
1328
  validateTestKit(testOptions.test_kit);
1329
1329
  const signal = externalSignal;
1330
- return await withExternalSchemaRoot(complianceIndex.adcp_version, scopedSchemaRoot, async () => {
1330
+ return await withExternalSchemaRoot(
1331
+ complianceIndex.adcp_version,
1332
+ scopedSchemaRoot,
1333
+ () => withServedReleaseSchemaRoots(testOptions.servedReleaseSchemaRoots, () => complyInSchemaScope())
1334
+ );
1335
+ async function complyInSchemaScope() {
1331
1336
  let effectiveOptions = applyAdcpVersionRunOptions(complianceIndex.adcp_version, {
1332
1337
  ...testOptions,
1333
1338
  // `comply()` has always defaulted an unset transport to MCP when it built
@@ -1631,7 +1636,7 @@ async function complyImpl(agentUrl, options) {
1631
1636
  total_duration_ms: Date.now() - start,
1632
1637
  notices: noticesDedup
1633
1638
  };
1634
- });
1639
+ }
1635
1640
  }
1636
1641
  function hasComplyTimeoutBudgetExpired(start, timeout_ms, now = Date.now()) {
1637
1642
  return timeout_ms !== void 0 && now - start >= timeout_ms;
@@ -16,5 +16,5 @@ export { isSandboxRequest, mergeSeededProductsIntoResponse, filterValidSeededPro
16
16
  export type { TestControllerBridge, TestControllerBridgeContext, BridgeFromSessionStoreOptions, SeededCreative, SeededMediaBuy, SeededAccountFinancials, } from '../server/test-controller-bridge.mjs';
17
17
  export { runAgainstLocalAgent } from './local-agent-runner.mjs';
18
18
  export type { LocalAgentRunResult, PerStoryboardOverride, RunAgainstLocalAgentOptions } from './local-agent-runner.mjs';
19
- export { registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot } from '../validation/index.mjs';
19
+ export { registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, withServedReleaseSchemaRoots, } from '../validation/index.mjs';
20
20
  export { runStoryboard, runStoryboardStep, applyAdcpVersionRunOptions, applyStoryboardVersionOptions, getFirstStepPreview, parseStoryboard, loadStoryboardFile, normalizeValidationOnlyTasks, VALIDATION_ONLY_TASK, applyFixtureBindingsToRequest, buildFixtureResolutionSpecs, FixtureBindingRegistry, matchesFixtureRequirements, normalizeFixtureMatchExpression, validateFixtureResolutionDeclarations, getComplianceCacheDir, loadComplianceIndex, listBundles, loadBundleStoryboards, listAllComplianceStoryboards, getComplianceStoryboardById, findBundleById, resolveBundleOrStoryboard, resolveStoryboardsForCapabilities, isComplianceVersionSupported, CapabilityResolutionError, TASK_TO_METHOD, executeStoryboardTask, expandCreativeAssetDirectives, findUnresolvedCreativeAssetDirectives, extractContext, injectContext, runValidations, resolvePath, RateLimitTripObserver, RATE_LIMIT_TRIP_CONTRACT, RATE_LIMIT_TRIP_DEFAULT_REPLAY_MAX_WAIT_SECONDS, RATE_LIMIT_TRIP_MAX_ATTEMPTS_MAX, RATE_LIMIT_TRIP_MAX_ATTEMPTS_MIN, validateRateLimitTripSpec, getSandboxEntities, getSandboxBrands, getSandboxBrand, isSandboxDomain, clearSandboxCache, registerAssertion, getAssertion, listAssertions, listDefaultAssertions, clearAssertionRegistry, resolveAssertions, type AssertionSpec, type AssertionContext, type AssertionResult, type RegisterAssertionOptions, type Storyboard, type StoryboardFixtureResolution, type FixtureResolutionStrategy, type FixtureMatchOperator, type FixtureMatchClause, type FixtureResolutionDeclaration, type ProductFixtureResolutionDeclaration, type PricingOptionFixtureResolutionDeclaration, type FixtureResolutionStatus, type FixtureResolutionRecord, type FixtureResolutionAttempt, type FixtureResolutionEvidence, type FixtureResolutionCoverageGap, type StoryboardInvariants, type StoryboardInvariantsObject, type StepInvariantsObject, type StoryboardPhase, type StoryboardStep, type RateLimitTripSpec, type StoryboardValidation, type RateLimitTripClient, type RateLimitTripFailureCode, type RateLimitTripObservation, type RateLimitTripObserverOptions, type RateLimitTripResponseSnapshot, type RateLimitTripStructuredResult, type RateLimitTripTaskOptions, type StoryboardContext, type StoryboardRunOptions, type TrustedMatchContextProviderEndpoint, type TrustedMatchContextRegistrationContext, type TrustedMatchContextRouterRunnerOptions, type TrustedMatchPublisherAuthOperation, type TrustedMatchPublisherCredentialState, type TrustedMatchPublisherAuthTls, type TrustedMatchPublisherAuthProbeConfiguration, type TrustedMatchPublisherAuthRunner, type ValidationResult, type StoryboardStepPreview, type StoryboardStepResult, type StoryboardStepHint, type StoryboardStepHintBase, type ContextValueRejectedHint, type ShapeDriftHint, type MissingRequiredFieldHint, type FormatMismatchHint, type MonotonicViolationHint, type ContextProvenanceEntry, type StoryboardPhaseResult, type StoryboardResult, type RunnerNotice, type NoticeCode, type NoticeSeverity, type AgentCapabilities, type BundleKind, type BundleRef, type CapabilityResolutionCode, type ComplianceIndex, type ComplianceIndexProtocol, type ComplianceIndexSpecialism, type ResolveOptions, type ResolvedBundle, type ResolvedStoryboards, type SandboxBrand, type SandboxAgent, type SandboxEntities, type BrandJson, type AdagentsJson, gradeOAuthMetadataGraph, gradeOAuthMetadataGraphVector, loadOAuthMetadataGraphVectors, normalizeOAuthResourceForComparison, redactOAuthUrlForOutput, type GradeOAuthMetadataGraphOptions, type OAuthMetadataGraphErrorCode, type OAuthMetadataGraphFinding, type OAuthMetadataGraphGrade, type OAuthMetadataGraphObservation, type OAuthMetadataGraphVector, type OAuthMetadataGraphVectorCorpus, BrandJsonSchema, AdagentsJsonSchema, MCP_SESSION_PROBE_TASK, } from './storyboard/index.mjs';
@@ -16,5 +16,5 @@ export { isSandboxRequest, mergeSeededProductsIntoResponse, filterValidSeededPro
16
16
  export type { TestControllerBridge, TestControllerBridgeContext, BridgeFromSessionStoreOptions, SeededCreative, SeededMediaBuy, SeededAccountFinancials, } from '../server/test-controller-bridge';
17
17
  export { runAgainstLocalAgent } from './local-agent-runner';
18
18
  export type { LocalAgentRunResult, PerStoryboardOverride, RunAgainstLocalAgentOptions } from './local-agent-runner';
19
- export { registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot } from '../validation';
19
+ export { registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot, withServedReleaseSchemaRoots, } from '../validation';
20
20
  export { runStoryboard, runStoryboardStep, applyAdcpVersionRunOptions, applyStoryboardVersionOptions, getFirstStepPreview, parseStoryboard, loadStoryboardFile, normalizeValidationOnlyTasks, VALIDATION_ONLY_TASK, applyFixtureBindingsToRequest, buildFixtureResolutionSpecs, FixtureBindingRegistry, matchesFixtureRequirements, normalizeFixtureMatchExpression, validateFixtureResolutionDeclarations, getComplianceCacheDir, loadComplianceIndex, listBundles, loadBundleStoryboards, listAllComplianceStoryboards, getComplianceStoryboardById, findBundleById, resolveBundleOrStoryboard, resolveStoryboardsForCapabilities, isComplianceVersionSupported, CapabilityResolutionError, TASK_TO_METHOD, executeStoryboardTask, expandCreativeAssetDirectives, findUnresolvedCreativeAssetDirectives, extractContext, injectContext, runValidations, resolvePath, RateLimitTripObserver, RATE_LIMIT_TRIP_CONTRACT, RATE_LIMIT_TRIP_DEFAULT_REPLAY_MAX_WAIT_SECONDS, RATE_LIMIT_TRIP_MAX_ATTEMPTS_MAX, RATE_LIMIT_TRIP_MAX_ATTEMPTS_MIN, validateRateLimitTripSpec, getSandboxEntities, getSandboxBrands, getSandboxBrand, isSandboxDomain, clearSandboxCache, registerAssertion, getAssertion, listAssertions, listDefaultAssertions, clearAssertionRegistry, resolveAssertions, type AssertionSpec, type AssertionContext, type AssertionResult, type RegisterAssertionOptions, type Storyboard, type StoryboardFixtureResolution, type FixtureResolutionStrategy, type FixtureMatchOperator, type FixtureMatchClause, type FixtureResolutionDeclaration, type ProductFixtureResolutionDeclaration, type PricingOptionFixtureResolutionDeclaration, type FixtureResolutionStatus, type FixtureResolutionRecord, type FixtureResolutionAttempt, type FixtureResolutionEvidence, type FixtureResolutionCoverageGap, type StoryboardInvariants, type StoryboardInvariantsObject, type StepInvariantsObject, type StoryboardPhase, type StoryboardStep, type RateLimitTripSpec, type StoryboardValidation, type RateLimitTripClient, type RateLimitTripFailureCode, type RateLimitTripObservation, type RateLimitTripObserverOptions, type RateLimitTripResponseSnapshot, type RateLimitTripStructuredResult, type RateLimitTripTaskOptions, type StoryboardContext, type StoryboardRunOptions, type TrustedMatchContextProviderEndpoint, type TrustedMatchContextRegistrationContext, type TrustedMatchContextRouterRunnerOptions, type TrustedMatchPublisherAuthOperation, type TrustedMatchPublisherCredentialState, type TrustedMatchPublisherAuthTls, type TrustedMatchPublisherAuthProbeConfiguration, type TrustedMatchPublisherAuthRunner, type ValidationResult, type StoryboardStepPreview, type StoryboardStepResult, type StoryboardStepHint, type StoryboardStepHintBase, type ContextValueRejectedHint, type ShapeDriftHint, type MissingRequiredFieldHint, type FormatMismatchHint, type MonotonicViolationHint, type ContextProvenanceEntry, type StoryboardPhaseResult, type StoryboardResult, type RunnerNotice, type NoticeCode, type NoticeSeverity, type AgentCapabilities, type BundleKind, type BundleRef, type CapabilityResolutionCode, type ComplianceIndex, type ComplianceIndexProtocol, type ComplianceIndexSpecialism, type ResolveOptions, type ResolvedBundle, type ResolvedStoryboards, type SandboxBrand, type SandboxAgent, type SandboxEntities, type BrandJson, type AdagentsJson, gradeOAuthMetadataGraph, gradeOAuthMetadataGraphVector, loadOAuthMetadataGraphVectors, normalizeOAuthResourceForComparison, redactOAuthUrlForOutput, type GradeOAuthMetadataGraphOptions, type OAuthMetadataGraphErrorCode, type OAuthMetadataGraphFinding, type OAuthMetadataGraphGrade, type OAuthMetadataGraphObservation, type OAuthMetadataGraphVector, type OAuthMetadataGraphVectorCorpus, BrandJsonSchema, AdagentsJsonSchema, MCP_SESSION_PROBE_TASK, } from './storyboard';
@@ -192,7 +192,8 @@ __export(testing_exports, {
192
192
  unregisterExternalSchemaRoot: () => import_validation.unregisterExternalSchemaRoot,
193
193
  validateFixtureResolutionDeclarations: () => import_storyboard.validateFixtureResolutionDeclarations,
194
194
  validateRateLimitTripSpec: () => import_storyboard.validateRateLimitTripSpec,
195
- withExternalSchemaRoot: () => import_validation.withExternalSchemaRoot
195
+ withExternalSchemaRoot: () => import_validation.withExternalSchemaRoot,
196
+ withServedReleaseSchemaRoots: () => import_validation.withServedReleaseSchemaRoots
196
197
  });
197
198
  module.exports = __toCommonJS(testing_exports);
198
199
  var import_pending_web_flow_store = require('./pending-web-flow-store.js');
@@ -384,5 +385,6 @@ var import_storyboard = require('./storyboard/index.js');
384
385
  unregisterExternalSchemaRoot,
385
386
  validateFixtureResolutionDeclarations,
386
387
  validateRateLimitTripSpec,
387
- withExternalSchemaRoot
388
+ withExternalSchemaRoot,
389
+ withServedReleaseSchemaRoots
388
390
  });
@@ -122,7 +122,12 @@ import {
122
122
  bridgeFromSessionStore
123
123
  } from "../server/test-controller-bridge.mjs";
124
124
  import { runAgainstLocalAgent } from "./local-agent-runner.mjs";
125
- import { registerExternalSchemaRoot, unregisterExternalSchemaRoot, withExternalSchemaRoot } from "../validation/index.mjs";
125
+ import {
126
+ registerExternalSchemaRoot,
127
+ unregisterExternalSchemaRoot,
128
+ withExternalSchemaRoot,
129
+ withServedReleaseSchemaRoots
130
+ } from "../validation/index.mjs";
126
131
  import {
127
132
  runStoryboard,
128
133
  runStoryboardStep,
@@ -359,5 +364,6 @@ export {
359
364
  unregisterExternalSchemaRoot,
360
365
  validateFixtureResolutionDeclarations,
361
366
  validateRateLimitTripSpec,
362
- withExternalSchemaRoot
367
+ withExternalSchemaRoot,
368
+ withServedReleaseSchemaRoots
363
369
  };
@@ -770,14 +770,14 @@ async function runStoryboard(agentUrlOrUrls, storyboard, options = {}) {
770
770
  options = (0, import_test_kit.resolveDeclaredTestKit)(storyboard, options);
771
771
  options = (0, import_native_a2a_compliance.applyNativeA2AComplianceTransportOptions)(options);
772
772
  const schemaRoot = getRunSchemaRoot(options);
773
+ const runBody = () => (0, import_schema_loader.withServedReleaseSchemaRoots)(
774
+ options.servedReleaseSchemaRoots,
775
+ () => runStoryboardBody(agentUrlOrUrls, storyboard, options)
776
+ );
773
777
  if (schemaRoot) {
774
- return await (0, import_schema_loader.withExternalSchemaRoot)(
775
- schemaRoot.adcpVersion,
776
- schemaRoot.schemaRoot,
777
- () => runStoryboardBody(agentUrlOrUrls, storyboard, options)
778
- );
778
+ return await (0, import_schema_loader.withExternalSchemaRoot)(schemaRoot.adcpVersion, schemaRoot.schemaRoot, runBody);
779
779
  }
780
- return await runStoryboardBody(agentUrlOrUrls, storyboard, options);
780
+ return await runBody();
781
781
  },
782
782
  { isolate: true }
783
783
  );
@@ -3102,14 +3102,14 @@ async function runStoryboardStep(agentUrl, storyboard, stepId, options = {}) {
3102
3102
  options = (0, import_test_kit.resolveDeclaredTestKit)(storyboard, options);
3103
3103
  options = (0, import_native_a2a_compliance.applyNativeA2AComplianceTransportOptions)(options);
3104
3104
  const schemaRoot = getRunSchemaRoot(options);
3105
+ const runBody = () => (0, import_schema_loader.withServedReleaseSchemaRoots)(
3106
+ options.servedReleaseSchemaRoots,
3107
+ () => runStoryboardStepBody(agentUrl, storyboard, stepId, options)
3108
+ );
3105
3109
  if (schemaRoot) {
3106
- return await (0, import_schema_loader.withExternalSchemaRoot)(
3107
- schemaRoot.adcpVersion,
3108
- schemaRoot.schemaRoot,
3109
- () => runStoryboardStepBody(agentUrl, storyboard, stepId, options)
3110
- );
3110
+ return await (0, import_schema_loader.withExternalSchemaRoot)(schemaRoot.adcpVersion, schemaRoot.schemaRoot, runBody);
3111
3111
  }
3112
- return await runStoryboardStepBody(agentUrl, storyboard, stepId, options);
3112
+ return await runBody();
3113
3113
  },
3114
3114
  { isolate: true }
3115
3115
  );
@@ -60,7 +60,8 @@ import {
60
60
  getSchemaValidatorByRef,
61
61
  resolveBundleKey,
62
62
  schemaAllowsTopLevelField,
63
- withExternalSchemaRoot
63
+ withExternalSchemaRoot,
64
+ withServedReleaseSchemaRoots
64
65
  } from "../../validation/schema-loader.mjs";
65
66
  import { ADCP_VERSION, parseAdcpMajorVersion } from "../../version.mjs";
66
67
  import {
@@ -792,14 +793,14 @@ async function runStoryboard(agentUrlOrUrls, storyboard, options = {}) {
792
793
  options = resolveDeclaredTestKit(storyboard, options);
793
794
  options = applyNativeA2AComplianceTransportOptions(options);
794
795
  const schemaRoot = getRunSchemaRoot(options);
796
+ const runBody = () => withServedReleaseSchemaRoots(
797
+ options.servedReleaseSchemaRoots,
798
+ () => runStoryboardBody(agentUrlOrUrls, storyboard, options)
799
+ );
795
800
  if (schemaRoot) {
796
- return await withExternalSchemaRoot(
797
- schemaRoot.adcpVersion,
798
- schemaRoot.schemaRoot,
799
- () => runStoryboardBody(agentUrlOrUrls, storyboard, options)
800
- );
801
+ return await withExternalSchemaRoot(schemaRoot.adcpVersion, schemaRoot.schemaRoot, runBody);
801
802
  }
802
- return await runStoryboardBody(agentUrlOrUrls, storyboard, options);
803
+ return await runBody();
803
804
  },
804
805
  { isolate: true }
805
806
  );
@@ -3124,14 +3125,14 @@ async function runStoryboardStep(agentUrl, storyboard, stepId, options = {}) {
3124
3125
  options = resolveDeclaredTestKit(storyboard, options);
3125
3126
  options = applyNativeA2AComplianceTransportOptions(options);
3126
3127
  const schemaRoot = getRunSchemaRoot(options);
3128
+ const runBody = () => withServedReleaseSchemaRoots(
3129
+ options.servedReleaseSchemaRoots,
3130
+ () => runStoryboardStepBody(agentUrl, storyboard, stepId, options)
3131
+ );
3127
3132
  if (schemaRoot) {
3128
- return await withExternalSchemaRoot(
3129
- schemaRoot.adcpVersion,
3130
- schemaRoot.schemaRoot,
3131
- () => runStoryboardStepBody(agentUrl, storyboard, stepId, options)
3132
- );
3133
+ return await withExternalSchemaRoot(schemaRoot.adcpVersion, schemaRoot.schemaRoot, runBody);
3133
3134
  }
3134
- return await runStoryboardStepBody(agentUrl, storyboard, stepId, options);
3135
+ return await runBody();
3135
3136
  },
3136
3137
  { isolate: true }
3137
3138
  );
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "15.9.4";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.9.6";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "15.9.4";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "15.9.6";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -259,6 +259,21 @@ function mapZodIssueToSchemaKeyword(issue) {
259
259
  }
260
260
  }
261
261
  function validateResponseSchema(validation, ctx, taskResult) {
262
+ const pinnedVersion = ctx.adcpVersion;
263
+ if (ctx.taskName === "get_adcp_capabilities" && pinnedVersion !== void 0) {
264
+ return (0, import_schema_loader.withServedValidationVersion)(
265
+ taskResult.data,
266
+ pinnedVersion,
267
+ (validationVersion) => validateResponseSchemaForVersion(
268
+ validation,
269
+ validationVersion === pinnedVersion ? ctx : { ...ctx, adcpVersion: validationVersion, responseAdcpVersion: validationVersion },
270
+ taskResult
271
+ )
272
+ );
273
+ }
274
+ return validateResponseSchemaForVersion(validation, ctx, taskResult);
275
+ }
276
+ function validateResponseSchemaForVersion(validation, ctx, taskResult) {
262
277
  const taskName = ctx.taskName;
263
278
  const schemaIdentityVersion = ctx.adcpVersion ?? ctx.responseAdcpVersion ?? import_version.ADCP_VERSION;
264
279
  const { schema_id, schema_url } = resolveSchemaIdentity(ctx.responseSchemaRef, schemaIdentityVersion);
@@ -356,7 +371,14 @@ function validateResponseSchema(validation, ctx, taskResult) {
356
371
  }
357
372
  function isExternalResponseSchemaAuthoritative(ctx) {
358
373
  const validationVersion = responseSchemaValidationVersion(ctx.adcpVersion, ctx.responseAdcpVersion);
359
- return validationVersion !== void 0 && (0, import_schema_loader.isExternalSchemaRootActive)(validationVersion);
374
+ if (validationVersion !== void 0 && (0, import_schema_loader.isExternalSchemaRootActive)(validationVersion)) return true;
375
+ const pinnedVersion = ctx.adcpVersion;
376
+ if (ctx.taskName !== "get_adcp_capabilities" || pinnedVersion === void 0 || !ctx.taskResult) return false;
377
+ return (0, import_schema_loader.withServedValidationVersion)(
378
+ ctx.taskResult.data,
379
+ pinnedVersion,
380
+ (version) => version !== pinnedVersion && (0, import_schema_loader.isExternalSchemaRootActive)(version)
381
+ );
360
382
  }
361
383
  function responseSchemaValidationVersion(adcpVersion, responseAdcpVersion) {
362
384
  if (adcpVersion && (0, import_schema_loader.isExternalSchemaRootActive)(adcpVersion)) return adcpVersion;
@@ -2,7 +2,11 @@ import { prepareResponseForSchemaValidation, TOOL_RESPONSE_SCHEMAS } from "../..
2
2
  import { injectLegacyEnvelopeStatus } from "../../utils/envelope-status-compat.mjs";
3
3
  import { TRANSPORT_SUFFIX_REGEX } from "../../utils/a2a-discovery.mjs";
4
4
  import { validateResponse } from "../../validation/schema-validator.mjs";
5
- import { hasSchemaBundle, isExternalSchemaRootActive } from "../../validation/schema-loader.mjs";
5
+ import {
6
+ hasSchemaBundle,
7
+ isExternalSchemaRootActive,
8
+ withServedValidationVersion
9
+ } from "../../validation/schema-loader.mjs";
6
10
  import { ADCP_VERSION, LIBRARY_VERSION } from "../../version.mjs";
7
11
  import { isPre31AdcpVersion } from "../../utils/adcp-version-config.mjs";
8
12
  import { gte as semverGte, valid as validSemver } from "semver";
@@ -234,6 +238,21 @@ function mapZodIssueToSchemaKeyword(issue) {
234
238
  }
235
239
  }
236
240
  function validateResponseSchema(validation, ctx, taskResult) {
241
+ const pinnedVersion = ctx.adcpVersion;
242
+ if (ctx.taskName === "get_adcp_capabilities" && pinnedVersion !== void 0) {
243
+ return withServedValidationVersion(
244
+ taskResult.data,
245
+ pinnedVersion,
246
+ (validationVersion) => validateResponseSchemaForVersion(
247
+ validation,
248
+ validationVersion === pinnedVersion ? ctx : { ...ctx, adcpVersion: validationVersion, responseAdcpVersion: validationVersion },
249
+ taskResult
250
+ )
251
+ );
252
+ }
253
+ return validateResponseSchemaForVersion(validation, ctx, taskResult);
254
+ }
255
+ function validateResponseSchemaForVersion(validation, ctx, taskResult) {
237
256
  const taskName = ctx.taskName;
238
257
  const schemaIdentityVersion = ctx.adcpVersion ?? ctx.responseAdcpVersion ?? ADCP_VERSION;
239
258
  const { schema_id, schema_url } = resolveSchemaIdentity(ctx.responseSchemaRef, schemaIdentityVersion);
@@ -331,7 +350,14 @@ function validateResponseSchema(validation, ctx, taskResult) {
331
350
  }
332
351
  function isExternalResponseSchemaAuthoritative(ctx) {
333
352
  const validationVersion = responseSchemaValidationVersion(ctx.adcpVersion, ctx.responseAdcpVersion);
334
- return validationVersion !== void 0 && isExternalSchemaRootActive(validationVersion);
353
+ if (validationVersion !== void 0 && isExternalSchemaRootActive(validationVersion)) return true;
354
+ const pinnedVersion = ctx.adcpVersion;
355
+ if (ctx.taskName !== "get_adcp_capabilities" || pinnedVersion === void 0 || !ctx.taskResult) return false;
356
+ return withServedValidationVersion(
357
+ ctx.taskResult.data,
358
+ pinnedVersion,
359
+ (version) => version !== pinnedVersion && isExternalSchemaRootActive(version)
360
+ );
335
361
  }
336
362
  function responseSchemaValidationVersion(adcpVersion, responseAdcpVersion) {
337
363
  if (adcpVersion && isExternalSchemaRootActive(adcpVersion)) return adcpVersion;