@adcp/sdk 7.10.2 → 7.11.1

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 (305) hide show
  1. package/compliance/cache/3.1.0-rc.2/domains/brand/index.yaml +160 -0
  2. package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/distributed_brand_resolution.yaml +415 -0
  3. package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/single_side_trust_extension.yaml +454 -0
  4. package/compliance/cache/3.1.0-rc.2/domains/creative/index.yaml +339 -0
  5. package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/billing_out_of_band.yaml +153 -0
  6. package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/canonical_supported_formats.yaml +212 -0
  7. package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
  8. package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/native_in_feed.yaml +543 -0
  9. package/compliance/cache/3.1.0-rc.2/domains/governance/index.yaml +682 -0
  10. package/compliance/cache/3.1.0-rc.2/domains/media-buy/index.yaml +789 -0
  11. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/audience_buy_flow.yaml +380 -0
  12. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/available_actions.yaml +565 -0
  13. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
  14. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/canonical_formats.yaml +861 -0
  15. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
  16. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
  17. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/create_media_buy_async.yaml +234 -0
  18. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
  19. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_reception.yaml +247 -0
  20. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/delivery_reporting.yaml +357 -0
  21. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment.yaml +633 -0
  22. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
  23. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/event_dedup_flow.yaml +399 -0
  24. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
  25. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_approved.yaml +214 -0
  26. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_conditions.yaml +199 -0
  27. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied.yaml +204 -0
  28. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
  29. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/invalid_transitions.yaml +289 -0
  30. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
  31. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
  32. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_accountability.yaml +244 -0
  33. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
  34. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
  35. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
  36. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
  37. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow.yaml +428 -0
  38. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
  39. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/product_signal_targeting.yaml +373 -0
  40. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize.yaml +399 -0
  41. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
  42. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
  43. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
  44. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_enforcement.yaml +517 -0
  45. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
  46. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/reach_buy_flow.yaml +823 -0
  47. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
  48. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_products.yaml +148 -0
  49. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
  50. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
  51. package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
  52. package/compliance/cache/3.1.0-rc.2/domains/media-buy/state-machine.yaml +442 -0
  53. package/compliance/cache/3.1.0-rc.2/domains/signals/index.yaml +266 -0
  54. package/compliance/cache/3.1.0-rc.2/domains/sponsored-intelligence/index.yaml +256 -0
  55. package/compliance/cache/3.1.0-rc.2/index.json +356 -0
  56. package/compliance/cache/3.1.0-rc.2/protocols/brand/index.yaml +160 -0
  57. package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/distributed_brand_resolution.yaml +415 -0
  58. package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/single_side_trust_extension.yaml +454 -0
  59. package/compliance/cache/3.1.0-rc.2/protocols/creative/index.yaml +339 -0
  60. package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/billing_out_of_band.yaml +153 -0
  61. package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/canonical_supported_formats.yaml +212 -0
  62. package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
  63. package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/native_in_feed.yaml +543 -0
  64. package/compliance/cache/3.1.0-rc.2/protocols/governance/index.yaml +682 -0
  65. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/index.yaml +789 -0
  66. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/audience_buy_flow.yaml +380 -0
  67. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/available_actions.yaml +565 -0
  68. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
  69. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/canonical_formats.yaml +861 -0
  70. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
  71. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
  72. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/create_media_buy_async.yaml +234 -0
  73. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
  74. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_reception.yaml +247 -0
  75. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/delivery_reporting.yaml +357 -0
  76. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment.yaml +633 -0
  77. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
  78. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/event_dedup_flow.yaml +399 -0
  79. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
  80. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_approved.yaml +214 -0
  81. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_conditions.yaml +199 -0
  82. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied.yaml +204 -0
  83. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
  84. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/invalid_transitions.yaml +289 -0
  85. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
  86. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
  87. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_accountability.yaml +244 -0
  88. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
  89. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
  90. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
  91. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
  92. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow.yaml +428 -0
  93. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
  94. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/product_signal_targeting.yaml +373 -0
  95. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize.yaml +399 -0
  96. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
  97. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
  98. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
  99. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_enforcement.yaml +517 -0
  100. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
  101. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/reach_buy_flow.yaml +823 -0
  102. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
  103. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_products.yaml +148 -0
  104. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
  105. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
  106. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
  107. package/compliance/cache/3.1.0-rc.2/protocols/media-buy/state-machine.yaml +442 -0
  108. package/compliance/cache/3.1.0-rc.2/protocols/signals/index.yaml +266 -0
  109. package/compliance/cache/3.1.0-rc.2/protocols/sponsored-intelligence/index.yaml +256 -0
  110. package/compliance/cache/3.1.0-rc.2/specialisms/audience-sync/index.yaml +313 -0
  111. package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/index.yaml +350 -0
  112. package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/scenarios/governance_denied.yaml +226 -0
  113. package/compliance/cache/3.1.0-rc.2/specialisms/collection-lists/index.yaml +359 -0
  114. package/compliance/cache/3.1.0-rc.2/specialisms/content-standards/index.yaml +572 -0
  115. package/compliance/cache/3.1.0-rc.2/specialisms/creative-ad-server/index.yaml +409 -0
  116. package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/generative-seller.yaml +807 -0
  117. package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/index.yaml +758 -0
  118. package/compliance/cache/3.1.0-rc.2/specialisms/creative-template/index.yaml +510 -0
  119. package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/index.yaml +143 -0
  120. package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +117 -0
  121. package/compliance/cache/3.1.0-rc.2/specialisms/governance-delivery-monitor/index.yaml +441 -0
  122. package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/denied.yaml +221 -0
  123. package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/index.yaml +330 -0
  124. package/compliance/cache/3.1.0-rc.2/specialisms/property-lists/index.yaml +482 -0
  125. package/compliance/cache/3.1.0-rc.2/specialisms/sales-broadcast-tv/index.yaml +738 -0
  126. package/compliance/cache/3.1.0-rc.2/specialisms/sales-catalog-driven/index.yaml +840 -0
  127. package/compliance/cache/3.1.0-rc.2/specialisms/sales-guaranteed/index.yaml +601 -0
  128. package/compliance/cache/3.1.0-rc.2/specialisms/sales-non-guaranteed/index.yaml +546 -0
  129. package/compliance/cache/3.1.0-rc.2/specialisms/sales-proposal-mode/index.yaml +586 -0
  130. package/compliance/cache/3.1.0-rc.2/specialisms/sales-social/index.yaml +919 -0
  131. package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/index.yaml +424 -0
  132. package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/scenarios/governance_denied.yaml +210 -0
  133. package/compliance/cache/3.1.0-rc.2/specialisms/signal-owned/index.yaml +317 -0
  134. package/compliance/cache/3.1.0-rc.2/specialisms/sponsored-intelligence/index.yaml +59 -0
  135. package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor-live.yaml +78 -0
  136. package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor.yaml +223 -0
  137. package/compliance/cache/3.1.0-rc.2/test-kits/billing-gate-runner.yaml +115 -0
  138. package/compliance/cache/3.1.0-rc.2/test-kits/bistro-oranje.yaml +126 -0
  139. package/compliance/cache/3.1.0-rc.2/test-kits/distributed-brand-runner.yaml +281 -0
  140. package/compliance/cache/3.1.0-rc.2/test-kits/nova-motors.yaml +262 -0
  141. package/compliance/cache/3.1.0-rc.2/test-kits/osei-natural.yaml +126 -0
  142. package/compliance/cache/3.1.0-rc.2/test-kits/parallel-dispatch-runner.yaml +196 -0
  143. package/compliance/cache/3.1.0-rc.2/test-kits/rate-limit-trip-runner.yaml +172 -0
  144. package/compliance/cache/3.1.0-rc.2/test-kits/signed-requests-runner.yaml +155 -0
  145. package/compliance/cache/3.1.0-rc.2/test-kits/single-side-trust-runner.yaml +294 -0
  146. package/compliance/cache/3.1.0-rc.2/test-kits/substitution-observer-runner.yaml +688 -0
  147. package/compliance/cache/3.1.0-rc.2/test-kits/summit-foods.yaml +125 -0
  148. package/compliance/cache/3.1.0-rc.2/test-kits/webhook-receiver-runner.yaml +265 -0
  149. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/001-minimal-plan.json +43 -0
  150. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/002-full-plan.json +217 -0
  151. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
  152. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
  153. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
  154. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
  155. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
  156. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
  157. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
  158. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
  159. package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
  160. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/README.md +220 -0
  161. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/canonicalization.json +241 -0
  162. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/keys.json +60 -0
  163. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
  164. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
  165. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
  166. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
  167. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
  168. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
  169. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
  170. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
  171. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
  172. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
  173. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
  174. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
  175. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
  176. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
  177. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
  178. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
  179. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
  180. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
  181. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
  182. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
  183. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
  184. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
  185. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
  186. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
  187. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
  188. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
  189. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
  190. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +26 -0
  191. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/001-basic-post.json +30 -0
  192. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
  193. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/003-es256-post.json +30 -0
  194. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
  195. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
  196. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
  197. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
  198. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
  199. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
  200. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
  201. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
  202. package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
  203. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/README.md +211 -0
  204. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/keys.json +61 -0
  205. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
  206. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
  207. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
  208. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
  209. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
  210. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
  211. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
  212. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
  213. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
  214. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
  215. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
  216. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
  217. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
  218. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
  219. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
  220. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
  221. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
  222. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
  223. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
  224. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
  225. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
  226. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
  227. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
  228. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
  229. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
  230. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
  231. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
  232. package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
  233. package/compliance/cache/3.1.0-rc.2/universal/billing-gate-dispatch.yaml +450 -0
  234. package/compliance/cache/3.1.0-rc.2/universal/canonical-format-validate-input.yaml +640 -0
  235. package/compliance/cache/3.1.0-rc.2/universal/capability-discovery.yaml +125 -0
  236. package/compliance/cache/3.1.0-rc.2/universal/collection-lists-pagination-integrity.yaml +306 -0
  237. package/compliance/cache/3.1.0-rc.2/universal/comply-controller-mode-gate.yaml +141 -0
  238. package/compliance/cache/3.1.0-rc.2/universal/content-standards-pagination-integrity.yaml +326 -0
  239. package/compliance/cache/3.1.0-rc.2/universal/deterministic-testing.yaml +1430 -0
  240. package/compliance/cache/3.1.0-rc.2/universal/error-compliance-signals.yaml +377 -0
  241. package/compliance/cache/3.1.0-rc.2/universal/error-compliance.yaml +528 -0
  242. package/compliance/cache/3.1.0-rc.2/universal/fictional-entities.yaml +307 -0
  243. package/compliance/cache/3.1.0-rc.2/universal/get-media-buys-pagination-integrity.yaml +160 -0
  244. package/compliance/cache/3.1.0-rc.2/universal/get-signals-pagination-integrity.yaml +210 -0
  245. package/compliance/cache/3.1.0-rc.2/universal/idempotency.yaml +861 -0
  246. package/compliance/cache/3.1.0-rc.2/universal/notification-config-event-scope.yaml +119 -0
  247. package/compliance/cache/3.1.0-rc.2/universal/notification-config-lifecycle.yaml +337 -0
  248. package/compliance/cache/3.1.0-rc.2/universal/notification-config-rejections.yaml +107 -0
  249. package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-creative-formats.yaml +265 -0
  250. package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-list-accounts.yaml +245 -0
  251. package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity.yaml +263 -0
  252. package/compliance/cache/3.1.0-rc.2/universal/property-lists-pagination-integrity.yaml +307 -0
  253. package/compliance/cache/3.1.0-rc.2/universal/read-tool-idempotency.yaml +405 -0
  254. package/compliance/cache/3.1.0-rc.2/universal/runner-output-contract.yaml +1285 -0
  255. package/compliance/cache/3.1.0-rc.2/universal/schema-validation-signals.yaml +181 -0
  256. package/compliance/cache/3.1.0-rc.2/universal/schema-validation.yaml +548 -0
  257. package/compliance/cache/3.1.0-rc.2/universal/security.yaml +539 -0
  258. package/compliance/cache/3.1.0-rc.2/universal/signed-requests.yaml +217 -0
  259. package/compliance/cache/3.1.0-rc.2/universal/stale-response-advisory.yaml +295 -0
  260. package/compliance/cache/3.1.0-rc.2/universal/storyboard-schema.yaml +2194 -0
  261. package/compliance/cache/3.1.0-rc.2/universal/v3-envelope-integrity.yaml +117 -0
  262. package/compliance/cache/3.1.0-rc.2/universal/version-negotiation.yaml +130 -0
  263. package/compliance/cache/3.1.0-rc.2/universal/webhook-emission.yaml +411 -0
  264. package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-bulk-webhooks.yaml +82 -0
  265. package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-product-webhooks.yaml +83 -0
  266. package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-products.yaml +151 -0
  267. package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signal-webhooks.yaml +83 -0
  268. package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signals.yaml +149 -0
  269. package/dist/lib/index.d.ts +1 -1
  270. package/dist/lib/index.d.ts.map +1 -1
  271. package/dist/lib/index.js +9 -5
  272. package/dist/lib/index.js.map +1 -1
  273. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  274. package/dist/lib/testing/storyboard/default-invariants.js +30 -1
  275. package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
  276. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  277. package/dist/lib/testing/storyboard/runner.js +84 -21
  278. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  279. package/dist/lib/testing/storyboard/types.d.ts +21 -0
  280. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  281. package/dist/lib/testing/storyboard/types.js.map +1 -1
  282. package/dist/lib/testing/types.d.ts +9 -0
  283. package/dist/lib/testing/types.d.ts.map +1 -1
  284. package/dist/lib/types/schemas.generated.d.ts +6707 -12040
  285. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  286. package/dist/lib/types/schemas.generated.js +1 -1
  287. package/dist/lib/types/schemas.generated.js.map +1 -1
  288. package/dist/lib/utils/signal-id-builders.d.ts +19 -0
  289. package/dist/lib/utils/signal-id-builders.d.ts.map +1 -1
  290. package/dist/lib/utils/signal-id-builders.js +30 -0
  291. package/dist/lib/utils/signal-id-builders.js.map +1 -1
  292. package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -1
  293. package/dist/lib/utils/tool-request-schemas.js +3 -0
  294. package/dist/lib/utils/tool-request-schemas.js.map +1 -1
  295. package/dist/lib/v2/projection/constants.d.ts +28 -0
  296. package/dist/lib/v2/projection/constants.d.ts.map +1 -0
  297. package/dist/lib/v2/projection/constants.js +31 -0
  298. package/dist/lib/v2/projection/constants.js.map +1 -0
  299. package/dist/lib/v2/projection/registry.d.ts.map +1 -1
  300. package/dist/lib/v2/projection/registry.js +9 -4
  301. package/dist/lib/v2/projection/registry.js.map +1 -1
  302. package/dist/lib/version.d.ts +3 -3
  303. package/dist/lib/version.js +3 -3
  304. package/package.json +1 -1
  305. package/skills/SHAPE-GOTCHAS.md +5 -0
