@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
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
id: pagination_integrity
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Pagination cursor integrity"
|
|
4
|
+
category: schema_validation
|
|
5
|
+
summary: "Validates the cursor↔has_more invariant by walking a paginated list_creatives response from a continuation page to a terminal page."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools:
|
|
8
|
+
- list_creatives
|
|
9
|
+
|
|
10
|
+
narrative: |
|
|
11
|
+
Pagination is cursor-based across AdCP. Every response carrying a
|
|
12
|
+
`pagination` block satisfies a single invariant: when `has_more` is true the
|
|
13
|
+
`cursor` MUST be present (callers need it to fetch the next page); when
|
|
14
|
+
`has_more` is false the `cursor` MUST be absent (a stale token on a terminal
|
|
15
|
+
page invites callers to follow it into undefined behavior).
|
|
16
|
+
|
|
17
|
+
The invariant is documented in prose on
|
|
18
|
+
`static/schemas/source/core/pagination-response.json` but JSON Schema does
|
|
19
|
+
not gate the two fields against each other. This storyboard exercises both
|
|
20
|
+
sides of the invariant on the same agent in a single run.
|
|
21
|
+
|
|
22
|
+
The runner seeds three creatives into the agent's library and lists them
|
|
23
|
+
back with `max_results=2`. The first page MUST cap at two creatives and
|
|
24
|
+
signal continuation with `has_more=true` plus a cursor. The runner then
|
|
25
|
+
follows that cursor; the next page returns the remaining creative(s) and
|
|
26
|
+
MUST signal `has_more=false` with no cursor. An agent that hides the third
|
|
27
|
+
fixture by reporting `has_more=false` on the first page (the
|
|
28
|
+
dishonest-pagination case) fails the first-page assertion. An agent that
|
|
29
|
+
carries a stale cursor onto the terminal page fails the second-page
|
|
30
|
+
assertion.
|
|
31
|
+
|
|
32
|
+
The `total_count` field is allowed to be absent (some backends cannot
|
|
33
|
+
compute it cheaply per the pagination-response schema) but when an agent
|
|
34
|
+
volunteers it, the value MUST match the seeded fixture count of three.
|
|
35
|
+
This is the count-honesty half of the invariant: an agent that returns
|
|
36
|
+
`total_count: 2` while three creatives are seeded is hiding inventory
|
|
37
|
+
the way `has_more: false` would, just on a different field.
|
|
38
|
+
`query_summary.total_matching` is required by the response schema and
|
|
39
|
+
asserted unconditionally; `query_summary.returned` MUST equal the size
|
|
40
|
+
of each page's slice (2 on the continuation page, 1 on the terminal
|
|
41
|
+
page) — drift here flags an agent whose summary numbers don't match
|
|
42
|
+
what it actually emitted.
|
|
43
|
+
|
|
44
|
+
agent:
|
|
45
|
+
interaction_model: stateful_preloaded
|
|
46
|
+
capabilities:
|
|
47
|
+
- has_creative_library
|
|
48
|
+
examples:
|
|
49
|
+
- "Any AdCP agent that exposes a paginated list_creatives"
|
|
50
|
+
|
|
51
|
+
caller:
|
|
52
|
+
role: buyer_agent
|
|
53
|
+
example: "Compliance test harness"
|
|
54
|
+
|
|
55
|
+
prerequisites:
|
|
56
|
+
description: |
|
|
57
|
+
The runner seeds three creatives ahead of time so a small page-size
|
|
58
|
+
request reliably triggers a continuation page on the first call. No
|
|
59
|
+
assets are required — the seeded creatives only need an id, status, and
|
|
60
|
+
format_id for list_creatives to surface them.
|
|
61
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
62
|
+
controller_seeding: true
|
|
63
|
+
|
|
64
|
+
fixtures:
|
|
65
|
+
creatives:
|
|
66
|
+
- creative_id: "pagination_integrity_creative_1"
|
|
67
|
+
status: "approved"
|
|
68
|
+
format_id:
|
|
69
|
+
id: "display_static"
|
|
70
|
+
- creative_id: "pagination_integrity_creative_2"
|
|
71
|
+
status: "approved"
|
|
72
|
+
format_id:
|
|
73
|
+
id: "display_static"
|
|
74
|
+
- creative_id: "pagination_integrity_creative_3"
|
|
75
|
+
status: "approved"
|
|
76
|
+
format_id:
|
|
77
|
+
id: "display_static"
|
|
78
|
+
|
|
79
|
+
phases:
|
|
80
|
+
- id: capability_discovery
|
|
81
|
+
title: "Capability discovery"
|
|
82
|
+
narrative: |
|
|
83
|
+
Confirm the agent supports the creative protocol before exercising
|
|
84
|
+
list_creatives.
|
|
85
|
+
steps:
|
|
86
|
+
- id: get_capabilities
|
|
87
|
+
title: "Check agent capabilities"
|
|
88
|
+
narrative: |
|
|
89
|
+
Verify that the agent declares creative in supported_protocols
|
|
90
|
+
before driving paginated list_creatives.
|
|
91
|
+
task: get_adcp_capabilities
|
|
92
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
93
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
94
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
95
|
+
comply_scenario: capability_discovery
|
|
96
|
+
stateful: false
|
|
97
|
+
expected: |
|
|
98
|
+
Return capabilities declaring creative in supported_protocols.
|
|
99
|
+
|
|
100
|
+
sample_request:
|
|
101
|
+
context:
|
|
102
|
+
correlation_id: "pagination_integrity--get_capabilities"
|
|
103
|
+
validations:
|
|
104
|
+
- check: response_schema
|
|
105
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
106
|
+
- check: field_present
|
|
107
|
+
path: "supported_protocols"
|
|
108
|
+
description: "Agent declares supported protocols"
|
|
109
|
+
|
|
110
|
+
- check: field_present
|
|
111
|
+
path: "context"
|
|
112
|
+
description: "Response echoes back the context object"
|
|
113
|
+
- check: field_value
|
|
114
|
+
path: "context.correlation_id"
|
|
115
|
+
value: "pagination_integrity--get_capabilities"
|
|
116
|
+
description: "Context correlation_id returned unchanged"
|
|
117
|
+
|
|
118
|
+
- id: pagination_walk
|
|
119
|
+
title: "Walk pages with a small max_results"
|
|
120
|
+
narrative: |
|
|
121
|
+
With three creatives seeded and `max_results: 2`, the first call MUST
|
|
122
|
+
return a continuation page (has_more=true with a cursor). The runner
|
|
123
|
+
then follows the cursor; the second call MUST return the terminal
|
|
124
|
+
page (has_more=false with no cursor).
|
|
125
|
+
|
|
126
|
+
steps:
|
|
127
|
+
- id: first_page
|
|
128
|
+
title: "Request the first page with max_results=2"
|
|
129
|
+
narrative: |
|
|
130
|
+
The buyer asks for up to two creatives. The agent has three matching
|
|
131
|
+
fixtures, so the request is non-terminal: callers expect
|
|
132
|
+
`has_more=true` and a `cursor` they can follow to retrieve the
|
|
133
|
+
remaining creative.
|
|
134
|
+
|
|
135
|
+
The runner captures `pagination.cursor` into `$context.next_cursor`
|
|
136
|
+
for the follow-up step. If the agent reports `has_more=false` on
|
|
137
|
+
this page (hiding the seeded third creative behind a dishonest
|
|
138
|
+
terminal signal), the field_value check on `pagination.has_more`
|
|
139
|
+
fails — surfacing exactly the bug class this storyboard exists to
|
|
140
|
+
catch.
|
|
141
|
+
task: list_creatives
|
|
142
|
+
schema_ref: "creative/list-creatives-request.json"
|
|
143
|
+
response_schema_ref: "creative/list-creatives-response.json"
|
|
144
|
+
doc_ref: "/creative/task-reference/list_creatives"
|
|
145
|
+
comply_scenario: pagination_integrity
|
|
146
|
+
stateful: true
|
|
147
|
+
context_outputs:
|
|
148
|
+
- name: next_cursor
|
|
149
|
+
path: "pagination.cursor"
|
|
150
|
+
expected: |
|
|
151
|
+
Return up to two creatives with:
|
|
152
|
+
- pagination.has_more = true
|
|
153
|
+
- pagination.cursor present (an opaque continuation token)
|
|
154
|
+
|
|
155
|
+
sample_request:
|
|
156
|
+
account:
|
|
157
|
+
account_id: "acct_pagination_integrity"
|
|
158
|
+
pagination:
|
|
159
|
+
max_results: 2
|
|
160
|
+
|
|
161
|
+
context:
|
|
162
|
+
correlation_id: "pagination_integrity--first_page"
|
|
163
|
+
validations:
|
|
164
|
+
- check: response_schema
|
|
165
|
+
description: "Response matches list-creatives-response.json schema"
|
|
166
|
+
- check: field_value
|
|
167
|
+
path: "pagination.has_more"
|
|
168
|
+
value: true
|
|
169
|
+
description: "Three fixtures seeded with max_results=2 → first page is non-terminal"
|
|
170
|
+
- check: field_present
|
|
171
|
+
path: "pagination.cursor"
|
|
172
|
+
description: "has_more=true requires a cursor — without one the caller cannot continue"
|
|
173
|
+
- check: field_value
|
|
174
|
+
path: "query_summary.total_matching"
|
|
175
|
+
value: 3
|
|
176
|
+
description: "Three fixtures seeded — total_matching MUST reflect the full result set, not just this page"
|
|
177
|
+
- check: field_value
|
|
178
|
+
path: "query_summary.returned"
|
|
179
|
+
value: 2
|
|
180
|
+
description: "max_results=2 capped this page at 2 items — query_summary.returned MUST match the slice"
|
|
181
|
+
- check: field_value_or_absent
|
|
182
|
+
path: "pagination.total_count"
|
|
183
|
+
allowed_values: [3]
|
|
184
|
+
description: "If volunteered, total_count MUST equal the seeded set size — under-reporting hides inventory the same way a dishonest has_more does"
|
|
185
|
+
|
|
186
|
+
- check: field_present
|
|
187
|
+
path: "context"
|
|
188
|
+
description: "Response echoes back the context object"
|
|
189
|
+
- check: field_value
|
|
190
|
+
path: "context.correlation_id"
|
|
191
|
+
value: "pagination_integrity--first_page"
|
|
192
|
+
description: "Context correlation_id returned unchanged"
|
|
193
|
+
|
|
194
|
+
- id: terminal_page
|
|
195
|
+
title: "Follow the cursor to the terminal page"
|
|
196
|
+
narrative: |
|
|
197
|
+
The buyer follows the captured cursor. With at most one remaining
|
|
198
|
+
creative the agent MUST return a terminal page: `has_more=false`
|
|
199
|
+
with no `cursor` field. A cursor on `has_more=false` is a stale
|
|
200
|
+
token that invites callers to follow it past the end of results.
|
|
201
|
+
|
|
202
|
+
The agent is free to sub-paginate — i.e. return a non-terminal
|
|
203
|
+
second page if it uses page sizes smaller than the runner's
|
|
204
|
+
`max_results=2`. This storyboard does not enforce exhaustion in
|
|
205
|
+
two calls; it enforces the cursor↔has_more invariant on every
|
|
206
|
+
page it observes. Sub-paginators land on a non-terminal second
|
|
207
|
+
page and fail the `has_more=false` assertion below — which is the
|
|
208
|
+
intended outcome for this storyboard's scope. Agents that
|
|
209
|
+
legitimately stream many small pages should expose larger
|
|
210
|
+
`max_results` ceilings or run a more elaborate pagination
|
|
211
|
+
storyboard.
|
|
212
|
+
task: list_creatives
|
|
213
|
+
schema_ref: "creative/list-creatives-request.json"
|
|
214
|
+
response_schema_ref: "creative/list-creatives-response.json"
|
|
215
|
+
doc_ref: "/creative/task-reference/list_creatives"
|
|
216
|
+
comply_scenario: pagination_integrity
|
|
217
|
+
stateful: true
|
|
218
|
+
expected: |
|
|
219
|
+
Return the remaining creative(s) with:
|
|
220
|
+
- pagination.has_more = false
|
|
221
|
+
- pagination.cursor absent (a stale cursor on a terminal page is a
|
|
222
|
+
dishonest pagination signal)
|
|
223
|
+
|
|
224
|
+
sample_request:
|
|
225
|
+
account:
|
|
226
|
+
account_id: "acct_pagination_integrity"
|
|
227
|
+
pagination:
|
|
228
|
+
cursor: "$context.next_cursor"
|
|
229
|
+
max_results: 2
|
|
230
|
+
|
|
231
|
+
context:
|
|
232
|
+
correlation_id: "pagination_integrity--terminal_page"
|
|
233
|
+
validations:
|
|
234
|
+
- check: response_schema
|
|
235
|
+
description: "Response matches list-creatives-response.json schema"
|
|
236
|
+
- check: field_value
|
|
237
|
+
path: "pagination.has_more"
|
|
238
|
+
value: false
|
|
239
|
+
description: "After two pages of two items the seeded set is exhausted"
|
|
240
|
+
- check: field_value_or_absent
|
|
241
|
+
path: "pagination.cursor"
|
|
242
|
+
allowed_values: [null]
|
|
243
|
+
description: "Terminal page MUST omit cursor (null also accepted for clients that explicitly clear the field)"
|
|
244
|
+
- check: field_value
|
|
245
|
+
path: "query_summary.total_matching"
|
|
246
|
+
value: 3
|
|
247
|
+
description: "total_matching MUST stay stable across pages — drift between pages is a query-summary bug"
|
|
248
|
+
- check: field_value
|
|
249
|
+
path: "query_summary.returned"
|
|
250
|
+
value: 1
|
|
251
|
+
description: "One creative left after the first page returned two — query_summary.returned MUST match the slice"
|
|
252
|
+
- check: field_value_or_absent
|
|
253
|
+
path: "pagination.total_count"
|
|
254
|
+
allowed_values: [3]
|
|
255
|
+
description: "total_count (when volunteered) MUST stay stable across pages and equal the seeded set size"
|
|
256
|
+
|
|
257
|
+
- check: field_present
|
|
258
|
+
path: "context"
|
|
259
|
+
description: "Response echoes back the context object"
|
|
260
|
+
- check: field_value
|
|
261
|
+
path: "context.correlation_id"
|
|
262
|
+
value: "pagination_integrity--terminal_page"
|
|
263
|
+
description: "Context correlation_id returned unchanged"
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
id: pagination_integrity_property_lists
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Pagination cursor integrity — list_property_lists"
|
|
4
|
+
category: schema_validation
|
|
5
|
+
summary: "Validates the cursor↔has_more invariant by walking a paginated list_property_lists response from a continuation page to a terminal page."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools:
|
|
8
|
+
- list_property_lists
|
|
9
|
+
|
|
10
|
+
narrative: |
|
|
11
|
+
Pagination is cursor-based across AdCP. Every response carrying a
|
|
12
|
+
`pagination` block satisfies a single invariant: when `has_more` is true the
|
|
13
|
+
`cursor` MUST be present (callers need it to fetch the next page); when
|
|
14
|
+
`has_more` is false the `cursor` MUST be absent (a stale token on a terminal
|
|
15
|
+
page invites callers to follow it into undefined behavior).
|
|
16
|
+
|
|
17
|
+
The invariant is documented in prose on
|
|
18
|
+
`static/schemas/source/core/pagination-response.json` but JSON Schema does
|
|
19
|
+
not gate the two fields against each other. This storyboard exercises both
|
|
20
|
+
sides of the invariant on `list_property_lists` in a single run.
|
|
21
|
+
|
|
22
|
+
The runner bootstraps three property lists via `create_property_list`, then
|
|
23
|
+
lists them back with `max_results=2`. The first page MUST cap at two lists
|
|
24
|
+
and signal continuation with `has_more=true` plus a cursor. The runner then
|
|
25
|
+
follows that cursor; the second call MUST return the terminal page with
|
|
26
|
+
`has_more=false` and no cursor. An agent that hides the third list by
|
|
27
|
+
reporting `has_more=false` on the first page fails the first-page assertion.
|
|
28
|
+
An agent that carries a stale cursor onto the terminal page fails the
|
|
29
|
+
second-page assertion.
|
|
30
|
+
|
|
31
|
+
The `total_count` field is allowed to be absent (some backends cannot
|
|
32
|
+
compute it cheaply per the pagination-response schema) but when an agent
|
|
33
|
+
volunteers it, the value MUST match the seeded count of three.
|
|
34
|
+
|
|
35
|
+
agent:
|
|
36
|
+
interaction_model: stateful_preloaded
|
|
37
|
+
capabilities: []
|
|
38
|
+
examples:
|
|
39
|
+
- "Any AdCP agent that exposes a paginated list_property_lists"
|
|
40
|
+
|
|
41
|
+
caller:
|
|
42
|
+
role: buyer_agent
|
|
43
|
+
example: "Compliance test harness"
|
|
44
|
+
|
|
45
|
+
prerequisites:
|
|
46
|
+
description: |
|
|
47
|
+
The storyboard bootstraps three property lists in the setup phase via
|
|
48
|
+
`create_property_list`. The seed-DAG does not include property lists, so
|
|
49
|
+
this storyboard uses the create-then-list pattern to keep itself
|
|
50
|
+
self-contained without extending the seed taxonomy.
|
|
51
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
52
|
+
controller_seeding: false
|
|
53
|
+
|
|
54
|
+
phases:
|
|
55
|
+
- id: capability_discovery
|
|
56
|
+
title: "Capability discovery"
|
|
57
|
+
narrative: |
|
|
58
|
+
Confirm the agent responds to get_adcp_capabilities before
|
|
59
|
+
exercising list_property_lists.
|
|
60
|
+
steps:
|
|
61
|
+
- id: get_capabilities
|
|
62
|
+
title: "Check agent capabilities"
|
|
63
|
+
narrative: |
|
|
64
|
+
Verify that the agent declares supported protocols before
|
|
65
|
+
driving paginated list_property_lists.
|
|
66
|
+
task: get_adcp_capabilities
|
|
67
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
68
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
69
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
70
|
+
comply_scenario: pagination_integrity_property_lists
|
|
71
|
+
stateful: false
|
|
72
|
+
expected: |
|
|
73
|
+
Return capabilities declaring supported protocols.
|
|
74
|
+
|
|
75
|
+
sample_request:
|
|
76
|
+
context:
|
|
77
|
+
correlation_id: "pagination_integrity_property_lists--get_capabilities"
|
|
78
|
+
validations:
|
|
79
|
+
- check: response_schema
|
|
80
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
81
|
+
- check: field_present
|
|
82
|
+
path: "supported_protocols"
|
|
83
|
+
description: "Agent declares supported protocols"
|
|
84
|
+
- check: field_present
|
|
85
|
+
path: "context"
|
|
86
|
+
description: "Response echoes back the context object"
|
|
87
|
+
- check: field_value
|
|
88
|
+
path: "context.correlation_id"
|
|
89
|
+
value: "pagination_integrity_property_lists--get_capabilities"
|
|
90
|
+
description: "Context correlation_id returned unchanged"
|
|
91
|
+
|
|
92
|
+
- id: setup
|
|
93
|
+
title: "Bootstrap three property lists"
|
|
94
|
+
narrative: |
|
|
95
|
+
Create three property lists so the pagination walk has a deterministic
|
|
96
|
+
set of three items to page through with max_results=2.
|
|
97
|
+
steps:
|
|
98
|
+
- id: create_list_1
|
|
99
|
+
title: "Create first property list"
|
|
100
|
+
narrative: |
|
|
101
|
+
Create an inclusion property list for approved news publisher
|
|
102
|
+
domains. The agent MUST accept this and return a list.list_id.
|
|
103
|
+
task: create_property_list
|
|
104
|
+
schema_ref: "property/create-property-list-request.json"
|
|
105
|
+
response_schema_ref: "property/create-property-list-response.json"
|
|
106
|
+
doc_ref: "/governance/task-reference/create_property_list"
|
|
107
|
+
comply_scenario: pagination_integrity_property_lists
|
|
108
|
+
stateful: true
|
|
109
|
+
expected: |
|
|
110
|
+
Accept the property list and return a list.list_id.
|
|
111
|
+
|
|
112
|
+
sample_request:
|
|
113
|
+
account:
|
|
114
|
+
brand:
|
|
115
|
+
domain: "acmeoutdoor.example"
|
|
116
|
+
operator: "pinnacle-agency.example"
|
|
117
|
+
name: "Approved News Publishers"
|
|
118
|
+
description: "Inclusion list of brand-safe news publisher domains."
|
|
119
|
+
idempotency_key: "$generate:uuid_v4#pagination_integrity_property_lists_setup_create_list_1"
|
|
120
|
+
context:
|
|
121
|
+
correlation_id: "pagination_integrity_property_lists--setup_1"
|
|
122
|
+
validations:
|
|
123
|
+
- check: response_schema
|
|
124
|
+
description: "Response matches create-property-list-response.json schema"
|
|
125
|
+
- check: field_present
|
|
126
|
+
path: "list.list_id"
|
|
127
|
+
description: "Response contains list.list_id"
|
|
128
|
+
|
|
129
|
+
- id: create_list_2
|
|
130
|
+
title: "Create second property list"
|
|
131
|
+
narrative: |
|
|
132
|
+
Create an exclusion property list for blocked gambling sites.
|
|
133
|
+
task: create_property_list
|
|
134
|
+
schema_ref: "property/create-property-list-request.json"
|
|
135
|
+
response_schema_ref: "property/create-property-list-response.json"
|
|
136
|
+
doc_ref: "/governance/task-reference/create_property_list"
|
|
137
|
+
comply_scenario: pagination_integrity_property_lists
|
|
138
|
+
stateful: true
|
|
139
|
+
expected: |
|
|
140
|
+
Accept the property list and return a list.list_id.
|
|
141
|
+
|
|
142
|
+
sample_request:
|
|
143
|
+
account:
|
|
144
|
+
brand:
|
|
145
|
+
domain: "acmeoutdoor.example"
|
|
146
|
+
operator: "pinnacle-agency.example"
|
|
147
|
+
name: "Gambling Sites Blocklist"
|
|
148
|
+
description: "Exclusion list of gambling and wagering domains."
|
|
149
|
+
idempotency_key: "$generate:uuid_v4#pagination_integrity_property_lists_setup_create_list_2"
|
|
150
|
+
context:
|
|
151
|
+
correlation_id: "pagination_integrity_property_lists--setup_2"
|
|
152
|
+
validations:
|
|
153
|
+
- check: response_schema
|
|
154
|
+
description: "Response matches create-property-list-response.json schema"
|
|
155
|
+
- check: field_present
|
|
156
|
+
path: "list.list_id"
|
|
157
|
+
description: "Response contains list.list_id"
|
|
158
|
+
|
|
159
|
+
- id: create_list_3
|
|
160
|
+
title: "Create third property list"
|
|
161
|
+
narrative: |
|
|
162
|
+
Create an inclusion property list for premium entertainment
|
|
163
|
+
properties.
|
|
164
|
+
task: create_property_list
|
|
165
|
+
schema_ref: "property/create-property-list-request.json"
|
|
166
|
+
response_schema_ref: "property/create-property-list-response.json"
|
|
167
|
+
doc_ref: "/governance/task-reference/create_property_list"
|
|
168
|
+
comply_scenario: pagination_integrity_property_lists
|
|
169
|
+
stateful: true
|
|
170
|
+
expected: |
|
|
171
|
+
Accept the property list and return a list.list_id.
|
|
172
|
+
|
|
173
|
+
sample_request:
|
|
174
|
+
account:
|
|
175
|
+
brand:
|
|
176
|
+
domain: "acmeoutdoor.example"
|
|
177
|
+
operator: "pinnacle-agency.example"
|
|
178
|
+
name: "Premium Entertainment Properties"
|
|
179
|
+
description: "Inclusion list of tier-one entertainment publisher domains."
|
|
180
|
+
idempotency_key: "$generate:uuid_v4#pagination_integrity_property_lists_setup_create_list_3"
|
|
181
|
+
context:
|
|
182
|
+
correlation_id: "pagination_integrity_property_lists--setup_3"
|
|
183
|
+
validations:
|
|
184
|
+
- check: response_schema
|
|
185
|
+
description: "Response matches create-property-list-response.json schema"
|
|
186
|
+
- check: field_present
|
|
187
|
+
path: "list.list_id"
|
|
188
|
+
description: "Response contains list.list_id"
|
|
189
|
+
|
|
190
|
+
- id: pagination_walk
|
|
191
|
+
title: "Walk pages with a small max_results"
|
|
192
|
+
narrative: |
|
|
193
|
+
With three property lists seeded and `max_results: 2`, the first call
|
|
194
|
+
MUST return a continuation page (has_more=true with a cursor). The runner
|
|
195
|
+
then follows the cursor; the second call MUST return the terminal page
|
|
196
|
+
(has_more=false with no cursor).
|
|
197
|
+
|
|
198
|
+
steps:
|
|
199
|
+
- id: first_page
|
|
200
|
+
title: "Request the first page with max_results=2"
|
|
201
|
+
narrative: |
|
|
202
|
+
The buyer asks for up to two property lists. The agent has three
|
|
203
|
+
matching lists, so the request is non-terminal: callers expect
|
|
204
|
+
`has_more=true` and a `cursor` they can follow to retrieve the
|
|
205
|
+
remaining list.
|
|
206
|
+
|
|
207
|
+
The runner captures `pagination.cursor` into `$context.next_cursor`
|
|
208
|
+
for the follow-up step. If the agent reports `has_more=false` on
|
|
209
|
+
this page (hiding the seeded third list behind a dishonest terminal
|
|
210
|
+
signal), the field_value check on `pagination.has_more` fails.
|
|
211
|
+
task: list_property_lists
|
|
212
|
+
schema_ref: "property/list-property-lists-request.json"
|
|
213
|
+
response_schema_ref: "property/list-property-lists-response.json"
|
|
214
|
+
doc_ref: "/governance/task-reference/list_property_lists"
|
|
215
|
+
comply_scenario: pagination_integrity_property_lists
|
|
216
|
+
stateful: true
|
|
217
|
+
context_outputs:
|
|
218
|
+
- name: next_cursor
|
|
219
|
+
path: "pagination.cursor"
|
|
220
|
+
expected: |
|
|
221
|
+
Return up to two property lists with:
|
|
222
|
+
- pagination.has_more = true
|
|
223
|
+
- pagination.cursor present (an opaque continuation token)
|
|
224
|
+
|
|
225
|
+
sample_request:
|
|
226
|
+
account:
|
|
227
|
+
brand:
|
|
228
|
+
domain: "acmeoutdoor.example"
|
|
229
|
+
operator: "pinnacle-agency.example"
|
|
230
|
+
pagination:
|
|
231
|
+
max_results: 2
|
|
232
|
+
|
|
233
|
+
context:
|
|
234
|
+
correlation_id: "pagination_integrity_property_lists--first_page"
|
|
235
|
+
validations:
|
|
236
|
+
- check: response_schema
|
|
237
|
+
description: "Response matches list-property-lists-response.json schema"
|
|
238
|
+
- check: field_value
|
|
239
|
+
path: "pagination.has_more"
|
|
240
|
+
value: true
|
|
241
|
+
description: "Three lists seeded with max_results=2 → first page is non-terminal"
|
|
242
|
+
- check: field_present
|
|
243
|
+
path: "pagination.cursor"
|
|
244
|
+
description: "has_more=true requires a cursor — without one the caller cannot continue"
|
|
245
|
+
- check: field_value_or_absent
|
|
246
|
+
path: "pagination.total_count"
|
|
247
|
+
allowed_values: [3]
|
|
248
|
+
description: "If volunteered, total_count MUST equal the seeded set size"
|
|
249
|
+
- check: field_present
|
|
250
|
+
path: "context"
|
|
251
|
+
description: "Response echoes back the context object"
|
|
252
|
+
- check: field_value
|
|
253
|
+
path: "context.correlation_id"
|
|
254
|
+
value: "pagination_integrity_property_lists--first_page"
|
|
255
|
+
description: "Context correlation_id returned unchanged"
|
|
256
|
+
|
|
257
|
+
- id: terminal_page
|
|
258
|
+
title: "Follow the cursor to the terminal page"
|
|
259
|
+
narrative: |
|
|
260
|
+
The buyer follows the captured cursor. With at most one remaining
|
|
261
|
+
list the agent MUST return a terminal page: `has_more=false` with no
|
|
262
|
+
`cursor` field. A cursor on `has_more=false` is a stale token that
|
|
263
|
+
invites callers to follow it past the end of results.
|
|
264
|
+
task: list_property_lists
|
|
265
|
+
schema_ref: "property/list-property-lists-request.json"
|
|
266
|
+
response_schema_ref: "property/list-property-lists-response.json"
|
|
267
|
+
doc_ref: "/governance/task-reference/list_property_lists"
|
|
268
|
+
comply_scenario: pagination_integrity_property_lists
|
|
269
|
+
stateful: true
|
|
270
|
+
expected: |
|
|
271
|
+
Return the remaining list(s) with:
|
|
272
|
+
- pagination.has_more = false
|
|
273
|
+
- pagination.cursor absent
|
|
274
|
+
|
|
275
|
+
sample_request:
|
|
276
|
+
account:
|
|
277
|
+
brand:
|
|
278
|
+
domain: "acmeoutdoor.example"
|
|
279
|
+
operator: "pinnacle-agency.example"
|
|
280
|
+
pagination:
|
|
281
|
+
cursor: "$context.next_cursor"
|
|
282
|
+
max_results: 2
|
|
283
|
+
|
|
284
|
+
context:
|
|
285
|
+
correlation_id: "pagination_integrity_property_lists--terminal_page"
|
|
286
|
+
validations:
|
|
287
|
+
- check: response_schema
|
|
288
|
+
description: "Response matches list-property-lists-response.json schema"
|
|
289
|
+
- check: field_value
|
|
290
|
+
path: "pagination.has_more"
|
|
291
|
+
value: false
|
|
292
|
+
description: "After two pages of two items the seeded set is exhausted"
|
|
293
|
+
- check: field_value_or_absent
|
|
294
|
+
path: "pagination.cursor"
|
|
295
|
+
allowed_values: [null]
|
|
296
|
+
description: "Terminal page MUST omit cursor (null also accepted for clients that explicitly clear the field)"
|
|
297
|
+
- check: field_value_or_absent
|
|
298
|
+
path: "pagination.total_count"
|
|
299
|
+
allowed_values: [3]
|
|
300
|
+
description: "total_count (when volunteered) MUST stay stable across pages and equal the seeded set size"
|
|
301
|
+
- check: field_present
|
|
302
|
+
path: "context"
|
|
303
|
+
description: "Response echoes back the context object"
|
|
304
|
+
- check: field_value
|
|
305
|
+
path: "context.correlation_id"
|
|
306
|
+
value: "pagination_integrity_property_lists--terminal_page"
|
|
307
|
+
description: "Context correlation_id returned unchanged"
|