@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,258 @@
|
|
|
1
|
+
id: pagination_integrity_creative_formats
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Pagination cursor integrity — list_creative_formats"
|
|
4
|
+
category: schema_validation
|
|
5
|
+
summary: "Validates the cursor↔has_more invariant on list_creative_formats by seeding two formats and walking pages with max_results=1."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools:
|
|
8
|
+
- list_creative_formats
|
|
9
|
+
|
|
10
|
+
narrative: |
|
|
11
|
+
Pagination is cursor-based across AdCP. Every response carrying a
|
|
12
|
+
`pagination` block satisfies one invariant: when `has_more` is true the
|
|
13
|
+
`cursor` MUST be present; when `has_more` is false the `cursor` MUST be
|
|
14
|
+
absent. This storyboard exercises both sides of the invariant on
|
|
15
|
+
`list_creative_formats`, mirroring the approach used by
|
|
16
|
+
`pagination-integrity.yaml` for `list_creatives`.
|
|
17
|
+
|
|
18
|
+
The runner seeds two creative formats into the agent's session ahead of
|
|
19
|
+
time so the result set has a knowable size at storyboard-author time. A
|
|
20
|
+
request with `max_results=1` MUST trigger a continuation page on the
|
|
21
|
+
first call (`has_more=true` with a cursor). Following that cursor MUST
|
|
22
|
+
produce a terminal page (`has_more=false` with no cursor).
|
|
23
|
+
|
|
24
|
+
The `list-creative-formats-response.json` schema does not define a
|
|
25
|
+
`query_summary` field, so this storyboard only asserts the
|
|
26
|
+
`pagination` block fields (`has_more`, `cursor`, `total_count`).
|
|
27
|
+
|
|
28
|
+
agent:
|
|
29
|
+
interaction_model: stateful_preloaded
|
|
30
|
+
capabilities:
|
|
31
|
+
- has_creative_formats
|
|
32
|
+
examples:
|
|
33
|
+
- "Any AdCP agent that exposes a paginated list_creative_formats"
|
|
34
|
+
|
|
35
|
+
caller:
|
|
36
|
+
role: buyer_agent
|
|
37
|
+
example: "Compliance test harness"
|
|
38
|
+
|
|
39
|
+
prerequisites:
|
|
40
|
+
description: |
|
|
41
|
+
The runner seeds two creative formats ahead of time so a max_results=1
|
|
42
|
+
request reliably triggers a continuation page on the first call.
|
|
43
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
44
|
+
controller_seeding: true
|
|
45
|
+
|
|
46
|
+
fixtures:
|
|
47
|
+
creative_formats:
|
|
48
|
+
- format_id: "pagination_integrity_format_1"
|
|
49
|
+
fixture:
|
|
50
|
+
name: "Pagination Integrity Format A"
|
|
51
|
+
type: "display"
|
|
52
|
+
- format_id: "pagination_integrity_format_2"
|
|
53
|
+
fixture:
|
|
54
|
+
name: "Pagination Integrity Format B"
|
|
55
|
+
type: "display"
|
|
56
|
+
|
|
57
|
+
phases:
|
|
58
|
+
- id: capability_discovery
|
|
59
|
+
title: "Capability discovery"
|
|
60
|
+
narrative: |
|
|
61
|
+
Confirm the agent supports list_creative_formats before exercising
|
|
62
|
+
pagination.
|
|
63
|
+
steps:
|
|
64
|
+
- id: get_capabilities
|
|
65
|
+
title: "Check agent capabilities"
|
|
66
|
+
narrative: |
|
|
67
|
+
Verify that the agent declares creative in supported_protocols
|
|
68
|
+
before driving paginated list_creative_formats.
|
|
69
|
+
task: get_adcp_capabilities
|
|
70
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
71
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
72
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
73
|
+
comply_scenario: capability_discovery
|
|
74
|
+
stateful: false
|
|
75
|
+
expected: |
|
|
76
|
+
Return capabilities declaring creative in supported_protocols.
|
|
77
|
+
|
|
78
|
+
sample_request:
|
|
79
|
+
context:
|
|
80
|
+
correlation_id: "pagination_integrity_creative_formats--get_capabilities"
|
|
81
|
+
validations:
|
|
82
|
+
- check: response_schema
|
|
83
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
84
|
+
- check: field_present
|
|
85
|
+
path: "supported_protocols"
|
|
86
|
+
description: "Agent declares supported protocols"
|
|
87
|
+
- check: field_present
|
|
88
|
+
path: "context"
|
|
89
|
+
description: "Response echoes back the context object"
|
|
90
|
+
- check: field_value
|
|
91
|
+
path: "context.correlation_id"
|
|
92
|
+
value: "pagination_integrity_creative_formats--get_capabilities"
|
|
93
|
+
description: "Context correlation_id returned unchanged"
|
|
94
|
+
|
|
95
|
+
- id: seed_formats
|
|
96
|
+
title: "Seed two creative formats"
|
|
97
|
+
narrative: |
|
|
98
|
+
Pre-populate exactly two creative formats via comply_test_controller
|
|
99
|
+
so the result set has a knowable size for the pagination walk.
|
|
100
|
+
steps:
|
|
101
|
+
- id: seed_format_1
|
|
102
|
+
title: "Seed first format fixture"
|
|
103
|
+
task: comply_test_controller
|
|
104
|
+
schema_ref: "compliance/comply-test-controller-request.json"
|
|
105
|
+
response_schema_ref: "compliance/comply-test-controller-response.json"
|
|
106
|
+
comply_scenario: seed_creative_format
|
|
107
|
+
stateful: true
|
|
108
|
+
expected: |
|
|
109
|
+
Return success: true.
|
|
110
|
+
sample_request:
|
|
111
|
+
account:
|
|
112
|
+
account_id: "acct_pagination_integrity_formats"
|
|
113
|
+
scenario: "seed_creative_format"
|
|
114
|
+
params:
|
|
115
|
+
format_id: "pagination_integrity_format_1"
|
|
116
|
+
fixture:
|
|
117
|
+
name: "Pagination Integrity Format A"
|
|
118
|
+
type: "display"
|
|
119
|
+
context:
|
|
120
|
+
correlation_id: "pagination_integrity_creative_formats--seed_1"
|
|
121
|
+
validations:
|
|
122
|
+
- check: field_value
|
|
123
|
+
path: "success"
|
|
124
|
+
value: true
|
|
125
|
+
description: "Seed acknowledged"
|
|
126
|
+
|
|
127
|
+
- id: seed_format_2
|
|
128
|
+
title: "Seed second format fixture"
|
|
129
|
+
task: comply_test_controller
|
|
130
|
+
schema_ref: "compliance/comply-test-controller-request.json"
|
|
131
|
+
response_schema_ref: "compliance/comply-test-controller-response.json"
|
|
132
|
+
comply_scenario: seed_creative_format
|
|
133
|
+
stateful: true
|
|
134
|
+
expected: |
|
|
135
|
+
Return success: true.
|
|
136
|
+
sample_request:
|
|
137
|
+
account:
|
|
138
|
+
account_id: "acct_pagination_integrity_formats"
|
|
139
|
+
scenario: "seed_creative_format"
|
|
140
|
+
params:
|
|
141
|
+
format_id: "pagination_integrity_format_2"
|
|
142
|
+
fixture:
|
|
143
|
+
name: "Pagination Integrity Format B"
|
|
144
|
+
type: "display"
|
|
145
|
+
context:
|
|
146
|
+
correlation_id: "pagination_integrity_creative_formats--seed_2"
|
|
147
|
+
validations:
|
|
148
|
+
- check: field_value
|
|
149
|
+
path: "success"
|
|
150
|
+
value: true
|
|
151
|
+
description: "Seed acknowledged"
|
|
152
|
+
|
|
153
|
+
- id: pagination_walk
|
|
154
|
+
title: "Walk pages with max_results=1"
|
|
155
|
+
narrative: |
|
|
156
|
+
With two formats seeded and `max_results: 1`, the first call MUST
|
|
157
|
+
return a continuation page (has_more=true with a cursor). The runner
|
|
158
|
+
then follows the cursor; the second call MUST return a terminal page
|
|
159
|
+
(has_more=false with no cursor).
|
|
160
|
+
|
|
161
|
+
steps:
|
|
162
|
+
- id: first_page
|
|
163
|
+
title: "Request the first page with max_results=1"
|
|
164
|
+
narrative: |
|
|
165
|
+
The buyer asks for one format at a time. The agent has two seeded
|
|
166
|
+
formats, so the first page is non-terminal. The runner captures
|
|
167
|
+
`pagination.cursor` for the follow-up step.
|
|
168
|
+
task: list_creative_formats
|
|
169
|
+
schema_ref: "creative/list-creative-formats-request.json"
|
|
170
|
+
response_schema_ref: "creative/list-creative-formats-response.json"
|
|
171
|
+
doc_ref: "/creative/task-reference/list_creative_formats"
|
|
172
|
+
comply_scenario: pagination_integrity
|
|
173
|
+
stateful: true
|
|
174
|
+
context_outputs:
|
|
175
|
+
- name: next_cursor
|
|
176
|
+
path: "pagination.cursor"
|
|
177
|
+
expected: |
|
|
178
|
+
Return one format with:
|
|
179
|
+
- pagination.has_more = true
|
|
180
|
+
- pagination.cursor present (an opaque continuation token)
|
|
181
|
+
|
|
182
|
+
sample_request:
|
|
183
|
+
account:
|
|
184
|
+
account_id: "acct_pagination_integrity_formats"
|
|
185
|
+
pagination:
|
|
186
|
+
max_results: 1
|
|
187
|
+
context:
|
|
188
|
+
correlation_id: "pagination_integrity_creative_formats--first_page"
|
|
189
|
+
validations:
|
|
190
|
+
- check: response_schema
|
|
191
|
+
description: "Response matches list-creative-formats-response.json schema"
|
|
192
|
+
- check: field_value
|
|
193
|
+
path: "pagination.has_more"
|
|
194
|
+
value: true
|
|
195
|
+
description: "Two formats seeded with max_results=1 → first page is non-terminal"
|
|
196
|
+
- check: field_present
|
|
197
|
+
path: "pagination.cursor"
|
|
198
|
+
description: "has_more=true requires a cursor — without one the caller cannot continue"
|
|
199
|
+
- check: field_value_or_absent
|
|
200
|
+
path: "pagination.total_count"
|
|
201
|
+
allowed_values: [2]
|
|
202
|
+
description: "If volunteered, total_count MUST equal the seeded set size of two"
|
|
203
|
+
- check: field_present
|
|
204
|
+
path: "context"
|
|
205
|
+
description: "Response echoes back the context object"
|
|
206
|
+
- check: field_value
|
|
207
|
+
path: "context.correlation_id"
|
|
208
|
+
value: "pagination_integrity_creative_formats--first_page"
|
|
209
|
+
description: "Context correlation_id returned unchanged"
|
|
210
|
+
|
|
211
|
+
- id: terminal_page
|
|
212
|
+
title: "Follow the cursor to the terminal page"
|
|
213
|
+
narrative: |
|
|
214
|
+
The buyer follows the captured cursor. With one format remaining
|
|
215
|
+
the agent MUST return a terminal page: `has_more=false` with no
|
|
216
|
+
`cursor` field. A cursor on `has_more=false` is a stale token
|
|
217
|
+
that invites callers to follow it past the end of results.
|
|
218
|
+
task: list_creative_formats
|
|
219
|
+
schema_ref: "creative/list-creative-formats-request.json"
|
|
220
|
+
response_schema_ref: "creative/list-creative-formats-response.json"
|
|
221
|
+
doc_ref: "/creative/task-reference/list_creative_formats"
|
|
222
|
+
comply_scenario: pagination_integrity
|
|
223
|
+
stateful: true
|
|
224
|
+
expected: |
|
|
225
|
+
Return the remaining format with:
|
|
226
|
+
- pagination.has_more = false
|
|
227
|
+
- pagination.cursor absent
|
|
228
|
+
|
|
229
|
+
sample_request:
|
|
230
|
+
account:
|
|
231
|
+
account_id: "acct_pagination_integrity_formats"
|
|
232
|
+
pagination:
|
|
233
|
+
cursor: "$context.next_cursor"
|
|
234
|
+
max_results: 1
|
|
235
|
+
context:
|
|
236
|
+
correlation_id: "pagination_integrity_creative_formats--terminal_page"
|
|
237
|
+
validations:
|
|
238
|
+
- check: response_schema
|
|
239
|
+
description: "Response matches list-creative-formats-response.json schema"
|
|
240
|
+
- check: field_value
|
|
241
|
+
path: "pagination.has_more"
|
|
242
|
+
value: false
|
|
243
|
+
description: "After two pages of one item the seeded set is exhausted"
|
|
244
|
+
- check: field_value_or_absent
|
|
245
|
+
path: "pagination.cursor"
|
|
246
|
+
allowed_values: [null]
|
|
247
|
+
description: "Terminal page MUST omit cursor (null also accepted for clients that explicitly clear the field)"
|
|
248
|
+
- check: field_value_or_absent
|
|
249
|
+
path: "pagination.total_count"
|
|
250
|
+
allowed_values: [2]
|
|
251
|
+
description: "total_count (when volunteered) MUST stay stable across pages and equal the seeded set size"
|
|
252
|
+
- check: field_present
|
|
253
|
+
path: "context"
|
|
254
|
+
description: "Response echoes back the context object"
|
|
255
|
+
- check: field_value
|
|
256
|
+
path: "context.correlation_id"
|
|
257
|
+
value: "pagination_integrity_creative_formats--terminal_page"
|
|
258
|
+
description: "Context correlation_id returned unchanged"
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
id: pagination_integrity_list_accounts
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Pagination cursor integrity — list_accounts"
|
|
4
|
+
category: schema_validation
|
|
5
|
+
summary: "Validates the cursor↔has_more invariant by walking a paginated list_accounts response from a continuation page to a terminal page."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools:
|
|
8
|
+
- list_accounts
|
|
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_accounts` in a single run.
|
|
21
|
+
|
|
22
|
+
The runner bootstraps three accounts via `sync_accounts`, then lists them
|
|
23
|
+
back with `max_results=2`. The first page MUST cap at two accounts and
|
|
24
|
+
signal continuation with `has_more=true` plus a cursor. The runner then
|
|
25
|
+
follows that cursor; the next page returns the remaining account and MUST
|
|
26
|
+
signal `has_more=false` with no cursor. An agent that hides the third
|
|
27
|
+
account by reporting `has_more=false` on the first page fails the
|
|
28
|
+
first-page assertion. An agent that carries a stale cursor onto the
|
|
29
|
+
terminal page fails the 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 account count of three.
|
|
34
|
+
|
|
35
|
+
agent:
|
|
36
|
+
interaction_model: stateful_preloaded
|
|
37
|
+
capabilities: []
|
|
38
|
+
examples:
|
|
39
|
+
- "Any AdCP agent that exposes a paginated list_accounts"
|
|
40
|
+
|
|
41
|
+
caller:
|
|
42
|
+
role: buyer_agent
|
|
43
|
+
example: "Compliance test harness"
|
|
44
|
+
|
|
45
|
+
prerequisites:
|
|
46
|
+
description: |
|
|
47
|
+
The storyboard bootstraps three accounts in the setup phase via
|
|
48
|
+
`sync_accounts`. The seed-DAG documented at
|
|
49
|
+
`static/compliance/source/universal/storyboard-schema.yaml` does not
|
|
50
|
+
include accounts (today's seed kinds are products, pricing_options,
|
|
51
|
+
creatives, plans, media_buys), so this storyboard deliberately
|
|
52
|
+
departs from the `controller_seeding: true` precedent used by
|
|
53
|
+
`pagination-integrity.yaml` (list_creatives) and bootstraps via
|
|
54
|
+
real protocol calls. Adding `seed_account` to the controller is
|
|
55
|
+
tracked separately; until then the create-then-list pattern keeps
|
|
56
|
+
the storyboard self-contained without extending the seed taxonomy.
|
|
57
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
58
|
+
controller_seeding: false
|
|
59
|
+
|
|
60
|
+
phases:
|
|
61
|
+
- id: capability_discovery
|
|
62
|
+
title: "Capability discovery"
|
|
63
|
+
narrative: |
|
|
64
|
+
Confirm the agent responds to get_adcp_capabilities before
|
|
65
|
+
exercising list_accounts.
|
|
66
|
+
steps:
|
|
67
|
+
- id: get_capabilities
|
|
68
|
+
title: "Check agent capabilities"
|
|
69
|
+
narrative: |
|
|
70
|
+
Verify that the agent declares supported protocols before
|
|
71
|
+
driving paginated list_accounts.
|
|
72
|
+
task: get_adcp_capabilities
|
|
73
|
+
schema_ref: "protocol/get-adcp-capabilities-request.json"
|
|
74
|
+
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
|
|
75
|
+
doc_ref: "/protocol/get_adcp_capabilities"
|
|
76
|
+
comply_scenario: capability_discovery
|
|
77
|
+
stateful: false
|
|
78
|
+
expected: |
|
|
79
|
+
Return capabilities declaring supported protocols.
|
|
80
|
+
|
|
81
|
+
sample_request:
|
|
82
|
+
context:
|
|
83
|
+
correlation_id: "pagination_integrity_list_accounts--get_capabilities"
|
|
84
|
+
validations:
|
|
85
|
+
- check: response_schema
|
|
86
|
+
description: "Response matches get-adcp-capabilities-response.json schema"
|
|
87
|
+
- check: field_present
|
|
88
|
+
path: "supported_protocols"
|
|
89
|
+
description: "Agent declares supported protocols"
|
|
90
|
+
|
|
91
|
+
- check: field_present
|
|
92
|
+
path: "context"
|
|
93
|
+
description: "Response echoes back the context object"
|
|
94
|
+
- check: field_value
|
|
95
|
+
path: "context.correlation_id"
|
|
96
|
+
value: "pagination_integrity_list_accounts--get_capabilities"
|
|
97
|
+
description: "Context correlation_id returned unchanged"
|
|
98
|
+
|
|
99
|
+
- id: setup
|
|
100
|
+
title: "Bootstrap three test accounts"
|
|
101
|
+
narrative: |
|
|
102
|
+
Sync three sandbox accounts so the pagination walk has a
|
|
103
|
+
deterministic set of three items to page through with max_results=2.
|
|
104
|
+
steps:
|
|
105
|
+
- id: sync_three_accounts
|
|
106
|
+
title: "Sync three sandbox accounts"
|
|
107
|
+
narrative: |
|
|
108
|
+
Create three sandbox accounts — Acme c/o Pinnacle, Nova c/o Pinnacle,
|
|
109
|
+
and Pinnacle Direct. The agent MUST accept all three and respond with
|
|
110
|
+
account_id values that subsequent list_accounts calls surface.
|
|
111
|
+
task: sync_accounts
|
|
112
|
+
schema_ref: "account/sync-accounts-request.json"
|
|
113
|
+
response_schema_ref: "account/sync-accounts-response.json"
|
|
114
|
+
doc_ref: "/accounts/task-reference/sync_accounts"
|
|
115
|
+
comply_scenario: pagination_integrity_list_accounts
|
|
116
|
+
stateful: true
|
|
117
|
+
expected: |
|
|
118
|
+
Accept all three accounts and return account_id for each.
|
|
119
|
+
|
|
120
|
+
sample_request:
|
|
121
|
+
accounts:
|
|
122
|
+
- brand:
|
|
123
|
+
domain: acme-corp.com
|
|
124
|
+
operator: pinnacle-media.com
|
|
125
|
+
billing: operator
|
|
126
|
+
sandbox: true
|
|
127
|
+
- brand:
|
|
128
|
+
domain: nova-brands.com
|
|
129
|
+
operator: pinnacle-media.com
|
|
130
|
+
billing: operator
|
|
131
|
+
sandbox: true
|
|
132
|
+
- brand:
|
|
133
|
+
domain: pinnacle-media.com
|
|
134
|
+
operator: pinnacle-media.com
|
|
135
|
+
billing: operator
|
|
136
|
+
sandbox: true
|
|
137
|
+
|
|
138
|
+
idempotency_key: "$generate:uuid_v4#pagination_integrity_list_accounts_setup_sync_three_accounts"
|
|
139
|
+
context:
|
|
140
|
+
correlation_id: "pagination_integrity_list_accounts--setup"
|
|
141
|
+
validations:
|
|
142
|
+
- check: response_schema
|
|
143
|
+
description: "Response matches sync-accounts-response.json schema"
|
|
144
|
+
- check: field_present
|
|
145
|
+
path: "accounts"
|
|
146
|
+
description: "Response contains accounts array"
|
|
147
|
+
|
|
148
|
+
- id: pagination_walk
|
|
149
|
+
title: "Walk pages with a small max_results"
|
|
150
|
+
narrative: |
|
|
151
|
+
With three accounts seeded and `max_results: 2`, the first call MUST
|
|
152
|
+
return a continuation page (has_more=true with a cursor). The runner
|
|
153
|
+
then follows the cursor; the second call MUST return the terminal
|
|
154
|
+
page (has_more=false with no cursor).
|
|
155
|
+
|
|
156
|
+
steps:
|
|
157
|
+
- id: first_page
|
|
158
|
+
title: "Request the first page with max_results=2"
|
|
159
|
+
narrative: |
|
|
160
|
+
The buyer asks for up to two accounts. The agent has three matching
|
|
161
|
+
accounts, so the request is non-terminal: callers expect
|
|
162
|
+
`has_more=true` and a `cursor` they can follow to retrieve the
|
|
163
|
+
remaining account.
|
|
164
|
+
|
|
165
|
+
The runner captures `pagination.cursor` into `$context.next_cursor`
|
|
166
|
+
for the follow-up step. If the agent reports `has_more=false` on
|
|
167
|
+
this page (hiding the seeded third account behind a dishonest
|
|
168
|
+
terminal signal), the field_value check on `pagination.has_more`
|
|
169
|
+
fails — surfacing exactly the bug class this storyboard exists to
|
|
170
|
+
catch.
|
|
171
|
+
task: list_accounts
|
|
172
|
+
schema_ref: "account/list-accounts-request.json"
|
|
173
|
+
response_schema_ref: "account/list-accounts-response.json"
|
|
174
|
+
doc_ref: "/accounts/task-reference/list_accounts"
|
|
175
|
+
comply_scenario: pagination_integrity_list_accounts
|
|
176
|
+
stateful: true
|
|
177
|
+
context_outputs:
|
|
178
|
+
- name: next_cursor
|
|
179
|
+
path: "pagination.cursor"
|
|
180
|
+
expected: |
|
|
181
|
+
Return up to two accounts with:
|
|
182
|
+
- pagination.has_more = true
|
|
183
|
+
- pagination.cursor present (an opaque continuation token)
|
|
184
|
+
|
|
185
|
+
sample_request:
|
|
186
|
+
pagination:
|
|
187
|
+
max_results: 2
|
|
188
|
+
|
|
189
|
+
context:
|
|
190
|
+
correlation_id: "pagination_integrity_list_accounts--first_page"
|
|
191
|
+
validations:
|
|
192
|
+
- check: response_schema
|
|
193
|
+
description: "Response matches list-accounts-response.json schema"
|
|
194
|
+
- check: field_value
|
|
195
|
+
path: "pagination.has_more"
|
|
196
|
+
value: true
|
|
197
|
+
description: "Three accounts seeded with max_results=2 → first page is non-terminal"
|
|
198
|
+
- check: field_present
|
|
199
|
+
path: "pagination.cursor"
|
|
200
|
+
description: "has_more=true requires a cursor — without one the caller cannot continue"
|
|
201
|
+
- check: field_value_or_absent
|
|
202
|
+
path: "pagination.total_count"
|
|
203
|
+
allowed_values: [3]
|
|
204
|
+
description: "If volunteered, total_count MUST equal the seeded set size — under-reporting hides accounts the same way a dishonest has_more does"
|
|
205
|
+
|
|
206
|
+
- check: field_present
|
|
207
|
+
path: "context"
|
|
208
|
+
description: "Response echoes back the context object"
|
|
209
|
+
- check: field_value
|
|
210
|
+
path: "context.correlation_id"
|
|
211
|
+
value: "pagination_integrity_list_accounts--first_page"
|
|
212
|
+
description: "Context correlation_id returned unchanged"
|
|
213
|
+
|
|
214
|
+
- id: terminal_page
|
|
215
|
+
title: "Follow the cursor to the terminal page"
|
|
216
|
+
narrative: |
|
|
217
|
+
The buyer follows the captured cursor. With at most one remaining
|
|
218
|
+
account the agent MUST return a terminal page: `has_more=false`
|
|
219
|
+
with no `cursor` field. A cursor on `has_more=false` is a stale
|
|
220
|
+
token that invites callers to follow it past the end of results.
|
|
221
|
+
task: list_accounts
|
|
222
|
+
schema_ref: "account/list-accounts-request.json"
|
|
223
|
+
response_schema_ref: "account/list-accounts-response.json"
|
|
224
|
+
doc_ref: "/accounts/task-reference/list_accounts"
|
|
225
|
+
comply_scenario: pagination_integrity_list_accounts
|
|
226
|
+
stateful: true
|
|
227
|
+
expected: |
|
|
228
|
+
Return the remaining account(s) with:
|
|
229
|
+
- pagination.has_more = false
|
|
230
|
+
- pagination.cursor absent (a stale cursor on a terminal page is a
|
|
231
|
+
dishonest pagination signal)
|
|
232
|
+
|
|
233
|
+
sample_request:
|
|
234
|
+
pagination:
|
|
235
|
+
cursor: "$context.next_cursor"
|
|
236
|
+
max_results: 2
|
|
237
|
+
|
|
238
|
+
context:
|
|
239
|
+
correlation_id: "pagination_integrity_list_accounts--terminal_page"
|
|
240
|
+
validations:
|
|
241
|
+
- check: response_schema
|
|
242
|
+
description: "Response matches list-accounts-response.json schema"
|
|
243
|
+
- check: field_value
|
|
244
|
+
path: "pagination.has_more"
|
|
245
|
+
value: false
|
|
246
|
+
description: "After two pages of two items the seeded set is exhausted"
|
|
247
|
+
- check: field_value_or_absent
|
|
248
|
+
path: "pagination.cursor"
|
|
249
|
+
allowed_values: [null]
|
|
250
|
+
description: "Terminal page MUST omit cursor (null also accepted for clients that explicitly clear the field)"
|
|
251
|
+
- check: field_value_or_absent
|
|
252
|
+
path: "pagination.total_count"
|
|
253
|
+
allowed_values: [3]
|
|
254
|
+
description: "total_count (when volunteered) MUST stay stable across pages and equal the seeded set size"
|
|
255
|
+
|
|
256
|
+
- check: field_present
|
|
257
|
+
path: "context"
|
|
258
|
+
description: "Response echoes back the context object"
|
|
259
|
+
- check: field_value
|
|
260
|
+
path: "context.correlation_id"
|
|
261
|
+
value: "pagination_integrity_list_accounts--terminal_page"
|
|
262
|
+
description: "Context correlation_id returned unchanged"
|