@adcp/sdk 6.9.0 → 6.10.0
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/bin/adcp.js +285 -5
- package/compliance/cache/3.0.6.previous/domains/brand/index.yaml +163 -0
- package/compliance/cache/3.0.6.previous/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.6.previous/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/inventory_list_targeting.yaml +271 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.6.previous/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.6.previous/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.6.previous/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.6.previous/index.json +324 -0
- package/compliance/cache/3.0.6.previous/protocols/brand/index.yaml +163 -0
- package/compliance/cache/3.0.6.previous/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.6.previous/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/inventory_list_targeting.yaml +271 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.6.previous/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.6.previous/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.6.previous/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.6.previous/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.6.previous/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.0.6.previous/specialisms/brand-rights/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.0.6.previous/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.6.previous/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-generative/generative-seller.yaml +758 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.6.previous/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-aware-seller/index.yaml +136 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.6.previous/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.6.previous/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-broadcast-tv/index.yaml +689 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-guaranteed/index.yaml +504 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.6.previous/specialisms/sales-social/index.yaml +584 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-marketplace/scenarios/governance_denied.yaml +207 -0
- package/compliance/cache/3.0.6.previous/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.6.previous/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.6.previous/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.6.previous/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.6.previous/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.6.previous/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.0.6.previous/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.6.previous/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.6.previous/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.6.previous/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.6.previous/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.6.previous/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.0.6.previous/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.0.6.previous/universal/deterministic-testing.yaml +1343 -0
- package/compliance/cache/3.0.6.previous/universal/error-compliance.yaml +474 -0
- package/compliance/cache/3.0.6.previous/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.6.previous/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.0.6.previous/universal/get-signals-pagination-integrity.yaml +211 -0
- package/compliance/cache/3.0.6.previous/universal/idempotency.yaml +593 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity-creative-formats.yaml +258 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity-list-accounts.yaml +262 -0
- package/compliance/cache/3.0.6.previous/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.0.6.previous/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.0.6.previous/universal/runner-output-contract.yaml +358 -0
- package/compliance/cache/3.0.6.previous/universal/schema-validation.yaml +526 -0
- package/compliance/cache/3.0.6.previous/universal/security.yaml +431 -0
- package/compliance/cache/3.0.6.previous/universal/signed-requests.yaml +205 -0
- package/compliance/cache/3.0.6.previous/universal/storyboard-schema.yaml +1176 -0
- package/compliance/cache/3.0.6.previous/universal/v3-envelope-integrity.yaml +106 -0
- package/compliance/cache/3.0.6.previous/universal/webhook-emission.yaml +337 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.ts +33 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +127 -1
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/credential-policy.d.ts +221 -0
- package/dist/lib/server/credential-policy.d.ts.map +1 -0
- package/dist/lib/server/credential-policy.js +260 -0
- package/dist/lib/server/credential-policy.js.map +1 -0
- package/dist/lib/server/dynamic-registry.d.ts +219 -0
- package/dist/lib/server/dynamic-registry.d.ts.map +1 -0
- package/dist/lib/server/dynamic-registry.js +245 -0
- package/dist/lib/server/dynamic-registry.js.map +1 -0
- package/dist/lib/server/index.d.ts +8 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +15 -4
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/operational-platform.d.ts +239 -0
- package/dist/lib/server/operational-platform.d.ts.map +1 -0
- package/dist/lib/server/operational-platform.js +94 -0
- package/dist/lib/server/operational-platform.js.map +1 -0
- package/dist/lib/server/wire-safe.d.ts +211 -0
- package/dist/lib/server/wire-safe.d.ts.map +1 -0
- package/dist/lib/server/wire-safe.js +231 -0
- package/dist/lib/server/wire-safe.js.map +1 -0
- package/dist/lib/server/wire-spec-fields.generated.d.ts +168 -0
- package/dist/lib/server/wire-spec-fields.generated.d.ts.map +1 -0
- package/dist/lib/server/wire-spec-fields.generated.js +172 -0
- package/dist/lib/server/wire-spec-fields.generated.js.map +1 -0
- package/dist/lib/testing/compliance/index.d.ts +2 -0
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js +6 -1
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/summary.d.ts +77 -0
- package/dist/lib/testing/compliance/summary.d.ts.map +1 -0
- package/dist/lib/testing/compliance/summary.js +176 -0
- package/dist/lib/testing/compliance/summary.js.map +1 -0
- package/dist/lib/testing/storyboard/compliance.d.ts +26 -0
- package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/compliance.js +51 -0
- package/dist/lib/testing/storyboard/compliance.js.map +1 -1
- package/dist/lib/testing/storyboard/index.d.ts +2 -2
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +4 -2
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +58 -5
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/package.json +2 -2
package/compliance/cache/3.0.6.previous/protocols/media-buy/scenarios/create_media_buy_async.yaml
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
id: media_buy_seller/create_media_buy_async
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Seller returns submitted task envelope when create_media_buy goes async"
|
|
4
|
+
category: media_buy_seller
|
|
5
|
+
summary: "Verifies the AdCP-payload wire shape of the submitted-arm response from create_media_buy: status='submitted', task_id present, no media_buy_id and no packages on the envelope."
|
|
6
|
+
track: media_buy
|
|
7
|
+
required_tools:
|
|
8
|
+
- create_media_buy
|
|
9
|
+
- comply_test_controller
|
|
10
|
+
|
|
11
|
+
narrative: |
|
|
12
|
+
When create_media_buy cannot confirm the buy synchronously — e.g., the seller is
|
|
13
|
+
routing the request through IO signing, batch processing, or any out-of-band human
|
|
14
|
+
workflow — the task layer carries the result, not the response. The seller emits the
|
|
15
|
+
submitted task envelope: status='submitted', task_id present, no media_buy_id, no
|
|
16
|
+
packages. The buyer then polls tasks/get with task_id (or waits for a webhook) until
|
|
17
|
+
the task completes and the media_buy_id arrives on the completion artifact.
|
|
18
|
+
|
|
19
|
+
This scenario anchors the AdCP-payload-level invariant for that envelope. Three things
|
|
20
|
+
matter and are easy to regress:
|
|
21
|
+
|
|
22
|
+
1. status MUST be the literal string 'submitted' (not 'pending', not a MediaBuyStatus
|
|
23
|
+
value, not omitted)
|
|
24
|
+
2. task_id MUST be present at the top of the payload, snake_case (A2A adapters MAY
|
|
25
|
+
surface it as taskId on the wire, but the payload field emitted by the agent is
|
|
26
|
+
task_id)
|
|
27
|
+
3. media_buy_id and packages MUST NOT appear on the envelope — they land on the task's
|
|
28
|
+
completion artifact, not here. Sellers that return media_buy_id with status='submitted'
|
|
29
|
+
break the buyer's polling contract; buyers cannot tell whether the buy is queued or
|
|
30
|
+
confirmed.
|
|
31
|
+
|
|
32
|
+
Determinism. The submitted arm is implementation-dependent — most sellers route most
|
|
33
|
+
buys synchronously. To make this storyboard runnable across implementations, the test
|
|
34
|
+
harness uses comply_test_controller force_create_media_buy_arm to drive the next
|
|
35
|
+
create_media_buy call into the submitted arm. The directive is keyed to the caller's
|
|
36
|
+
authenticated sandbox account (account + principal pair); sellers that do not implement
|
|
37
|
+
the controller scenario return UNKNOWN_SCENARIO and the runner grades this storyboard
|
|
38
|
+
not_applicable rather than failed.
|
|
39
|
+
|
|
40
|
+
Round-trip integrity. The deterministic task_id is captured from the controller
|
|
41
|
+
response and reused as the expected task_id on the create_media_buy assertion, so the
|
|
42
|
+
storyboard catches sellers that fabricate a fresh task_id instead of honoring the
|
|
43
|
+
registered directive.
|
|
44
|
+
|
|
45
|
+
Out of scope (by design). Transport-level wire-shape assertions — A2A Task.state and
|
|
46
|
+
artifact.metadata.adcp_task_id placement, MCP structuredContent envelope details — are
|
|
47
|
+
runner-side concerns, not storyboard assertions. The runner exercises this scenario
|
|
48
|
+
against both transports and probes the transport envelope independently. See
|
|
49
|
+
adcp-client#904 for the runner-side probes; this storyboard provides the deterministic
|
|
50
|
+
driver.
|
|
51
|
+
|
|
52
|
+
The submitted → completed transition (forcing the task to resolve and asserting the
|
|
53
|
+
completion artifact carries media_buy_id) is deferred to a follow-up scenario. It needs
|
|
54
|
+
a force_task_completion controller scenario that does not exist yet.
|
|
55
|
+
|
|
56
|
+
agent:
|
|
57
|
+
interaction_model: media_buy_seller
|
|
58
|
+
capabilities:
|
|
59
|
+
- sells_media
|
|
60
|
+
- supports_test_controller
|
|
61
|
+
examples:
|
|
62
|
+
- "Sellers that route some create_media_buy calls through IO signing or batch processing"
|
|
63
|
+
- "Any seller exposing comply_test_controller in sandbox mode"
|
|
64
|
+
|
|
65
|
+
caller:
|
|
66
|
+
role: buyer_agent
|
|
67
|
+
example: "Pinnacle Agency (buyer)"
|
|
68
|
+
|
|
69
|
+
prerequisites:
|
|
70
|
+
description: |
|
|
71
|
+
Seller exposes comply_test_controller in sandbox mode and supports
|
|
72
|
+
force_create_media_buy_arm. The directive is keyed to the caller's
|
|
73
|
+
authenticated sandbox account; without controller support, the storyboard
|
|
74
|
+
grades not_applicable — sellers cannot be deterministically driven into
|
|
75
|
+
the submitted arm by buyer-initiated requests alone.
|
|
76
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
77
|
+
controller_seeding: true
|
|
78
|
+
|
|
79
|
+
fixtures:
|
|
80
|
+
products:
|
|
81
|
+
- product_id: "async_signed_io_q2"
|
|
82
|
+
delivery_type: "guaranteed"
|
|
83
|
+
channels: ["video"]
|
|
84
|
+
format_ids:
|
|
85
|
+
- id: "video_30s"
|
|
86
|
+
pricing_options:
|
|
87
|
+
- product_id: "async_signed_io_q2"
|
|
88
|
+
pricing_option_id: "cpm_guaranteed"
|
|
89
|
+
pricing_model: "cpm"
|
|
90
|
+
currency: "USD"
|
|
91
|
+
fixed_price: 18.0
|
|
92
|
+
|
|
93
|
+
phases:
|
|
94
|
+
- id: force_submitted_arm
|
|
95
|
+
title: "Drive next create_media_buy into submitted arm"
|
|
96
|
+
narrative: |
|
|
97
|
+
Tell the controller that the next create_media_buy call from the caller's
|
|
98
|
+
authenticated sandbox account should return the submitted task envelope.
|
|
99
|
+
The controller stores the directive against the (account, principal) pair
|
|
100
|
+
and consumes it on the next create_media_buy call. Sellers that do not
|
|
101
|
+
implement force_create_media_buy_arm return UNKNOWN_SCENARIO and the
|
|
102
|
+
runner grades this storyboard not_applicable.
|
|
103
|
+
|
|
104
|
+
steps:
|
|
105
|
+
- id: force_arm_submitted
|
|
106
|
+
title: "Force submitted arm on next create_media_buy"
|
|
107
|
+
requires_tool: comply_test_controller
|
|
108
|
+
narrative: |
|
|
109
|
+
Direct the controller to return the submitted envelope with a
|
|
110
|
+
deterministic task_id on the buyer's next create_media_buy call. The
|
|
111
|
+
message field is set to a representative IO-signing explanation so
|
|
112
|
+
buyers exercising prompt-injection sanitization on submitted.message
|
|
113
|
+
have a stable string to assert against.
|
|
114
|
+
task: comply_test_controller
|
|
115
|
+
comply_scenario: create_media_buy
|
|
116
|
+
stateful: true
|
|
117
|
+
context_outputs:
|
|
118
|
+
- name: forced_task_id
|
|
119
|
+
path: "forced.task_id"
|
|
120
|
+
expected: |
|
|
121
|
+
Return a successful directive:
|
|
122
|
+
- success: true
|
|
123
|
+
- forced.arm: submitted
|
|
124
|
+
- forced.task_id: deterministic task handle the next create_media_buy will return
|
|
125
|
+
|
|
126
|
+
sample_request:
|
|
127
|
+
scenario: "force_create_media_buy_arm"
|
|
128
|
+
params:
|
|
129
|
+
arm: "submitted"
|
|
130
|
+
task_id: "task_async_signed_io_q2"
|
|
131
|
+
message: "Awaiting IO signature from sales team; typical turnaround 2–4 hours"
|
|
132
|
+
context:
|
|
133
|
+
correlation_id: "create_media_buy_async--force_arm_submitted"
|
|
134
|
+
validations:
|
|
135
|
+
- check: field_value
|
|
136
|
+
path: "success"
|
|
137
|
+
allowed_values: [true]
|
|
138
|
+
description: "Controller accepts the directive"
|
|
139
|
+
- check: field_value
|
|
140
|
+
path: "forced.arm"
|
|
141
|
+
value: "submitted"
|
|
142
|
+
description: "Controller echoes the forced arm"
|
|
143
|
+
- check: field_present
|
|
144
|
+
path: "forced.task_id"
|
|
145
|
+
description: "Controller echoes the deterministic task_id"
|
|
146
|
+
- check: field_present
|
|
147
|
+
path: "context"
|
|
148
|
+
description: "Response echoes back the context object"
|
|
149
|
+
- check: field_value
|
|
150
|
+
path: "context.correlation_id"
|
|
151
|
+
value: "create_media_buy_async--force_arm_submitted"
|
|
152
|
+
description: "Context correlation_id returned unchanged"
|
|
153
|
+
|
|
154
|
+
- id: submitted_arm_response
|
|
155
|
+
title: "create_media_buy returns submitted task envelope"
|
|
156
|
+
narrative: |
|
|
157
|
+
The buyer makes a normal create_media_buy call. Because the controller
|
|
158
|
+
registered a directive against this sandbox account, the seller MUST emit
|
|
159
|
+
the submitted task envelope: status='submitted', task_id matching the
|
|
160
|
+
forced value, no media_buy_id, no packages.
|
|
161
|
+
|
|
162
|
+
The response_schema check carries the absence invariant — the submitted
|
|
163
|
+
arm in create-media-buy-response.json has not.anyOf clauses for both
|
|
164
|
+
media_buy_id and packages, so a seller that emits either under
|
|
165
|
+
status='submitted' fails schema validation. The explicit field_value
|
|
166
|
+
check on status pins the literal 'submitted' value, since a malformed
|
|
167
|
+
seller might omit the discriminator and still satisfy the parent oneOf
|
|
168
|
+
via the error or success branch. The task_id check uses the captured
|
|
169
|
+
$context.forced_task_id so the storyboard fails if the seller ignores
|
|
170
|
+
the registered directive and fabricates its own task_id.
|
|
171
|
+
|
|
172
|
+
steps:
|
|
173
|
+
- id: create_media_buy_submitted
|
|
174
|
+
title: "Call create_media_buy and observe the submitted envelope"
|
|
175
|
+
task: create_media_buy
|
|
176
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
177
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
178
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
179
|
+
comply_scenario: create_media_buy
|
|
180
|
+
stateful: true
|
|
181
|
+
expected: |
|
|
182
|
+
Return the submitted task envelope:
|
|
183
|
+
- status: 'submitted' (literal, not a MediaBuyStatus value)
|
|
184
|
+
- task_id: matches the value registered by force_create_media_buy_arm
|
|
185
|
+
- no media_buy_id (issued on task completion, not here)
|
|
186
|
+
- no packages (issued on task completion, not here)
|
|
187
|
+
- message (optional): seller's explanation of the wait
|
|
188
|
+
|
|
189
|
+
sample_request:
|
|
190
|
+
brand:
|
|
191
|
+
domain: "acmeoutdoor.example"
|
|
192
|
+
account:
|
|
193
|
+
brand:
|
|
194
|
+
domain: "acmeoutdoor.example"
|
|
195
|
+
operator: "pinnacle-agency.example"
|
|
196
|
+
sandbox: true
|
|
197
|
+
start_time: "2026-07-01T00:00:00Z"
|
|
198
|
+
end_time: "2026-09-30T23:59:59Z"
|
|
199
|
+
packages:
|
|
200
|
+
- product_id: "async_signed_io_q2"
|
|
201
|
+
budget: 30000
|
|
202
|
+
pricing_option_id: "cpm_guaranteed"
|
|
203
|
+
push_notification_config:
|
|
204
|
+
url: "https://buyer.example/webhooks/adcp"
|
|
205
|
+
authentication:
|
|
206
|
+
schemes:
|
|
207
|
+
- "HMAC-SHA256"
|
|
208
|
+
credentials: "media-buy-seller-webhook-secret-token"
|
|
209
|
+
idempotency_key: "$generate:uuid_v4#media_buy_seller_create_media_buy_async_submitted_arm_response_create_media_buy_submitted"
|
|
210
|
+
context:
|
|
211
|
+
correlation_id: "create_media_buy_async--create_media_buy_submitted"
|
|
212
|
+
validations:
|
|
213
|
+
- check: response_schema
|
|
214
|
+
description: "Response matches create-media-buy-response.json — submitted-arm not.required clauses block media_buy_id and packages"
|
|
215
|
+
- check: field_value
|
|
216
|
+
path: "status"
|
|
217
|
+
value: "submitted"
|
|
218
|
+
description: "Status is the literal 'submitted' task-status value, not a MediaBuyStatus"
|
|
219
|
+
- check: field_present
|
|
220
|
+
path: "task_id"
|
|
221
|
+
description: "task_id is present at the top of the envelope (snake_case payload field, even when the A2A adapter surfaces it as taskId on the wire)"
|
|
222
|
+
- check: field_value
|
|
223
|
+
path: "task_id"
|
|
224
|
+
value: "$context.forced_task_id"
|
|
225
|
+
description: "task_id matches the captured value from the controller directive — sellers that fabricate a fresh task_id instead of honoring the registered one fail here"
|
|
226
|
+
- check: field_present
|
|
227
|
+
path: "context"
|
|
228
|
+
description: "Response echoes back the context object"
|
|
229
|
+
- check: field_value
|
|
230
|
+
path: "context.correlation_id"
|
|
231
|
+
value: "create_media_buy_async--create_media_buy_submitted"
|
|
232
|
+
description: "Context correlation_id returned unchanged"
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
id: media_buy_seller/creative_fate_after_cancellation
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Creative lifecycle is decoupled from media buy lifecycle"
|
|
4
|
+
category: media_buy_seller
|
|
5
|
+
summary: "Validates that canceling a media buy releases package-creative assignments but leaves the underlying creatives in the library with their review state intact, and that buyers can reuse released creatives on a new buy."
|
|
6
|
+
track: media_buy
|
|
7
|
+
required_tools:
|
|
8
|
+
- get_products
|
|
9
|
+
- create_media_buy
|
|
10
|
+
- update_media_buy
|
|
11
|
+
- sync_creatives
|
|
12
|
+
- list_creatives
|
|
13
|
+
|
|
14
|
+
narrative: |
|
|
15
|
+
Per the creative library model (docs/creative/creative-libraries#creative-state-and-assignment-state-are-separate)
|
|
16
|
+
and the Media Buy State Transitions rule, canceling or rejecting a media buy
|
|
17
|
+
releases its package-creative assignments but leaves the creatives themselves
|
|
18
|
+
in the library. The creatives remain reusable by `creative_id` in a subsequent
|
|
19
|
+
`create_media_buy` or `sync_creatives` call, and a seller MUST NOT implicitly
|
|
20
|
+
reject a creative because its containing buy was canceled — a creative
|
|
21
|
+
rejection MUST be a deliberate review decision with its own `rejection_reason`.
|
|
22
|
+
|
|
23
|
+
This scenario walks the whole flow end-to-end:
|
|
24
|
+
|
|
25
|
+
1. Create a buy, sync a creative, assign it to a package (setup)
|
|
26
|
+
2. Confirm the creative is in the library with a non-terminal review state (pre-cancel)
|
|
27
|
+
3. Cancel the buy
|
|
28
|
+
4. Confirm the creative is STILL in the library with its review state intact —
|
|
29
|
+
not archived, not auto-rejected as a side effect of the cancel
|
|
30
|
+
5. Reuse the same `creative_id` on a new buy via `sync_creatives` assignment
|
|
31
|
+
|
|
32
|
+
A seller that evaporates library creatives on buy cancellation, or that flips
|
|
33
|
+
`status: rejected` on creatives whose only assignment was released by a cancel,
|
|
34
|
+
fails this scenario. A seller that correctly decouples the two lifecycles
|
|
35
|
+
passes.
|
|
36
|
+
|
|
37
|
+
agent:
|
|
38
|
+
interaction_model: media_buy_seller
|
|
39
|
+
capabilities:
|
|
40
|
+
- sells_media
|
|
41
|
+
examples:
|
|
42
|
+
- "Any media buy seller with a creative library"
|
|
43
|
+
|
|
44
|
+
caller:
|
|
45
|
+
role: buyer_agent
|
|
46
|
+
example: "Pinnacle Agency (buyer)"
|
|
47
|
+
|
|
48
|
+
prerequisites:
|
|
49
|
+
description: |
|
|
50
|
+
Seller supports create_media_buy, update_media_buy with cancellation, sync_creatives,
|
|
51
|
+
and list_creatives. Catalog-driven sellers and sellers without a creative library
|
|
52
|
+
grade this scenario not_applicable (creative lifecycle assumes a library surface).
|
|
53
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
54
|
+
|
|
55
|
+
phases:
|
|
56
|
+
- id: setup
|
|
57
|
+
title: "Create a buy and assign a creative"
|
|
58
|
+
narrative: |
|
|
59
|
+
Discover a product, create a media buy, sync one creative with an inline
|
|
60
|
+
assignment to the buy's first package. Capture the media_buy_id, package_id,
|
|
61
|
+
and creative_id for subsequent phases.
|
|
62
|
+
|
|
63
|
+
steps:
|
|
64
|
+
- id: get_products_brief
|
|
65
|
+
title: "Discover a product"
|
|
66
|
+
task: get_products
|
|
67
|
+
schema_ref: "media-buy/get-products-request.json"
|
|
68
|
+
response_schema_ref: "media-buy/get-products-response.json"
|
|
69
|
+
doc_ref: "/media-buy/task-reference/get_products"
|
|
70
|
+
comply_scenario: full_sales_flow
|
|
71
|
+
stateful: false
|
|
72
|
+
expected: |
|
|
73
|
+
Return at least one product with a pricing option and at least one format_id.
|
|
74
|
+
sample_request:
|
|
75
|
+
buying_mode: "brief"
|
|
76
|
+
brief: "Display inventory on outdoor lifestyle content for creative-reuse testing."
|
|
77
|
+
account:
|
|
78
|
+
brand:
|
|
79
|
+
domain: "acmeoutdoor.example"
|
|
80
|
+
operator: "pinnacle-agency.example"
|
|
81
|
+
context:
|
|
82
|
+
correlation_id: "creative_fate--get_products"
|
|
83
|
+
context_outputs:
|
|
84
|
+
- path: "products[0].product_id"
|
|
85
|
+
key: "product_id"
|
|
86
|
+
- path: "products[0].pricing_options[0].pricing_option_id"
|
|
87
|
+
key: "pricing_option_id"
|
|
88
|
+
- path: "products[0].format_ids[0].agent_url"
|
|
89
|
+
key: "format_agent_url"
|
|
90
|
+
- path: "products[0].format_ids[0].id"
|
|
91
|
+
key: "format_id"
|
|
92
|
+
validations:
|
|
93
|
+
- check: response_schema
|
|
94
|
+
description: "Response matches get-products-response.json schema"
|
|
95
|
+
- check: field_present
|
|
96
|
+
path: "products[0].format_ids[0].id"
|
|
97
|
+
description: "Product exposes at least one format_id for creative sync"
|
|
98
|
+
|
|
99
|
+
- id: create_buy
|
|
100
|
+
title: "Create the initial media buy"
|
|
101
|
+
task: create_media_buy
|
|
102
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
103
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
104
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
105
|
+
comply_scenario: create_media_buy
|
|
106
|
+
stateful: true
|
|
107
|
+
expected: |
|
|
108
|
+
Media buy created with media_buy_id and at least one package.
|
|
109
|
+
|
|
110
|
+
sample_request:
|
|
111
|
+
brand:
|
|
112
|
+
domain: "acmeoutdoor.example"
|
|
113
|
+
account:
|
|
114
|
+
brand:
|
|
115
|
+
domain: "acmeoutdoor.example"
|
|
116
|
+
operator: "pinnacle-agency.example"
|
|
117
|
+
idempotency_key: "creative-fate-setup-create-buy-v1"
|
|
118
|
+
start_time: "2026-09-01T00:00:00Z"
|
|
119
|
+
end_time: "2026-09-30T23:59:59Z"
|
|
120
|
+
packages:
|
|
121
|
+
- product_id: "$context.product_id"
|
|
122
|
+
budget: 5000
|
|
123
|
+
pricing_option_id: "$context.pricing_option_id"
|
|
124
|
+
context:
|
|
125
|
+
correlation_id: "creative_fate--create_buy"
|
|
126
|
+
context_outputs:
|
|
127
|
+
- path: "media_buy_id"
|
|
128
|
+
key: "media_buy_id"
|
|
129
|
+
- path: "packages[0].package_id"
|
|
130
|
+
key: "package_id"
|
|
131
|
+
validations:
|
|
132
|
+
- check: response_schema
|
|
133
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
134
|
+
- check: field_present
|
|
135
|
+
path: "media_buy_id"
|
|
136
|
+
description: "Seller returns media_buy_id"
|
|
137
|
+
- check: field_present
|
|
138
|
+
path: "packages[0].package_id"
|
|
139
|
+
description: "Seller returns package_id for the newly created package"
|
|
140
|
+
|
|
141
|
+
- id: sync_creative_with_assignment
|
|
142
|
+
title: "Sync a creative and assign to the package"
|
|
143
|
+
narrative: |
|
|
144
|
+
Sync one creative into the library and assign it to the package in a single
|
|
145
|
+
sync_creatives call. The creative enters the library with the library's
|
|
146
|
+
review flow; the assignment binds it to the media buy's package.
|
|
147
|
+
task: sync_creatives
|
|
148
|
+
schema_ref: "creative/sync-creatives-request.json"
|
|
149
|
+
response_schema_ref: "creative/sync-creatives-response.json"
|
|
150
|
+
doc_ref: "/creative/task-reference/sync_creatives"
|
|
151
|
+
comply_scenario: creative_sync
|
|
152
|
+
stateful: true
|
|
153
|
+
expected: |
|
|
154
|
+
Creative accepted into the library (action: created), assignment acknowledged.
|
|
155
|
+
Creative status is one of: pending_review, approved, processing.
|
|
156
|
+
|
|
157
|
+
sample_request:
|
|
158
|
+
account:
|
|
159
|
+
brand:
|
|
160
|
+
domain: "acmeoutdoor.example"
|
|
161
|
+
operator: "pinnacle-agency.example"
|
|
162
|
+
creatives:
|
|
163
|
+
- creative_id: "acme_reuse_banner_001"
|
|
164
|
+
name: "Acme Outdoor reuse banner"
|
|
165
|
+
format_id:
|
|
166
|
+
agent_url: "$context.format_agent_url"
|
|
167
|
+
id: "$context.format_id"
|
|
168
|
+
assets:
|
|
169
|
+
image:
|
|
170
|
+
asset_type: "image"
|
|
171
|
+
url: "https://cdn.pinnacle-agency.example/acme-reuse-banner.png"
|
|
172
|
+
width: 300
|
|
173
|
+
height: 250
|
|
174
|
+
mime_type: "image/png"
|
|
175
|
+
assignments:
|
|
176
|
+
- creative_id: "acme_reuse_banner_001"
|
|
177
|
+
package_id: "$context.package_id"
|
|
178
|
+
idempotency_key: "creative-fate-setup-sync-v1"
|
|
179
|
+
context:
|
|
180
|
+
correlation_id: "creative_fate--sync_creative_with_assignment"
|
|
181
|
+
context_outputs:
|
|
182
|
+
- path: "creatives[0].creative_id"
|
|
183
|
+
key: "creative_id"
|
|
184
|
+
validations:
|
|
185
|
+
- check: response_schema
|
|
186
|
+
description: "Response matches sync-creatives-response.json schema"
|
|
187
|
+
- check: field_present
|
|
188
|
+
path: "creatives[0].creative_id"
|
|
189
|
+
description: "Response echoes back the buyer-supplied creative_id"
|
|
190
|
+
|
|
191
|
+
- id: verify_creative_in_library_pre_cancel
|
|
192
|
+
title: "Baseline: creative is in the library with a non-terminal review state"
|
|
193
|
+
narrative: |
|
|
194
|
+
Before canceling the buy, list the creative via list_creatives and record the
|
|
195
|
+
review state. The purpose of this phase is to establish the baseline the
|
|
196
|
+
post-cancel phase compares against: the creative exists and has a status
|
|
197
|
+
that is NOT `rejected` or `archived`.
|
|
198
|
+
|
|
199
|
+
steps:
|
|
200
|
+
- id: list_creatives_before_cancel
|
|
201
|
+
title: "Look up the creative in the library"
|
|
202
|
+
task: list_creatives
|
|
203
|
+
schema_ref: "creative/list-creatives-request.json"
|
|
204
|
+
response_schema_ref: "creative/list-creatives-response.json"
|
|
205
|
+
doc_ref: "/creative/task-reference/list_creatives"
|
|
206
|
+
comply_scenario: creative_library
|
|
207
|
+
stateful: true
|
|
208
|
+
expected: |
|
|
209
|
+
list_creatives returns the creative with a non-terminal review state
|
|
210
|
+
(processing, pending_review, or approved).
|
|
211
|
+
|
|
212
|
+
sample_request:
|
|
213
|
+
account:
|
|
214
|
+
brand:
|
|
215
|
+
domain: "acmeoutdoor.example"
|
|
216
|
+
operator: "pinnacle-agency.example"
|
|
217
|
+
filters:
|
|
218
|
+
creative_ids:
|
|
219
|
+
- "$context.creative_id"
|
|
220
|
+
context:
|
|
221
|
+
correlation_id: "creative_fate--list_creatives_before_cancel"
|
|
222
|
+
validations:
|
|
223
|
+
- check: response_schema
|
|
224
|
+
description: "Response matches list-creatives-response.json schema"
|
|
225
|
+
- check: field_present
|
|
226
|
+
path: "creatives[0].creative_id"
|
|
227
|
+
description: "Creative is present in the library"
|
|
228
|
+
- check: field_value
|
|
229
|
+
path: "creatives[0].status"
|
|
230
|
+
allowed_values: ["processing", "pending_review", "approved"]
|
|
231
|
+
description: "Creative status is non-terminal (not rejected or archived) before cancel"
|
|
232
|
+
|
|
233
|
+
- id: cancel_buy
|
|
234
|
+
title: "Cancel the media buy"
|
|
235
|
+
narrative: |
|
|
236
|
+
Cancel the media buy with `canceled: true`. The seller MUST transition the buy
|
|
237
|
+
to `canceled` and release the creative's package assignment per
|
|
238
|
+
docs/media-buy/specification#media-buy-state-transitions.
|
|
239
|
+
|
|
240
|
+
steps:
|
|
241
|
+
- id: update_media_buy_canceled
|
|
242
|
+
title: "update_media_buy with canceled: true"
|
|
243
|
+
task: update_media_buy
|
|
244
|
+
schema_ref: "media-buy/update-media-buy-request.json"
|
|
245
|
+
response_schema_ref: "media-buy/update-media-buy-response.json"
|
|
246
|
+
doc_ref: "/media-buy/task-reference/update_media_buy"
|
|
247
|
+
comply_scenario: media_buy_lifecycle
|
|
248
|
+
stateful: true
|
|
249
|
+
expected: |
|
|
250
|
+
Seller acknowledges the cancellation and transitions the buy to `canceled`.
|
|
251
|
+
|
|
252
|
+
sample_request:
|
|
253
|
+
account:
|
|
254
|
+
brand:
|
|
255
|
+
domain: "acmeoutdoor.example"
|
|
256
|
+
operator: "pinnacle-agency.example"
|
|
257
|
+
media_buy_id: "$context.media_buy_id"
|
|
258
|
+
canceled: true
|
|
259
|
+
cancellation_reason: "Creative-fate scenario: releasing assignment to verify library persistence."
|
|
260
|
+
idempotency_key: "creative-fate-cancel-v1"
|
|
261
|
+
context:
|
|
262
|
+
correlation_id: "creative_fate--update_media_buy_canceled"
|
|
263
|
+
validations:
|
|
264
|
+
- check: response_schema
|
|
265
|
+
description: "Response matches update-media-buy-response.json schema"
|
|
266
|
+
|
|
267
|
+
- id: verify_creative_persists_post_cancel
|
|
268
|
+
title: "Creative remains in the library with review state intact"
|
|
269
|
+
narrative: |
|
|
270
|
+
After the cancel, the creative's library entry MUST still exist and its review
|
|
271
|
+
state MUST NOT be `rejected` (which would indicate implicit-reject-on-cancel,
|
|
272
|
+
forbidden by the spec) and SHOULD NOT be `archived` (which would indicate the
|
|
273
|
+
seller evaporated library state on buy cancellation, inconsistent with the
|
|
274
|
+
decoupled-lifecycle contract). Allowed terminal-adjacent states are
|
|
275
|
+
`processing`, `pending_review`, `approved` — whatever the review flow produced.
|
|
276
|
+
|
|
277
|
+
steps:
|
|
278
|
+
- id: list_creatives_after_cancel
|
|
279
|
+
title: "Look up the creative again, post-cancel"
|
|
280
|
+
task: list_creatives
|
|
281
|
+
schema_ref: "creative/list-creatives-request.json"
|
|
282
|
+
response_schema_ref: "creative/list-creatives-response.json"
|
|
283
|
+
doc_ref: "/creative/task-reference/list_creatives"
|
|
284
|
+
comply_scenario: creative_library
|
|
285
|
+
stateful: true
|
|
286
|
+
expected: |
|
|
287
|
+
Creative still present with non-rejected, non-archived status. A seller
|
|
288
|
+
that returns an empty list, or that has flipped the creative to
|
|
289
|
+
`rejected` or `archived` as a side effect of the cancel, fails.
|
|
290
|
+
|
|
291
|
+
sample_request:
|
|
292
|
+
account:
|
|
293
|
+
brand:
|
|
294
|
+
domain: "acmeoutdoor.example"
|
|
295
|
+
operator: "pinnacle-agency.example"
|
|
296
|
+
filters:
|
|
297
|
+
creative_ids:
|
|
298
|
+
- "$context.creative_id"
|
|
299
|
+
context:
|
|
300
|
+
correlation_id: "creative_fate--list_creatives_after_cancel"
|
|
301
|
+
validations:
|
|
302
|
+
- check: response_schema
|
|
303
|
+
description: "Response matches list-creatives-response.json schema"
|
|
304
|
+
- check: field_present
|
|
305
|
+
path: "creatives[0].creative_id"
|
|
306
|
+
description: "Creative still in the library after buy cancellation"
|
|
307
|
+
- check: field_value
|
|
308
|
+
path: "creatives[0].creative_id"
|
|
309
|
+
value: "acme_reuse_banner_001"
|
|
310
|
+
description: "Creative ID is unchanged (not re-keyed on cancel)"
|
|
311
|
+
- check: field_value
|
|
312
|
+
path: "creatives[0].status"
|
|
313
|
+
allowed_values: ["processing", "pending_review", "approved"]
|
|
314
|
+
description: "Creative status is NOT rejected and NOT archived — no implicit review cascade from the buy cancel"
|
|
315
|
+
|
|
316
|
+
- id: reuse_creative_on_new_buy
|
|
317
|
+
title: "Reuse the released creative on a new media buy"
|
|
318
|
+
narrative: |
|
|
319
|
+
With the old buy canceled and the assignment released, the buyer creates a NEW
|
|
320
|
+
media buy and references the same creative_id in a fresh assignment. The seller
|
|
321
|
+
MUST accept the assignment — the creative_id resolves to the persisted library
|
|
322
|
+
entry, demonstrating end-to-end reusability.
|
|
323
|
+
|
|
324
|
+
steps:
|
|
325
|
+
- id: create_second_buy
|
|
326
|
+
title: "Create a second media buy"
|
|
327
|
+
task: create_media_buy
|
|
328
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
329
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
330
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
331
|
+
comply_scenario: create_media_buy
|
|
332
|
+
stateful: true
|
|
333
|
+
expected: |
|
|
334
|
+
Second media buy created successfully with a new media_buy_id and package_id.
|
|
335
|
+
|
|
336
|
+
sample_request:
|
|
337
|
+
brand:
|
|
338
|
+
domain: "acmeoutdoor.example"
|
|
339
|
+
account:
|
|
340
|
+
brand:
|
|
341
|
+
domain: "acmeoutdoor.example"
|
|
342
|
+
operator: "pinnacle-agency.example"
|
|
343
|
+
idempotency_key: "creative-fate-second-buy-v1"
|
|
344
|
+
start_time: "2026-10-01T00:00:00Z"
|
|
345
|
+
end_time: "2026-10-31T23:59:59Z"
|
|
346
|
+
packages:
|
|
347
|
+
- product_id: "$context.product_id"
|
|
348
|
+
budget: 5000
|
|
349
|
+
pricing_option_id: "$context.pricing_option_id"
|
|
350
|
+
context:
|
|
351
|
+
correlation_id: "creative_fate--create_second_buy"
|
|
352
|
+
context_outputs:
|
|
353
|
+
- path: "media_buy_id"
|
|
354
|
+
key: "second_media_buy_id"
|
|
355
|
+
- path: "packages[0].package_id"
|
|
356
|
+
key: "second_package_id"
|
|
357
|
+
validations:
|
|
358
|
+
- check: response_schema
|
|
359
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
360
|
+
- check: field_present
|
|
361
|
+
path: "media_buy_id"
|
|
362
|
+
description: "Second media_buy_id returned"
|
|
363
|
+
- check: field_present
|
|
364
|
+
path: "packages[0].package_id"
|
|
365
|
+
description: "Second package_id returned"
|
|
366
|
+
|
|
367
|
+
- id: reassign_creative
|
|
368
|
+
title: "Assign the original creative_id to the new package"
|
|
369
|
+
narrative: |
|
|
370
|
+
Reference the original creative by creative_id only (no assets, no re-upload)
|
|
371
|
+
and assign it to the new package. The seller resolves the creative_id from
|
|
372
|
+
the library; if the creative was evaporated on cancel, this call fails.
|
|
373
|
+
task: sync_creatives
|
|
374
|
+
schema_ref: "creative/sync-creatives-request.json"
|
|
375
|
+
response_schema_ref: "creative/sync-creatives-response.json"
|
|
376
|
+
doc_ref: "/creative/task-reference/sync_creatives"
|
|
377
|
+
comply_scenario: creative_sync
|
|
378
|
+
stateful: true
|
|
379
|
+
expected: |
|
|
380
|
+
Assignment accepted. No creative-not-found or similar error.
|
|
381
|
+
|
|
382
|
+
sample_request:
|
|
383
|
+
account:
|
|
384
|
+
brand:
|
|
385
|
+
domain: "acmeoutdoor.example"
|
|
386
|
+
operator: "pinnacle-agency.example"
|
|
387
|
+
creatives:
|
|
388
|
+
# Buyer-authoritative id set in sync_creative_with_assignment —
|
|
389
|
+
# use it literally instead of round-tripping through
|
|
390
|
+
# `$context.creative_id`. That context key is populated from
|
|
391
|
+
# the seller's response at `creatives[0].creative_id`; sellers
|
|
392
|
+
# whose envelope doesn't surface that exact path resolve to
|
|
393
|
+
# undefined and the template engine strips the creative,
|
|
394
|
+
# leaving `creatives: undefined` which fails pre-flight zod.
|
|
395
|
+
- creative_id: "acme_reuse_banner_001"
|
|
396
|
+
name: "Reassigned creative"
|
|
397
|
+
format_id:
|
|
398
|
+
agent_url: "https://your-platform.example.com"
|
|
399
|
+
id: "display_300x250"
|
|
400
|
+
assets:
|
|
401
|
+
image:
|
|
402
|
+
asset_type: "image"
|
|
403
|
+
url: "https://test-assets.adcontextprotocol.org/acme-outdoor/banner_300x250.jpg"
|
|
404
|
+
width: 300
|
|
405
|
+
height: 250
|
|
406
|
+
assignments:
|
|
407
|
+
- creative_id: "acme_reuse_banner_001"
|
|
408
|
+
package_id: "$context.second_package_id"
|
|
409
|
+
idempotency_key: "creative-fate-reassign-v1"
|
|
410
|
+
context:
|
|
411
|
+
correlation_id: "creative_fate--reassign_creative"
|
|
412
|
+
validations:
|
|
413
|
+
- check: response_schema
|
|
414
|
+
description: "Response matches sync-creatives-response.json schema"
|