Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/account-budget-timezone-storyboards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"adcontextprotocol": patch
---

Add capability-gated compliance storyboards for seller-fixed, buyer-selected,
and seller-assigned account timezones; account-based and feature-fixed daily
budget-cap boundaries; buyer cap-timezone overrides; and independent account,
reporting, and billing clocks. Cover buyer-preference mismatches against a
seller-fixed UTC clock, portable natural-key reconnects, and selecting a second
advertised timezone as a separate immutable account identity. Reject
unadvertised buyer timezone overrides with the canonical unsupported-feature
error.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"deploy:cdn-artifacts-cutover:dry-run": "wrangler deploy --config workers/artifact-cdn/wrangler.cutover.toml --dry-run",
"verify:cdn-artifacts-cutover": "node scripts/verify-cdn-artifacts-cutover.mjs",
"typecheck": "tsc --project server/tsconfig.json --noEmit",
"test:schemas": "node tests/schema-validation.test.cjs && node --test tests/trusted-match-offer-creative-data.test.cjs tests/accessibility-violation-details.test.cjs tests/portfolio-routing-scope.test.cjs tests/catalog-item-availability-updates.test.cjs tests/schema-deprecation-metadata.test.cjs tests/creative-rotation.test.cjs tests/lint-schema-enum-drift.test.cjs tests/synthetic-depiction.test.cjs && npm run test:geo-region-targeting",
"test:schemas": "node tests/schema-validation.test.cjs && node --test tests/trusted-match-offer-creative-data.test.cjs tests/accessibility-violation-details.test.cjs tests/portfolio-routing-scope.test.cjs tests/catalog-item-availability-updates.test.cjs tests/timezone-resolution-storyboards.test.cjs tests/schema-deprecation-metadata.test.cjs tests/creative-rotation.test.cjs tests/lint-schema-enum-drift.test.cjs tests/synthetic-depiction.test.cjs && npm run test:geo-region-targeting",
"test:performance-feedback": "node --test --test-force-exit --test-timeout=30000 tests/performance-feedback-contract.test.cjs",
"test:dist-schema-version-ids": "node --test --test-force-exit --test-timeout=30000 tests/dist-schema-version-ids.test.cjs",
"test:examples": "node tests/example-validation-simple.test.cjs && npm run test:tmp-context-merge",
Expand Down
439 changes: 417 additions & 22 deletions static/compliance/source/protocols/media-buy/index.yaml

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
id: media_buy_seller/account_timezone_seller_assigned
version: "1.0.0"
title: "Seller-assigned account timezone discovery"
category: media_buy_seller
summary: "Verifies that buyers omit timezone input and discover the seller-assigned immutable value from account readback."
track: media_buy
introduced_in: "3.2"

requires_capability:
path: account.timezone.account_selection
equals: seller_assigned

required_tools:
- get_adcp_capabilities
- sync_accounts
- list_accounts

narrative: |
In seller-assigned account-fixed mode, the buyer does not choose a timezone.
The seller assigns or recovers the upstream account clock, returns it from
provisioning, and keeps it stable on later account reads. A buyer connecting
to an existing upstream account must use the returned canonical timezone even
when its own current preference differs.

agent:
interaction_model: media_buy_seller
capabilities:
- sells_media
- seller_assigned_account_timezone

caller:
role: buyer_agent
example: "Pinnacle Agency (buyer)"

prerequisites:
description: "The seller advertises account_fixed timezone assignment by the seller."
test_kit: "test-kits/acme-outdoor.yaml"

phases:
- id: discover_and_provision
title: "Provision without buyer timezone input"
steps:
- id: discover_assignment_mode
title: "Confirm seller assignment"
task: get_adcp_capabilities
schema_ref: "protocol/get-adcp-capabilities-request.json"
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
doc_ref: "/protocol/get_adcp_capabilities"
stateful: false
sample_request: {}
validations:
- check: response_schema
description: "Capability response matches the canonical schema"
- check: field_value
path: "account.timezone.mode"
value: "account_fixed"
description: "Seller assignment is an account-fixed mode"
- check: field_value
path: "account.timezone.account_selection"
value: "seller_assigned"
description: "Seller owns timezone assignment"
- check: field_absent
path: "account.timezone.supported_timezones"
description: "Seller assignment exposes no buyer allowlist"
- check: field_absent
path: "account.timezone.fixed_timezone"
description: "Different accounts may use different assigned timezones"

- id: provision_without_timezone
title: "Let the seller assign the account timezone"
task: sync_accounts
schema_ref: "account/sync-accounts-request.json"
response_schema_ref: "account/sync-accounts-response.json"
doc_ref: "/accounts/tasks/sync_accounts"
stateful: true
sample_request:
accounts:
- brand:
domain: "acmeoutdoor.example"
operator: "pinnacle-agency.example"
billing: "operator"
Comment thread
bokelley marked this conversation as resolved.
sandbox: true
idempotency_key: "$generate:uuid_v4#account_timezone_seller_assigned_provision"
context_outputs:
- name: account_timezone
path: "accounts[0].timezone"
validations:
- check: response_schema
description: "Provisioning response matches the canonical schema"
- check: field_value
path: "accounts[0].action"
allowed_values: ["created", "updated", "unchanged"]
description: "Provisioning succeeds instead of returning a per-account failure"
- check: field_present
path: "accounts[0].timezone"
description: "Seller returns the assigned immutable timezone"
- check: field_value
path: "accounts[0].brand.domain"
value: "acmeoutdoor.example"
description: "Provisioning echoes the reusable brand natural key"
- check: field_value
path: "accounts[0].operator"
value: "pinnacle-agency.example"
description: "Provisioning echoes the reusable operator natural key"

