@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,688 @@
1
+ # Substitution Observer Runner — Harness Contract Test Kit
2
+ #
3
+ # Applies to:
4
+ # - Any storyboard that exercises catalog-item macro substitution and needs
5
+ # to assert the RFC 3986 percent-encoding rule from
6
+ # docs/creative/universal-macros.mdx#substitution-safety-catalog-item-macros.
7
+ # - Current consumers (when phases are gated on this contract):
8
+ # - specialisms/sales-catalog-driven/index.yaml (substitution_safety phase)
9
+ # - specialisms/creative-generative/index.yaml (catalog_substitution_safety phase)
10
+ # - specialisms/sales-social/index.yaml (catalog_substitution_safety phase)
11
+ # - Future consumers: sales-retail-media (post-retail-media-epic),
12
+ # sales-broadcast-tv dynamic-creative phases, and anywhere else catalog
13
+ # values expand into URL contexts through a previewable surface.
14
+ #
15
+ # The #2620 rule: sales agents MUST percent-encode catalog-item macro values
16
+ # such that only RFC 3986 `unreserved` characters remain unescaped before
17
+ # substitution into URL contexts. Nested macro expansion is prohibited.
18
+ #
19
+ # The ATTACK SURFACE is impression-time URL emission. AdCP's API surface does
20
+ # not normally expose substituted output — it happens at serve time outside
21
+ # the protocol. Two observable AdCP-layer hooks exist:
22
+ #
23
+ # preview_creative responses (preview_html / preview_url)
24
+ # build_creative responses with include_preview: true
25
+ #
26
+ # This contract defines how a runner consumes those preview artifacts,
27
+ # extracts tracker URLs with substituted catalog-item values, and asserts
28
+ # the values are encoded per the #2620 rule.
29
+ #
30
+ # Clean seam: the runner does NOT reimplement URL parsing, HTML extraction,
31
+ # or the encoding check. It delegates to @adcp/client primitives (proposed:
32
+ # `SubstitutionObserver` with `extract_tracker_urls` and `assert_rfc3986_safe`
33
+ # helpers) so the same library production receivers would use is what the
34
+ # conformance runner exercises. Library fixes cover both.
35
+
36
+ id: substitution_observer_runner
37
+ # Shape extension vs webhook-receiver-runner: this contract applies to
38
+ # specialisms rather than universals, because catalog-macro substitution is a
39
+ # specialism-scoped behavior (only catalog-accepting sellers emit it). The
40
+ # `applies_to.specialisms` key is a deliberate structural addition for this
41
+ # class of contract.
42
+ applies_to:
43
+ specialisms:
44
+ - sales_catalog_driven
45
+ - creative_generative
46
+ - sales_social
47
+ universals: []
48
+
49
+ description: |
50
+ Coordination contract between a runner that observes substituted tracker
51
+ URLs in preview artifacts and an agent under test that emits catalog-driven
52
+ creatives. The runner ingests preview_html or follows preview_url, extracts
53
+ tracker URLs bound to catalog-item macros, and asserts RFC 3986 percent-
54
+ encoding of catalog-item values per docs/creative/universal-macros#substitution-safety-catalog-item-macros.
55
+
56
+ endpoint_scope: sandbox
57
+ # Storyboards consuming this contract synthesize attacker-shaped catalog
58
+ # values (e.g., title containing `abc&cmd=drop` or `\r\nHost: evil`) and
59
+ # push them via sync_catalogs. Running those against production would
60
+ # pollute live catalogs. Graders MUST target a sandbox/staging endpoint.
61
+
62
+ harness_mode: black_box
63
+
64
+ # --- Observation mechanism ---
65
+ #
66
+ # The runner captures preview output from two response shapes (either is
67
+ # sufficient — the storyboard author names which to observe):
68
+ #
69
+ # preview_html (inline HTML string in the response)
70
+ # The runner parses the HTML and extracts tracker URLs from the
71
+ # attribute set enumerated below. Zero network dependency.
72
+ #
73
+ # preview_url (HTTPS URL the runner fetches subject to the SSRF policy
74
+ # enumerated below)
75
+ # The runner performs a single GET against the URL and extracts
76
+ # identically.
77
+ #
78
+ # Both paths land at the same @adcp/client.SubstitutionObserver.extract_tracker_urls
79
+ # primitive, which returns a deterministic list of `{ url, source_attr, line_hint }`
80
+ # records that storyboards match against.
81
+
82
+ observation_modes:
83
+ - mode: html_inline
84
+ default_for: [lint, fast, full_conformance]
85
+ description: |
86
+ Runner reads preview_html from the response and parses it. No network
87
+ fetch. Appropriate for CI lint gates and SDK self-tests.
88
+ runner_config:
89
+ source_path: preview_html
90
+ html_parser: "@adcp/client.SubstitutionObserver.parse_html"
91
+
92
+ - mode: url_fetch
93
+ default_for: [adcp_verified]
94
+ description: |
95
+ Runner fetches preview_url over HTTPS, expects 200 + text/html, and
96
+ parses the body. Required for AdCP Verified grading where the preview
97
+ is a live asset.
98
+ runner_config:
99
+ source_path: preview_url
100
+ fetch:
101
+ method: GET
102
+ follow_redirects: false
103
+ max_body_bytes: 262144 # 256 KiB — matches typical creative preview sizes
104
+ max_connect_seconds: 3
105
+ timeout_seconds: 10
106
+ required_content_types: ["text/html", "application/xhtml+xml"]
107
+ # SSRF policy is NORMATIVE IN THIS CONTRACT (not deferred to a library).
108
+ # Verified graders MUST enforce every rule below. The runner MAY delegate
109
+ # the implementation to @adcp/client.SubstitutionObserver.enforce_ssrf_policy
110
+ # (or equivalent) provided the delegate implements this exact deny list.
111
+ ssrf_policy:
112
+ schemes_allowed: ["https"]
113
+ schemes_denied: ["http", "file", "gopher", "ftp", "ftps", "data", "javascript", "about", "ws", "wss"]
114
+ hosts_denied_ipv4_cidrs:
115
+ - "0.0.0.0/8" # "this network"
116
+ - "10.0.0.0/8" # RFC 1918 private
117
+ - "100.64.0.0/10" # CGNAT
118
+ - "127.0.0.0/8" # loopback
119
+ - "169.254.0.0/16" # link-local (incl. 169.254.169.254 IMDS v1/v2)
120
+ - "172.16.0.0/12" # RFC 1918 private
121
+ - "192.0.0.0/24" # IETF protocol assignments
122
+ - "192.168.0.0/16" # RFC 1918 private
123
+ - "224.0.0.0/4" # multicast
124
+ - "240.0.0.0/4" # reserved
125
+ hosts_denied_ipv6_cidrs:
126
+ - "::1/128" # loopback
127
+ - "::/128" # unspecified
128
+ - "::ffff:0:0/96" # IPv4-mapped (re-check as IPv4)
129
+ - "64:ff9b::/96" # IPv4/IPv6 translation
130
+ - "fc00::/7" # unique local
131
+ - "fe80::/10" # link-local
132
+ - "ff00::/8" # multicast
133
+ hosts_denied_metadata:
134
+ # Cloud metadata hosts by name — the IP CIDRs above catch the standard
135
+ # 169.254.169.254 cases, but some providers expose hostname aliases.
136
+ - "metadata.google.internal"
137
+ - "metadata"
138
+ - "metadata.packet.net"
139
+ - "fd00:ec2::254" # IMDS IPv6
140
+ host_literal_policy_verified: reject
141
+ # In AdCP Verified grading, reject ANY bare IP literal in preview_url
142
+ # (both IPv4 and IPv6) regardless of range — forces resolution through
143
+ # a public DNS name the grader can audit. Local-dev flags MAY relax this.
144
+ dns_revalidation: required
145
+ # After DNS resolution, EVERY resolved address MUST be re-checked against
146
+ # hosts_denied_*. Resolve once, bind to the resolved address for the
147
+ # request — do NOT pass the hostname to the HTTP client (closes DNS
148
+ # rebinding between resolve and connect).
149
+ redirects: follow_false_strict
150
+ # follow_redirects: false is already set above; this field documents
151
+ # the companion: if the origin returns 3xx, treat it as a failure
152
+ # (`preview_url_unusable` + sub-reason `redirect_returned`), do NOT
153
+ # chase — redirect chasing would require re-running the full SSRF
154
+ # policy at each hop and is out of scope for v1.
155
+
156
+ # --- HTML attribute extraction set (normative) ---
157
+ #
158
+ # The runner extracts tracker URLs from the following attributes only. This
159
+ # set is normative — runner MUST NOT under-extract (missing one of these
160
+ # attributes lets a seller hide an unencoded value); runner MUST NOT over-
161
+ # extract (e.g., arbitrary `data-*` attributes whose values happen to parse
162
+ # as URLs but are not trackers). Extension to additional attributes MAY
163
+ # happen in a future contract revision; today's set is closed.
164
+
165
+ html_attribute_extraction_set:
166
+ tag_attribute_pairs:
167
+ - { tag: "a", attr: "href" }
168
+ - { tag: "img", attr: "src" }
169
+ - { tag: "img", attr: "srcset" } # may contain multiple URLs
170
+ - { tag: "iframe", attr: "src" }
171
+ - { tag: "source", attr: "src" }
172
+ - { tag: "source", attr: "srcset" }
173
+ - { tag: "link", attr: "href" }
174
+ - { tag: "meta", attr: "content" } # refresh redirects, og:image, etc.
175
+ - { tag: "*", attr: "data-impression-url" }
176
+ - { tag: "*", attr: "data-click-url" }
177
+ - { tag: "*", attr: "data-tracker-url" }
178
+ - { tag: "*", attr: "data-vast-url" }
179
+ srcset_handling: parse_per_descriptor
180
+ # srcset values are space-separated URL+descriptor pairs (e.g.,
181
+ # "a.jpg 1x, b.jpg 2x"). The runner MUST extract every URL component.
182
+ comment_nodes: ignored
183
+ script_text_content: ignored
184
+ # Tracker URLs in `<script>`-emitted document.write or similar are out
185
+ # of scope v1 — if a seller hides substitution inside script text, the
186
+ # runner does not see it (covered under "preview/serve code-path
187
+ # divergence" in out-of-scope, below).
188
+
189
+ # --- Macro-position alignment algorithm (normative) ---
190
+ #
191
+ # The runner needs to map each extracted URL back to a position in the
192
+ # submitted macro_template so it can compare the substituted bytes against
193
+ # the expected_encoded form of the bound catalog-item value. The algorithm:
194
+ #
195
+ # 1. Parse `macro_template` with a WHATWG URL parser (absolute URLs only).
196
+ # Extract: scheme, host, port, path_segments[], query_pairs[{k,v}],
197
+ # fragment.
198
+ # 2. Parse each extracted observed URL with the SAME parser. If an
199
+ # extracted URL is relative in the preview HTML, resolve against a
200
+ # synthetic base (`https://observer.test/`) so relative-resolution
201
+ # does not introduce cross-runner variance.
202
+ # 3. Align query_pairs by key. A template pair {k: "sku", v: "{SKU}"}
203
+ # aligns to the observed pair whose key parses to the same sequence
204
+ # after percent-decoding `k`. If multiple observed pairs share a key,
205
+ # align positionally (template pair index N → observed pair index N
206
+ # among matching-key pairs).
207
+ # 4. Align path_segments positionally. A template segment "{JOB_ID}"
208
+ # aligns to the observed segment at the same index.
209
+ # 5. For each alignment, the observed value is the substituted output
210
+ # for that binding. Compare bytes against `expected_encoded` per the
211
+ # hex-case policy below.
212
+ #
213
+ # This algorithm is deterministic and does NOT depend on substring search
214
+ # or regex — substring alignment fails on attacker values that happen to
215
+ # equal other parts of the URL.
216
+
217
+ # --- Hex case policy (normative) ---
218
+ #
219
+ # RFC 3986 §2.1 states producers SHOULD use uppercase hex digits in
220
+ # percent-encoded triplets. This contract REQUIRES producers (sellers) to
221
+ # emit uppercase hex (`%C3%A9`, not `%c3%a9`) to match the fixture's
222
+ # expected_encoded values byte-for-byte.
223
+ #
224
+ # However, VERIFIERS (runners performing the byte comparison) MUST apply
225
+ # case-insensitive comparison on the hex digits only — the two hex digits
226
+ # inside a `%NN` triplet compare case-insensitively, every byte outside a
227
+ # triplet compares case-sensitively. This accommodates legitimate producer
228
+ # variation without silently accepting a non-conformant triplet encoding
229
+ # (e.g., `%g7` is invalid regardless of case).
230
+ #
231
+ # Implementation note: @adcp/client.SubstitutionObserver.assert_rfc3986_safe
232
+ # MUST implement the case-insensitive triplet comparison; runners MUST NOT
233
+ # do naive byte-equal comparison.
234
+
235
+ hex_case_policy:
236
+ producer_requirement: uppercase
237
+ verifier_comparison: case_insensitive_hex_digits_only
238
+
239
+ # --- Attacker-shaped catalog values ---
240
+ #
241
+ # The canonical vectors live in the unit-test fixture at
242
+ # static/test-vectors/catalog-macro-substitution.json. The fixture is the
243
+ # SINGLE SOURCE OF TRUTH for `raw_value` and `expected_encoded` — the
244
+ # runner MUST load the fixture at run time and look up each vector by name.
245
+ # This contract NAMES the vectors a consuming storyboard can reference;
246
+ # it does NOT duplicate the encoded values (they would drift).
247
+
248
+ attacker_value_catalog:
249
+ source_fixture: static/test-vectors/catalog-macro-substitution.json
250
+ canonical_vector_names:
251
+ - reserved-character-breakout
252
+ - nested-expansion-preserved-as-literal
253
+ - crlf-injection-neutralized
254
+ - non-ascii-utf8-percent-encoding
255
+ - nfc-normalization-before-encoding
256
+ - mixed-path-and-query-contexts
257
+ - bidi-override-neutralized
258
+ - url-scheme-injection-neutralized
259
+
260
+ # --- Storyboard-layer step task ---
261
+ #
262
+ # The contract exposes one primary step task:
263
+ #
264
+ # task: expect_substitution_safe
265
+ #
266
+ # Arguments:
267
+ # source:
268
+ # html_inline | url_fetch
269
+ # Which observation mode the runner uses. Default: html_inline.
270
+ # source_path:
271
+ # JSON-pointer into the previous step's response where the preview
272
+ # artifact lives. Example: "/creative_manifest/preview_html".
273
+ # macro_template:
274
+ # The URL template containing AdCP macros (the value submitted via
275
+ # sync_creatives). Example: "https://track.example/imp?sku={SKU}"
276
+ # catalog_bindings:
277
+ # Array of { macro, catalog_item_id, vector_name } entries. The runner
278
+ # loads the fixture (by source_fixture path above), looks up each
279
+ # vector_name, and binds `{macro}` to the vector's raw_value →
280
+ # expected_encoded pair. Storyboard authors DO NOT duplicate
281
+ # raw_value/expected_encoded inline; the fixture is authoritative.
282
+ #
283
+ # Optional override fields for non-canonical vectors (e.g., seller-
284
+ # specific payloads not in the fixture): `raw_value` and
285
+ # `expected_encoded` MAY be inlined, and when inlined the runner skips
286
+ # the fixture lookup. Runners MUST redact `raw_value` from error
287
+ # reports for inlined custom vectors (treat as potentially sensitive);
288
+ # canonical fixture values MAY be echoed verbatim because the fixture
289
+ # is public.
290
+ # require_every_binding_observed:
291
+ # Default `true`. When true, the step fails if any declared binding is
292
+ # not observed in the extracted URLs — catches a seller that silently
293
+ # strips a macro rather than substituting it. Storyboard authors MUST
294
+ # explicitly set `false` and document why (e.g., preview shows one
295
+ # item from a larger catalog) when partial observation is legitimate.
296
+ # The previous name `require_all_bindings_observed` is deprecated; the
297
+ # new name disambiguates "every declared binding" from "every URL
298
+ # matches some binding."
299
+ #
300
+ # Validations (runner-internal; storyboards reference them by name):
301
+ #
302
+ # substitution_encoded:
303
+ # For each binding, the observed value at the aligned macro position
304
+ # MUST equal the fixture's `expected_encoded` under the hex_case_policy
305
+ # comparison. Raw-value leakage (any byte of `raw_value` appearing
306
+ # literally at the macro position) fails with
307
+ # `substitution_encoding_violation` plus the binding, observed URL,
308
+ # byte offset of divergence, and expected form.
309
+ #
310
+ # nested_expansion_not_re_scanned:
311
+ # For the `nested-expansion-preserved-as-literal` vector specifically:
312
+ # the observed URL MUST contain `%7BDEVICE_ID%7D` (encoded braces) and
313
+ # MUST NOT contain any resolved value for {DEVICE_ID}. A second-round
314
+ # expansion fails with `nested_macro_re_expansion`.
315
+ #
316
+ # url_scheme_preserved:
317
+ # For the `url-scheme-injection-neutralized` vector at an
318
+ # href-whole-value macro binding (i.e., the macro occupies the entire
319
+ # attribute value, like `<a href="{CLICK}">`): the scheme of the
320
+ # parsed observed URL MUST equal the scheme of the template. A
321
+ # substituted value that changes the scheme (e.g., `javascript:`
322
+ # appearing as the scheme of the observed URL) fails with
323
+ # `substitution_scheme_injection`.
324
+ #
325
+ # rfc3986_unreserved_only_at_macro_position:
326
+ # A stricter check than substitution_encoded — verifies that every
327
+ # byte emitted at the macro position is either unreserved
328
+ # (ALPHA / DIGIT / "-" / "." / "_" / "~") or a percent-encoded triplet.
329
+ # Producers using a reserved-char allowlist (rather than
330
+ # unreserved-whitelist) fail specifically on the CRLF and bidi
331
+ # vectors.
332
+
333
+ step_task:
334
+ name: expect_substitution_safe
335
+ schema_ref: static/compliance/source/universal/storyboard-schema.yaml
336
+ error_modes:
337
+ - substitution_encoding_violation
338
+ - nested_macro_re_expansion
339
+ - substitution_scheme_injection
340
+ - substitution_binding_missing
341
+ - preview_source_unavailable
342
+ - preview_url_unusable # collapses fetch-failed + body-not-html + ssrf-blocked into one code with sub-reasons
343
+ preview_url_unusable_sub_reasons:
344
+ - http_status # non-200 response
345
+ - content_type # not text/html or application/xhtml+xml
346
+ - size_exceeded # body > max_body_bytes
347
+ - redirect_returned # 3xx without follow
348
+ - ssrf_blocked # ssrf_policy deny-hit, with specific rule id in the detail
349
+ - fetch_timeout # exceeded max_connect_seconds or timeout_seconds
350
+
351
+ # --- PHASE_TEMPLATE: canonical three-step substitution-safety phase ---
352
+ #
353
+ # This block is ADVISORY documentation, not a runtime-enforced schema. Future
354
+ # storyboard authors adding a third, fourth, or Nth consumer of this contract
355
+ # SHOULD copy the shape below and substitute the placeholders marked with
356
+ # `<<PLACEHOLDER>>` — domain, catalog_id prefix, correlation_id prefix, step-id
357
+ # slug stem, narrative pronoun. Deviating from the template is legitimate
358
+ # (different specialisms have different observation points and format needs);
359
+ # the value is that starting from the template avoids silent drift on the
360
+ # load-bearing fields (`require_every_binding_observed: true`, fixture-lookup
361
+ # binding shape, `requires_contract: substitution_observer_runner`).
362
+ #
363
+ # Existing consumers to reference:
364
+ # - specialisms/sales-catalog-driven/index.yaml (substitution_safety)
365
+ # - specialisms/creative-generative/index.yaml (catalog_substitution_safety)
366
+ #
367
+ # Placeholders:
368
+ # <<SPECIALISM_SLUG>> e.g., sales_catalog_driven, creative_generative
369
+ # <<BRAND_DOMAIN>> fictional brand domain from the chosen test-kit
370
+ # (amsterdam-steakhouse.example, acmeoutdoor.example, …)
371
+ # <<OPERATOR_DOMAIN>> typically pinnacle-agency.example across kits
372
+ # <<CATALOG_ID_PREFIX>> a stable prefix that will NOT collide with other
373
+ # catalogs synced earlier in the storyboard
374
+ # <<PHASE_ID>> substitution_safety | catalog_substitution_safety | …
375
+ # <<CORRELATION_ID_PREFIX>> kebab-slug form of <<SPECIALISM_SLUG>>
376
+ # <<BUILD_TASK>> preview-returning task — typically `build_creative`
377
+ # with `include_preview: true`, or `preview_creative`
378
+ # where native. Match the specialism's existing
379
+ # preview-producing step.
380
+ # <<BUILD_SCHEMA_REF>> schema_ref for the build task request
381
+ # <<BUILD_RESPONSE_SCHEMA_REF>> response_schema_ref for the build task
382
+ # <<BUILD_COMPLY_SCENARIO>> creative_flow (match the existing specialism)
383
+ # <<TARGET_FORMAT_ID>> an OBJECT `{ agent_url, id }` the agent advertises —
384
+ # e.g., `{ agent_url: "https://creative.adcontextprotocol.org",
385
+ # id: "product_carousel_3_to_10" }` for DPA shapes. Not a scalar.
386
+ # <<TEMPLATE_URL>> the URL template whose macro positions the runner
387
+ # will observe (must contain the macro used in
388
+ # catalog_bindings)
389
+ # <<MESSAGE_BRIEF>> natural-language brief. For generative specialisms,
390
+ # MUST explicitly ask for the literal macro token
391
+ # (unsubstituted) so the observer catches the template;
392
+ # for template-shaped specialisms, describe the
393
+ # catalog-driven render.
394
+ # <<IDEMPOTENCY_PREFIX>> convention: `<<SPECIALISM_SLUG>>_<<PHASE_ID>>_<step-id>`
395
+ # for `$generate:uuid_v4#<prefix>` inputs.
396
+ #
397
+ # phase_template:
398
+ # id: <<PHASE_ID>>
399
+ # title: "Catalog-item macro substitution safety"
400
+ # narrative: |
401
+ # Per docs/creative/universal-macros#substitution-safety-catalog-item-macros,
402
+ # sales/creative agents MUST normalize catalog-item values to Unicode NFC
403
+ # and then percent-encode them such that only RFC 3986 `unreserved`
404
+ # characters remain unescaped before substituting them into a URL context.
405
+ # Nested macro expansion is prohibited.
406
+ #
407
+ # This phase exercises the rule with attacker-shaped catalog values drawn
408
+ # from the fixture at `static/test-vectors/catalog-macro-substitution.json`.
409
+ # The phase is gated on the `substitution_observer_runner` test-kit
410
+ # contract — runners that do not advertise it grade the expect step as
411
+ # `not_applicable` while the earlier sync and build steps still run.
412
+ #
413
+ # Scope note: this phase validates substitution on the PREVIEW surface
414
+ # only. Sellers with divergent preview vs impression-time substitution
415
+ # paths MAY pass here while failing at serve time; serve-time attestation
416
+ # or log-introspection observability is tracked separately (#2651).
417
+ #
418
+ # steps:
419
+ # - id: sync_substitution_probe_catalog
420
+ # task: sync_catalogs
421
+ # schema_ref: "media-buy/sync-catalogs-request.json"
422
+ # response_schema_ref: "media-buy/sync-catalogs-response.json"
423
+ # doc_ref: "/media-buy/task-reference/sync_catalogs"
424
+ # stateful: true
425
+ # sample_request:
426
+ # account:
427
+ # brand: { domain: "<<BRAND_DOMAIN>>" }
428
+ # operator: "<<OPERATOR_DOMAIN>>"
429
+ # catalogs:
430
+ # - catalog_id: <<CATALOG_ID_PREFIX>>_substitution_probe_v1
431
+ # type: "product"
432
+ # content_id_type: "sku"
433
+ # items:
434
+ # # Minimum 3 vectors (canonical baseline). Specialisms with higher
435
+ # # risk profile (generative, user-text-in-copy) SHOULD add crlf +
436
+ # # bidi; specialisms with template-bound substitution MAY stay at 3.
437
+ # - { item_id: "reserved_char_breakout", sku: "00013&cmd=drop" , … }
438
+ # - { item_id: "nested_expansion", sku: "vacancy-{DEVICE_ID}-42", … }
439
+ # - { item_id: "non_ascii", sku: "café-amsterdam" , … }
440
+ # # OPTIONAL — add for higher-risk specialisms:
441
+ # # - { item_id: "crlf_injection", sku: "abc\r\nHost: evil.ex" , … }
442
+ # # - { item_id: "bidi_override", sku: "VIN-\u202E1234" , … }
443
+ # # - { item_id: "nfc_normalization", sku: "cafe\u0301-amsterdam" , … }
444
+ # # Specialisms with whole-value macro binding MAY add url_scheme_injection.
445
+ # idempotency_key: "$generate:uuid_v4#<<IDEMPOTENCY_PREFIX>>_sync_substitution_probe_catalog"
446
+ # context: { correlation_id: "<<CORRELATION_ID_PREFIX>>--sync_substitution_probe_catalog" }
447
+ #
448
+ # - id: build_substitution_probe_creative
449
+ # task: <<BUILD_TASK>>
450
+ # schema_ref: <<BUILD_SCHEMA_REF>>
451
+ # response_schema_ref: <<BUILD_RESPONSE_SCHEMA_REF>>
452
+ # comply_scenario: <<BUILD_COMPLY_SCENARIO>>
453
+ # stateful: true
454
+ # sample_request:
455
+ # message: <<MESSAGE_BRIEF>>
456
+ # target_format_id:
457
+ # agent_url: <<TARGET_FORMAT_ID.agent_url>>
458
+ # id: <<TARGET_FORMAT_ID.id>>
459
+ # account:
460
+ # brand: { domain: "<<BRAND_DOMAIN>>" }
461
+ # operator: "<<OPERATOR_DOMAIN>>"
462
+ # quality: "draft"
463
+ # include_preview: true
464
+ # idempotency_key: "$generate:uuid_v4#<<IDEMPOTENCY_PREFIX>>_build_substitution_probe_creative"
465
+ # context: { correlation_id: "<<CORRELATION_ID_PREFIX>>--build_substitution_probe_creative" }
466
+ #
467
+ # - id: expect_substitution_safe
468
+ # task: expect_substitution_safe
469
+ # requires_contract: substitution_observer_runner
470
+ # source: html_inline
471
+ # source_path: "/creative_manifest/preview_html"
472
+ # macro_template: <<TEMPLATE_URL>>
473
+ # # LOAD-BEARING: Setting `require_every_binding_observed: false` bypasses
474
+ # # the silent-strip detection called out in the #2647 security review —
475
+ # # a seller that emits `?sku=` (empty value) instead of substituting the
476
+ # # macro passes the test with zero observed bindings. Only legitimate
477
+ # # when partial-catalog preview is a documented specialism feature AND
478
+ # # the narrative explicitly justifies the deviation.
479
+ # require_every_binding_observed: true
480
+ # catalog_bindings:
481
+ # - { macro: "{SKU}", catalog_item_id: "reserved_char_breakout", vector_name: "reserved-character-breakout" }
482
+ # - { macro: "{SKU}", catalog_item_id: "nested_expansion", vector_name: "nested-expansion-preserved-as-literal" }
483
+ # - { macro: "{SKU}", catalog_item_id: "non_ascii", vector_name: "non-ascii-utf8-percent-encoding" }
484
+ # # Add the corresponding bindings when items above are expanded.
485
+
486
+ # --- @adcp/client primitives the runner consumes ---
487
+ #
488
+ # The runner does NOT reimplement HTML parsing, URL extraction, or the RFC
489
+ # 3986 encoding check. It consumes library primitives so production code
490
+ # paths match conformance paths.
491
+ #
492
+ # The library surface is deliberately split into `observer/` (runner-side)
493
+ # and `encoder/` (seller-side) modules sharing RFC 3986 primitives
494
+ # underneath. Runners import only observer/; sellers implementing the
495
+ # #2620 rule import only encoder/. Premature coupling is avoided.
496
+
497
+ client_primitives:
498
+ substitution_observer:
499
+ reference: SubstitutionObserver
500
+ methods:
501
+ - "parse_html(html: string) -> TrackerUrlRecord[]"
502
+ - "fetch_and_parse(url: URL) -> Promise<TrackerUrlRecord[]>"
503
+ - "match_bindings(records: TrackerUrlRecord[], template: URL, bindings: CatalogBinding[]) -> BindingMatch[]"
504
+ - "assert_rfc3986_safe(match: BindingMatch) -> AssertionResult"
505
+ - "assert_no_nested_expansion(match: BindingMatch, prohibited_pattern: RegExp) -> AssertionResult"
506
+ - "assert_scheme_preserved(match: BindingMatch, template_scheme: string) -> AssertionResult"
507
+ - "enforce_ssrf_policy(url: URL, policy: SsrfPolicy) -> PolicyResult"
508
+ proposed_location: "@adcp/client/src/substitution/observer/"
509
+ doc: "To be filed as an adcp-client PR when #2638 lands."
510
+
511
+ encoder_companion:
512
+ # Sibling module for seller-side production use. Shares RFC 3986
513
+ # primitives with observer/ so a single bug fix covers both.
514
+ reference: SubstitutionEncoder
515
+ methods:
516
+ - "encode_for_url_context(raw_value: string) -> string"
517
+ - "reject_if_contains_macro(raw_value: string) -> void | throw"
518
+ proposed_location: "@adcp/client/src/substitution/encoder/"
519
+ doc: "Seller-facing counterpart to observer/. Same library, disjoint API."
520
+
521
+ tracker_url_record:
522
+ reference: TrackerUrlRecord
523
+ shape: |
524
+ {
525
+ url: URL; // parsed URL object
526
+ source_attr: string; // 'href' | 'src' | 'srcset' | 'data-impression-url' | …
527
+ source_tag: string; // 'a' | 'img' | 'iframe' | 'meta' | …
528
+ line_hint: number | null; // best-effort line number in preview HTML
529
+ }
530
+
531
+ catalog_binding:
532
+ reference: CatalogBinding
533
+ shape: |
534
+ {
535
+ macro: string; // e.g., "{GTIN}"
536
+ catalog_item_id: string; // looks up raw_value from preceding
537
+ // sync_catalogs response + fixture
538
+ vector_name: string; // e.g., "reserved-character-breakout"
539
+ raw_value?: string; // optional override (custom vectors)
540
+ expected_encoded?: string; // optional override (custom vectors)
541
+ }
542
+
543
+ # --- Grading decision tree ---
544
+ #
545
+ # A step gated on this contract grades as follows:
546
+ #
547
+ # not_applicable:
548
+ # Runner does not advertise substitution_observer_runner in its
549
+ # capabilities, OR the specialism under test does not expose a preview
550
+ # surface (preview_html, preview_url, or equivalent). Recorded as
551
+ # not_applicable with a reason; does NOT contribute to the pass rate.
552
+ #
553
+ # pass:
554
+ # Every declared binding in `catalog_bindings` (when
555
+ # require_every_binding_observed is true — the default) is observed at
556
+ # an aligned macro position, each byte-equal (under hex_case_policy) to
557
+ # the fixture's `expected_encoded` for that vector. The nested-expansion
558
+ # vector additionally passes `nested_expansion_not_re_scanned`.
559
+ #
560
+ # fail with `substitution_encoding_violation`:
561
+ # At least one binding's observed value differs from expected_encoded.
562
+ # Runner MUST include the binding, the observed URL, the offending byte
563
+ # offset, and the expected encoding in the error report.
564
+ #
565
+ # fail with `nested_macro_re_expansion`:
566
+ # The nested-expansion-preserved-as-literal vector's macro position
567
+ # contains any byte sequence that resolves as a second-round AdCP
568
+ # macro. Includes the resolved macro name and its unexpected value.
569
+ #
570
+ # fail with `substitution_scheme_injection`:
571
+ # A binding at an href-whole-value position produced an observed URL
572
+ # whose scheme differs from the template's scheme. Includes the
573
+ # template scheme, observed scheme, and binding.
574
+ #
575
+ # fail with `substitution_binding_missing`:
576
+ # `require_every_binding_observed: true` (default) and one or more
577
+ # bindings are not present in the extracted URLs. Catches a seller
578
+ # that silently drops the macro.
579
+ #
580
+ # fail with `preview_source_unavailable`:
581
+ # The configured `source_path` resolves to null or an empty string in
582
+ # the observed response. The seller's preview shape does not satisfy
583
+ # the contract; specialism MAY grade not_applicable if the agent does
584
+ # not advertise preview support.
585
+ #
586
+ # fail with `preview_url_unusable`:
587
+ # The url_fetch path failed. Sub-reason set to one of http_status,
588
+ # content_type, size_exceeded, redirect_returned, ssrf_blocked, or
589
+ # fetch_timeout. `ssrf_blocked` includes the specific policy rule id
590
+ # (e.g., `hosts_denied_ipv4_cidrs:169.254.0.0/16`) so runner operators
591
+ # can distinguish grader-policy failures from seller bugs.
592
+
593
+ # --- Error-report payload handling ---
594
+ #
595
+ # Canonical fixture vectors in attacker_value_catalog.canonical_vector_names
596
+ # are public — runners MAY echo raw_value and expected_encoded verbatim in
597
+ # error reports, logs, and grader telemetry.
598
+ #
599
+ # CUSTOM vectors (a storyboard author inlining their own raw_value /
600
+ # expected_encoded for a seller-specific payload) MUST be redacted in error
601
+ # reports: runners MUST replace the raw_value with a SHA-256 hex digest
602
+ # prefixed `sha256:` UNLESS the grader was started with an explicit
603
+ # --include-raw-payloads flag (default-off, disabled in AdCP Verified).
604
+ # This prevents CI logs from becoming a searchable repository of seller-
605
+ # reported attack payloads.
606
+
607
+ error_report_payload_policy:
608
+ canonical_vectors: echo_verbatim
609
+ custom_vectors: redact_to_sha256_unless_flag
610
+ grader_flag_name: "--include-raw-payloads"
611
+ grader_flag_default: false
612
+ verified_mode: flag_disabled
613
+
614
+ # --- Out of scope v1 ---
615
+ #
616
+ # The following are deliberate non-goals for the initial contract:
617
+ #
618
+ # - Macros outside the catalog-item class. Trusted macros (MEDIA_BUY_ID,
619
+ # DEVICE_ID, GEO) are not observed by this contract. Extension to a
620
+ # universal URL-encoding check across all macros is tracked as a
621
+ # potential 3.2+ scope, not v1.
622
+ #
623
+ # - HTML-attribute context assertions for non-URL-bearing attributes.
624
+ # This contract DOES extract from URL-bearing attributes (the
625
+ # `html_attribute_extraction_set` above) because those are the
626
+ # substitution surfaces #2620 governs. Non-URL attribute contexts —
627
+ # e.g., `<div data-title="{PRODUCT_TITLE}">` where the value goes into
628
+ # a text context, not a URL context — are the publisher's
629
+ # HTML-attribute-escaping responsibility and out of AdCP's scope per
630
+ # the #2620 rule text. A runner that detects a catalog value in a
631
+ # non-URL attribute SHOULD warn but MUST NOT fail.
632
+ #
633
+ # - VAST XML bodies. VAST macros use [SQUARE_BRACKETS] and resolve in
634
+ # the player, not in AdCP. Runners MAY extract tracker URLs from VAST
635
+ # CDATA blocks for the AdCP-macro check but MUST NOT assert on VAST
636
+ # macro substitution.
637
+ #
638
+ # - Non-preview surfaces (post-impression log introspection, direct
639
+ # ad-server querying). Those require a different contract — not this
640
+ # one — and are a separate 3.2+ RFC.
641
+ #
642
+ # - Preview/serve code-path equivalence. This contract assumes the
643
+ # preview renderer shares substitution implementation with the
644
+ # impression-time renderer. Sellers with divergent paths (a separate
645
+ # serving tier, a compiled-ahead-of-time preview cache, etc.) MAY
646
+ # pass preview conformance while failing at serve time. Post-impression
647
+ # log introspection (above) is the complementary check. AdCP Verified
648
+ # grading SHOULD require sellers to attest to shared-path
649
+ # implementation; until that attestation exists, this contract's
650
+ # coverage claim is scoped to the preview surface only.
651
+ #
652
+ # - Script-emitted substitution. Tracker URLs written to the document
653
+ # via <script> content (document.write, innerHTML, attachShadow) are
654
+ # not extracted by `html_inline` or `url_fetch`. A seller hiding
655
+ # substitution inside script text is not caught by v1; the runner
656
+ # treats script text as opaque (see `html_attribute_extraction_set`
657
+ # above).
658
+
659
+ # --- Scope summary (machine-readable) ---
660
+
661
+ scope:
662
+ in_scope:
663
+ - catalog_item_macro_substitution
664
+ - url_contexts_impression_click_vast_landing
665
+ - preview_html_observation
666
+ - preview_url_fetch_observation_with_ssrf_policy
667
+ - html_attribute_extraction_bounded_set
668
+ - rfc3986_unreserved_only_byte_comparison
669
+ - nested_macro_expansion_prohibition
670
+ - url_scheme_preservation_at_whole_value_position
671
+ out_of_scope:
672
+ - non_catalog_macros
673
+ - non_url_html_attribute_contexts
674
+ - vast_xml_macro_substitution
675
+ - post_impression_log_introspection
676
+ - preview_serve_code_path_equivalence
677
+ - script_emitted_substitution
678
+
679
+ # --- References ---
680
+
681
+ references:
682
+ spec: docs/creative/universal-macros.mdx#substitution-safety-catalog-item-macros
683
+ upstream_rule_pr: "#2620"
684
+ contract_rfc: "#2638"
685
+ consumer_coverage_rfc: "#2640"
686
+ unit_test_fixture: static/test-vectors/catalog-macro-substitution.json
687
+ sibling_contract_webhook: static/compliance/source/test-kits/webhook-receiver-runner.yaml
688
+ sibling_contract_signed_requests: static/compliance/source/test-kits/signed-requests-runner.yaml