@adcp/sdk 6.9.0 → 6.11.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/decisioning/async-outcome.d.ts +17 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -1
- package/dist/lib/server/decisioning/async-outcome.js +23 -18
- package/dist/lib/server/decisioning/async-outcome.js.map +1 -1
- package/dist/lib/server/decisioning/context.d.ts +8 -2
- package/dist/lib/server/decisioning/context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -0
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +6 -4
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +5 -2
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +5 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.js +4 -1
- package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +10 -2
- package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -1
- 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/test-controller.d.ts +2 -0
- package/dist/lib/server/test-controller.d.ts.map +1 -1
- package/dist/lib/server/test-controller.js +6 -11
- package/dist/lib/server/test-controller.js.map +1 -1
- 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/comply-controller.d.ts +2 -0
- package/dist/lib/testing/comply-controller.d.ts.map +1 -1
- package/dist/lib/testing/comply-controller.js.map +1 -1
- 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
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
id: sales_catalog_driven
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Catalog-driven creative and conversion tracking"
|
|
4
|
+
protocol: media-buy
|
|
5
|
+
category: sales_catalog_driven
|
|
6
|
+
summary: "Seller that renders dynamic ads from product catalogs, tracks conversions, and optimizes delivery based on performance feedback."
|
|
7
|
+
track: media_buy
|
|
8
|
+
required_tools:
|
|
9
|
+
- get_products
|
|
10
|
+
- create_media_buy
|
|
11
|
+
requires_scenarios:
|
|
12
|
+
- media_buy_seller/refine_products
|
|
13
|
+
- media_buy_seller/delivery_reporting
|
|
14
|
+
- media_buy_seller/pending_creatives_to_start
|
|
15
|
+
- media_buy_seller/invalid_transitions
|
|
16
|
+
|
|
17
|
+
# Cross-step assertion (adcp#2664). status.monotonic rejects resource
|
|
18
|
+
# status transitions observed across steps that aren't on the spec
|
|
19
|
+
# lifecycle graph — e.g. active → pending_creatives on a media_buy or
|
|
20
|
+
# approved → pending on a catalog_item.
|
|
21
|
+
invariants:
|
|
22
|
+
- status.monotonic
|
|
23
|
+
|
|
24
|
+
narrative: |
|
|
25
|
+
You run a platform that supports catalog-driven advertising — think Snap Dynamic Ads,
|
|
26
|
+
Meta Product Catalogs, or retail media product listing ads. The buyer pushes a product
|
|
27
|
+
catalog (menu items, retail products, hotel listings), and your platform renders ads
|
|
28
|
+
dynamically from that feed. When a user converts, events are logged back and attributed
|
|
29
|
+
to catalog items, closing the optimization loop.
|
|
30
|
+
|
|
31
|
+
This storyboard walks through the full catalog-to-conversion flow: account setup,
|
|
32
|
+
catalog sync, creative formats for catalog items, media buy with catalog packages,
|
|
33
|
+
event source configuration, conversion logging, and performance feedback.
|
|
34
|
+
|
|
35
|
+
The key difference from the standard media buy flow is that creatives are catalog-driven —
|
|
36
|
+
the buyer doesn't build individual ads. They push a feed, and your platform renders
|
|
37
|
+
the right item to the right user at the right time.
|
|
38
|
+
|
|
39
|
+
agent:
|
|
40
|
+
interaction_model: media_buy_seller
|
|
41
|
+
capabilities:
|
|
42
|
+
- sells_media
|
|
43
|
+
- accepts_catalogs
|
|
44
|
+
- supports_conversion_tracking
|
|
45
|
+
- catalog_driven_creative
|
|
46
|
+
examples:
|
|
47
|
+
- "Snap (Dynamic Ads)"
|
|
48
|
+
- "Retail media networks"
|
|
49
|
+
- "Travel platforms"
|
|
50
|
+
- "Local commerce platforms"
|
|
51
|
+
|
|
52
|
+
caller:
|
|
53
|
+
role: buyer_agent
|
|
54
|
+
example: "Scope3 (DSP)"
|
|
55
|
+
|
|
56
|
+
prerequisites:
|
|
57
|
+
description: |
|
|
58
|
+
The caller needs a product catalog (feed URL or inline items) and an event source
|
|
59
|
+
for conversion tracking. The test kit provides a sample brand with catalog-compatible
|
|
60
|
+
assets.
|
|
61
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
62
|
+
|
|
63
|
+
phases:
|
|
64
|
+
- id: capability_discovery
|
|
65
|
+
title: "Capability discovery"
|
|
66
|
+
narrative: |
|
|
67
|
+
The buyer calls get_adcp_capabilities to confirm the agent supports media buying before sending briefs or creating buys.
|
|
68
|
+
|
|
69
|
+
steps:
|
|
70
|
+
- id: get_capabilities
|
|
71
|
+
title: "Check agent capabilities"
|
|
72
|
+
narrative: |
|
|
73
|
+
Verify that the agent declares the expected protocol support before
|
|
74
|
+
proceeding with domain-specific operations.
|
|
75
|
+
task: get_adcp_capabilities
|
|
76
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
77
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
78
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
79
|
+
comply_scenario: capability_discovery
|
|
80
|
+
stateful: false
|
|
81
|
+
expected: |
|
|
82
|
+
Return capabilities declaring media_buy in supported_protocols, confirming the agent sells media.
|
|
83
|
+
sample_request:
|
|
84
|
+
context:
|
|
85
|
+
correlation_id: "sales_catalog_driven--get_capabilities"
|
|
86
|
+
validations:
|
|
87
|
+
- check: response_schema
|
|
88
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
89
|
+
- check: field_present
|
|
90
|
+
path: "supported_protocols"
|
|
91
|
+
description: "Agent declares supported protocols"
|
|
92
|
+
|
|
93
|
+
- check: field_present
|
|
94
|
+
path: "context"
|
|
95
|
+
description: "Response echoes back the context object"
|
|
96
|
+
- check: field_value
|
|
97
|
+
path: "context.correlation_id"
|
|
98
|
+
value: "sales_catalog_driven--get_capabilities"
|
|
99
|
+
description: "Context correlation_id returned unchanged"
|
|
100
|
+
- id: account_setup
|
|
101
|
+
title: "Account setup"
|
|
102
|
+
narrative: |
|
|
103
|
+
The buyer establishes an account relationship with your platform. For catalog-driven
|
|
104
|
+
campaigns, the account must be active before any catalog sync can happen.
|
|
105
|
+
|
|
106
|
+
steps:
|
|
107
|
+
- id: sync_accounts
|
|
108
|
+
title: "Establish account"
|
|
109
|
+
narrative: |
|
|
110
|
+
The buyer registers their brand and operator. Sandbox accounts are provisioned
|
|
111
|
+
instantly for testing catalog flows.
|
|
112
|
+
task: sync_accounts
|
|
113
|
+
schema_ref: "account/sync-accounts-request.json"
|
|
114
|
+
response_schema_ref: "account/sync-accounts-response.json"
|
|
115
|
+
doc_ref: "/accounts/tasks/sync_accounts"
|
|
116
|
+
stateful: true
|
|
117
|
+
expected: |
|
|
118
|
+
Return the account with account_id, status (active for sandbox), and billing terms.
|
|
119
|
+
|
|
120
|
+
sample_request:
|
|
121
|
+
accounts:
|
|
122
|
+
- brand:
|
|
123
|
+
domain: "amsterdam-steakhouse.example"
|
|
124
|
+
operator: "pinnacle-agency.example"
|
|
125
|
+
billing: "operator"
|
|
126
|
+
sandbox: true
|
|
127
|
+
|
|
128
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_account_setup_sync_accounts"
|
|
129
|
+
context:
|
|
130
|
+
correlation_id: "sales_catalog_driven--sync_accounts"
|
|
131
|
+
validations:
|
|
132
|
+
- check: response_schema
|
|
133
|
+
description: "Response matches sync-accounts-response.json schema"
|
|
134
|
+
- check: field_present
|
|
135
|
+
path: "accounts[0].account_id"
|
|
136
|
+
description: "Account has a platform-assigned ID"
|
|
137
|
+
|
|
138
|
+
- check: field_present
|
|
139
|
+
path: "context"
|
|
140
|
+
description: "Response echoes back the context object"
|
|
141
|
+
- check: field_value
|
|
142
|
+
path: "context.correlation_id"
|
|
143
|
+
value: "sales_catalog_driven--sync_accounts"
|
|
144
|
+
description: "Context correlation_id returned unchanged"
|
|
145
|
+
- id: catalog_sync
|
|
146
|
+
title: "Product catalog sync"
|
|
147
|
+
narrative: |
|
|
148
|
+
The buyer pushes their product catalog to your platform. This is the foundation of
|
|
149
|
+
catalog-driven advertising — every ad your platform renders comes from this feed.
|
|
150
|
+
|
|
151
|
+
For a restaurant, this is the menu. For retail, it is the product feed. For travel,
|
|
152
|
+
it is hotel or flight listings. Your platform validates each item against your
|
|
153
|
+
format requirements (image dimensions, required fields, pricing format) and returns
|
|
154
|
+
per-item approval status.
|
|
155
|
+
|
|
156
|
+
Large feeds may go async — the buyer gets back a submitted status and waits for
|
|
157
|
+
your platform to finish processing. Small feeds (inline items) are processed
|
|
158
|
+
synchronously.
|
|
159
|
+
|
|
160
|
+
steps:
|
|
161
|
+
- id: discover_catalog_formats
|
|
162
|
+
title: "Check catalog format requirements"
|
|
163
|
+
narrative: |
|
|
164
|
+
Before pushing catalog items, the buyer checks what creative formats your
|
|
165
|
+
platform supports for catalog-driven ads. This tells the buyer what image
|
|
166
|
+
dimensions, text lengths, and required fields each catalog item needs.
|
|
167
|
+
task: list_creative_formats
|
|
168
|
+
schema_ref: "creative/list-creative-formats-request.json"
|
|
169
|
+
response_schema_ref: "creative/list-creative-formats-response.json"
|
|
170
|
+
doc_ref: "/creative/task-reference/list_creative_formats"
|
|
171
|
+
comply_scenario: creative_lifecycle
|
|
172
|
+
stateful: false
|
|
173
|
+
expected: |
|
|
174
|
+
Return creative formats that accept catalog assets. Look for formats with
|
|
175
|
+
catalog-specific asset slots (product_image, product_title, price, description).
|
|
176
|
+
|
|
177
|
+
sample_request:
|
|
178
|
+
channels: ["display", "native"]
|
|
179
|
+
|
|
180
|
+
context:
|
|
181
|
+
correlation_id: "sales_catalog_driven--discover_catalog_formats"
|
|
182
|
+
validations:
|
|
183
|
+
- check: response_schema
|
|
184
|
+
description: "Response matches list-creative-formats-response.json schema"
|
|
185
|
+
- check: field_present
|
|
186
|
+
path: "formats"
|
|
187
|
+
description: "Response contains formats array"
|
|
188
|
+
|
|
189
|
+
- check: field_present
|
|
190
|
+
path: "context"
|
|
191
|
+
description: "Response echoes back the context object"
|
|
192
|
+
- check: field_value
|
|
193
|
+
path: "context.correlation_id"
|
|
194
|
+
value: "sales_catalog_driven--discover_catalog_formats"
|
|
195
|
+
description: "Context correlation_id returned unchanged"
|
|
196
|
+
- check: field_present
|
|
197
|
+
path: "formats[0].format_id.agent_url"
|
|
198
|
+
description: "Format IDs include agent_url"
|
|
199
|
+
- check: field_present
|
|
200
|
+
path: "formats[0].format_id.id"
|
|
201
|
+
description: "Format IDs include id — must match those in get_products"
|
|
202
|
+
- id: sync_catalogs
|
|
203
|
+
title: "Push product catalog"
|
|
204
|
+
narrative: |
|
|
205
|
+
The buyer pushes their product feed. This can be a URL to an existing feed
|
|
206
|
+
(your platform fetches and re-fetches on a schedule) or inline items for
|
|
207
|
+
small catalogs.
|
|
208
|
+
|
|
209
|
+
Your platform validates each item: images meet minimum dimensions, required
|
|
210
|
+
fields are present, prices are formatted correctly. Items that fail validation
|
|
211
|
+
are rejected with specific reasons. Items that pass are approved and available
|
|
212
|
+
for dynamic creative rendering.
|
|
213
|
+
task: sync_catalogs
|
|
214
|
+
schema_ref: "media-buy/sync-catalogs-request.json"
|
|
215
|
+
response_schema_ref: "media-buy/sync-catalogs-response.json"
|
|
216
|
+
doc_ref: "/media-buy/task-reference/sync_catalogs"
|
|
217
|
+
stateful: true
|
|
218
|
+
expected: |
|
|
219
|
+
Return per-catalog results with:
|
|
220
|
+
- catalog_id and action (created/updated)
|
|
221
|
+
- item_count, items_approved, items_pending, items_rejected
|
|
222
|
+
- item_issues for rejected items with specific reasons
|
|
223
|
+
- next_fetch_at for URL-based feeds
|
|
224
|
+
|
|
225
|
+
sample_request:
|
|
226
|
+
account:
|
|
227
|
+
brand:
|
|
228
|
+
domain: "amsterdam-steakhouse.example"
|
|
229
|
+
operator: "pinnacle-agency.example"
|
|
230
|
+
catalogs:
|
|
231
|
+
- catalog_id: "menu_spring_2026"
|
|
232
|
+
type: "product"
|
|
233
|
+
name: "Spring 2026 Menu"
|
|
234
|
+
items:
|
|
235
|
+
- item_id: "ribeye_36oz"
|
|
236
|
+
title: "36oz Tomahawk Ribeye"
|
|
237
|
+
description: "Dry-aged 45 days, served with truffle butter and roasted bone marrow"
|
|
238
|
+
url: "https://amsterdam-steakhouse.example/menu/ribeye-36oz"
|
|
239
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/menu/ribeye-36oz-hero.jpg"
|
|
240
|
+
price:
|
|
241
|
+
amount: 89.00
|
|
242
|
+
currency: "USD"
|
|
243
|
+
- item_id: "seafood_tower"
|
|
244
|
+
title: "Grand Seafood Tower"
|
|
245
|
+
description: "Oysters, king crab, lobster tail, shrimp cocktail, tuna tartare"
|
|
246
|
+
url: "https://amsterdam-steakhouse.example/menu/seafood-tower"
|
|
247
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/menu/seafood-tower-hero.jpg"
|
|
248
|
+
price:
|
|
249
|
+
amount: 145.00
|
|
250
|
+
currency: "USD"
|
|
251
|
+
- item_id: "wagyu_flight"
|
|
252
|
+
title: "A5 Wagyu Tasting Flight"
|
|
253
|
+
description: "Three cuts of Japanese A5 Wagyu — striploin, ribeye cap, tenderloin"
|
|
254
|
+
url: "https://amsterdam-steakhouse.example/menu/wagyu-flight"
|
|
255
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/menu/wagyu-flight-hero.jpg"
|
|
256
|
+
price:
|
|
257
|
+
amount: 195.00
|
|
258
|
+
currency: "USD"
|
|
259
|
+
|
|
260
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_catalog_sync_sync_catalogs"
|
|
261
|
+
context:
|
|
262
|
+
correlation_id: "sales_catalog_driven--sync_catalogs"
|
|
263
|
+
validations:
|
|
264
|
+
- check: response_schema
|
|
265
|
+
description: "Response matches sync-catalogs-response.json schema"
|
|
266
|
+
- check: field_present
|
|
267
|
+
path: "catalogs[0].catalog_id"
|
|
268
|
+
description: "Catalog has an ID"
|
|
269
|
+
- check: field_present
|
|
270
|
+
path: "catalogs[0].item_count"
|
|
271
|
+
description: "Catalog reports item count"
|
|
272
|
+
- check: field_present
|
|
273
|
+
path: "catalogs[0].items_approved"
|
|
274
|
+
description: "Catalog reports approved item count"
|
|
275
|
+
|
|
276
|
+
- check: field_present
|
|
277
|
+
path: "context"
|
|
278
|
+
description: "Response echoes back the context object"
|
|
279
|
+
- check: field_value
|
|
280
|
+
path: "context.correlation_id"
|
|
281
|
+
value: "sales_catalog_driven--sync_catalogs"
|
|
282
|
+
description: "Context correlation_id returned unchanged"
|
|
283
|
+
- id: substitution_safety
|
|
284
|
+
title: "Catalog-item macro substitution safety"
|
|
285
|
+
narrative: |
|
|
286
|
+
Per docs/creative/universal-macros#substitution-safety-catalog-item-macros,
|
|
287
|
+
sales agents MUST percent-encode catalog-item macro values such that only
|
|
288
|
+
RFC 3986 `unreserved` characters remain unescaped before substituting them
|
|
289
|
+
into a URL context. Nested macro expansion is prohibited.
|
|
290
|
+
|
|
291
|
+
This phase exercises the rule with three attacker-shaped catalog values
|
|
292
|
+
drawn from the unit-test fixture at `static/test-vectors/catalog-macro-substitution.json`:
|
|
293
|
+
reserved-char breakout, nested-expansion preservation, and non-ASCII
|
|
294
|
+
UTF-8. The remaining canonical vectors (CRLF injection, bidi-override,
|
|
295
|
+
mixed path/query, url-scheme injection) are exercised at the unit-test
|
|
296
|
+
layer and, where a specialism's template shape supports them, in
|
|
297
|
+
specialism-specific substitution-safety phases (see
|
|
298
|
+
`creative-generative/index.yaml` for CRLF + bidi coverage).
|
|
299
|
+
|
|
300
|
+
The `expect_substitution_safe` step is gated on the
|
|
301
|
+
`substitution_observer_runner` test-kit contract (see
|
|
302
|
+
`test-kits/substitution-observer-runner.yaml`). Runners that do not
|
|
303
|
+
advertise the contract grade the step as `not_applicable` — the earlier
|
|
304
|
+
`sync_attacker_shaped_catalog` and `build_catalog_aware_creative` steps
|
|
305
|
+
still run (they exercise the catalog-acceptance and build paths), but
|
|
306
|
+
the substituted-URL assertion is skipped.
|
|
307
|
+
|
|
308
|
+
steps:
|
|
309
|
+
- id: sync_attacker_shaped_catalog
|
|
310
|
+
title: "Push a catalog with attacker-shaped values"
|
|
311
|
+
narrative: |
|
|
312
|
+
Push a small catalog whose fields contain the six canonical
|
|
313
|
+
attacker-shaped values from the substitution-safety fixture. The
|
|
314
|
+
seller MUST accept the payload at sync_catalogs (the rule applies at
|
|
315
|
+
substitution time, not at ingest — the seller is free to pass values
|
|
316
|
+
through, then encode them at serve time).
|
|
317
|
+
task: sync_catalogs
|
|
318
|
+
schema_ref: "media-buy/sync-catalogs-request.json"
|
|
319
|
+
response_schema_ref: "media-buy/sync-catalogs-response.json"
|
|
320
|
+
doc_ref: "/media-buy/task-reference/sync_catalogs"
|
|
321
|
+
stateful: true
|
|
322
|
+
expected: |
|
|
323
|
+
Catalog accepted with per-item counts. Runner captures the item_ids
|
|
324
|
+
for downstream assertion binding.
|
|
325
|
+
|
|
326
|
+
sample_request:
|
|
327
|
+
account:
|
|
328
|
+
brand:
|
|
329
|
+
domain: "amsterdam-steakhouse.example"
|
|
330
|
+
operator: "pinnacle-agency.example"
|
|
331
|
+
catalogs:
|
|
332
|
+
- catalog_id: "substitution_safety_probe_v1"
|
|
333
|
+
type: "product"
|
|
334
|
+
content_id_type: "sku"
|
|
335
|
+
name: "Substitution safety probe"
|
|
336
|
+
items:
|
|
337
|
+
# item_id is the vector name; the `sku` field carries the
|
|
338
|
+
# attacker-shaped value that substitution must encode.
|
|
339
|
+
- item_id: "reserved_char_breakout"
|
|
340
|
+
sku: "00013&cmd=drop"
|
|
341
|
+
title: "Reserved-char breakout probe"
|
|
342
|
+
url: "https://amsterdam-steakhouse.example/probe/reserved"
|
|
343
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/probe/reserved.jpg"
|
|
344
|
+
price: { amount: 1.00, currency: "USD" }
|
|
345
|
+
- item_id: "nested_expansion"
|
|
346
|
+
sku: "vacancy-{DEVICE_ID}-42"
|
|
347
|
+
title: "Nested-expansion probe"
|
|
348
|
+
url: "https://amsterdam-steakhouse.example/probe/nested"
|
|
349
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/probe/nested.jpg"
|
|
350
|
+
price: { amount: 1.00, currency: "USD" }
|
|
351
|
+
- item_id: "non_ascii"
|
|
352
|
+
sku: "café-amsterdam"
|
|
353
|
+
title: "Non-ASCII UTF-8 probe"
|
|
354
|
+
url: "https://amsterdam-steakhouse.example/probe/non-ascii"
|
|
355
|
+
image_url: "https://cdn.amsterdam-steakhouse.example/probe/non-ascii.jpg"
|
|
356
|
+
price: { amount: 1.00, currency: "USD" }
|
|
357
|
+
|
|
358
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_substitution_safety_sync_attacker_shaped_catalog"
|
|
359
|
+
context:
|
|
360
|
+
correlation_id: "sales_catalog_driven--sync_attacker_shaped_catalog"
|
|
361
|
+
validations:
|
|
362
|
+
- check: response_schema
|
|
363
|
+
description: "Response matches sync-catalogs-response.json schema"
|
|
364
|
+
- check: field_present
|
|
365
|
+
path: "catalogs[0].catalog_id"
|
|
366
|
+
description: "Catalog accepted"
|
|
367
|
+
|
|
368
|
+
- id: build_catalog_aware_creative
|
|
369
|
+
title: "Build a creative with catalog-item macros in tracker URLs"
|
|
370
|
+
narrative: |
|
|
371
|
+
Build a creative whose impression and click trackers include
|
|
372
|
+
catalog-item macros bound to the `sku` field of the attacker-shaped
|
|
373
|
+
catalog items above. Request `include_preview: true` so the
|
|
374
|
+
substitution-observer runner has a preview surface to inspect.
|
|
375
|
+
task: build_creative
|
|
376
|
+
schema_ref: "media-buy/build-creative-request.json"
|
|
377
|
+
response_schema_ref: "media-buy/build-creative-response.json"
|
|
378
|
+
doc_ref: "/creative/task-reference/build_creative"
|
|
379
|
+
comply_scenario: creative_flow
|
|
380
|
+
stateful: true
|
|
381
|
+
expected: |
|
|
382
|
+
Creative manifest returned with preview_html or preview_url populated.
|
|
383
|
+
|
|
384
|
+
sample_request:
|
|
385
|
+
message: "Build a catalog-driven display ad for the substitution_safety_probe_v1 catalog. Use {SKU} in impression and click tracker URLs."
|
|
386
|
+
target_format_id:
|
|
387
|
+
agent_url: "https://your-agent.example.com"
|
|
388
|
+
id: "display_300x250_catalog"
|
|
389
|
+
account:
|
|
390
|
+
brand:
|
|
391
|
+
domain: "amsterdam-steakhouse.example"
|
|
392
|
+
operator: "pinnacle-agency.example"
|
|
393
|
+
quality: "draft"
|
|
394
|
+
include_preview: true
|
|
395
|
+
|
|
396
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_substitution_safety_build_catalog_aware_creative"
|
|
397
|
+
context:
|
|
398
|
+
correlation_id: "sales_catalog_driven--build_catalog_aware_creative"
|
|
399
|
+
validations:
|
|
400
|
+
- check: response_schema
|
|
401
|
+
description: "Response matches build-creative-response.json schema"
|
|
402
|
+
- check: field_present
|
|
403
|
+
path: "creative_manifest.format_id"
|
|
404
|
+
description: "Creative manifest returned"
|
|
405
|
+
|
|
406
|
+
- id: expect_substitution_safe
|
|
407
|
+
title: "Assert substituted tracker URLs percent-encode attacker shapes"
|
|
408
|
+
narrative: |
|
|
409
|
+
The runner inspects the preview artifact from the previous step,
|
|
410
|
+
extracts tracker URLs that bind `{SKU}` to a catalog item from the
|
|
411
|
+
attacker-shaped catalog, and asserts each value is percent-encoded
|
|
412
|
+
per RFC 3986 (unreserved-whitelist). Raw-byte leakage fails. Every
|
|
413
|
+
declared binding MUST be observed — a seller that silently strips
|
|
414
|
+
`{SKU}` rather than substituting it fails with
|
|
415
|
+
`substitution_binding_missing`.
|
|
416
|
+
task: expect_substitution_safe
|
|
417
|
+
requires_contract: substitution_observer_runner
|
|
418
|
+
source: html_inline
|
|
419
|
+
source_path: "/creative_manifest/preview_html"
|
|
420
|
+
macro_template: "https://track.example/imp?sku={SKU}"
|
|
421
|
+
require_every_binding_observed: true
|
|
422
|
+
catalog_bindings:
|
|
423
|
+
# Each binding: `catalog_item_id` is the item_id in the synced
|
|
424
|
+
# catalog; `vector_name` is the fixture entry whose raw_value and
|
|
425
|
+
# expected_encoded the runner loads from
|
|
426
|
+
# static/test-vectors/catalog-macro-substitution.json.
|
|
427
|
+
- macro: "{SKU}"
|
|
428
|
+
catalog_item_id: "reserved_char_breakout"
|
|
429
|
+
vector_name: "reserved-character-breakout"
|
|
430
|
+
- macro: "{SKU}"
|
|
431
|
+
catalog_item_id: "nested_expansion"
|
|
432
|
+
vector_name: "nested-expansion-preserved-as-literal"
|
|
433
|
+
- macro: "{SKU}"
|
|
434
|
+
catalog_item_id: "non_ascii"
|
|
435
|
+
vector_name: "non-ascii-utf8-percent-encoding"
|
|
436
|
+
- id: create_buy
|
|
437
|
+
title: "Create catalog-driven media buy"
|
|
438
|
+
narrative: |
|
|
439
|
+
The buyer creates a media buy with catalog-driven packages. Instead of assigning
|
|
440
|
+
individual creatives, the buyer references the synced catalog. Your platform
|
|
441
|
+
renders the right catalog items dynamically based on user context, intent signals,
|
|
442
|
+
and inventory availability.
|
|
443
|
+
|
|
444
|
+
The key schema difference: packages include a catalogs[] array instead of (or
|
|
445
|
+
alongside) creative_assignments[].
|
|
446
|
+
|
|
447
|
+
steps:
|
|
448
|
+
- id: get_products
|
|
449
|
+
title: "Discover catalog-compatible products"
|
|
450
|
+
narrative: |
|
|
451
|
+
The buyer finds products that support catalog-driven delivery. These products
|
|
452
|
+
accept catalog references and render dynamic ads from the feed.
|
|
453
|
+
task: get_products
|
|
454
|
+
schema_ref: "media-buy/get-products-request.json"
|
|
455
|
+
response_schema_ref: "media-buy/get-products-response.json"
|
|
456
|
+
doc_ref: "/media-buy/task-reference/get_products"
|
|
457
|
+
comply_scenario: full_sales_flow
|
|
458
|
+
stateful: false
|
|
459
|
+
expected: |
|
|
460
|
+
Return products that support catalog-driven creative. Products should indicate
|
|
461
|
+
catalog compatibility in their format requirements.
|
|
462
|
+
|
|
463
|
+
sample_request:
|
|
464
|
+
buying_mode: "brief"
|
|
465
|
+
brief: "Dynamic product ads for a high-end steakhouse. Geo-targeted to 10 miles around Amsterdam location. Drive reservations and foot traffic."
|
|
466
|
+
account:
|
|
467
|
+
brand:
|
|
468
|
+
domain: "amsterdam-steakhouse.example"
|
|
469
|
+
operator: "pinnacle-agency.example"
|
|
470
|
+
|
|
471
|
+
context:
|
|
472
|
+
correlation_id: "sales_catalog_driven--get_products"
|
|
473
|
+
validations:
|
|
474
|
+
- check: response_schema
|
|
475
|
+
description: "Response matches get-products-response.json schema"
|
|
476
|
+
- check: field_present
|
|
477
|
+
path: "products"
|
|
478
|
+
description: "Response contains products"
|
|
479
|
+
|
|
480
|
+
- check: field_present
|
|
481
|
+
path: "context"
|
|
482
|
+
description: "Response echoes back the context object"
|
|
483
|
+
- check: field_value
|
|
484
|
+
path: "context.correlation_id"
|
|
485
|
+
value: "sales_catalog_driven--get_products"
|
|
486
|
+
description: "Context correlation_id returned unchanged"
|
|
487
|
+
- check: field_present
|
|
488
|
+
path: "products[0].format_ids"
|
|
489
|
+
description: "Products include format_ids for creative requirements"
|
|
490
|
+
- check: field_present
|
|
491
|
+
path: "products[0].format_ids[0].agent_url"
|
|
492
|
+
description: "Format IDs include agent_url — must match this agent's URL"
|
|
493
|
+
- check: field_present
|
|
494
|
+
path: "products[0].format_ids[0].id"
|
|
495
|
+
description: "Format IDs include id — must be accepted back in sync_creatives"
|
|
496
|
+
- id: create_media_buy
|
|
497
|
+
title: "Create media buy with catalog packages"
|
|
498
|
+
narrative: |
|
|
499
|
+
The buyer creates the media buy with packages that reference the synced catalog.
|
|
500
|
+
Each package has a catalogs[] array specifying which catalog feeds drive the
|
|
501
|
+
dynamic creative for that line item.
|
|
502
|
+
|
|
503
|
+
Your platform optimizes across catalog items within each package's budget
|
|
504
|
+
envelope — showing the ribeye to steak lovers and the seafood tower to
|
|
505
|
+
seafood enthusiasts.
|
|
506
|
+
task: create_media_buy
|
|
507
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
508
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
509
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
510
|
+
comply_scenario: create_media_buy
|
|
511
|
+
stateful: true
|
|
512
|
+
expected: |
|
|
513
|
+
Create the media buy with catalog-driven packages. Return:
|
|
514
|
+
- media_buy_id
|
|
515
|
+
- status: active
|
|
516
|
+
- packages with catalog references preserved
|
|
517
|
+
|
|
518
|
+
sample_request:
|
|
519
|
+
brand:
|
|
520
|
+
domain: "amsterdam-steakhouse.example"
|
|
521
|
+
account:
|
|
522
|
+
brand:
|
|
523
|
+
domain: "amsterdam-steakhouse.example"
|
|
524
|
+
operator: "pinnacle-agency.example"
|
|
525
|
+
start_time: "2026-04-07T00:00:00Z"
|
|
526
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
527
|
+
packages:
|
|
528
|
+
- product_id: "local_display_dynamic"
|
|
529
|
+
pricing_option_id: "cpm_standard"
|
|
530
|
+
budget: 5000
|
|
531
|
+
catalogs:
|
|
532
|
+
- catalog_id: "menu_spring_2026"
|
|
533
|
+
type: "product"
|
|
534
|
+
|
|
535
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_create_buy_create_media_buy"
|
|
536
|
+
context:
|
|
537
|
+
correlation_id: "sales_catalog_driven--create_media_buy"
|
|
538
|
+
context_outputs:
|
|
539
|
+
- name: media_buy_id
|
|
540
|
+
path: "media_buy_id"
|
|
541
|
+
validations:
|
|
542
|
+
- check: response_schema
|
|
543
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
544
|
+
|
|
545
|
+
- check: field_present
|
|
546
|
+
path: "context"
|
|
547
|
+
description: "Response echoes back the context object"
|
|
548
|
+
- check: field_value
|
|
549
|
+
path: "context.correlation_id"
|
|
550
|
+
value: "sales_catalog_driven--create_media_buy"
|
|
551
|
+
description: "Context correlation_id returned unchanged"
|
|
552
|
+
- id: event_setup
|
|
553
|
+
title: "Conversion tracking setup"
|
|
554
|
+
narrative: |
|
|
555
|
+
The buyer configures event sources so your platform can attribute conversions to
|
|
556
|
+
catalog items. For a restaurant, the events are reservations and walk-ins. For
|
|
557
|
+
retail, they are purchases and add-to-carts.
|
|
558
|
+
|
|
559
|
+
Your platform returns setup snippets (pixel code, SDK instructions) that the
|
|
560
|
+
buyer installs on their conversion surfaces.
|
|
561
|
+
|
|
562
|
+
steps:
|
|
563
|
+
- id: sync_event_sources
|
|
564
|
+
title: "Configure event sources"
|
|
565
|
+
narrative: |
|
|
566
|
+
The buyer tells your platform where conversion events will come from —
|
|
567
|
+
a website pixel, a mobile SDK, or a server-to-server integration. Your
|
|
568
|
+
platform returns the integration code.
|
|
569
|
+
task: sync_event_sources
|
|
570
|
+
schema_ref: "media-buy/sync-event-sources-request.json"
|
|
571
|
+
response_schema_ref: "media-buy/sync-event-sources-response.json"
|
|
572
|
+
doc_ref: "/media-buy/task-reference/sync_event_sources"
|
|
573
|
+
stateful: true
|
|
574
|
+
expected: |
|
|
575
|
+
Return event sources with:
|
|
576
|
+
- event_source_id and seller_id
|
|
577
|
+
- setup.snippet: integration code (JavaScript pixel, HTML tag, or pixel URL)
|
|
578
|
+
- setup.instructions: human-readable integration guide
|
|
579
|
+
- action: created or updated
|
|
580
|
+
|
|
581
|
+
sample_request:
|
|
582
|
+
account:
|
|
583
|
+
brand:
|
|
584
|
+
domain: "amsterdam-steakhouse.example"
|
|
585
|
+
operator: "pinnacle-agency.example"
|
|
586
|
+
event_sources:
|
|
587
|
+
- event_source_id: "amsterdam_website"
|
|
588
|
+
name: "Amsterdam Steakhouse Website"
|
|
589
|
+
event_types: ["purchase", "add_to_cart", "page_view", "lead"]
|
|
590
|
+
allowed_domains: ["amsterdam-steakhouse.example", "book.amsterdam-steakhouse.example"]
|
|
591
|
+
|
|
592
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_event_setup_sync_event_sources"
|
|
593
|
+
context:
|
|
594
|
+
correlation_id: "sales_catalog_driven--sync_event_sources"
|
|
595
|
+
ext:
|
|
596
|
+
test_platform:
|
|
597
|
+
test_run: true
|
|
598
|
+
validations:
|
|
599
|
+
- check: response_schema
|
|
600
|
+
description: "Response matches sync-event-sources-response.json schema"
|
|
601
|
+
- check: field_present
|
|
602
|
+
path: "event_sources[0].setup.snippet"
|
|
603
|
+
description: "Event source includes setup snippet"
|
|
604
|
+
|
|
605
|
+
- check: field_present
|
|
606
|
+
path: "context"
|
|
607
|
+
description: "Response echoes back the context object"
|
|
608
|
+
- check: field_value
|
|
609
|
+
path: "context.correlation_id"
|
|
610
|
+
value: "sales_catalog_driven--sync_event_sources"
|
|
611
|
+
description: "Context correlation_id returned unchanged"
|
|
612
|
+
- id: conversion_tracking
|
|
613
|
+
title: "Log conversions"
|
|
614
|
+
narrative: |
|
|
615
|
+
The campaign is running and customers are converting. The buyer logs conversion
|
|
616
|
+
events back to your platform, attributing them to catalog items via content_ids.
|
|
617
|
+
|
|
618
|
+
When someone books a reservation after seeing the ribeye ad, the event includes
|
|
619
|
+
content_ids: ["ribeye_36oz"] — linking the conversion to the catalog item that
|
|
620
|
+
drove it. Your platform uses this signal to optimize which items to show.
|
|
621
|
+
|
|
622
|
+
steps:
|
|
623
|
+
- id: log_events
|
|
624
|
+
title: "Send conversion events"
|
|
625
|
+
narrative: |
|
|
626
|
+
The buyer sends a batch of conversion events. Each event includes the event
|
|
627
|
+
type, value, and content_ids linking to catalog items. Your platform processes
|
|
628
|
+
these for attribution and optimization.
|
|
629
|
+
task: log_event
|
|
630
|
+
schema_ref: "media-buy/log-event-request.json"
|
|
631
|
+
response_schema_ref: "media-buy/log-event-response.json"
|
|
632
|
+
doc_ref: "/media-buy/task-reference/log_event"
|
|
633
|
+
stateful: true
|
|
634
|
+
expected: |
|
|
635
|
+
Process the events and return:
|
|
636
|
+
- events_received and events_processed counts
|
|
637
|
+
- partial_failures for events that failed validation
|
|
638
|
+
- match_quality: how well events matched to ad exposures (0.0-1.0)
|
|
639
|
+
|
|
640
|
+
sample_request:
|
|
641
|
+
account:
|
|
642
|
+
brand:
|
|
643
|
+
domain: "acmeoutdoor.example"
|
|
644
|
+
operator: "pinnacle-agency.example"
|
|
645
|
+
event_source_id: "amsterdam_website"
|
|
646
|
+
events:
|
|
647
|
+
- event_id: "evt_001"
|
|
648
|
+
event_type: "purchase"
|
|
649
|
+
event_time: "2026-04-15T19:30:00Z"
|
|
650
|
+
content_ids: ["ribeye_36oz"]
|
|
651
|
+
value: 89.00
|
|
652
|
+
currency: "USD"
|
|
653
|
+
- event_id: "evt_002"
|
|
654
|
+
event_type: "lead"
|
|
655
|
+
event_time: "2026-04-15T20:15:00Z"
|
|
656
|
+
content_ids: ["wagyu_flight"]
|
|
657
|
+
value: 195.00
|
|
658
|
+
currency: "USD"
|
|
659
|
+
- event_id: "evt_003"
|
|
660
|
+
event_type: "page_view"
|
|
661
|
+
event_time: "2026-04-15T20:45:00Z"
|
|
662
|
+
content_ids: ["seafood_tower"]
|
|
663
|
+
|
|
664
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_conversion_tracking_log_events"
|
|
665
|
+
context:
|
|
666
|
+
correlation_id: "sales_catalog_driven--log_events"
|
|
667
|
+
validations:
|
|
668
|
+
- check: response_schema
|
|
669
|
+
description: "Response matches log-event-response.json schema"
|
|
670
|
+
- check: field_present
|
|
671
|
+
path: "events_received"
|
|
672
|
+
description: "Response reports events received"
|
|
673
|
+
- check: field_present
|
|
674
|
+
path: "match_quality"
|
|
675
|
+
description: "Response includes match quality score"
|
|
676
|
+
|
|
677
|
+
- check: field_present
|
|
678
|
+
path: "context"
|
|
679
|
+
description: "Response echoes back the context object"
|
|
680
|
+
- check: field_value
|
|
681
|
+
path: "context.correlation_id"
|
|
682
|
+
value: "sales_catalog_driven--log_events"
|
|
683
|
+
description: "Context correlation_id returned unchanged"
|
|
684
|
+
- id: optimization_loop
|
|
685
|
+
title: "Performance feedback and optimization"
|
|
686
|
+
narrative: |
|
|
687
|
+
The buyer closes the optimization loop by telling your platform how the campaign
|
|
688
|
+
is performing against their goals. A performance_index above 1.0 means the
|
|
689
|
+
campaign is exceeding expectations — your platform should maintain or increase
|
|
690
|
+
delivery. Below 1.0 means underperforming — your platform should adjust targeting,
|
|
691
|
+
item selection, or pacing.
|
|
692
|
+
|
|
693
|
+
steps:
|
|
694
|
+
- id: provide_feedback
|
|
695
|
+
title: "Submit performance feedback"
|
|
696
|
+
narrative: |
|
|
697
|
+
The buyer reports that the campaign is driving 1.4x the expected reservation
|
|
698
|
+
rate. Your platform uses this signal to optimize delivery — showing more of
|
|
699
|
+
the high-performing catalog items and adjusting bid strategies.
|
|
700
|
+
task: provide_performance_feedback
|
|
701
|
+
schema_ref: "media-buy/provide-performance-feedback-request.json"
|
|
702
|
+
response_schema_ref: "media-buy/provide-performance-feedback-response.json"
|
|
703
|
+
doc_ref: "/media-buy/task-reference/provide_performance_feedback"
|
|
704
|
+
stateful: true
|
|
705
|
+
expected: |
|
|
706
|
+
Acknowledge the feedback. The seller should adjust delivery optimization
|
|
707
|
+
based on the performance_index signal.
|
|
708
|
+
|
|
709
|
+
sample_request:
|
|
710
|
+
account:
|
|
711
|
+
brand:
|
|
712
|
+
domain: "acmeoutdoor.example"
|
|
713
|
+
operator: "pinnacle-agency.example"
|
|
714
|
+
media_buy_id: "$context.media_buy_id"
|
|
715
|
+
measurement_period:
|
|
716
|
+
start: "2026-04-07T00:00:00Z"
|
|
717
|
+
end: "2026-04-14T23:59:59Z"
|
|
718
|
+
performance_index: 1.4
|
|
719
|
+
metric_type: "conversion_rate"
|
|
720
|
+
feedback_source: "buyer_attribution"
|
|
721
|
+
|
|
722
|
+
idempotency_key: "$generate:uuid_v4#sales_catalog_driven_optimization_loop_provide_feedback"
|
|
723
|
+
context:
|
|
724
|
+
correlation_id: "sales_catalog_driven--provide_feedback"
|
|
725
|
+
ext:
|
|
726
|
+
test_platform:
|
|
727
|
+
test_run: true
|
|
728
|
+
validations:
|
|
729
|
+
- check: response_schema
|
|
730
|
+
description: "Response matches provide-performance-feedback-response.json schema"
|
|
731
|
+
- check: field_value
|
|
732
|
+
path: "success"
|
|
733
|
+
value: true
|
|
734
|
+
description: "Feedback accepted"
|
|
735
|
+
|
|
736
|
+
- check: field_present
|
|
737
|
+
path: "context"
|
|
738
|
+
description: "Response echoes back the context object"
|
|
739
|
+
- check: field_value
|
|
740
|
+
path: "context.correlation_id"
|
|
741
|
+
value: "sales_catalog_driven--provide_feedback"
|
|
742
|
+
description: "Context correlation_id returned unchanged"
|
|
743
|
+
- id: check_delivery
|
|
744
|
+
title: "Monitor delivery with catalog attribution"
|
|
745
|
+
narrative: |
|
|
746
|
+
The buyer checks delivery metrics to see which catalog items are driving
|
|
747
|
+
performance and how spend is allocated across the product feed.
|
|
748
|
+
task: get_media_buy_delivery
|
|
749
|
+
schema_ref: "media-buy/get-media-buy-delivery-request.json"
|
|
750
|
+
response_schema_ref: "media-buy/get-media-buy-delivery-response.json"
|
|
751
|
+
doc_ref: "/media-buy/task-reference/get_media_buy_delivery"
|
|
752
|
+
comply_scenario: reporting_flow
|
|
753
|
+
stateful: true
|
|
754
|
+
expected: |
|
|
755
|
+
Return delivery metrics including impressions, clicks, spend, and
|
|
756
|
+
conversion data attributed to catalog items.
|
|
757
|
+
|
|
758
|
+
sample_request:
|
|
759
|
+
account:
|
|
760
|
+
brand:
|
|
761
|
+
domain: "amsterdam-steakhouse.example"
|
|
762
|
+
operator: "pinnacle-agency.example"
|
|
763
|
+
media_buy_ids:
|
|
764
|
+
- "$context.media_buy_id"
|
|
765
|
+
include_package_daily_breakdown: true
|
|
766
|
+
|
|
767
|
+
context:
|
|
768
|
+
correlation_id: "sales_catalog_driven--check_delivery"
|
|
769
|
+
validations:
|
|
770
|
+
- check: response_schema
|
|
771
|
+
description: "Response matches get-media-buy-delivery-response.json schema"
|
|
772
|
+
|
|
773
|
+
- check: field_present
|
|
774
|
+
path: "context"
|
|
775
|
+
description: "Response echoes back the context object"
|
|
776
|
+
- check: field_value
|
|
777
|
+
path: "context.correlation_id"
|
|
778
|
+
value: "sales_catalog_driven--check_delivery"
|
|
779
|
+
description: "Context correlation_id returned unchanged"
|