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
9 changes: 9 additions & 0 deletions .changeset/4383-comply-test-controller-require-account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"adcontextprotocol": minor
---

`comply_test_controller`: `account.sandbox: true` is now **required** on every controller request. The follow-up to #4382 / #3755 — sample_request blocks across all 25 controller call-sites in the storyboard suite have been swept to include the field, and the request schema's `required` array now lists `account` alongside `scenario`. Schema examples updated to match.

Lint coverage is automatic: the existing `lint-storyboard-sample-request-schema.cjs` runs ajv against every storyboard sample_request, so any new `comply_test_controller` step that omits `account.sandbox: true` fails CI with `required@/:account` and is blocked without an allowlist entry. No new lint code needed — the schema tightening is the gate.

This operationalizes the (Sandbox) verdict's defense-in-depth: the seller-side persisted-record check is the load-bearing gate, and now the wire format enforces it too. Closes #4383.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ phases:
- forced.task_id: deterministic task handle the next create_media_buy will return

sample_request:
account:
sandbox: true
scenario: "force_create_media_buy_arm"
params:
arm: "submitted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ phases:
expected: |
The test controller acknowledges the simulated delivery data.
sample_request:
account:
sandbox: true
scenario: "simulate_delivery"
params:
media_buy_id: "$context.media_buy_id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ phases:
expected: |
The test controller acknowledges the simulated delivery data.
sample_request:
account:
sandbox: true
scenario: "simulate_delivery"
params:
media_buy_id: "$context.media_buy_id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ phases:
The test controller acknowledges the simulated delivery data including
the vendor_metric_values.
sample_request:
account:
sandbox: true
scenario: "simulate_delivery"
params:
media_buy_id: "$context.media_buy_id"
Expand Down
38 changes: 38 additions & 0 deletions static/compliance/source/universal/deterministic-testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ phases:
- scenarios: array or object of scenario names

sample_request:
account:
sandbox: true
scenario: 'list_scenarios'

context:
Expand Down Expand Up @@ -150,6 +152,8 @@ phases:
- error: UNKNOWN_SCENARIO

sample_request:
account:
sandbox: true
scenario: 'nonexistent_scenario'
params: {}

Expand Down Expand Up @@ -196,6 +200,8 @@ phases:
UNKNOWN_SCENARIO (when scenario not on this tenant)

sample_request:
account:
sandbox: true
scenario: 'force_creative_status'
params: {}

Expand Down Expand Up @@ -242,6 +248,8 @@ phases:
UNKNOWN_SCENARIO (when scenario not on this tenant)

sample_request:
account:
sandbox: true
scenario: 'force_creative_status'
params:
creative_id: 'comply-test-nonexistent-000000000000'
Expand Down Expand Up @@ -358,6 +366,8 @@ phases:
- current_state: suspended

sample_request:
account:
sandbox: true
scenario: 'force_account_status'
params:
account_id: '$context.account_id'
Expand Down Expand Up @@ -400,6 +410,8 @@ phases:
- current_state: active

sample_request:
account:
sandbox: true
scenario: 'force_account_status'
params:
account_id: '$context.account_id'
Expand Down Expand Up @@ -439,6 +451,8 @@ phases:
Return a successful state transition to payment_required.

sample_request:
account:
sandbox: true
scenario: 'force_account_status'
params:
account_id: '$context.account_id'
Expand Down Expand Up @@ -472,6 +486,8 @@ phases:
Account restored to active state.

sample_request:
account:
sandbox: true
scenario: 'force_account_status'
params:
account_id: '$context.account_id'
Expand Down Expand Up @@ -559,6 +575,8 @@ phases:
Return a successful state transition to active.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_media_buy_status'
Expand Down Expand Up @@ -639,6 +657,8 @@ phases:
Return a successful transition to completed.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_media_buy_status'
Expand Down Expand Up @@ -684,6 +704,8 @@ phases:
- error: INVALID_TRANSITION

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_media_buy_status'
Expand Down Expand Up @@ -783,6 +805,8 @@ phases:
Successful transition to approved.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_creative_status'
Expand Down Expand Up @@ -823,6 +847,8 @@ phases:
Successful transition to archived.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_creative_status'
Expand Down Expand Up @@ -861,6 +887,8 @@ phases:
Return error with INVALID_TRANSITION.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_creative_status'
Expand Down Expand Up @@ -952,6 +980,8 @@ phases:
Successful transition to rejected with reason preserved.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'force_creative_status'
Expand Down Expand Up @@ -1037,6 +1067,8 @@ phases:
Successful transition to terminated.