@@ -0,0 +1,1285 @@
1
+ # Runner Output Contract
2
+ #
3
+ # Defines the failure-result shape that any AdCP compliance runner MUST emit
4
+ # when it reports storyboard results to a user or coding agent. Applies to
5
+ # evaluate_agent_quality, `@adcp/client storyboard run`, and any other harness
6
+ # that executes the storyboards published under /compliance/{version}/.
7
+ #
8
+ # Rationale
9
+ # ---------
10
+ # A failing validation is only actionable if the implementor can see:
11
+ # 1. The exact request the runner sent.
12
+ # 2. The exact response the agent returned.
13
+ # 3. Which field failed (as an RFC 6901 JSON Pointer).
14
+ # 4. What the runner expected vs. what it observed.
15
+ # 5. The identity of the schema applied (so the implementor can re-validate
16
+ # locally against the same artifact).
17
+ #
18
+ # Without these, a buyer building an agent cannot diagnose failures even when
19
+ # their own local validation passes — a mismatch between the schema they tested
20
+ # against and the schema the runner used is indistinguishable from a genuine
21
+ # agent bug.
22
+ #
23
+ # Storyboard AUTHORING is covered in storyboard-schema.yaml. This contract
24
+ # covers runner OUTPUT.
25
+ #
26
+ # --- Schema definition ---
27
+
28
+ id: runner_output_contract
29
+ version: "2.4.0"
30
+ title: "Runner output contract"
31
+ summary: "Required failure-detail shape that AdCP storyboard runners MUST emit so implementors can self-diagnose validation failures."
32
+
33
+ # Single source of truth for the storyboard-authored check enum.
34
+ # Storyboards MUST only declare step.validations[].check values from this
35
+ # list. Synthesized codes (capture_path_not_resolvable,
36
+ # unresolved_substitution) are emitted by the runner — not authored — and
37
+ # MUST NOT appear here. The build-time lint
38
+ # `scripts/lint-storyboard-check-enum.cjs` reads this field and rejects any
39
+ # storyboard that declares an unknown check kind, complementing the runtime
40
+ # forward-compat default (which exists for cross-version skew between
41
+ # storyboard and runner, not for catching typos at publish time).
42
+ authored_check_kinds:
43
+ - response_schema
44
+ - field_present
45
+ - field_absent
46
+ - envelope_field_present
47
+ - envelope_field_absent
48
+ - field_value
49
+ - field_value_or_absent
50
+ - status_code
51
+ - http_status
52
+ - http_status_in
53
+ - error_code
54
+ - on_401_require_header
55
+ - resource_equals_agent_url
56
+ - any_of
57
+ - refs_resolve
58
+ - a2a_submitted_artifact
59
+ - a2a_context_continuity
60
+ - field_less_than
61
+ - field_equals_context
62
+ - upstream_traffic
63
+ - canonical_format_satisfaction
64
+
65
+ # Cross-response check kinds — applied across the response set of a
66
+ # step that dispatches multiple requests under a runner contract that
67
+ # produces a structured multi-response observation, today either
68
+ # `parallel_dispatch_runner` (N parallel dispatches with the same
69
+ # idempotency_key) or `rate_limit_trip_runner` (sequential burst +
70
+ # replay). These kinds are NOT applicable to single-dispatch steps: a
71
+ # runner that applies them per-response produces nonsense (a single
72
+ # response trivially has cardinality 1 on any field). Runners MUST gate
73
+ # dispatch of these checks on the step declaring the appropriate
74
+ # `requires_contract:` and its accompanying parameter block
75
+ # (`parallel_dispatch:` or `rate_limit_trip:`); otherwise grade the
76
+ # validation `not_applicable` per the forward-compat clause.
77
+ #
78
+ # The `lint-storyboard-check-enum.cjs` lint reads BOTH this list and
79
+ # `authored_check_kinds` as the canonical published-time enum, so
80
+ # storyboards declaring either kind pass the typo gate.
81
+ cross_response_check_kinds:
82
+ - cross_response_field_equal
83
+ - cross_response_count_distinct
84
+ - replay_not_cached_rate_limit
85
+
86
+ # Conforming implementation: adcp-client PR #611
87
+ # (src/lib/testing/storyboard/types.ts — RunnerRequestRecord,
88
+ # RunnerResponseRecord, ValidationResult, RunnerSkipResult, etc.).
89
+ # The concrete shapes, redaction pattern, and header allowlist below are
90
+ # taken from that implementation.
91
+
92
+ # A storyboard step result is produced per step the runner executes. Each
93
+ # step result carries zero or more validation results — one per `check` in
94
+ # the storyboard's step.validations array, plus any transport-level check
95
+ # the runner performs (e.g., extraction path).
96
+
97
+ step_result:
98
+ description: |
99
+ Runners MUST emit one step result per executed step. Skipped steps MUST
100
+ include a skip result block. Failed steps MUST include at least one
101
+ validation result with passed: false. Not-selected steps are not step
102
+ results; they are reported in run_summary.not_selected with
103
+ selection_result records.
104
+ required_fields:
105
+ - storyboard_id # e.g. "capability_discovery"
106
+ - phase_id # e.g. "protocol_discovery"
107
+ - step_id # e.g. "get_capabilities"
108
+ - task # AdCP task name invoked, e.g. "get_adcp_capabilities"
109
+ - passed # boolean — all required validations passed
110
+ - duration_ms # wall-clock time for this step
111
+ - validations # array of validation_result objects (see below)
112
+ - extraction # transport extraction record (see below)
113
+ optional_fields:
114
+ - skip # skip_result block when the step was not run
115
+ # after being selected for this run
116
+ - error # transport-level error (no validations attempted)
117
+ - request # exact request the runner sent (see request block)
118
+ - response # exact response observed (see response block)
119
+ - notices # array of notice objects attached to this step's
120
+ # result — informational signals that MUST NOT
121
+ # change `passed`. See the notice block below for
122
+ # the field shape and the canonical first-day codes.
123
+
124
+ validation_result:
125
+ description: |
126
+ Every validation result — whether passed or failed — MUST carry the fields
127
+ below. Failed validations MUST include request, response, json_pointer,
128
+ expected, and actual unless the failure is transport-level (in which case
129
+ json_pointer, expected, and actual MAY be null and the step-level error
130
+ field carries the transport failure).
131
+
132
+ Forward compatibility: when a runner encounters an authored `check` value
133
+ it does not recognize (e.g., a storyboard declares a check type added in a
134
+ later spec minor version than the runner implements), the runner MUST emit
135
+ a validation_result with passed: true, check: <the unrecognized value>,
136
+ description: copied from the storyboard, and a `note` field describing the
137
+ coverage gap (e.g., "runner does not implement check type
138
+ 'upstream_traffic' — graded as not_applicable to preserve forward
139
+ compatibility"). The result MUST contribute to a per-step `not_applicable`
140
+ counter the runner exposes alongside steps_passed/failed/skipped/not_selected, so
141
+ consumers can distinguish "runner is older than the storyboard" from
142
+ "storyboard validations passed cleanly." Runners MUST NOT fail steps
143
+ on unrecognized check values — additive check-type extensions are
144
+ explicitly part of the spec evolution model.
145
+ required_fields:
146
+ - check # Validation kind. For storyboard-authored checks,
147
+ # mirrors the storyboard's step.validations[].check:
148
+ # response_schema | field_present |
149
+ # field_absent | envelope_field_present |
150
+ # envelope_field_absent | field_value |
151
+ # field_value_or_absent | status_code | http_status |
152
+ # http_status_in | error_code | on_401_require_header |
153
+ # resource_equals_agent_url | any_of | refs_resolve |
154
+ # a2a_submitted_artifact | field_less_than |
155
+ # field_equals_context | upstream_traffic |
156
+ # canonical_format_satisfaction |
157
+ # cross_response_field_equal |
158
+ # cross_response_count_distinct (the last two are
159
+ # cross-response checks; see cross_response_check_kinds
160
+ # above and storyboard-schema.yaml > Cross-response
161
+ # assertions for semantics).
162
+ #
163
+ # For runner-synthesized grading (not authored in the
164
+ # storyboard validations array, generated by the runner
165
+ # after the authored checks complete):
166
+ # capture_path_not_resolvable | unresolved_substitution
167
+ #
168
+ # See storyboard-schema.yaml > "Runner grading codes"
169
+ # for the semantics of each synthesized code, and
170
+ # storyboard-schema.yaml > "upstream_traffic" for the
171
+ # authored upstream-side-effect check.
172
+ - passed # boolean
173
+ - description # human-readable description copied from the
174
+ # storyboard validation entry (so the implementor
175
+ # sees the same text the author wrote).
176
+ # For synthesized checks, the runner MUST generate
177
+ # a descriptive string naming the affected path or
178
+ # substitution token.
179
+ required_on_failure:
180
+ - request # exact request the runner sent (see request block).
181
+ # NULL for unresolved_substitution — the request was
182
+ # never sent (pre-wire failure).
183
+ # For upstream_traffic: the comply_test_controller
184
+ # query_upstream_traffic request the runner issued,
185
+ # not the storyboard step's AdCP request.
186
+ - response # exact response observed (see response block).
187
+ # NULL for unresolved_substitution — no response
188
+ # exists (pre-wire failure).
189
+ # For upstream_traffic: the query_upstream_traffic
190
+ # response carrying the recorded_calls array.
191
+ - json_pointer # RFC 6901 pointer to the failing field in the
192
+ # response, or the request for input-level
193
+ # failures. Null when the failure is transport-level
194
+ # and no payload was returned. Also null for
195
+ # unresolved_substitution (pre-wire; no response
196
+ # path implicated) — see notes.synthesized_checks.
197
+ # For upstream_traffic, points into the recorded_calls
198
+ # array (e.g., "/recorded_calls/0/payload") when a
199
+ # specific call's payload failed payload_must_contain;
200
+ # null when the failure is a count mismatch
201
+ # (no specific call implicated).
202
+ - expected # machine-readable expected value:
203
+ # response_schema → schema $id that was applied
204
+ # field_value → expected value (any JSON type)
205
+ # field_value_or_absent → value or allowed_values array
206
+ # from the storyboard validation
207
+ # field_present → the path that should resolve
208
+ # field_absent → null (the field must not be present)
209
+ # envelope_field_present → the path that should resolve
210
+ # in the protocol envelope
211
+ # envelope_field_absent → null (the envelope field must
212
+ # not be present)
213
+ # status_code → expected status
214
+ # error_code → expected error code
215
+ # any_of → array of acceptable forms
216
+ # field_less_than → comparand the field MUST be
217
+ # strictly less than. When the
218
+ # comparand was resolved from
219
+ # `context_key`, the runtime
220
+ # value (a finite number) is
221
+ # captured here; when from a
222
+ # literal `value`, that literal.
223
+ # field_equals_context → comparand the field MUST
224
+ # deep-equal. The runtime value
225
+ # resolved from
226
+ # `validation.context_key` in the
227
+ # storyboard accumulator.
228
+ # capture_path_not_resolvable → the context_outputs path
229
+ # string that failed to resolve
230
+ # (e.g. "signals[0].signal_agent_segment_id")
231
+ # unresolved_substitution → the unresolved token string
232
+ # (e.g. "$context.first_signal_agent_segment_id"
233
+ # or "{{prior_step.search.id}}")
234
+ # upstream_traffic → object with the declared
235
+ # assertion: { min_count,
236
+ # endpoint_pattern, payload_must_contain,
237
+ # identifier_paths, purpose_filter,
238
+ # since, attestation_mode_required } —
239
+ # whichever fields the storyboard set.
240
+ # canonical_format_satisfaction
241
+ # → object { accepted, local_satisfied }
242
+ # where accepted is the boolean value
243
+ # from the storyboard validation and
244
+ # local_satisfied mirrors the expected
245
+ # local package/product satisfaction
246
+ # verdict.
247
+ # cross_response_field_equal
248
+ # → object { path } — the JSON path
249
+ # asserted equal across every
250
+ # resolved response in the step's
251
+ # dispatch set.
252
+ # cross_response_count_distinct
253
+ # → object { path, allowed_values } —
254
+ # the path scanned, plus the
255
+ # permitted cardinalities of
256
+ # distinct values observed at
257
+ # that path across the resolved
258
+ # response set (typically [1]
259
+ # for rule-9 tests).
260
+ - actual # machine-readable actual value observed:
261
+ # response_schema → array of schema errors
262
+ # (each { instance_path,
263
+ # schema_path, keyword,
264
+ # message })
265
+ # field_value → actual value (any JSON type)
266
+ # field_value_or_absent → actual value (any JSON type);
267
+ # null when the field was absent
268
+ # field_present → null (the field was missing)
269
+ # or the observed non-object
270
+ # value
271
+ # field_absent → observed value at path (any JSON
272
+ # type); emitted only on failure
273
+ # envelope_field_present → null (the field was missing)
274
+ # or the observed non-object
275
+ # value (scoped to envelope)
276
+ # envelope_field_absent → observed value at path (any JSON
277
+ # type); emitted only on failure
278
+ # and scoped to envelope
279
+ # field_less_than → the observed value at `path`
280
+ # (number when resolvable, null
281
+ # when the field was missing).
282
+ # field_equals_context → the observed value at `path`
283
+ # (any JSON type, null when the
284
+ # field was missing).
285
+ # capture_path_not_resolvable → the value that was
286
+ # resolved at the path, or null
287
+ # when the path did not exist.
288
+ # Runners MUST treat null, "",
289
+ # and structurally-absent paths
290
+ # as equally non-resolvable for
291
+ # this check — capture of a null
292
+ # or empty-string value produces
293
+ # fabricated state and is as
294
+ # incorrect as a missing path.
295
+ # unresolved_substitution → null (no response payload
296
+ # available at substitution time)
297
+ # upstream_traffic → object summarizing what was
298
+ # observed: { matched_count,
299
+ # total_calls, missing_payload_paths,
300
+ # missing_identifier_values }.
301
+ # The full recorded_calls array
302
+ # lives in `response.payload`;
303
+ # canonical_format_satisfaction
304
+ # → object { accepted, local_satisfied,
305
+ # rejection? } where accepted is the
306
+ # observed task success boolean,
307
+ # local_satisfied is the runner's
308
+ # package/product satisfaction verdict,
309
+ # and rejection summarizes format-related
310
+ # rejection evidence when the task failed.
311
+ # cross_response_field_equal
312
+ # → object { observed_values: [...] } —
313
+ # the values observed at `path` on
314
+ # each resolved response, in dispatch
315
+ # order. Empty when no response
316
+ # carried the path.
317
+ # cross_response_count_distinct
318
+ # → object { observed_cardinality,
319
+ # observed_values: [...] } — the
320
+ # number of distinct values seen at
321
+ # `path` across the resolved response
322
+ # set, plus the values themselves.
323
+ # `actual` is the diagnostic summary.
324
+ - schema_id # $id of the response schema applied. Required
325
+ # when check == response_schema, null otherwise.
326
+ # MUST be null for capture_path_not_resolvable,
327
+ # unresolved_substitution, upstream_traffic, and
328
+ # canonical_format_satisfaction.
329
+ - schema_url # Resolvable URL the implementor can fetch to
330
+ # validate locally. Required when
331
+ # check == response_schema, null otherwise.
332
+ # MUST be null for capture_path_not_resolvable,
333
+ # unresolved_substitution, upstream_traffic, and
334
+ # canonical_format_satisfaction.
335
+ notes:
336
+ synthesized_checks: |
337
+ capture_path_not_resolvable and unresolved_substitution are emitted by
338
+ the runner after storyboard-authored checks complete. They MUST appear in
339
+ the step's validations array so the "failed steps MUST include at least
340
+ one validation result with passed: false" invariant is satisfied.
341
+ For capture_path_not_resolvable, json_pointer MUST be the RFC 6901 form
342
+ of the context_outputs path that failed to resolve (e.g. "/signals/0/
343
+ signal_agent_segment_id"). For unresolved_substitution, json_pointer MUST
344
+ be null (the substitution is pre-wire and no response path is implicated).
345
+ cross_step_comparison_checks: |
346
+ field_less_than and field_equals_context are authored checks that compare
347
+ a field on this step's response against a value from the storyboard
348
+ accumulator (populated by prior steps' `context_outputs`). Three
349
+ consumer-facing rendering rules runners MUST follow:
350
+
351
+ 1. `expected` carries the RESOLVED RUNTIME comparand, not the storyboard's
352
+ `context_key` string. A consumer diffing `validation_result.expected`
353
+ across two storyboard runs will see different values when the prior
354
+ step's response differed — that's load-bearing for diagnosing
355
+ filtered-vs-baseline regressions. The `context_key` field on the
356
+ storyboard validation is authoring-time metadata; it is NOT echoed
357
+ into validation_result.
358
+
359
+ 2. `context_key_absent` observation: when the storyboard sets
360
+ `context_key` and the named entry is missing from the accumulator
361
+ (the prior capturing step was legitimately skipped on a branch-set
362
+ path), the validation_result MUST carry `passed: true` with an
363
+ `observations: [<descriptive string>]` entry naming the absent key.
364
+ `expected` and `actual` MAY be omitted in this path. A genuinely
365
+ missing capture (prior step ran but its capture path didn't resolve)
366
+ is NOT this case — that grades `capture_path_not_resolvable` ON THE
367
+ PRIOR STEP per the synthesized_checks rule.
368
+
369
+ 3. Step-ordering dependency: cross-step comparison checks read from the
370
+ accumulator built up over prior step executions. Runners that
371
+ parallelize step execution MUST honour the storyboard's declared
372
+ ordering for any step that names a `context_key` referencing an
373
+ earlier step's `context_outputs`.
374
+ upstream_traffic_check: |
375
+ upstream_traffic is an authored check (declared in the storyboard's
376
+ step.validations array) that asserts side-effects against a sandbox the
377
+ adopter exposes through the comply_test_controller tool's
378
+ query_upstream_traffic scenario. The runner queries the controller after
379
+ the step completes, scoped to traffic recorded since the step's request
380
+ timestamp, and applies the assertion. Adopters who do not advertise
381
+ query_upstream_traffic in list_scenarios grade the check
382
+ not_applicable (skip_result.reason: missing_test_controller with detail
383
+ naming the scenario) — the contract is opt-in by adopter capability.
384
+ See storyboard-schema.yaml > "upstream_traffic" for the authored shape
385
+ and comply-test-controller-request.json > query_upstream_traffic for
386
+ the controller-side query contract.
387
+ upstream_traffic_timestamp_boundary: |
388
+ The runner's lower-bound timestamp for query_upstream_traffic MUST be
389
+ the runner's own wall-clock at the moment it issued the storyboard
390
+ step's AdCP request (or the prior step's request timestamp when the
391
+ storyboard declares `since: <prior_step_id>`). The bound is INCLUSIVE.
392
+ Runners SHOULD subtract a clock-skew tolerance (50ms minimum, 250ms
393
+ recommended) before sending the bound to the controller, so a recorded
394
+ call timestamped microseconds before the runner's clock measurement is
395
+ not silently excluded. Controllers MUST emit recorded_calls timestamps
396
+ matching the wall clock at outbound-request-send time (not log-flush
397
+ time) and MUST order them monotonically non-decreasing. Runners MUST
398
+ attribute calls to a step using their own clock-bracket of when they
399
+ issued and received the AdCP request, not the controller's
400
+ since_timestamp echo (which is informational only — see
401
+ comply-test-controller-response.json > UpstreamTrafficSuccess >
402
+ since_timestamp).
403
+ upstream_traffic_threat_model: |
404
+ upstream_traffic raises the bar against UNINTENTIONAL façades —
405
+ adapters that satisfy AdCP schema requirements with synthetic
406
+ placeholders without forwarding payloads upstream. It is NOT an
407
+ adversarial integrity check. Adopters self-report their own traffic
408
+ through query_upstream_traffic; a determined façade can fabricate
409
+ recorded_calls entries. Spec consumers — compliance dashboards,
410
+ adapter directories, conformance-tier UIs — MUST NOT present
411
+ upstream_traffic passing as cryptographic proof of adapter behavior.
412
+ The conformance value is "unintentional façades fail this check"; an
413
+ adversarial-integrity attestation path (signed traffic-summary
414
+ endpoint, agent-side telemetry digest, etc.) is its own future RFC,
415
+ not this contract.
416
+ upstream_traffic_digest_mode: |
417
+ Recorded calls returned in `attestation_mode: digest` (see
418
+ comply-test-controller-response.json > UpstreamTrafficSuccess >
419
+ recorded_calls > DigestAttestation) swap raw payload introspection
420
+ for digest-based echo verification:
421
+ - `recorded_calls[].payload_length` MUST be the byte length of the
422
+ exact payload bytes covered by `payload_digest_sha256`: RFC 8785
423
+ (JCS) canonical bytes for JSON-shaped content after redaction, or
424
+ post-redaction raw body bytes for non-JSON content. It is not the
425
+ original outbound body length before JSON parsing, redaction, or
426
+ canonicalization.
427
+ - The runner verifies `identifier_paths` by computing SHA-256 of each
428
+ resolved identifier value, sending the digests in the controller
429
+ query's `params.identifier_value_digests`, and reading the
430
+ per-digest `found: true | false` proof from
431
+ `recorded_calls[].identifier_match_proofs[]`. Plaintext
432
+ identifiers never reach the controller in this path.
433
+ - `payload_must_contain` arbitrary path assertions are NOT
434
+ supported in digest mode — the runner emits a per-affected-entry
435
+ validation_result with `passed: true`, `check: payload_must_contain`,
436
+ and a `note` field explaining the mode constraint, contributing
437
+ to `validations_not_applicable` on run_summary (NOT
438
+ steps_failed). The same validation continues to grade against
439
+ recorded_calls returned in raw mode, so a mixed-mode response
440
+ (some calls raw, some digest) produces partial coverage rather
441
+ than blanket not_applicable.
442
+ - If the controller cannot produce a digest-mode upstream_traffic
443
+ response because the parsed JSON-like value tree contains a
444
+ non-finite numeric value (`NaN`, `+Infinity`, or `-Infinity`),
445
+ it MUST NOT coerce that value to `null`, a string, or any other
446
+ placeholder for digest computation; it returns ControllerError
447
+ with error code `JCS_NON_FINITE_NUMBER`. The runner emits the affected
448
+ upstream_traffic validation_result with `passed: true` and a
449
+ `note` citing the RFC 8785/JCS non-finite-number constraint,
450
+ contributing to `validations_not_applicable` on run_summary
451
+ (NOT steps_failed).
452
+ - `min_count` and `endpoint_pattern` are unchanged — count and URL
453
+ matching work identically in both modes.
454
+ Storyboards that strictly require raw introspection set
455
+ `attestation_mode_required: "raw"` on the storyboard upstream_traffic
456
+ check; runners then grade calls returned in digest mode as
457
+ not_applicable for the entire check (not just per-assertion). Use
458
+ sparingly — see storyboard-schema.yaml > "upstream_traffic" >
459
+ `attestation_mode_required` for the rationale.
460
+ response_schema_validator_semantics: |
461
+ Runners MUST apply the referenced JSON schema using a JSON Schema
462
+ draft-07 compliant validator configured to honour the schema's own
463
+ `additionalProperties` declaration without global override. When a
464
+ schema or any sub-schema reached via `$ref`, `allOf`, `oneOf`, or
465
+ `anyOf` declares `"additionalProperties": true` (explicitly or by
466
+ omission — draft-07 default is `true`), the runner MUST NOT fail a
467
+ response that includes fields beyond those enumerated in `properties`.
468
+ In draft-07, `oneOf` branch-selection does not grant a validator
469
+ licence to apply stricter `additionalProperties` constraints than
470
+ those declared on the selected branch.
471
+
472
+ Configuring the validator in a way that contradicts the schema's own
473
+ `additionalProperties` declaration is a conformance violation of this
474
+ contract (e.g., AJV `removeAdditional: 'all'` or a schema-level
475
+ `additionalProperties: false` override; Zod `.strict()` on a derived
476
+ schema object). A seller returning a spec-valid response with optional
477
+ or newly-added fields (such as `authorization` or `sandbox` on
478
+ sync-accounts items) is conformant. A runner that fails such a
479
+ response because its internal schema representation is stricter than
480
+ the canonical JSON Schema produces a false negative that blocks
481
+ legitimate conformance progress.
482
+
483
+ The AdCP spec-side lint (`scripts/lint-storyboard-response-schema.cjs`,
484
+ AJV `strict: false`, no `removeAdditional`) sets the precedent. This
485
+ clause makes the same requirement normative for all conforming runners.
486
+ Any runner correctly implementing draft-07 JSON Schema validation
487
+ already satisfies it.
488
+ optional_fields:
489
+ - remediation # runner-suggested fix when the failure maps to
490
+ # a well-known cause (e.g., "agent did not echo
491
+ # context.correlation_id — see
492
+ # docs/building/implementation/task-lifecycle")
493
+ - severity # "required" | "advisory" — copied from the
494
+ # storyboard validation entry's severity field
495
+ # (default: "required"). When "advisory", a
496
+ # passed: false validation_result MUST NOT
497
+ # cause its step to grade as failed; the step
498
+ # grades on its remaining required validations.
499
+ # Advisory failures contribute to
500
+ # validations_advisory_failed on run_summary
501
+ # and MUST NOT contribute to steps_failed,
502
+ # validations_failed, or any other
503
+ # required-failure counter — the two counter
504
+ # surfaces are deliberately separate so a
505
+ # consumer aggregating "passed: false" across
506
+ # validations_failed never double-counts
507
+ # advisory results.
508
+ #
509
+ # Rendered-output rule: when a runner emits
510
+ # advisory results to a human-facing surface
511
+ # (chat transcripts, markdown reports,
512
+ # compliance dashboards, LLM summaries),
513
+ # advisory entries MUST be visually
514
+ # distinguished from required failures —
515
+ # prefix with the literal `[ADVISORY]`,
516
+ # render in a muted style, or section them
517
+ # under a separate "advisory findings"
518
+ # header. The machine-readable step_result
519
+ # carries severity verbatim for programmatic
520
+ # consumers; this rule applies only to
521
+ # rendered surfaces. Without this, a façade
522
+ # that declares its anti-façade validations
523
+ # as advisory produces a stream of
524
+ # `passed: false` entries indistinguishable
525
+ # from required failures, eroding the
526
+ # conformance signal.
527
+ #
528
+ # See storyboard-schema.yaml > "Validation"
529
+ # for the author-side semantics and use case
530
+ # (rollout gating during runner adoption
531
+ # windows).
532
+ - severity_promoted_from_advisory
533
+ # boolean | absent. Tri-state contract:
534
+ # true — storyboard declared
535
+ # expires_after_version AND
536
+ # runner_capability_version >=
537
+ # that value, so the runner
538
+ # promoted severity to "required"
539
+ # at execution time. `severity`
540
+ # MUST also be "required" (the
541
+ # promoted value).
542
+ # false — storyboard declared
543
+ # expires_after_version but
544
+ # runner_capability_version is
545
+ # older, so promotion did not fire.
546
+ # `severity` is the storyboard's
547
+ # declared advisory.
548
+ # absent — storyboard did not declare
549
+ # expires_after_version (severity
550
+ # applied verbatim) OR the check
551
+ # grades not_applicable due to
552
+ # forward-compat (no grading
553
+ # occurred, so no promotion was
554
+ # evaluated; per
555
+ # storyboard-schema.yaml >
556
+ # expires_after_version
557
+ # forward-compat ordering rule).
558
+ # The tri-state is required so consumers can
559
+ # distinguish "promoted" from "not promoted
560
+ # because runner is too old" from "not
561
+ # applicable" without re-reading the
562
+ # storyboard. Reports SHOULD render the
563
+ # promotion provenance on the true case —
564
+ # e.g., "[REQUIRED — was advisory through
565
+ # capability v{expires_after_version};
566
+ # promoted at v{runner_capability_version}]".
567
+
568
+ request:
569
+ description: |
570
+ Exact request the runner sent, per transport. Runners MUST redact secrets
571
+ before emission — see the `security` block below.
572
+ required_fields:
573
+ - transport # "mcp" | "a2a" | "http"
574
+ - operation # task/tool/skill name actually invoked (matches
575
+ # step.task after any test-kit interpolation)
576
+ - payload # fully-resolved JSON payload after test-kit
577
+ # substitution and context injection, with
578
+ # secret-bearing fields replaced per the
579
+ # redaction policy in the security block.
580
+ optional_fields:
581
+ - headers # Runners SHOULD NOT populate this field by
582
+ # default — see security.request_headers. The
583
+ # field exists for future auth-override captures
584
+ # that carry a fully-redacted form.
585
+ - url # full URL for http/a2a; omit for stdio MCP
586
+
587
+ response:
588
+ description: |
589
+ Exact response observed from the agent, per transport.
590
+ required_fields:
591
+ - transport # "mcp" | "a2a" | "http"
592
+ - payload # MCP: { isError, structuredContent, content }
593
+ # A2A: the Task object — record task.status.state
594
+ # alongside payload. Extract from
595
+ # task.artifacts[0].parts[] DataPart for final
596
+ # states and task.status.message.parts[] for
597
+ # interim states (per
598
+ # docs/building/implementation/a2a-response-extraction.mdx).
599
+ # http: parsed body
600
+ optional_fields:
601
+ - status # HTTP status where applicable
602
+ - headers # observed response headers, filtered through
603
+ # the allowlist in security.response_headers
604
+ - duration_ms # wall-clock time for this request
605
+
606
+ extraction:
607
+ description: |
608
+ Runners MUST follow the MCP response-extraction algorithm at
609
+ docs/building/implementation/mcp-response-extraction.mdx and the A2A
610
+ equivalent. When both structuredContent and content[].text are present,
611
+ structuredContent wins. Recording the path that was actually used lets
612
+ the implementor distinguish a runner extraction bug from an agent bug.
613
+ required_fields:
614
+ - path # "structured_content" | "text_fallback" |
615
+ # "error" | "none"
616
+ optional_fields:
617
+ - note # e.g. "structuredContent contained only
618
+ # adcp_error — treated as error"
619
+
620
+ security:
621
+ description: |
622
+ Runner output is consumed in compliance reports, chat transcripts, and
623
+ shared dashboards where credentials or breadcrumbs a hostile agent plants
624
+ in a response must not surface. A runner claiming contract conformance
625
+ without the rules below could leak tokens through a compliant-looking
626
+ report — defeating the contract's purpose. These rules are normative.
627
+
628
+ payload_redaction:
629
+ description: |
630
+ Runners MUST recursively redact key-value pairs from request.payload
631
+ and response.payload before emitting the step result. Values at keys
632
+ matching the pattern below are replaced with the literal string
633
+ "[redacted]". Matching is case-insensitive and applies at any depth.
634
+ pattern: |
635
+ ^(authorization|credentials?|token|api[_-]?key|password|secret|
636
+ client[_-]secret|refresh[_-]token|access[_-]token|bearer|
637
+ session[_-]token|offering[_-]token|cookie|set[_-]cookie)$
638
+ notes: |
639
+ The pattern above is the MINIMUM floor taken from the adcp-client#611
640
+ conforming implementation. Runners MAY extend it for operator-
641
+ specific key names (e.g., internal vendor headers) but MUST NOT
642
+ narrow it. Redaction happens after the payload is serialized for
643
+ the report, not at transport time — the wire request carries real
644
+ credentials; the emitted record does not.
645
+
646
+ response_headers:
647
+ description: |
648
+ Response headers MUST pass through an allowlist before emission. Any
649
+ header not in the allowlist MUST be dropped (not redacted — absent).
650
+ Dropping rather than redacting avoids publishing the set of header
651
+ names a hostile agent added, which itself can be a breadcrumb.
652
+ allowlist:
653
+ - content-type
654
+ - content-length
655
+ - content-encoding
656
+ - www-authenticate
657
+ - location
658
+ - retry-after
659
+ - x-request-id
660
+ - x-correlation-id
661
+ notes: |
662
+ www-authenticate is retained because it's load-bearing for auth-probe
663
+ validations (on_401_require_header). Matching is case-insensitive.
664
+
665
+ request_headers:
666
+ description: |
667
+ Runners SHOULD NOT populate request.headers. A runner that builds
668
+ `Authorization: Bearer <token>` headers in-flight would leak the token
669
+ by echoing the observed request into a shared report. When a runner
670
+ does populate request.headers (e.g., for auth-override probes that
671
+ intentionally send bogus credentials), values at keys matching the
672
+ payload_redaction pattern MUST be replaced with "[redacted]" and all
673
+ other headers MUST pass through the response_headers allowlist.
674
+
675
+ rendered_output_fencing:
676
+ description: |
677
+ Several validation_result and skip_result fields carry strings whose
678
+ origin is not the runner: the agent under test, the storyboard author,
679
+ or an adopter-supplied test controller. When a runner renders these
680
+ into a shared surface (chat transcript, markdown report, summary fed
681
+ to another LLM), the strings MUST be fenced with a nonce or otherwise
682
+ isolated so a hostile message cannot inject instructions into a
683
+ downstream summarizer. This applies to rendered output, not to the
684
+ machine-readable step_result — raw strings stay in the JSON for
685
+ programmatic consumers.
686
+
687
+ Load-bearing fields that MUST be fenced when rendered:
688
+ - validation_result.error (transport-level errors,
689
+ agent-controlled when the
690
+ error message is echoed)
691
+ - validation_result.actual (agent-controlled response
692
+ values, including string
693
+ forms)
694
+ - validation_result.description (storyboard-author-controlled
695
+ — copied verbatim from the
696
+ storyboard validation entry)
697
+ - validation_result.note (runner-generated but
698
+ interpolates the
699
+ storyboard's unrecognized
700
+ check value verbatim — see
701
+ forward-compat clause above)
702
+ - skip_result.detail (runner-generated but
703
+ interpolates storyboard
704
+ IDs and adopter-supplied
705
+ strings)
706
+ - response.payload (for upstream_traffic checks)
707
+ (carries recorded_calls[]
708
+ where url, payload, and
709
+ endpoint are all
710
+ agent-controlled — a
711
+ hostile adapter that hits
712
+ an attacker-controlled URL
713
+ plants the URL string in
714
+ the payload, and a
715
+ hostile adopter controller
716
+ returns whatever it wants)
717
+
718
+ Inversion rule: any field whose value is copied from storyboard input,
719
+ agent-under-test output, or an adopter-supplied test controller MUST be
720
+ fenced when rendered. Runner-generated identifiers (step_id, schema_id,
721
+ check enum values from the spec's known list) are exempt.
722
+
723
+ Advisory-severity differentiation: validation_result entries with
724
+ severity: advisory MUST render visually distinct from required-severity
725
+ results (literal `[ADVISORY]` prefix, muted style, or grouped under a
726
+ separate "advisory findings" section). This is orthogonal to fencing —
727
+ both rules apply to advisory results that carry agent- or
728
+ storyboard-controlled strings. See validation_result.severity above for
729
+ the rationale (façade-resistance: a façade declaring its anti-façade
730
+ validations as advisory must not blend visually into required failures).
731
+
732
+ Promotion-provenance rendering: when a renderer constructs human
733
+ copy describing severity_promoted_from_advisory: true (e.g., "was
734
+ advisory through capability v{expires_after_version}; promoted at
735
+ v{runner_capability_version}"), the storyboard-supplied
736
+ expires_after_version value MUST be fenced. The semver lint rejects
737
+ malformed values at publish time, but defense-in-depth treats the
738
+ string as untrusted-author input when interpolated into LLM-rendered
739
+ surfaces. permanent_advisory.reason is also storyboard-author-controlled
740
+ and MUST be fenced when rendered.
741
+
742
+ skip_result:
743
+ description: |
744
+ When a track, storyboard, phase, or step is skipped, runners MUST
745
+ distinguish between the reasons below so an implementor knows whether
746
+ the skip is informative (the agent did not claim the protocol) or
747
+ masking (the runner could not apply the storyboard even though the
748
+ agent claimed the protocol).
749
+
750
+ Selection is separate from skipping. If the caller asks for a narrower
751
+ suite or run mode (for example, "Sandbox only") and the runner excludes
752
+ live-only storyboards before execution, those items are `not_selected`,
753
+ not `skipped`. A `skip_result` is emitted only after an item was selected
754
+ for this run and the runner could not execute it because an applicability
755
+ gate, required tool, test controller, prerequisite, or harness contract
756
+ was unavailable.
757
+ required_fields:
758
+ - reason # not_applicable | no_phases |
759
+ # prerequisite_failed | missing_tool |
760
+ # missing_test_controller |
761
+ # unsatisfied_contract | peer_branch_taken |
762
+ # peer_substituted | requirement_unmet
763
+ - detail # human-readable explanation citing the
764
+ # declared supported_protocols / specialisms
765
+ # and, if relevant, the missing tool,
766
+ # prerequisite step id, or contract key.
767
+ reasons:
768
+ not_applicable: |
769
+ The item was selected for this run, but an applicability gate evaluated
770
+ false. Examples: the agent did not declare the protocol or specialism
771
+ this storyboard targets, or a scenario's requires_capability check found
772
+ an optional capability set to false. detail MUST cite the failed gate
773
+ and the agent's relevant declared supported_protocols, specialisms, or
774
+ capability value.
775
+
776
+ When the runner excludes an item before execution because it is outside
777
+ the caller's requested suite, run mode, AdCP version, or verification
778
+ profile, use selection_result instead. Do not report run-mode exclusions
779
+ as not_applicable skips.
780
+
781
+ Branch-set grading uses `peer_branch_taken` (see below), not this
782
+ reason — keeping the two distinct lets dashboards filter coverage
783
+ gaps (not_applicable) separately from runtime branch routing
784
+ (peer_branch_taken).
785
+ no_phases: |
786
+ The storyboard is a placeholder with no phases to run (e.g., a
787
+ protocol baseline that has not been populated yet). detail MUST cite
788
+ the storyboard id and version.
789
+ prerequisite_failed: |
790
+ A prior step this one depends on did not pass. detail MUST cite the
791
+ prerequisite step id.
792
+ missing_tool: |
793
+ The agent declared the protocol or specialism but does not expose a
794
+ required tool. detail MUST cite the tool name declared in the
795
+ storyboard's required_tools and the agent's advertised tool list.
796
+ missing_test_controller: |
797
+ The storyboard requires comply_test_controller and the agent did not
798
+ advertise it. Applies only to deterministic_testing phases.
799
+ unsatisfied_contract: |
800
+ A test-kit harness contract (e.g., signed-requests-runner) is not in
801
+ scope for this grading run. detail MUST cite the contract key. Per
802
+ the signed-requests-runner contract, unsatisfied contracts grade as
803
+ FAIL, not SKIP, for the storyboards that declare them — this reason
804
+ applies only where the contract explicitly permits SKIP.
805
+ peer_branch_taken: |
806
+ The step is part of an `any_of` branch set (see storyboard-schema.yaml
807
+ > "Branch sets") whose `branch_set.id` was already contributed by a
808
+ peer optional phase, making this non-chosen branch moot. detail MUST
809
+ follow the shape
810
+ "<branch_set.id> contributed by <peer_phase_id>.<peer_step_id> —
811
+ <this_phase_id> is moot" so downstream tooling can parse which peer
812
+ carried the contribution. Kept distinct from not_applicable: coverage
813
+ gaps (agent doesn't support a protocol) and runtime branch routing
814
+ (agent took the other path) are different signals and must not be
815
+ conflated in dashboards or summaries.
816
+ peer_substituted: |
817
+ The step would otherwise grade `missing_tool` or
818
+ `missing_test_controller`, but a same-phase peer step declared
819
+ `provides_state_for: <this_step_id>` (see storyboard-schema.yaml >
820
+ `provides_state_for`) and passed — the substitute established
821
+ equivalent state for downstream stateful steps, so the cascade is
822
+ waived. detail MUST follow the shape
823
+ "<this_step_id> state provided by <peer_phase_id>.<peer_step_id>"
824
+ so downstream tooling can parse which substitute carried the state.
825
+ Kept distinct from peer_branch_taken (branch-set routing for
826
+ mutually exclusive behaviors) and not_applicable (coverage gap):
827
+ this signal indicates the agent did declare the specialism but
828
+ offers an interchangeable tool that the storyboard accepts as an
829
+ equivalent state contract.
830
+ requirement_unmet: |
831
+ A storyboard-level load-time precondition was not satisfied. Two
832
+ storyboard-schema fields produce this reason, distinguished by the
833
+ `detail` sub-reason prefix so dashboards can aggregate independently:
834
+
835
+ requires: — runtime context gates
836
+ (see storyboard-schema.yaml > `requires`).
837
+ detail names the unmet requirement value
838
+ directly, e.g. "controller",
839
+ "seeded_state", or an unrecognized
840
+ forward-compat value. This legacy form
841
+ is BARE — no `requires:` prefix is
842
+ synthesized — and remains the canonical
843
+ wire shape for single-gate `requires:`
844
+ failures.
845
+
846
+ required_any_of_tools: — tool-family advertisement gates
847
+ (see storyboard-schema.yaml >
848
+ `required_any_of_tools`). detail
849
+ carries the canonical sub-reason prefix
850
+ "missing_required_tool_family:" followed
851
+ by " needs <tool_a> or <tool_b>[ or
852
+ <tool_c>...]" and, when a rationale was
853
+ declared, a trailing " (<rationale>)"
854
+ parenthetical. Canonical single-line
855
+ example:
856
+ `missing_required_tool_family: needs list_accounts or sync_accounts (AdCP 3.0.9 §accounts/overview)`
857
+
858
+ Family-list separator. When a family contains more than two tools,
859
+ runners MUST join names with the literal three-character " or "
860
+ separator (no Oxford comma; no list-style punctuation). Dashboards
861
+ that parse the family list MAY split on " or " safely. Tool names
862
+ are constrained by the spec's tool-name charset and do not contain
863
+ the literal " or " substring.
864
+
865
+ Wire-shape posture for aggregation. Runners SHOULD emit a single
866
+ sub-reason in `detail` even when multiple gates are unmet —
867
+ surfacing the first-evaluated gate is the canonical wire shape and
868
+ keeps `detail` programmatically parseable. When a runner aggregates
869
+ multiple unmet gates into one `detail` string for human display,
870
+ it MUST use "; " (semicolon + space) as the sub-reason separator
871
+ and MUST preserve each sub-reason's standalone form (the bare
872
+ `requires:` legacy value, or the prefixed `missing_required_tool_family:
873
+ …` shape). Example multi-gate aggregation:
874
+ `controller; missing_required_tool_family: needs list_accounts or sync_accounts (AdCP 3.0.9 §accounts/overview)`.
875
+
876
+ Automated consumers SHOULD parse only the first sub-reason from
877
+ aggregated `detail` (everything up to the first "; ") and surface
878
+ multi-gate state through a separate UI affordance rather than
879
+ treating `detail` as a structured list.
880
+
881
+ The sub-reason prefix is the canonical attribution string —
882
+ dashboards and skip-cause aggregators MUST switch on the prefix to
883
+ separate tool-family gates from `requires:` gates when summarizing
884
+ the first sub-reason.
885
+
886
+ Distinct from missing_test_controller (which fires mid-run at a
887
+ specific step when comply_test_controller is absent) — this reason
888
+ fires at load time for the whole storyboard, before any step
889
+ executes. When `requires: [controller]` is set, the runner MUST
890
+ emit this reason at storyboard scope, not missing_test_controller
891
+ at step scope.
892
+
893
+ Distinct from missing_tool (which fires at step scope when a tool
894
+ declared in the storyboard's `required_tools` is absent — a coverage
895
+ skip). `required_any_of_tools` is a load-time gate on tool
896
+ advertisement, not a per-step coverage signal.
897
+
898
+ Forward compatibility: runners that encounter a `requires` value
899
+ they do not recognize MUST emit this reason with the unrecognized
900
+ value in detail, rather than fail-loading the storyboard. Using
901
+ requirement_unmet (not not_applicable) correctly signals "an unmet
902
+ gate" vs. "agent did not claim the protocol" — the two are distinct
903
+ signals for dashboards and summaries.
904
+ description: |
905
+ Runners MAY internally track narrower skip reasons (e.g., a grader
906
+ distinguishing `rate_abuse_opt_out` from `live_side_effect_opt_in_required`).
907
+ Such runners MUST still populate `reason` with one of the canonical
908
+ values above and encode the narrower cause in `detail`. Machine-
909
+ readable consumers can then switch on a stable enum; human-readable
910
+ consumers still see the specific cause. See
911
+ DETAILED_SKIP_TO_CANONICAL in the conforming implementation for a
912
+ concrete mapping.
913
+
914
+ selection_result:
915
+ description: |
916
+ When a track, storyboard, phase, or step is outside the run the caller
917
+ requested, runners MUST report it as not_selected rather than skipped.
918
+ Not-selected items are not attempted, do not imply an agent capability
919
+ gap, and MUST NOT contribute to steps_skipped or any skip-by-reason
920
+ counter.
921
+
922
+ This distinction is load-bearing for Sandbox verification and buyer
923
+ dashboards. "Sandbox only" means live-only probes are excluded by the
924
+ selected suite; it does not mean the seller skipped or failed those
925
+ probes. By contrast, a selected storyboard that cannot run because the
926
+ seller did not advertise an optional capability, omitted
927
+ comply_test_controller, or lacks a required tool remains a skip_result
928
+ with its own reason.
929
+ required_fields:
930
+ - reason # run_mode_excluded | explicit_scope_excluded |
931
+ # version_excluded | profile_excluded
932
+ - detail # human-readable explanation citing the
933
+ # selected run mode, explicit storyboard scope,
934
+ # AdCP version, or verification profile rule
935
+ # that excluded the item.
936
+ reasons:
937
+ run_mode_excluded: |
938
+ The item is incompatible with the selected run mode. Example:
939
+ a live-only probe is outside a Sandbox-only run. detail MUST cite
940
+ both the selected mode and the excluded mode requirement.
941
+ explicit_scope_excluded: |
942
+ The caller supplied an explicit storyboard, track, protocol, or
943
+ specialism scope that does not include this item. detail MUST cite
944
+ the selected scope.
945
+ version_excluded: |
946
+ The item is not applicable to the AdCP version selected for this run.
947
+ detail MUST cite the selected AdCP version and the item's
948
+ introduced_in or removed_in bound when known.
949
+ profile_excluded: |
950
+ A named verification profile intentionally excludes this item before
951
+ execution. detail MUST cite the profile name and profile rule.
952
+
953
+ notice:
954
+ description: |
955
+ Advisory signal attached to a storyboard step result or run summary.
956
+ Notices are informational — they MUST NOT contribute to steps_failed,
957
+ validations_failed, or any other required-failure counter, and they
958
+ MUST NOT change `step_result.passed` or run-level pass/fail counters.
959
+
960
+ Notices fill the gap between three existing signals:
961
+ - Validation failures (passed: false) — the agent did something wrong.
962
+ - Skip reasons — the runner could not apply the storyboard.
963
+ - Advisory-severity validations — the storyboard author marked a check
964
+ as non-blocking during a runner adoption window.
965
+
966
+ A notice is none of those: it is a forward-looking or migration advisory
967
+ about a passing observation. Examples: an agent still advertising a
968
+ deprecated specialism that the spec recommends dropping; an agent that
969
+ passes today but advertises a capability shape that will be required at
970
+ a named future spec version; an adopter using a legacy fallback that is
971
+ scheduled for removal at a named future version.
972
+
973
+ Spec storyboards that motivate canonical notices SHOULD reference the
974
+ notice `code` (not the prose). The reference adopter currently
975
+ motivating the contract is the `signed_requests_specialism_deprecated`
976
+ notice in `universal/signed-requests.yaml` — the runner SHOULD emit
977
+ this notice when an agent claims the deprecated `signed-requests`
978
+ specialism alongside `request_signing.supported: true`, advising
979
+ the agent to drop the now-redundant specialism claim.
980
+
981
+ Forward compatibility: receivers MUST treat an unknown `code` or
982
+ `severity` value as well-formed and surface the notice verbatim. New
983
+ codes and severities ship additively; rejecting on unknown values
984
+ defeats the contract.
985
+
986
+ required_fields:
987
+ - severity # "info" | "deprecation" | "future_required"
988
+ # info — passing behavior is fine
989
+ # today; advisory context only
990
+ # (e.g., "this agent is using
991
+ # an alternate but supported
992
+ # pathway").
993
+ # deprecation — agent-side claim or behavior
994
+ # is allowed today but the
995
+ # spec recommends migration
996
+ # (e.g., legacy specialism
997
+ # enum values still accepted
998
+ # for back-compat).
999
+ # future_required — capability that is optional
1000
+ # today will be required at a
1001
+ # named future spec version;
1002
+ # agents that do not advertise
1003
+ # it will fail compliance
1004
+ # after the cut. `effective_version`
1005
+ # MUST be populated.
1006
+ - code # stable machine-readable identifier
1007
+ # (SCREAMING_SNAKE-or-lowercase_snake; the
1008
+ # canonical first-day codes below use
1009
+ # lowercase_snake). Runners MUST NOT change
1010
+ # the code for the same advisory across
1011
+ # versions — consumers aggregate by code.
1012
+ # Unknown codes from a forward-compat runner
1013
+ # MUST be surfaced verbatim by receivers, not
1014
+ # rejected.
1015
+ - message # human-readable description. Runners MUST
1016
+ # fence this string when rendering to a
1017
+ # shared LLM-fed surface per the same rules
1018
+ # as skip_result.detail — the storyboard
1019
+ # author controls the substring.
1020
+ optional_fields:
1021
+ - effective_version # When severity is "future_required", the
1022
+ # AdCP version that flips the requirement
1023
+ # (e.g., "4.0"). REQUIRED for future_required
1024
+ # severity, MAY be present on "deprecation"
1025
+ # to name the removal version, MUST NOT be
1026
+ # set on "info".
1027
+ - requirement # When the notice is tied to a structured
1028
+ # `requires:` name in storyboard-schema.yaml,
1029
+ # repeat the requirement value here so
1030
+ # dashboards can correlate notices with the
1031
+ # gate that motivated them.
1032
+ - capability_path # Dotted path into the agent's
1033
+ # `get_adcp_capabilities` response that
1034
+ # motivated the notice
1035
+ # (e.g., "request_signing.supported",
1036
+ # "webhook_signing.legacy_hmac_fallback").
1037
+ # Lets consumers link the notice to the
1038
+ # exact capability flag without parsing the
1039
+ # message string.
1040
+ - reference_url # optional spec or issue URL with more context
1041
+ # (e.g., the upstream issue tracking the
1042
+ # deprecation, or the relevant section in
1043
+ # /docs/building/by-layer/L3/error-handling.mdx).
1044
+ canonical_codes:
1045
+ description: |
1046
+ First-day published codes runners SHOULD emit when the underlying
1047
+ condition holds. Additional codes are registered by adding entries
1048
+ here in subsequent spec revisions; runners MAY emit codes outside
1049
+ this list (consumers must accept unknown codes per the forward-compat
1050
+ rule above), but SHOULD prefer canonical codes when one fits.
1051
+ signed_requests_specialism_deprecated:
1052
+ severity: deprecation
1053
+ spec_source: universal/signed-requests.yaml
1054
+ capability_path: specialisms
1055
+ message_template: |
1056
+ Agent advertises the deprecated `signed-requests` specialism
1057
+ enum value. Drop it and rely solely on
1058
+ `request_signing.supported: true`. The enum value is removed
1059
+ in AdCP 4.0 (see adcontextprotocol/adcp#3078).
1060
+ request_signing_required_in_4_0:
1061
+ severity: future_required
1062
+ effective_version: "4.0"
1063
+ spec_source: protocol/get-adcp-capabilities-response.json#request_signing
1064
+ capability_path: request_signing.supported
1065
+ message_template: |
1066
+ `request_signing.supported: true` is optional in 3.x but required
1067
+ for spend-committing operations in AdCP 4.0. Agents that do not
1068
+ advertise support will fail compliance on the 4.0 cut.
1069
+ legacy_hmac_fallback_removed_in_4_0:
1070
+ severity: deprecation
1071
+ effective_version: "4.0"
1072
+ spec_source: protocol/get-adcp-capabilities-response.json#webhook_signing.legacy_hmac_fallback
1073
+ capability_path: webhook_signing.legacy_hmac_fallback
1074
+ message_template: |
1075
+ Agent advertises `webhook_signing.legacy_hmac_fallback: true`.
1076
+ The HMAC fallback path is deprecated and removed in AdCP 4.0;
1077
+ receivers SHOULD migrate to RFC 9421 signatures only.
1078
+
1079
+ cascade_rules:
1080
+ description: |
1081
+ Rules governing when a runner MUST propagate `prerequisite_failed` to
1082
+ downstream stateful steps and when it MUST NOT. These complement the
1083
+ per-reason text in `skip_result.reasons`: the skip reason describes WHY
1084
+ a step was skipped; cascade rules describe what effect that skip has on
1085
+ later phases. Runners MUST evaluate these rules after per-step grading
1086
+ completes, before downstream skip propagation runs.
1087
+ default_cascade: |
1088
+ When a stateful step produces `passed: false` (a genuine failure), or
1089
+ skips with `prerequisite_failed`, `unsatisfied_contract`, or
1090
+ `peer_branch_taken`, the runner MUST cascade `prerequisite_failed` to
1091
+ downstream stateful phases so implementors know that dependent coverage
1092
+ collapsed. Steps that skip with `peer_substituted` do NOT trigger the
1093
+ cascade — the `provides_state_for` mechanism already waived it (see
1094
+ `skip_result.reasons.peer_substituted`). Steps that skip with
1095
+ `not_applicable`, `missing_tool`, or `missing_test_controller` do NOT
1096
+ trigger the cascade when the `sole_stateful_step_exemption` below applies.
1097
+ sole_stateful_step_exemption: |
1098
+ When ALL of the following hold, the runner MUST NOT cascade
1099
+ `prerequisite_failed` to downstream stateful phases:
1100
+
1101
+ 1. The step grades `not_applicable`, `missing_tool`, or
1102
+ `missing_test_controller`.
1103
+ 2. It is the sole stateful step in its phase (no other stateful step
1104
+ exists in the same phase that could have established substitute state).
1105
+ 3. No same-phase peer step has declared `provides_state_for:
1106
+ <this_step_id>`.
1107
+
1108
+ When these conditions are met, downstream phases evaluate independently —
1109
+ their stateful steps do NOT receive `prerequisite_failed` from this step
1110
+ and are graded on their own merits. The skipping step still emits its own
1111
+ skip_result with the original reason (`not_applicable | missing_tool |
1112
+ missing_test_controller`); the exemption suppresses only the cascade, not
1113
+ the step's own skip reason.
1114
+
1115
+ Rationale: a sole stateful step has no peer that could have established
1116
+ substitute state. The platform legitimately does not implement this pathway
1117
+ (e.g., proposal-mode / implicit-account adopters that materialize account
1118
+ state via the first `get_products` call rather than `sync_accounts`).
1119
+ Cascading `prerequisite_failed` to all downstream stateful phases collapses
1120
+ useful coverage on the framework paths the adopter does implement.
1121
+
1122
+ When the skipping step has at least one stateful peer in the phase, the
1123
+ existing rules apply: `provides_state_for` declarations defer the cascade
1124
+ (see `skip_result.reasons.peer_substituted`), and unrescued hard-missing
1125
+ or real failures trip it.
1126
+
1127
+ Note on `not_applicable`: unlike `missing_tool` and
1128
+ `missing_test_controller` (where the agent declared the specialism but
1129
+ lacks the tool/controller), `not_applicable` means the agent did not
1130
+ declare the specialism at all. The cascade exemption still applies because
1131
+ the structural condition — no peer available to establish substitute state —
1132
+ is identical. A sole-stateful-step `not_applicable` that cascades to all
1133
+ downstream phases would collapse coverage for agents that legitimately omit
1134
+ a pathway; the exemption prevents this collapse regardless of the specific
1135
+ skip reason. Dashboard consumers that need to distinguish "agent does not
1136
+ support the specialism" from "agent supports it via an alternate tool"
1137
+ should read the step's `reason` field rather than inferring from whether
1138
+ downstream phases ran.
1139
+
1140
+ References: adcp-client#1146 (original `not_applicable` exemption);
1141
+ adcp-client#1545 (extension to `missing_tool` / `missing_test_controller`);
1142
+ adcp-client-python#550 (adopter pattern that surfaced the cross-runner gap).
1143
+
1144
+ run_summary:
1145
+ description: |
1146
+ Runners MUST expose a top-level summary for every run. UI surfaces
1147
+ (Addie, CLI, web) may present a condensed form, but the full summary
1148
+ MUST be available in the machine-readable (--json / structuredContent)
1149
+ output.
1150
+ notes:
1151
+ capture_failures_count_as_failed: |
1152
+ Steps that fail due to capture_path_not_resolvable or
1153
+ unresolved_substitution MUST contribute to steps_failed, not
1154
+ steps_skipped. The capturing step failing is a conformance failure
1155
+ on that step; the downstream consumer step that cannot run due to
1156
+ the missing context value uses the skip_result.reason:
1157
+ prerequisite_failed path and contributes to steps_skipped. This
1158
+ attribution is load-bearing — silently swallowing a capture failure
1159
+ and reporting only the downstream skip points the diagnostic at the
1160
+ wrong place.
1161
+ upstream_traffic_not_applicable: |
1162
+ Steps whose only failing validation is upstream_traffic against an
1163
+ adopter that did not advertise query_upstream_traffic via
1164
+ list_scenarios MUST NOT contribute to steps_failed. The runner
1165
+ grades the upstream_traffic validation as not_applicable (with
1166
+ skip_result.reason: missing_test_controller, detail:
1167
+ "query_upstream_traffic scenario not advertised") and the step
1168
+ grades on its remaining authored checks. An adopter that exposes
1169
+ the scenario but returns an empty recorded_calls array DOES grade
1170
+ as failed for upstream_traffic — the difference is "controller
1171
+ not present" (opt-out) vs "controller present and observed nothing"
1172
+ (façade signal).
1173
+ required_fields:
1174
+ - total_steps
1175
+ - steps_passed
1176
+ - steps_failed
1177
+ - steps_skipped
1178
+ - steps_not_selected # count of steps excluded before execution by
1179
+ # suite selection, run mode, AdCP version, or
1180
+ # verification profile. MUST NOT be included
1181
+ # in steps_skipped.
1182
+ - tracks # per-track status with the skip distinctions above
1183
+ - schemas_used # array of { schema_id, schema_url } so an
1184
+ # implementor can re-validate locally against
1185
+ # the exact artifacts the runner applied
1186
+ - runner_capability_version
1187
+ # semver self-declared by the runner so
1188
+ # consumers can correlate a run's grading
1189
+ # behavior with the spec capability the
1190
+ # runner offers. Authors target capability
1191
+ # versions when they write
1192
+ # expires_after_version on advisory
1193
+ # validations (see storyboard-schema.yaml >
1194
+ # expires_after_version) and the runner's
1195
+ # promotion logic compares its declared
1196
+ # value against the storyboard's expiry. The
1197
+ # runner chooses what its capability version
1198
+ # corresponds to — @adcp/sdk semver, the
1199
+ # AdCP spec version it implements, or a
1200
+ # runner-binary version — and is responsible
1201
+ # for advancing it as new check kinds and
1202
+ # grading semantics ship. Adopters who run
1203
+ # multiple runners against the same agent
1204
+ # SHOULD select the highest-capability runner
1205
+ # for conformance grading.
1206
+ optional_fields:
1207
+ - not_selected # array of selection_result objects, or
1208
+ # implementation-specific objects carrying at
1209
+ # least selection_result.reason/detail plus the
1210
+ # storyboard/phase/step identity. Required for
1211
+ # human-facing reports that mention a
1212
+ # not-selected count; otherwise the count is not
1213
+ # actionable.
1214
+ - not_selected_by_reason # object mapping selection_result.reason values
1215
+ # to counts. Recommended for dashboards and
1216
+ # buyer profile evaluators.
1217
+ - skipped_by_reason # object mapping skip_result.reason values to
1218
+ # counts. Recommended whenever steps_skipped > 0
1219
+ # so consumers can distinguish optional
1220
+ # capability skips from missing required
1221
+ # surfaces without parsing prose detail strings.
1222
+ - validations_not_applicable # count of validation_result entries graded
1223
+ # not_applicable due to forward-compat
1224
+ # (runner does not implement the storyboard's
1225
+ # declared check type). Surfaces "runner is
1226
+ # older than the storyboard" as a distinct
1227
+ # signal from clean passes.
1228
+ - notices # array of notice objects scoped to the run
1229
+ # rather than a specific step (e.g., a
1230
+ # `request_signing_required_in_4_0` notice
1231
+ # emitted once per run when the agent does
1232
+ # not advertise `request_signing.supported`,
1233
+ # regardless of which storyboard the
1234
+ # observation surfaced on). Runners MAY
1235
+ # emit the same code on step_result.notices
1236
+ # AND run_summary.notices when an advisory
1237
+ # is both step-specific and run-wide;
1238
+ # consumers dedupe by `code`. See the
1239
+ # notice block above for shape and
1240
+ # canonical_codes.
1241
+ - validations_advisory_failed # count of validation_result entries with
1242
+ # passed: false and severity: advisory.
1243
+ # These do NOT contribute to steps_failed
1244
+ # (the step grades on its required
1245
+ # validations); this counter surfaces them
1246
+ # for visibility without polluting the
1247
+ # conformance verdict.
1248
+ #
1249
+ # Rendered-summary rule: when the runner
1250
+ # renders a human-facing summary line
1251
+ # (CLI, dashboard, chat surface),
1252
+ # validations_advisory_failed MUST be
1253
+ # displayed adjacent to steps_failed in
1254
+ # the same line or section, NOT buried
1255
+ # at the bottom of the summary. Otherwise
1256
+ # a façade declaring its anti-façade
1257
+ # validations as advisory produces a
1258
+ # passing summary line that hides the
1259
+ # advisory failures from human
1260
+ # reviewers. The two counters together
1261
+ # are the conformance signal.
1262
+ #
1263
+ # Use case: author-managed rollout
1264
+ # gating during runner adoption windows
1265
+ # — see storyboard-schema.yaml >
1266
+ # "Validation" severity field.
1267
+
1268
+ # --- Non-goals ---
1269
+ #
1270
+ # This contract does NOT specify:
1271
+ # - Output formatting (markdown, JSON shape in the outer envelope, colors).
1272
+ # - Storage or retention of run artifacts.
1273
+ # - Scoring weights or pass/fail thresholds for a "compliant" verdict.
1274
+ # - How to render results in conversational interfaces.
1275
+ # Runners remain free to add fields, nest them under implementation-specific
1276
+ # keys, and render them however best fits the surface. The contract is about
1277
+ # minimum actionability.
1278
+
1279
+ references:
1280
+ storyboard_schema: static/compliance/source/universal/storyboard-schema.yaml
1281
+ mcp_extraction: docs/building/implementation/mcp-response-extraction.mdx
1282
+ a2a_extraction: docs/building/implementation/a2a-response-extraction.mdx
1283
+ transport_errors: docs/building/implementation/transport-errors.mdx
1284
+ signed_requests_runner: static/compliance/source/test-kits/signed-requests-runner.yaml
1285
+ conforming_implementation: https://github.com/adcontextprotocol/adcp-client/pull/611