@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.
- package/compliance/cache/3.1.0-rc.2/domains/brand/index.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/distributed_brand_resolution.yaml +415 -0
- package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/single_side_trust_extension.yaml +454 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/index.yaml +339 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/billing_out_of_band.yaml +153 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/canonical_supported_formats.yaml +212 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/native_in_feed.yaml +543 -0
- package/compliance/cache/3.1.0-rc.2/domains/governance/index.yaml +682 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/index.yaml +789 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/audience_buy_flow.yaml +380 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/available_actions.yaml +565 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/canonical_formats.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/create_media_buy_async.yaml +234 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_reception.yaml +247 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/delivery_reporting.yaml +357 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment.yaml +633 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/event_dedup_flow.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_approved.yaml +214 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_conditions.yaml +199 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/invalid_transitions.yaml +289 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_accountability.yaml +244 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow.yaml +428 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/product_signal_targeting.yaml +373 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_enforcement.yaml +517 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/reach_buy_flow.yaml +823 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.1.0-rc.2/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.1.0-rc.2/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.1.0-rc.2/index.json +356 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/index.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/distributed_brand_resolution.yaml +415 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/single_side_trust_extension.yaml +454 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/index.yaml +339 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/billing_out_of_band.yaml +153 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/canonical_supported_formats.yaml +212 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/native_in_feed.yaml +543 -0
- package/compliance/cache/3.1.0-rc.2/protocols/governance/index.yaml +682 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/index.yaml +789 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/audience_buy_flow.yaml +380 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/available_actions.yaml +565 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/canonical_formats.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/create_media_buy_async.yaml +234 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_reception.yaml +247 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/delivery_reporting.yaml +357 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment.yaml +633 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/event_dedup_flow.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_approved.yaml +214 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_conditions.yaml +199 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/invalid_transitions.yaml +289 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_accountability.yaml +244 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow.yaml +428 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/product_signal_targeting.yaml +373 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_enforcement.yaml +517 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/reach_buy_flow.yaml +823 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.1.0-rc.2/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.1.0-rc.2/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/audience-sync/index.yaml +313 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/scenarios/governance_denied.yaml +226 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-ad-server/index.yaml +409 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/generative-seller.yaml +807 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/index.yaml +758 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-template/index.yaml +510 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/index.yaml +143 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +117 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-broadcast-tv/index.yaml +738 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-catalog-driven/index.yaml +840 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-guaranteed/index.yaml +601 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-non-guaranteed/index.yaml +546 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-proposal-mode/index.yaml +586 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-social/index.yaml +919 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/index.yaml +424 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/scenarios/governance_denied.yaml +210 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-owned/index.yaml +317 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sponsored-intelligence/index.yaml +59 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor-live.yaml +78 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor.yaml +223 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/billing-gate-runner.yaml +115 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/distributed-brand-runner.yaml +281 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/parallel-dispatch-runner.yaml +196 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/rate-limit-trip-runner.yaml +172 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/single-side-trust-runner.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/substitution-observer-runner.yaml +688 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/README.md +220 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.1.0-rc.2/universal/billing-gate-dispatch.yaml +450 -0
- package/compliance/cache/3.1.0-rc.2/universal/canonical-format-validate-input.yaml +640 -0
- package/compliance/cache/3.1.0-rc.2/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.1.0-rc.2/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.1.0-rc.2/universal/comply-controller-mode-gate.yaml +141 -0
- package/compliance/cache/3.1.0-rc.2/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.1.0-rc.2/universal/deterministic-testing.yaml +1430 -0
- package/compliance/cache/3.1.0-rc.2/universal/error-compliance-signals.yaml +377 -0
- package/compliance/cache/3.1.0-rc.2/universal/error-compliance.yaml +528 -0
- package/compliance/cache/3.1.0-rc.2/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/universal/get-signals-pagination-integrity.yaml +210 -0
- package/compliance/cache/3.1.0-rc.2/universal/idempotency.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-event-scope.yaml +119 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-lifecycle.yaml +337 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-rejections.yaml +107 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-creative-formats.yaml +265 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-list-accounts.yaml +245 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.1.0-rc.2/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/universal/read-tool-idempotency.yaml +405 -0
- package/compliance/cache/3.1.0-rc.2/universal/runner-output-contract.yaml +1285 -0
- package/compliance/cache/3.1.0-rc.2/universal/schema-validation-signals.yaml +181 -0
- package/compliance/cache/3.1.0-rc.2/universal/schema-validation.yaml +548 -0
- package/compliance/cache/3.1.0-rc.2/universal/security.yaml +539 -0
- package/compliance/cache/3.1.0-rc.2/universal/signed-requests.yaml +217 -0
- package/compliance/cache/3.1.0-rc.2/universal/stale-response-advisory.yaml +295 -0
- package/compliance/cache/3.1.0-rc.2/universal/storyboard-schema.yaml +2194 -0
- package/compliance/cache/3.1.0-rc.2/universal/v3-envelope-integrity.yaml +117 -0
- package/compliance/cache/3.1.0-rc.2/universal/version-negotiation.yaml +130 -0
- package/compliance/cache/3.1.0-rc.2/universal/webhook-emission.yaml +411 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-bulk-webhooks.yaml +82 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-product-webhooks.yaml +83 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-products.yaml +151 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signal-webhooks.yaml +83 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signals.yaml +149 -0
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +9 -5
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/storyboard/default-invariants.js +30 -1
- package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +84 -21
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +21 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/types.d.ts +9 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.d.ts +6707 -12040
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +1 -1
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/utils/signal-id-builders.d.ts +19 -0
- package/dist/lib/utils/signal-id-builders.d.ts.map +1 -1
- package/dist/lib/utils/signal-id-builders.js +30 -0
- package/dist/lib/utils/signal-id-builders.js.map +1 -1
- package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -1
- package/dist/lib/utils/tool-request-schemas.js +3 -0
- package/dist/lib/utils/tool-request-schemas.js.map +1 -1
- package/dist/lib/v2/projection/constants.d.ts +28 -0
- package/dist/lib/v2/projection/constants.d.ts.map +1 -0
- package/dist/lib/v2/projection/constants.js +31 -0
- package/dist/lib/v2/projection/constants.js.map +1 -0
- package/dist/lib/v2/projection/registry.d.ts.map +1 -1
- package/dist/lib/v2/projection/registry.js +9 -4
- package/dist/lib/v2/projection/registry.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/package.json +1 -1
- package/skills/SHAPE-GOTCHAS.md +5 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
id: v3_envelope_integrity
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "v3 envelope integrity — no legacy status fields"
|
|
4
|
+
category: schema_validation
|
|
5
|
+
summary: "v3 protocol envelopes MUST NOT carry task_status or response_status — v2 legacy field names that have no semantics in v3."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools: [] # protocol-level: get_adcp_capabilities is mandatory for all agents
|
|
8
|
+
|
|
9
|
+
narrative: |
|
|
10
|
+
AdCP 3.0 normalises all task lifecycle state onto a single `status` field (values
|
|
11
|
+
defined in the task-status enum). The v2 `task_status` and `response_status` field
|
|
12
|
+
names have no semantics in v3 — carrying them on a v3 envelope is a normative
|
|
13
|
+
MUST NOT per the migration guide, task-lifecycle.mdx, and the protocol-envelope
|
|
14
|
+
schema. See docs/reference/migration/index.mdx and
|
|
15
|
+
docs/building/implementation/task-lifecycle.mdx.
|
|
16
|
+
|
|
17
|
+
This storyboard documents the machine-check assertion and asserts the canonical v3
|
|
18
|
+
`status` field is present using the `envelope_field_present` check type, which
|
|
19
|
+
walks the protocol envelope rather than the inner response schema. The explicit
|
|
20
|
+
envelope-root field-absence checks assert that task_status and response_status are
|
|
21
|
+
absent using `envelope_field_absent`; protocol-envelope.json carries the matching
|
|
22
|
+
top-level `not: { anyOf: [{ required: [task_status] }, { required:
|
|
23
|
+
[response_status] }] }` schema constraint.
|
|
24
|
+
|
|
25
|
+
Scope: envelope top-level only. Domain data inside `payload` (e.g., a reporting
|
|
26
|
+
row carrying a field named task_status) is outside this prohibition and is not
|
|
27
|
+
checked here.
|
|
28
|
+
|
|
29
|
+
agent:
|
|
30
|
+
interaction_model: "*" # applies to every agent regardless of protocol or specialism
|
|
31
|
+
examples:
|
|
32
|
+
- "Any AdCP agent (seller, signals, creative, retail media, SI, governance)"
|
|
33
|
+
|
|
34
|
+
caller:
|
|
35
|
+
role: buyer_agent
|
|
36
|
+
example: "Compliance test harness"
|
|
37
|
+
|
|
38
|
+
prerequisites:
|
|
39
|
+
description: |
|
|
40
|
+
No test-kit credentials required. get_adcp_capabilities is a public operation
|
|
41
|
+
that every AdCP agent must expose without authentication.
|
|
42
|
+
|
|
43
|
+
phases:
|
|
44
|
+
- id: envelope_integrity_check
|
|
45
|
+
title: "v3 envelope must not carry legacy v2 status field names"
|
|
46
|
+
narrative: |
|
|
47
|
+
Call get_adcp_capabilities and verify the response envelope carries the
|
|
48
|
+
canonical v3 status field and omits the legacy v2 field names
|
|
49
|
+
task_status and response_status.
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
- id: no_legacy_status_fields
|
|
53
|
+
title: "Envelope carries canonical v3 status; no legacy v2 status field names"
|
|
54
|
+
narrative: |
|
|
55
|
+
get_adcp_capabilities is the lightest call every agent supports and
|
|
56
|
+
requires no credentials. The response envelope must carry the canonical
|
|
57
|
+
v3 `status` field and must not carry task_status or response_status.
|
|
58
|
+
The protocol-envelope.json schema's top-level `not: { anyOf: [...] }`
|
|
59
|
+
constraint forbids either field, making this constraint detectable by
|
|
60
|
+
any schema-aware validator without runner-specific primitives.
|
|
61
|
+
|
|
62
|
+
MCP transport note: the `status` field must appear at the top level of
|
|
63
|
+
`structuredContent` (or the first parseable `content[].text` JSON object
|
|
64
|
+
for older MCP servers) — it is NOT a JSON-RPC result-level field. The extracted AdCP
|
|
65
|
+
response IS the protocol envelope: `status` lives alongside task-specific
|
|
66
|
+
payload fields in the same flat object. The `get-adcp-capabilities-response.json`
|
|
67
|
+
schema validates only the task-specific fields (capabilities, context echo,
|
|
68
|
+
etc.) and does not cover protocol envelope fields like `status` — an agent
|
|
69
|
+
whose MCP response passes response_schema validation but omits `status` is
|
|
70
|
+
still non-conformant. See docs/building/implementation/mcp-response-extraction
|
|
71
|
+
for the normative MCP extraction algorithm and the expected structuredContent
|
|
72
|
+
shape, including the required `status` field at the top level.
|
|
73
|
+
task: get_adcp_capabilities
|
|
74
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
75
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
76
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
77
|
+
comply_scenario: envelope_integrity
|
|
78
|
+
stateful: false
|
|
79
|
+
expected: |
|
|
80
|
+
Response envelope (all transports):
|
|
81
|
+
- MUST contain status (the v3 canonical field)
|
|
82
|
+
- MUST NOT contain task_status (v2 legacy, no v3 semantics)
|
|
83
|
+
- MUST NOT contain response_status (v2 legacy, no v3 semantics)
|
|
84
|
+
Both forbidden fields are blocked by the top-level `not: { anyOf: [...] }`
|
|
85
|
+
constraint in protocol-envelope.json, so any schema-aware validator that
|
|
86
|
+
validates the full protocol envelope will detect violations.
|
|
87
|
+
|
|
88
|
+
For MCP agents specifically: `status` MUST be present at the top level of
|
|
89
|
+
structuredContent (or the first parseable content[].text JSON object). It is not a JSON-RPC sibling
|
|
90
|
+
field — it lives inside the content payload, at the same level as the
|
|
91
|
+
task-specific response fields. An agent returning only the task payload
|
|
92
|
+
without `status` fails this check regardless of whether the payload itself
|
|
93
|
+
validates against the task response schema.
|
|
94
|
+
|
|
95
|
+
sample_request:
|
|
96
|
+
context:
|
|
97
|
+
correlation_id: "v3_envelope_integrity--no_legacy_status"
|
|
98
|
+
|
|
99
|
+
validations:
|
|
100
|
+
- check: response_schema
|
|
101
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
102
|
+
- check: envelope_field_present
|
|
103
|
+
path: "status"
|
|
104
|
+
description: "Envelope carries the canonical v3 status field"
|
|
105
|
+
- check: envelope_field_absent
|
|
106
|
+
path: "task_status"
|
|
107
|
+
description: "Envelope root MUST NOT carry task_status (v2 legacy; no v3 semantics)"
|
|
108
|
+
- check: envelope_field_absent
|
|
109
|
+
path: "response_status"
|
|
110
|
+
description: "Envelope root MUST NOT carry response_status (v2 legacy; no v3 semantics)"
|
|
111
|
+
- check: field_present
|
|
112
|
+
path: "context"
|
|
113
|
+
description: "Response echoes back the context object"
|
|
114
|
+
- check: field_value
|
|
115
|
+
path: "context.correlation_id"
|
|
116
|
+
value: "v3_envelope_integrity--no_legacy_status"
|
|
117
|
+
description: "Context correlation_id returned unchanged"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
id: version_negotiation
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Release-precision version negotiation"
|
|
4
|
+
category: version_negotiation
|
|
5
|
+
summary: "Sellers advertise supported releases on capabilities and echo the served release on every response."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools: [] # protocol-level: get_adcp_capabilities is mandatory for all agents
|
|
8
|
+
|
|
9
|
+
narrative: |
|
|
10
|
+
AdCP 3.1 introduces release-precision (VERSION.RELEASE, e.g. "3.1") version
|
|
11
|
+
negotiation alongside the legacy major-precision (`adcp_major_version` integer)
|
|
12
|
+
carried since 3.0. Both directions of the negotiation are SHOULD-level through
|
|
13
|
+
3.x and graduate to MUST at 4.0 — this storyboard exercises both halves so
|
|
14
|
+
sellers can discover gaps before the 3.2 grader cutover flips advisory results
|
|
15
|
+
to blocking failures.
|
|
16
|
+
|
|
17
|
+
Two checks ride on a single get_adcp_capabilities call:
|
|
18
|
+
|
|
19
|
+
1. **Seller advertises** `adcp.supported_versions` — an array of release-precision
|
|
20
|
+
strings the seller speaks. Authoritative for buyer-side pinning; the legacy
|
|
21
|
+
`adcp.major_versions` integer array remains required through 3.x for
|
|
22
|
+
backwards compatibility.
|
|
23
|
+
|
|
24
|
+
2. **Seller echoes** `adcp_version` at the envelope root — the release the seller
|
|
25
|
+
actually served. Buyers SHOULD validate the response against the echoed
|
|
26
|
+
release's schema, not against their own pin. Legacy 3.0 sellers that don't
|
|
27
|
+
read the field omit the echo (`additionalProperties: true` makes the field
|
|
28
|
+
invisible to them) — buyers fall back to their constructor pin.
|
|
29
|
+
|
|
30
|
+
Per the [migration table](/docs/reference/versioning#migration-timeline), both
|
|
31
|
+
surfaces are advisory at 3.1 and become blocking failure at 3.2. The advisory
|
|
32
|
+
marker on each validation makes that promotion a single-PR change at 3.2 cut
|
|
33
|
+
rather than a per-adopter compliance break at the boundary.
|
|
34
|
+
|
|
35
|
+
Scope: protocol envelope and capabilities advertisement only. The
|
|
36
|
+
`VERSION_UNSUPPORTED` error path (buyer pins a release outside the seller's
|
|
37
|
+
`supported_versions`) is exercised separately by error_compliance — running it
|
|
38
|
+
here requires the runner to send a deliberately-mismatched pin and is left to
|
|
39
|
+
follow-up.
|
|
40
|
+
|
|
41
|
+
agent:
|
|
42
|
+
interaction_model: "*" # applies to every agent regardless of protocol or specialism
|
|
43
|
+
examples:
|
|
44
|
+
- "Any AdCP agent (seller, signals, creative, retail media, SI, governance)"
|
|
45
|
+
|
|
46
|
+
caller:
|
|
47
|
+
role: buyer_agent
|
|
48
|
+
example: "Compliance test harness"
|
|
49
|
+
|
|
50
|
+
prerequisites:
|
|
51
|
+
description: |
|
|
52
|
+
No test-kit credentials required. get_adcp_capabilities is a public operation
|
|
53
|
+
that every AdCP agent must expose without authentication.
|
|
54
|
+
|
|
55
|
+
phases:
|
|
56
|
+
- id: capabilities_advertise_and_echo
|
|
57
|
+
title: "Capabilities advertise supported_versions; response echoes adcp_version"
|
|
58
|
+
narrative: |
|
|
59
|
+
Call get_adcp_capabilities. The single response carries both halves of the
|
|
60
|
+
negotiation contract — `adcp.supported_versions` in the body (seller's
|
|
61
|
+
advertisement) and `adcp_version` on the envelope (seller's echo of what
|
|
62
|
+
it served). Sellers SHOULD populate both at 3.1; the grader reports
|
|
63
|
+
missing entries as advisory findings without failing certification.
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- id: get_capabilities_with_version
|
|
67
|
+
title: "Verify seller advertises supported_versions and echoes adcp_version"
|
|
68
|
+
narrative: |
|
|
69
|
+
The runner emits `adcp_version` on the request envelope based on its
|
|
70
|
+
configured pin (the SDK's release-precision constructor option). The
|
|
71
|
+
seller honors the pin within the resolution algorithm in
|
|
72
|
+
docs/reference/versioning.mdx, echoes the served release on the response
|
|
73
|
+
envelope, and lists every release it speaks under
|
|
74
|
+
`adcp.supported_versions` in the response body.
|
|
75
|
+
|
|
76
|
+
A seller serving only 3.0 (no awareness of the new fields) passes the
|
|
77
|
+
request schema unchanged — `adcp_version` rides on the envelope and is
|
|
78
|
+
invisible to readers that don't look for it. The advisory checks below
|
|
79
|
+
will report missing `supported_versions` advertisement and missing
|
|
80
|
+
envelope echo without failing the step.
|
|
81
|
+
task: get_adcp_capabilities
|
|
82
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
83
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
84
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
85
|
+
comply_scenario: version_negotiation
|
|
86
|
+
stateful: false
|
|
87
|
+
expected: |
|
|
88
|
+
Response carries both halves of the negotiation contract:
|
|
89
|
+
- Body: adcp.supported_versions (array of release-precision strings, e.g.
|
|
90
|
+
["3.0", "3.1"]) declaring every release the seller speaks. Authoritative
|
|
91
|
+
for buyer-side pinning. SHOULD at 3.1, MUST at 4.0.
|
|
92
|
+
- Envelope: adcp_version (release-precision string) echoing the release
|
|
93
|
+
the seller actually served. SHOULD at 3.1, MUST at 4.0. Buyers SHOULD
|
|
94
|
+
validate the response against the echoed release's schema.
|
|
95
|
+
|
|
96
|
+
Legacy `adcp.major_versions` (integer array) remains required through 3.x.
|
|
97
|
+
|
|
98
|
+
sample_request:
|
|
99
|
+
context:
|
|
100
|
+
correlation_id: "version_negotiation--get_capabilities_with_version"
|
|
101
|
+
|
|
102
|
+
validations:
|
|
103
|
+
- check: response_schema
|
|
104
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
105
|
+
|
|
106
|
+
- check: field_present
|
|
107
|
+
path: "adcp.major_versions"
|
|
108
|
+
description: "Legacy major-precision advertisement present (required through 3.x)"
|
|
109
|
+
|
|
110
|
+
- check: field_present
|
|
111
|
+
path: "adcp.supported_versions"
|
|
112
|
+
severity: advisory
|
|
113
|
+
permanent_advisory:
|
|
114
|
+
reason: "Per docs/reference/versioning.mdx > Migration timeline, sellers SHOULD declare supported_versions at 3.1 and the compliance grader reports presence as advisory. At 3.2 the storyboard cut promotes this validation to required (manual flip — not gated on runner_capability_version because the 3.2 boundary is a protocol-spec cutover, not a runner-capability cutover). 4.0 promotes to MUST per the spec. Marking permanent_advisory here is a deliberate use of the field to defer promotion to the 3.2 storyboard PR rather than relying on the expires_after_version semver gate."
|
|
115
|
+
description: "Seller advertises release-precision supported_versions (advisory at 3.1, required at 3.2)"
|
|
116
|
+
|
|
117
|
+
- check: field_present
|
|
118
|
+
path: "adcp_version"
|
|
119
|
+
severity: advisory
|
|
120
|
+
permanent_advisory:
|
|
121
|
+
reason: "Per docs/reference/versioning.mdx > Migration timeline, sellers SHOULD echo adcp_version at 3.1 and the compliance grader reports presence as advisory. At 3.2 the storyboard cut promotes this validation to required (manual flip — see the supported_versions check above for the same rationale). 4.0 promotes to MUST per the spec."
|
|
122
|
+
description: "Seller echoes adcp_version on the response envelope (advisory at 3.1, required at 3.2)"
|
|
123
|
+
|
|
124
|
+
- check: field_present
|
|
125
|
+
path: "context"
|
|
126
|
+
description: "Response echoes back the context object"
|
|
127
|
+
- check: field_value
|
|
128
|
+
path: "context.correlation_id"
|
|
129
|
+
value: "version_negotiation--get_capabilities_with_version"
|
|
130
|
+
description: "Context correlation_id returned unchanged"
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
id: webhook_emission
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Webhook emission — outbound webhook conformance (signing + idempotency)"
|
|
4
|
+
category: core
|
|
5
|
+
summary: "Any agent that emits webhooks MUST carry a stable idempotency_key across retries and — when the buyer has not opted into the deprecated HMAC fallback — MUST sign deliveries under the RFC 9421 webhook profile. Graded by a runner hosting a webhook receiver during storyboard execution."
|
|
6
|
+
track: core
|
|
7
|
+
|
|
8
|
+
narrative: |
|
|
9
|
+
Webhook emission is a cross-cutting capability, not a specialism. Sellers emit
|
|
10
|
+
webhooks on `create_media_buy` status changes. Rights agents emit revocation
|
|
11
|
+
notifications. Governance agents emit `collection_list_changed` and
|
|
12
|
+
`property_list_changed`. Content-standards agents emit artifact webhooks.
|
|
13
|
+
Every agent that accepts `push_notification_config` on any operation is in
|
|
14
|
+
scope for this universal — no capability flag, no opt-in.
|
|
15
|
+
|
|
16
|
+
Two load-bearing conformance requirements apply to every outbound webhook:
|
|
17
|
+
|
|
18
|
+
1. **`idempotency_key` is present on every payload and stable across retries.**
|
|
19
|
+
Required by adcontextprotocol/adcp#2417. Receivers dedupe on this field;
|
|
20
|
+
a sender that regenerates the key on retry breaks at-least-once delivery
|
|
21
|
+
semantics and creates duplicate side effects downstream.
|
|
22
|
+
|
|
23
|
+
2. **RFC 9421 webhook signing is baseline in 3.0** unless the buyer opts into
|
|
24
|
+
the deprecated HMAC fallback via `push_notification_config.authentication`.
|
|
25
|
+
Required by adcontextprotocol/adcp#2423. Signatures carry
|
|
26
|
+
`tag="adcp/webhook-signing/v1"`, cover `content-digest`, and verify
|
|
27
|
+
against the seller's brand.json-published JWKS.
|
|
28
|
+
|
|
29
|
+
Grading is observable-behavior only. The runner hosts a webhook receiver per
|
|
30
|
+
the contract at `test-kits/webhook-receiver-runner.yaml`, drives storyboards
|
|
31
|
+
that trigger webhooks from whatever operations the agent advertises, and
|
|
32
|
+
asserts on what the agent sends back.
|
|
33
|
+
|
|
34
|
+
This universal grades not_applicable when the runner does not host a webhook
|
|
35
|
+
receiver (e.g., lint-only runs against an agent that has no webhook-emitting
|
|
36
|
+
operations, or runs where the operator has not configured the receiver
|
|
37
|
+
contract).
|
|
38
|
+
|
|
39
|
+
**9421 is the on-ramp.** Any agent advertising webhook-emitting operations
|
|
40
|
+
MUST publish a `webhook-signing` JWKS at its `brand.json` `agents[].jwks_uri`
|
|
41
|
+
and MUST emit valid 9421 signatures when triggered with no `authentication`
|
|
42
|
+
block on `push_notification_config`. Agents without published signing keys
|
|
43
|
+
fail the `signing_keys_published` precheck before the signature phase runs;
|
|
44
|
+
agents with keys but invalid signatures fail `signature_validity`. The
|
|
45
|
+
deprecated HMAC fallback remains a buyer-side registration option in 3.x
|
|
46
|
+
(`push_notification_config.authentication`), but it is not a path that
|
|
47
|
+
exempts the agent from publishing 9421 keys — the runner registers as a
|
|
48
|
+
9421-default buyer, and the agent is graded on what it does in that mode.
|
|
49
|
+
This closes the on-ramp loophole that previously let agents self-declare
|
|
50
|
+
themselves out of the signing phase via `webhook_auth_mode == 'hmac_legacy'`.
|
|
51
|
+
|
|
52
|
+
**Clean seam**: the runner does NOT reimplement signature verification or
|
|
53
|
+
idempotency dedup. It delegates to `@adcp/client` primitives —
|
|
54
|
+
`AsyncHandlerConfig.webhookDedup`, `WebhookMetadata.idempotency_key`, and
|
|
55
|
+
the 9421 webhook verifier once that lands in the client library. The same
|
|
56
|
+
code that production receivers rely on is what the conformance runner
|
|
57
|
+
exercises; a single bug fix in the library covers both surfaces.
|
|
58
|
+
|
|
59
|
+
agent:
|
|
60
|
+
interaction_model: webhook_emitter
|
|
61
|
+
capabilities:
|
|
62
|
+
- emits_webhooks
|
|
63
|
+
examples:
|
|
64
|
+
- "Any AdCP seller that accepts push_notification_config on create_media_buy, update_media_buy, or equivalent async operations"
|
|
65
|
+
- "Rights agents that post revocation notifications"
|
|
66
|
+
- "Governance agents that emit collection_list_changed or property_list_changed webhooks"
|
|
67
|
+
- "Content-standards agents that emit artifact webhooks"
|
|
68
|
+
|
|
69
|
+
caller:
|
|
70
|
+
role: compliance_runner
|
|
71
|
+
example: "AdCP Verified runner with webhook receiver capability"
|
|
72
|
+
|
|
73
|
+
prerequisites:
|
|
74
|
+
description: |
|
|
75
|
+
The runner MUST be configured with a webhook receiver per the contract at
|
|
76
|
+
`test-kits/webhook-receiver-runner.yaml`. The receiver operates in one of
|
|
77
|
+
two modes: `loopback_mock` (intercepts at the `@adcp/client` AsyncHandler
|
|
78
|
+
layer — zero network deps, used for lint runs) or `proxy_url` (operator-
|
|
79
|
+
supplied HTTPS URL routing into the runner — used for AdCP Verified
|
|
80
|
+
grading). Runners without a receiver grade this universal as
|
|
81
|
+
not_applicable.
|
|
82
|
+
|
|
83
|
+
The agent under test MUST advertise the operations it supports in
|
|
84
|
+
`get_adcp_capabilities`. The runner drives whichever webhook-emitting
|
|
85
|
+
operations are advertised; operations the agent does not support are
|
|
86
|
+
skipped cleanly, not graded as failures.
|
|
87
|
+
|
|
88
|
+
Agents advertising webhook-emitting operations MUST publish a JWKS at the
|
|
89
|
+
`jwks_uri` on their brand.json `agents[]` entry containing a key with
|
|
90
|
+
`adcp_use: "webhook-signing"`. The `signing_keys_published` precheck
|
|
91
|
+
asserts this directly; agents without published signing keys fail
|
|
92
|
+
`webhook_signing_keys_unpublished` before the signature phase runs.
|
|
93
|
+
test_kit: "test-kits/webhook-receiver-runner.yaml"
|
|
94
|
+
|
|
95
|
+
phases:
|
|
96
|
+
- id: capability_discovery
|
|
97
|
+
title: "Capability discovery"
|
|
98
|
+
narrative: |
|
|
99
|
+
Discover which async operations the agent supports so the runner knows
|
|
100
|
+
which to drive for webhook emission.
|
|
101
|
+
|
|
102
|
+
steps:
|
|
103
|
+
- id: get_capabilities
|
|
104
|
+
title: "Discover webhook-emitting operations"
|
|
105
|
+
narrative: |
|
|
106
|
+
The runner calls `get_adcp_capabilities` and inspects which async
|
|
107
|
+
operations the agent supports. If the agent advertises none that
|
|
108
|
+
accept `push_notification_config`, this universal does not apply
|
|
109
|
+
and grading returns not_applicable (not a failure).
|
|
110
|
+
task: get_adcp_capabilities
|
|
111
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
112
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
113
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
114
|
+
comply_scenario: capability_discovery
|
|
115
|
+
stateful: false
|
|
116
|
+
expected: |
|
|
117
|
+
Return a capabilities block including supported_protocols. Webhook-
|
|
118
|
+
emitting operations are discovered via the transport handshake
|
|
119
|
+
(MCP tools/list, A2A skills), not the capabilities body; grading
|
|
120
|
+
returns a stable not_applicable marker downstream when no webhook-
|
|
121
|
+
emitting operation resolves through
|
|
122
|
+
$test_kit.operations.primary_webhook_emitter.
|
|
123
|
+
sample_request:
|
|
124
|
+
context:
|
|
125
|
+
correlation_id: "webhook_emission--get_capabilities"
|
|
126
|
+
validations:
|
|
127
|
+
- check: field_present
|
|
128
|
+
path: "supported_protocols"
|
|
129
|
+
description: "Agent declares its supported AdCP protocols"
|
|
130
|
+
|
|
131
|
+
- id: idempotency_key_presence
|
|
132
|
+
title: "Every webhook payload carries idempotency_key"
|
|
133
|
+
narrative: |
|
|
134
|
+
The runner triggers a webhook-emitting operation with a
|
|
135
|
+
push_notification_config pointed at the runner's per-step receiver. The
|
|
136
|
+
first inbound webhook MUST carry an `idempotency_key` matching the
|
|
137
|
+
required pattern (`^[A-Za-z0-9_.:-]{16,255}$`). Absence of the field or
|
|
138
|
+
a pattern mismatch fails the phase.
|
|
139
|
+
|
|
140
|
+
This is the baseline conformance with adcontextprotocol/adcp#2417 —
|
|
141
|
+
receivers cannot dedupe without it, so "I forgot to emit the field" is
|
|
142
|
+
the single highest-impact publisher bug the universal catches.
|
|
143
|
+
|
|
144
|
+
steps:
|
|
145
|
+
- id: trigger_webhook_operation
|
|
146
|
+
title: "Trigger an operation that emits a webhook"
|
|
147
|
+
narrative: |
|
|
148
|
+
Runner calls the first operation the capability block advertises as
|
|
149
|
+
webhook-emitting (typically `create_media_buy` for sales agents,
|
|
150
|
+
`acquire_rights` for rights agents, etc.), passing
|
|
151
|
+
`push_notification_config.url = {{runner.webhook_url:trigger_webhook_operation}}`
|
|
152
|
+
— no `authentication` block (9421 is the baseline for conformance).
|
|
153
|
+
task: "$test_kit.operations.primary_webhook_emitter"
|
|
154
|
+
task_default: create_media_buy
|
|
155
|
+
schema_ref: "$test_kit.schemas.primary_request"
|
|
156
|
+
response_schema_ref: "$test_kit.schemas.primary_response"
|
|
157
|
+
doc_ref: "/building/implementation/webhooks"
|
|
158
|
+
comply_scenario: webhook_trigger
|
|
159
|
+
stateful: false
|
|
160
|
+
sample_request:
|
|
161
|
+
push_notification_config:
|
|
162
|
+
url: "{{runner.webhook_url:trigger_webhook_operation}}"
|
|
163
|
+
idempotency_key: "$generate:uuid_v4#webhook_emission_trigger"
|
|
164
|
+
context:
|
|
165
|
+
correlation_id: "webhook_emission--trigger_webhook_operation"
|
|
166
|
+
expected: |
|
|
167
|
+
Agent accepts the request and begins async execution. Response either
|
|
168
|
+
returns an immediate terminal status (no webhook needed) or an
|
|
169
|
+
interim status indicating async processing (webhook will follow).
|
|
170
|
+
|
|
171
|
+
- id: expect_webhook_presence
|
|
172
|
+
title: "Assert inbound webhook carries a valid idempotency_key"
|
|
173
|
+
narrative: |
|
|
174
|
+
Wait for a webhook at the per-step URL. When it arrives, validate
|
|
175
|
+
the payload against the webhook schema and assert the
|
|
176
|
+
idempotency_key is present and matches the required pattern.
|
|
177
|
+
task: expect_webhook
|
|
178
|
+
triggered_by: trigger_webhook_operation
|
|
179
|
+
filter:
|
|
180
|
+
operation_id: "{{prior_step.trigger_webhook_operation.operation_id}}"
|
|
181
|
+
timeout_seconds: 30
|
|
182
|
+
expect_idempotency_key: true
|
|
183
|
+
webhook_payload_schema_ref: "core/mcp-webhook-payload.json"
|
|
184
|
+
stateful: true
|
|
185
|
+
expected: |
|
|
186
|
+
Webhook arrives within 30 seconds. Payload validates against
|
|
187
|
+
mcp-webhook-payload.json. idempotency_key is present and matches
|
|
188
|
+
the pattern `^[A-Za-z0-9_.:-]{16,255}$`. Any other status fails the
|
|
189
|
+
phase with a specific error code: no_webhook_received,
|
|
190
|
+
schema_violation, missing_idempotency_key, or
|
|
191
|
+
invalid_idempotency_key_format.
|
|
192
|
+
|
|
193
|
+
- id: idempotency_key_stability
|
|
194
|
+
title: "idempotency_key is byte-identical across retries of the same event"
|
|
195
|
+
narrative: |
|
|
196
|
+
The runner's receiver deterministically returns HTTP 503 for the first
|
|
197
|
+
`count` deliveries, then 200. The runner records the idempotency_key on
|
|
198
|
+
every delivery and asserts all recorded keys are byte-identical. A
|
|
199
|
+
sender that regenerates the key on retry breaks at-least-once semantics
|
|
200
|
+
and fails the phase.
|
|
201
|
+
|
|
202
|
+
This is the conformance test that cannot be replaced by schema
|
|
203
|
+
validation — schema validation catches "no key at all" but not "wrong
|
|
204
|
+
key on retry." Only a live observation catches publisher-side retry
|
|
205
|
+
bugs.
|
|
206
|
+
|
|
207
|
+
steps:
|
|
208
|
+
- id: trigger_retry_scenario
|
|
209
|
+
title: "Trigger a webhook that will be retried via 5xx response"
|
|
210
|
+
narrative: |
|
|
211
|
+
Runner calls a webhook-emitting operation with
|
|
212
|
+
push_notification_config.url = {{runner.webhook_url:trigger_retry_scenario}}.
|
|
213
|
+
The runner's receiver at that URL returns 503 for the first 3
|
|
214
|
+
deliveries and 200 afterwards. Any conformant at-least-once sender
|
|
215
|
+
will retry on each 5xx and eventually succeed.
|
|
216
|
+
task: "$test_kit.operations.primary_webhook_emitter"
|
|
217
|
+
task_default: create_media_buy
|
|
218
|
+
schema_ref: "$test_kit.schemas.primary_request"
|
|
219
|
+
response_schema_ref: "$test_kit.schemas.primary_response"
|
|
220
|
+
doc_ref: "/building/implementation/webhooks"
|
|
221
|
+
comply_scenario: webhook_retry_trigger
|
|
222
|
+
stateful: false
|
|
223
|
+
sample_request:
|
|
224
|
+
push_notification_config:
|
|
225
|
+
url: "{{runner.webhook_url:trigger_retry_scenario}}"
|
|
226
|
+
idempotency_key: "$generate:uuid_v4#webhook_emission_retry_trigger"
|
|
227
|
+
context:
|
|
228
|
+
correlation_id: "webhook_emission--trigger_retry_scenario"
|
|
229
|
+
expected: |
|
|
230
|
+
Agent accepts the request and begins async execution. The webhook
|
|
231
|
+
it emits will be rejected with 503 by the runner and retried.
|
|
232
|
+
|
|
233
|
+
- id: expect_key_stable_across_retries
|
|
234
|
+
title: "Assert idempotency_key byte-identical across all deliveries"
|
|
235
|
+
narrative: |
|
|
236
|
+
Runner records every delivery and asserts all recorded keys are
|
|
237
|
+
byte-identical. Requires at least 2 deliveries observed within the
|
|
238
|
+
timeout window — a sender that doesn't retry at all cannot be
|
|
239
|
+
graded on retry stability.
|
|
240
|
+
task: expect_webhook_retry_keys_stable
|
|
241
|
+
triggered_by: trigger_retry_scenario
|
|
242
|
+
filter:
|
|
243
|
+
operation_id: "{{prior_step.trigger_retry_scenario.operation_id}}"
|
|
244
|
+
retry_trigger:
|
|
245
|
+
count: 3
|
|
246
|
+
http_status: 503
|
|
247
|
+
timeout_seconds: 90
|
|
248
|
+
expect_min_deliveries: 2
|
|
249
|
+
stateful: true
|
|
250
|
+
expected: |
|
|
251
|
+
At least 2 deliveries of the same logical event observed within
|
|
252
|
+
90 seconds; all deliveries carry byte-identical idempotency_key.
|
|
253
|
+
Fails with insufficient_retries if fewer than 2 deliveries arrive,
|
|
254
|
+
idempotency_key_rotated if the key changes across deliveries, or
|
|
255
|
+
idempotency_key_format_changed if a later delivery carries a
|
|
256
|
+
different-shaped value.
|
|
257
|
+
|
|
258
|
+
- id: signing_keys_published
|
|
259
|
+
title: "Agent publishes a webhook-signing JWKS at brand.json"
|
|
260
|
+
narrative: |
|
|
261
|
+
Precheck: any agent advertising webhook-emitting operations MUST publish
|
|
262
|
+
a JWKS at the `jwks_uri` on its `brand.json` `agents[]` entry containing
|
|
263
|
+
at least one key with `adcp_use: "webhook-signing"`. This is the on-ramp
|
|
264
|
+
gate — an agent that has only ever signed HMAC and never published a
|
|
265
|
+
9421 signing key fails here, before the signature phase even runs.
|
|
266
|
+
|
|
267
|
+
The runner resolves the agent's `brand.json` from its
|
|
268
|
+
`get_adcp_capabilities` advertisement (or, for agents not yet member-
|
|
269
|
+
registered, from operator configuration), fetches the JWKS at
|
|
270
|
+
`agents[].jwks_uri`, and asserts at least one key has
|
|
271
|
+
`adcp_use: "webhook-signing"` and a non-revoked status. Absent or
|
|
272
|
+
malformed JWKS produces `webhook_signing_keys_unpublished`; JWKS present
|
|
273
|
+
but with no webhook-signing key produces
|
|
274
|
+
`webhook_signing_keys_wrong_purpose`.
|
|
275
|
+
|
|
276
|
+
This phase is observable-only and stateless — no traffic flows. It runs
|
|
277
|
+
before the signature phase so an operator debugging "why did signing
|
|
278
|
+
fail" gets a specific keys-vs-signing diagnostic instead of a generic
|
|
279
|
+
`signature_key_unknown` deep in the verifier checklist.
|
|
280
|
+
|
|
281
|
+
steps:
|
|
282
|
+
- id: fetch_brand_json
|
|
283
|
+
title: "Fetch brand.json and resolve jwks_uri"
|
|
284
|
+
narrative: |
|
|
285
|
+
Runner fetches the agent's `brand.json` (resolved from
|
|
286
|
+
`get_adcp_capabilities` or operator configuration), iterates the
|
|
287
|
+
`agents[]` array, and asserts at least one entry exposes a
|
|
288
|
+
`jwks_uri` reachable at HTTP 200.
|
|
289
|
+
task: fetch_brand_jwks
|
|
290
|
+
stateful: false
|
|
291
|
+
expected: |
|
|
292
|
+
brand.json reachable and parseable; at least one `agents[]` entry
|
|
293
|
+
has a `jwks_uri` returning a valid JWKS document. Fails with
|
|
294
|
+
`brand_json_unreachable`, `brand_json_malformed`, or
|
|
295
|
+
`agents_jwks_uri_missing`.
|
|
296
|
+
|
|
297
|
+
- id: assert_webhook_signing_key_present
|
|
298
|
+
title: "Assert JWKS contains a webhook-signing key"
|
|
299
|
+
narrative: |
|
|
300
|
+
Runner inspects the JWKS and asserts at least one key has
|
|
301
|
+
`adcp_use: "webhook-signing"`. Keys advertising other purposes
|
|
302
|
+
(`request-signing`, `webhook-receipts`, etc.) do not satisfy this
|
|
303
|
+
check — purpose-separation is enforced per the `adcp_use` rule
|
|
304
|
+
(one cryptoKeyVersion per signing purpose; receivers enforce
|
|
305
|
+
purpose at JWK `adcp_use`, not RFC 9421 tag).
|
|
306
|
+
task: assert_jwks_purpose
|
|
307
|
+
stateful: false
|
|
308
|
+
expected: |
|
|
309
|
+
At least one JWK in the agent's published JWKS carries
|
|
310
|
+
`adcp_use: "webhook-signing"` and is not marked revoked. Fails
|
|
311
|
+
with `webhook_signing_keys_unpublished` (no JWKS or empty JWKS),
|
|
312
|
+
`webhook_signing_keys_wrong_purpose` (JWKS present but no key
|
|
313
|
+
with the webhook-signing purpose), or
|
|
314
|
+
`webhook_signing_keys_all_revoked` (all webhook-signing keys
|
|
315
|
+
revoked).
|
|
316
|
+
|
|
317
|
+
- id: signature_validity
|
|
318
|
+
title: "Webhook signatures validate under the 9421 profile"
|
|
319
|
+
narrative: |
|
|
320
|
+
Every outbound webhook MUST verify under the 14-step webhook verifier
|
|
321
|
+
checklist per
|
|
322
|
+
docs/building/implementation/security.mdx#verifier-checklist-for-webhooks.
|
|
323
|
+
The runner registers the trigger as a 9421-default buyer (no
|
|
324
|
+
`authentication` block on `push_notification_config`); the agent is
|
|
325
|
+
graded on the signatures it emits in that mode.
|
|
326
|
+
|
|
327
|
+
Verification is delegated to the `@adcp/client` 9421 webhook verifier
|
|
328
|
+
(see test-kits/webhook-receiver-runner.yaml client_primitives section).
|
|
329
|
+
Until the client verifier lands in a published release, this phase
|
|
330
|
+
grades as `not_applicable` rather than skipping silently — operators
|
|
331
|
+
get an explicit "verifier not yet available" signal instead of a
|
|
332
|
+
false-pass.
|
|
333
|
+
|
|
334
|
+
Negative conformance — signatures that MUST be rejected with a specific
|
|
335
|
+
webhook_signature_* error code — is tested via static conformance
|
|
336
|
+
vectors at `/compliance/{version}/test-vectors/webhook-signing/`
|
|
337
|
+
(follow-up), not by this phase. This phase only grades positive-path
|
|
338
|
+
agents emitting conformant signatures on live traffic.
|
|
339
|
+
|
|
340
|
+
steps:
|
|
341
|
+
- id: trigger_signed_webhook
|
|
342
|
+
title: "Trigger a webhook the agent will sign"
|
|
343
|
+
narrative: |
|
|
344
|
+
Runner calls a webhook-emitting operation with no `authentication`
|
|
345
|
+
block on push_notification_config, forcing 9421 signing per the
|
|
346
|
+
baseline rule.
|
|
347
|
+
task: "$test_kit.operations.primary_webhook_emitter"
|
|
348
|
+
task_default: create_media_buy
|
|
349
|
+
schema_ref: "$test_kit.schemas.primary_request"
|
|
350
|
+
response_schema_ref: "$test_kit.schemas.primary_response"
|
|
351
|
+
doc_ref: "/building/implementation/webhooks"
|
|
352
|
+
comply_scenario: webhook_signed_trigger
|
|
353
|
+
stateful: false
|
|
354
|
+
sample_request:
|
|
355
|
+
push_notification_config:
|
|
356
|
+
url: "{{runner.webhook_url:trigger_signed_webhook}}"
|
|
357
|
+
idempotency_key: "$generate:uuid_v4#webhook_emission_signed_trigger"
|
|
358
|
+
context:
|
|
359
|
+
correlation_id: "webhook_emission--trigger_signed_webhook"
|
|
360
|
+
expected: |
|
|
361
|
+
Agent accepts the request; the webhook it emits will carry
|
|
362
|
+
Signature-Input, Signature, and Content-Digest headers per the
|
|
363
|
+
9421 webhook profile.
|
|
364
|
+
|
|
365
|
+
- id: expect_signature_valid
|
|
366
|
+
title: "Assert webhook signature verifies under the 9421 profile"
|
|
367
|
+
narrative: |
|
|
368
|
+
Runner delegates to the @adcp/client 9421 webhook verifier (14-step
|
|
369
|
+
checklist). A passing signature means: covered components include
|
|
370
|
+
`@method`, `@target-uri`, `@authority`, `content-type`,
|
|
371
|
+
`content-digest`; `tag` is `adcp/webhook-signing/v1`; `alg` is
|
|
372
|
+
allowlisted; `keyid` resolves via the agent's brand.json
|
|
373
|
+
`agents[]` jwks_uri; content-digest recomputes cleanly; nonce is
|
|
374
|
+
not replayed.
|
|
375
|
+
task: expect_webhook_signature_valid
|
|
376
|
+
triggered_by: trigger_signed_webhook
|
|
377
|
+
filter:
|
|
378
|
+
operation_id: "{{prior_step.trigger_signed_webhook.operation_id}}"
|
|
379
|
+
timeout_seconds: 30
|
|
380
|
+
require_tag: "adcp/webhook-signing/v1"
|
|
381
|
+
stateful: true
|
|
382
|
+
expected: |
|
|
383
|
+
Signature verifies under the 9421 webhook profile. Fails with the
|
|
384
|
+
specific webhook_signature_* error code on any checklist failure
|
|
385
|
+
(e.g., signature_invalid, signature_expired, signature_key_unknown,
|
|
386
|
+
signature_digest_mismatch, signature_tag_invalid). Not_applicable
|
|
387
|
+
if the client library doesn't yet implement 9421 webhook
|
|
388
|
+
verification.
|
|
389
|
+
|
|
390
|
+
grading:
|
|
391
|
+
pass_criteria: |
|
|
392
|
+
Phases idempotency_key_presence, idempotency_key_stability,
|
|
393
|
+
signing_keys_published, and signature_validity MUST pass when the agent
|
|
394
|
+
advertises any webhook-emitting operation and the runner hosts a webhook
|
|
395
|
+
receiver. Agents without a published webhook-signing JWKS fail
|
|
396
|
+
signing_keys_published — there is no exemption for "HMAC legacy mode."
|
|
397
|
+
Agents that advertise no webhook-emitting operations grade the entire
|
|
398
|
+
universal as not_applicable. Runners without a webhook receiver grade the
|
|
399
|
+
entire universal as not_applicable. signature_validity may grade
|
|
400
|
+
not_applicable if the runner's `@adcp/client` 9421 webhook verifier is
|
|
401
|
+
not yet available; this is an explicit operator signal, not a silent
|
|
402
|
+
skip.
|
|
403
|
+
report_format: |
|
|
404
|
+
Per-phase pass/fail/not_applicable, with per-step error codes on failure.
|
|
405
|
+
Retry-stability failures include a diff of the observed keys across
|
|
406
|
+
deliveries so operators can debug sender-side retry bugs without re-running
|
|
407
|
+
the full suite. signing_keys_published failures cite the specific gap —
|
|
408
|
+
`webhook_signing_keys_unpublished`, `webhook_signing_keys_wrong_purpose`,
|
|
409
|
+
or `webhook_signing_keys_all_revoked` — so operators distinguish "never
|
|
410
|
+
set up keys" from "set up keys with the wrong purpose label" without
|
|
411
|
+
reading the JWKS by hand.
|