sample_request:
account:
sandbox: true
scenario: 'force_session_status'
params:
session_id: '$context.session_id'
Expand Down Expand Up @@ -1162,6 +1194,8 @@ phases:
Return success with simulated delivery metrics acknowledged.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'simulate_delivery'
Expand Down Expand Up @@ -1295,6 +1329,8 @@ phases:
Return success with budget spend simulated to 95%.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'simulate_budget_spend'
Expand Down Expand Up @@ -1331,6 +1367,8 @@ phases:
Return success with budget fully depleted.

sample_request:
account:
sandbox: true
brand:
domain: 'acmeoutdoor.example'
scenario: 'simulate_budget_spend'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ phases:
Return success: true.
sample_request:
account:
sandbox: true
account_id: "acct_pagination_integrity_formats"
scenario: "seed_creative_format"
params:
Expand All @@ -135,6 +136,7 @@ phases:
Return success: true.
sample_request:
account:
sandbox: true
account_id: "acct_pagination_integrity_formats"
scenario: "seed_creative_format"
params:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@
},
"account": {
"type": "object",
"description": "Sandbox account assertion. The runner SHOULD set sandbox: true on every comply_test_controller request; required in a future version. The seller MUST refuse the request (returning a structured error) if the targeted account is not a sandbox account in the seller's persisted records. This field is a caller-side declaration of intent — it does not grant sandbox status; sellers verify against their own account state. The (Sandbox) verification tier is defined by this gate: real production endpoints accept sandbox-flagged traffic and process it without real-world side effects, no separate test-mode endpoint required. See spec issue #3755 and the (Sandbox) framing in #4379. NOTE: optional in this version while existing storyboards add the field; the const: true constraint applies when present, so a request asserting sandbox: false schema-rejects regardless. A subsequent version bump will move this field into the required array; follow-up issue tracks the storyboard sweep that unblocks that.",
"description": "Sandbox account assertion. The runner MUST set sandbox: true on every comply_test_controller request. The seller MUST refuse the request (returning a structured error) if the targeted account is not a sandbox account in the seller's persisted records. This field is a caller-side declaration of intent — it does not grant sandbox status; sellers verify against their own account state. The (Sandbox) verification tier is defined by this gate: real production endpoints accept sandbox-flagged traffic and process it without real-world side effects, no separate test-mode endpoint required. See spec issue #3755 and the (Sandbox) framing in #4379.",
"required": [
"sandbox"
],
Expand All @@ -579,14 +579,18 @@
}
},
"required": [
"scenario"
"scenario",
"account"
],
"additionalProperties": true,
"examples": [
{
"description": "List supported scenarios",
"data": {
"scenario": "list_scenarios"
"scenario": "list_scenarios",
"account": {
"sandbox": true
}
}
},
{
Expand All @@ -597,6 +601,9 @@
"creative_id": "cr-123",
"status": "rejected",
"rejection_reason": "Brand safety policy violation"
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -607,6 +614,9 @@
"params": {
"account_id": "acct-456",
"status": "suspended"
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -618,6 +628,9 @@
"arm": "submitted",
"task_id": "task_async_signed_io_q2",
"message": "Awaiting IO signature from sales team; typical turnaround 2–4 hours"
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -638,6 +651,9 @@
}
]
}
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -649,6 +665,9 @@
"session_id": "sess-abc",
"status": "terminated",
"termination_reason": "session_timeout"
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -664,6 +683,9 @@
"amount": 150,
"currency": "USD"
}
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -674,6 +696,9 @@
"params": {
"media_buy_id": "mb-789",
"spend_percentage": 95
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -697,6 +722,9 @@
}
]
}
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -712,6 +740,9 @@
"id": "video_30s"
}
}
},
"account": {
"sandbox": true
}
}
},
Expand All @@ -723,6 +754,9 @@
"since_timestamp": "2026-05-02T14:30:00Z",
"endpoint_pattern": "POST *",
"limit": 100
},
"account": {
"sandbox": true
}
}
}
Expand Down
Loading