- id: readback
title: "Discover the assigned timezone again"
depends_on: [discover_and_provision]
steps:
- id: list_seller_assigned_account
title: "Read the provisioned account"
task: list_accounts
schema_ref: "account/list-accounts-request.json"
response_schema_ref: "account/list-accounts-response.json"
doc_ref: "/accounts/tasks/list_accounts"
stateful: false
sample_request:
account:
brand:
domain: "acmeoutdoor.example"
operator: "pinnacle-agency.example"
sandbox: true
validations:
- check: response_schema
description: "Account read matches the canonical schema"
- check: field_equals_context
path: "accounts[0].timezone"
context_key: "account_timezone"
description: "Readback preserves the assigned timezone"
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
id: media_buy_seller/account_timezone_seller_fixed
version: "1.0.0"
title: "Seller-fixed account timezone resolution"
category: media_buy_seller
summary: "Verifies that seller-fixed account capabilities declare one timezone and every account write and read echoes it."
track: media_buy
introduced_in: "3.2"

requires_capability:
path: account.timezone.mode
equals: seller_fixed

required_tools:
- get_adcp_capabilities
- sync_accounts
- list_accounts

narrative: |
A seller-fixed account clock is one seller-wide operational timezone. The
capability must declare that value, buyers omit timezone during provisioning,
and the seller echoes the effective value on both sync and list surfaces.
Buyer-local labels or preferences such as West Coast and East Coast never
override this contract: when the seller is fixed to UTC, both buyer teams use
UTC for the account even though their own local clocks differ.

agent:
interaction_model: media_buy_seller
capabilities:
- sells_media
- seller_fixed_account_timezone

caller:
role: buyer_agent
example: "Pinnacle Agency (buyer)"

prerequisites:
description: "The seller advertises account.timezone.mode seller_fixed."
test_kit: "test-kits/acme-outdoor.yaml"

phases:
- id: discover_and_provision
title: "Discover and apply the seller-wide timezone"
steps:
- id: discover_seller_timezone
title: "Read the seller-fixed timezone"
task: get_adcp_capabilities
schema_ref: "protocol/get-adcp-capabilities-request.json"
response_schema_ref: "protocol/get-adcp-capabilities-response.json"
doc_ref: "/protocol/get_adcp_capabilities"
stateful: false
sample_request: {}
context_outputs:
- name: account_timezone
path: "account.timezone.fixed_timezone"
validations:
- check: response_schema
description: "Capability response matches the canonical schema"
- check: field_value
path: "account.timezone.mode"
value: "seller_fixed"
description: "Seller declares the seller-fixed mode"
- check: field_present
path: "account.timezone.fixed_timezone"
description: "Seller-fixed mode declares its mandatory timezone"
- check: field_absent
path: "account.timezone.account_selection"
description: "Seller-fixed mode does not expose per-account selection"
- check: field_absent
path: "account.timezone.supported_timezones"
description: "Seller-fixed mode does not expose a buyer selection list"

- id: provision_without_timezone
title: "Provision without buyer timezone input"
task: sync_accounts
schema_ref: "account/sync-accounts-request.json"
response_schema_ref: "account/sync-accounts-response.json"
doc_ref: "/accounts/tasks/sync_accounts"
stateful: true
sample_request:
accounts:
- brand:
domain: "acmeoutdoor.example"
operator: "pinnacle-agency.example"
billing: "operator"
Comment thread
bokelley marked this conversation as resolved.
sandbox: true
idempotency_key: "$generate:uuid_v4#account_timezone_seller_fixed_provision"
validations:
- check: response_schema
description: "Provisioning response matches the canonical schema"
- check: field_value
path: "accounts[0].action"
allowed_values: ["created", "updated", "unchanged"]
description: "Provisioning succeeds instead of returning a per-account failure"
- check: field_equals_context
path: "accounts[0].timezone"
context_key: "account_timezone"
description: "Provisioning echoes the seller-wide timezone"
- check: field_value
path: "accounts[0].brand.domain"
value: "acmeoutdoor.example"
description: "Provisioning echoes the reusable brand natural key"
- check: field_value
path: "accounts[0].operator"
value: "pinnacle-agency.example"
description: "Provisioning echoes the reusable operator natural key"

- id: readback
title: "Read back the immutable account timezone"
depends_on: [discover_and_provision]
steps:
- id: list_seller_fixed_account
title: "Read the provisioned account"
task: list_accounts
schema_ref: "account/list-accounts-request.json"
response_schema_ref: "account/list-accounts-response.json"
doc_ref: "/accounts/tasks/list_accounts"
stateful: false
sample_request:
account:
brand:
domain: "acmeoutdoor.example"
operator: "pinnacle-agency.example"
sandbox: true
validations:
- check: response_schema
description: "Account read matches the canonical schema"
- check: field_equals_context
path: "accounts[0].timezone"
context_key: "account_timezone"
description: "Readback preserves the seller-wide timezone"
Loading
Loading