@adcp/client 4.21.0 → 4.22.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/AGENTS.md +278 -0
- package/README.md +96 -61
- package/bin/adcp.js +342 -4
- package/dist/lib/agents/index.generated.d.ts +9 -1
- package/dist/lib/agents/index.generated.d.ts.map +1 -1
- package/dist/lib/agents/index.generated.js +12 -0
- package/dist/lib/agents/index.generated.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts +2 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +10 -1
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/discovery/property-crawler.d.ts +4 -0
- package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
- package/dist/lib/discovery/property-crawler.js +10 -2
- package/dist/lib/discovery/property-crawler.js.map +1 -1
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +6 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +8 -6
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +24 -11
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +3 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/serve.d.ts +45 -0
- package/dist/lib/server/serve.d.ts.map +1 -0
- package/dist/lib/server/serve.js +86 -0
- package/dist/lib/server/serve.js.map +1 -0
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +1 -0
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +48 -63
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
- package/dist/lib/testing/compliance/types.d.ts +1 -1
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +23 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/orchestrator.d.ts +8 -0
- package/dist/lib/testing/orchestrator.d.ts.map +1 -1
- package/dist/lib/testing/orchestrator.js +8 -0
- package/dist/lib/testing/orchestrator.js.map +1 -1
- package/dist/lib/testing/storyboard/context.d.ts +34 -0
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/context.js +257 -0
- package/dist/lib/testing/storyboard/context.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +15 -0
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/index.js +48 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts +53 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/loader.js +114 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -0
- package/dist/lib/testing/storyboard/path.d.ts +29 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/path.js +121 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.js +410 -0
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/runner.js +280 -0
- package/dist/lib/testing/storyboard/runner.js.map +1 -0
- package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/task-map.js +84 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -0
- package/dist/lib/testing/storyboard/types.d.ts +156 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/types.js +10 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -0
- package/dist/lib/testing/storyboard/validations.d.ts +17 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/validations.js +166 -0
- package/dist/lib/testing/storyboard/validations.js.map +1 -0
- package/dist/lib/testing/types.d.ts +2 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +2 -2
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/schemas.generated.d.ts +193 -34
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +87 -5
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +280 -3
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +34 -3
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/validate-user-agent.d.ts +8 -0
- package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
- package/dist/lib/utils/validate-user-agent.js +15 -0
- package/dist/lib/utils/validate-user-agent.js.map +1 -0
- package/dist/lib/version.d.ts +6 -0
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +7 -1
- package/dist/lib/version.js.map +1 -1
- package/docs/README.md +42 -0
- package/docs/guides/BUILD-AN-AGENT.md +292 -0
- package/docs/llms.txt +634 -0
- package/examples/README.md +106 -0
- package/examples/adcp.config.json +30 -0
- package/examples/basic-a2a.ts +76 -0
- package/examples/basic-mcp.ts +50 -0
- package/examples/batch-preview-test.ts +266 -0
- package/examples/conversation-client.ts +291 -0
- package/examples/debug-preview-response.ts +73 -0
- package/examples/debug-preview-with-logging.ts +50 -0
- package/examples/easy-config-demo.ts +242 -0
- package/examples/env-config.ts +51 -0
- package/examples/error-compliant-server.ts +237 -0
- package/examples/generative-creative-demo.ts +205 -0
- package/examples/inspect-card-formats.ts +161 -0
- package/examples/logger-usage.ts +165 -0
- package/examples/oauth-cli-example.ts +154 -0
- package/examples/pr78-async-patterns-demo.ts +247 -0
- package/examples/signals-agent.ts +162 -0
- package/examples/simple-getting-started.ts +225 -0
- package/examples/simple-protocol-demo.ts +75 -0
- package/examples/test-helpers-demo.ts +239 -0
- package/examples/zod-validation-example.ts +126 -0
- package/package.json +12 -2
- package/skills/adcp/SKILL.md +13 -2
- package/storyboards/audience_sync.yaml +199 -0
- package/storyboards/behavioral_analysis.yaml +244 -0
- package/storyboards/brand_rights.yaml +131 -0
- package/storyboards/creative_ad_server.yaml +171 -0
- package/storyboards/creative_sales_agent.yaml +169 -0
- package/storyboards/creative_template.yaml +306 -0
- package/storyboards/deterministic_testing.yaml +925 -0
- package/storyboards/error_compliance.yaml +231 -0
- package/storyboards/governance_content_standards.yaml +213 -0
- package/storyboards/governance_property_lists.yaml +372 -0
- package/storyboards/media_buy_catalog_creative.yaml +457 -0
- package/storyboards/media_buy_governance_escalation.yaml +467 -0
- package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
- package/storyboards/media_buy_non_guaranteed.yaml +288 -0
- package/storyboards/media_buy_proposal_mode.yaml +369 -0
- package/storyboards/media_buy_seller.yaml +560 -0
- package/storyboards/media_buy_state_machine.yaml +254 -0
- package/storyboards/schema.yaml +65 -0
- package/storyboards/schema_validation.yaml +166 -0
- package/storyboards/si_session.yaml +384 -0
- package/storyboards/signal_marketplace.yaml +283 -0
- package/storyboards/signal_owned.yaml +211 -0
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
id: deterministic_testing
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Deterministic testing"
|
|
4
|
+
category: core
|
|
5
|
+
summary: "Uses comply_test_controller to force state transitions and simulate delivery/budget, verifying state machines and reporting."
|
|
6
|
+
track: core
|
|
7
|
+
required_tools:
|
|
8
|
+
- comply_test_controller
|
|
9
|
+
platform_types:
|
|
10
|
+
- display_ad_server
|
|
11
|
+
- video_ad_server
|
|
12
|
+
- social_platform
|
|
13
|
+
- retail_media
|
|
14
|
+
- search_platform
|
|
15
|
+
- audio_platform
|
|
16
|
+
- linear_tv_platform
|
|
17
|
+
- dsp
|
|
18
|
+
- pmax_platform
|
|
19
|
+
- ai_ad_network
|
|
20
|
+
- ai_platform
|
|
21
|
+
- generative_dsp
|
|
22
|
+
|
|
23
|
+
narrative: |
|
|
24
|
+
Sellers that implement the comply_test_controller tool enable deterministic compliance
|
|
25
|
+
testing. The controller forces server-side state transitions without relying on real
|
|
26
|
+
async workflows, letting the test harness verify state machine behavior, operation
|
|
27
|
+
gating, and reporting accuracy.
|
|
28
|
+
|
|
29
|
+
This storyboard covers the full controller surface: scenario listing, account state
|
|
30
|
+
machines, media buy lifecycle, creative status transitions, SI session management,
|
|
31
|
+
delivery simulation, and budget spend simulation.
|
|
32
|
+
|
|
33
|
+
agent:
|
|
34
|
+
interaction_model: media_buy_seller
|
|
35
|
+
capabilities:
|
|
36
|
+
- sells_media
|
|
37
|
+
- supports_test_controller
|
|
38
|
+
examples:
|
|
39
|
+
- "Any seller with comply_test_controller"
|
|
40
|
+
|
|
41
|
+
caller:
|
|
42
|
+
role: buyer_agent
|
|
43
|
+
example: "Comply test harness"
|
|
44
|
+
|
|
45
|
+
prerequisites:
|
|
46
|
+
description: |
|
|
47
|
+
The seller must expose the comply_test_controller tool. The controller is detected
|
|
48
|
+
via list_scenarios before any state transitions are attempted. Phases that require
|
|
49
|
+
specific scenarios are skipped if the controller does not support them.
|
|
50
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
51
|
+
|
|
52
|
+
phases:
|
|
53
|
+
- id: controller_validation
|
|
54
|
+
title: "Controller validation"
|
|
55
|
+
narrative: |
|
|
56
|
+
Validates that the comply_test_controller is functional and responds correctly
|
|
57
|
+
to scenario discovery, unknown scenarios, missing parameters, and nonexistent
|
|
58
|
+
entity references.
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- id: list_scenarios
|
|
62
|
+
title: "List supported scenarios"
|
|
63
|
+
requires_tool: comply_test_controller
|
|
64
|
+
narrative: |
|
|
65
|
+
Call the controller with scenario: list_scenarios to discover which
|
|
66
|
+
force_* and simulate_* scenarios the seller supports.
|
|
67
|
+
task: comply_test_controller
|
|
68
|
+
comply_scenario: controller_validation
|
|
69
|
+
stateful: false
|
|
70
|
+
context_outputs:
|
|
71
|
+
- name: supported_scenarios
|
|
72
|
+
path: "scenarios"
|
|
73
|
+
expected: |
|
|
74
|
+
Return a list of supported scenarios. The response should include:
|
|
75
|
+
- success: true
|
|
76
|
+
- scenarios: array or object of scenario names
|
|
77
|
+
|
|
78
|
+
sample_request:
|
|
79
|
+
scenario: "list_scenarios"
|
|
80
|
+
|
|
81
|
+
validations:
|
|
82
|
+
- check: field_present
|
|
83
|
+
path: "scenarios"
|
|
84
|
+
description: "Controller returns supported scenarios"
|
|
85
|
+
- check: field_value
|
|
86
|
+
path: "success"
|
|
87
|
+
allowed_values:
|
|
88
|
+
- true
|
|
89
|
+
description: "list_scenarios succeeds"
|
|
90
|
+
|
|
91
|
+
- id: unknown_scenario
|
|
92
|
+
title: "Unknown scenario returns error"
|
|
93
|
+
requires_tool: comply_test_controller
|
|
94
|
+
narrative: |
|
|
95
|
+
Send a nonexistent scenario name. The controller should return
|
|
96
|
+
UNKNOWN_SCENARIO error code.
|
|
97
|
+
task: comply_test_controller
|
|
98
|
+
comply_scenario: controller_validation
|
|
99
|
+
stateful: false
|
|
100
|
+
expected: |
|
|
101
|
+
Return an error response with:
|
|
102
|
+
- success: false
|
|
103
|
+
- error: UNKNOWN_SCENARIO
|
|
104
|
+
|
|
105
|
+
sample_request:
|
|
106
|
+
scenario: "nonexistent_scenario"
|
|
107
|
+
params: {}
|
|
108
|
+
|
|
109
|
+
validations:
|
|
110
|
+
- check: field_value
|
|
111
|
+
path: "success"
|
|
112
|
+
allowed_values:
|
|
113
|
+
- false
|
|
114
|
+
description: "Unknown scenario fails"
|
|
115
|
+
- check: field_value
|
|
116
|
+
path: "error"
|
|
117
|
+
allowed_values:
|
|
118
|
+
- "UNKNOWN_SCENARIO"
|
|
119
|
+
description: "Error code is UNKNOWN_SCENARIO"
|
|
120
|
+
|
|
121
|
+
- id: missing_params
|
|
122
|
+
title: "Missing params returns error"
|
|
123
|
+
requires_tool: comply_test_controller
|
|
124
|
+
narrative: |
|
|
125
|
+
Call force_creative_status with empty params. The controller should
|
|
126
|
+
return INVALID_PARAMS error code.
|
|
127
|
+
task: comply_test_controller
|
|
128
|
+
comply_scenario: controller_validation
|
|
129
|
+
stateful: false
|
|
130
|
+
expected: |
|
|
131
|
+
Return an error response with:
|
|
132
|
+
- success: false
|
|
133
|
+
- error: INVALID_PARAMS
|
|
134
|
+
|
|
135
|
+
sample_request:
|
|
136
|
+
scenario: "force_creative_status"
|
|
137
|
+
params: {}
|
|
138
|
+
|
|
139
|
+
validations:
|
|
140
|
+
- check: field_value
|
|
141
|
+
path: "success"
|
|
142
|
+
allowed_values:
|
|
143
|
+
- false
|
|
144
|
+
description: "Missing params fails"
|
|
145
|
+
- check: field_value
|
|
146
|
+
path: "error"
|
|
147
|
+
allowed_values:
|
|
148
|
+
- "INVALID_PARAMS"
|
|
149
|
+
description: "Error code is INVALID_PARAMS"
|
|
150
|
+
|
|
151
|
+
- id: not_found_entity
|
|
152
|
+
title: "Nonexistent entity returns NOT_FOUND"
|
|
153
|
+
requires_tool: comply_test_controller
|
|
154
|
+
narrative: |
|
|
155
|
+
Call force_creative_status with a nonexistent creative_id. The controller
|
|
156
|
+
should return NOT_FOUND error code.
|
|
157
|
+
task: comply_test_controller
|
|
158
|
+
comply_scenario: controller_validation
|
|
159
|
+
stateful: false
|
|
160
|
+
expected: |
|
|
161
|
+
Return an error response with:
|
|
162
|
+
- success: false
|
|
163
|
+
- error: NOT_FOUND
|
|
164
|
+
|
|
165
|
+
sample_request:
|
|
166
|
+
scenario: "force_creative_status"
|
|
167
|
+
params:
|
|
168
|
+
creative_id: "comply-test-nonexistent-000000000000"
|
|
169
|
+
status: "approved"
|
|
170
|
+
|
|
171
|
+
validations:
|
|
172
|
+
- check: field_value
|
|
173
|
+
path: "success"
|
|
174
|
+
allowed_values:
|
|
175
|
+
- false
|
|
176
|
+
description: "Nonexistent entity fails"
|
|
177
|
+
- check: field_value
|
|
178
|
+
path: "error"
|
|
179
|
+
allowed_values:
|
|
180
|
+
- "NOT_FOUND"
|
|
181
|
+
description: "Error code is NOT_FOUND"
|
|
182
|
+
|
|
183
|
+
- id: deterministic_account
|
|
184
|
+
title: "Deterministic account state machine"
|
|
185
|
+
narrative: |
|
|
186
|
+
Forces account status transitions via the controller and verifies them through
|
|
187
|
+
list_accounts. Tests suspension gating (operations blocked when suspended),
|
|
188
|
+
payment_required state, and reactivation.
|
|
189
|
+
|
|
190
|
+
steps:
|
|
191
|
+
- id: list_accounts_for_state
|
|
192
|
+
title: "Find account for state machine test"
|
|
193
|
+
requires_tool: comply_test_controller
|
|
194
|
+
narrative: |
|
|
195
|
+
List accounts to find an active account for state transitions.
|
|
196
|
+
task: list_accounts
|
|
197
|
+
comply_scenario: deterministic_account
|
|
198
|
+
stateful: false
|
|
199
|
+
context_outputs:
|
|
200
|
+
- name: account_id
|
|
201
|
+
path: "accounts[0].account_id"
|
|
202
|
+
expected: |
|
|
203
|
+
Return at least one account with an account_id.
|
|
204
|
+
|
|
205
|
+
sample_request: {}
|
|
206
|
+
|
|
207
|
+
validations:
|
|
208
|
+
- check: field_present
|
|
209
|
+
path: "accounts[0].account_id"
|
|
210
|
+
description: "At least one account exists"
|
|
211
|
+
|
|
212
|
+
- id: force_account_suspended
|
|
213
|
+
title: "Force account to suspended"
|
|
214
|
+
requires_tool: comply_test_controller
|
|
215
|
+
narrative: |
|
|
216
|
+
Use the controller to force the account into suspended state. Operations
|
|
217
|
+
like create_media_buy should be blocked while the account is suspended.
|
|
218
|
+
task: comply_test_controller
|
|
219
|
+
comply_scenario: deterministic_account
|
|
220
|
+
stateful: true
|
|
221
|
+
expected: |
|
|
222
|
+
Return a successful state transition:
|
|
223
|
+
- success: true
|
|
224
|
+
- previous_state: the account's prior status
|
|
225
|
+
- current_state: suspended
|
|
226
|
+
|
|
227
|
+
sample_request:
|
|
228
|
+
scenario: "force_account_status"
|
|
229
|
+
params:
|
|
230
|
+
account_id: "{{account_id}}"
|
|
231
|
+
status: "suspended"
|
|
232
|
+
|
|
233
|
+
validations:
|
|
234
|
+
- check: field_value
|
|
235
|
+
path: "success"
|
|
236
|
+
allowed_values:
|
|
237
|
+
- true
|
|
238
|
+
description: "Account suspension succeeds"
|
|
239
|
+
- check: field_value
|
|
240
|
+
path: "current_state"
|
|
241
|
+
allowed_values:
|
|
242
|
+
- "suspended"
|
|
243
|
+
description: "Account is now suspended"
|
|
244
|
+
|
|
245
|
+
- id: force_account_active
|
|
246
|
+
title: "Reactivate account"
|
|
247
|
+
requires_tool: comply_test_controller
|
|
248
|
+
narrative: |
|
|
249
|
+
Restore the account to active state. Verify the transition from suspended
|
|
250
|
+
back to active succeeds.
|
|
251
|
+
task: comply_test_controller
|
|
252
|
+
comply_scenario: deterministic_account
|
|
253
|
+
stateful: true
|
|
254
|
+
expected: |
|
|
255
|
+
Return a successful state transition:
|
|
256
|
+
- success: true
|
|
257
|
+
- previous_state: suspended
|
|
258
|
+
- current_state: active
|
|
259
|
+
|
|
260
|
+
sample_request:
|
|
261
|
+
scenario: "force_account_status"
|
|
262
|
+
params:
|
|
263
|
+
account_id: "{{account_id}}"
|
|
264
|
+
status: "active"
|
|
265
|
+
|
|
266
|
+
validations:
|
|
267
|
+
- check: field_value
|
|
268
|
+
path: "success"
|
|
269
|
+
allowed_values:
|
|
270
|
+
- true
|
|
271
|
+
description: "Account reactivation succeeds"
|
|
272
|
+
- check: field_value
|
|
273
|
+
path: "current_state"
|
|
274
|
+
allowed_values:
|
|
275
|
+
- "active"
|
|
276
|
+
description: "Account is now active"
|
|
277
|
+
|
|
278
|
+
- id: force_account_payment_required
|
|
279
|
+
title: "Force account to payment_required"
|
|
280
|
+
requires_tool: comply_test_controller
|
|
281
|
+
narrative: |
|
|
282
|
+
Force the account into payment_required state. This tests a distinct
|
|
283
|
+
non-terminal blocked state.
|
|
284
|
+
task: comply_test_controller
|
|
285
|
+
comply_scenario: deterministic_account
|
|
286
|
+
stateful: true
|
|
287
|
+
expected: |
|
|
288
|
+
Return a successful state transition to payment_required.
|
|
289
|
+
|
|
290
|
+
sample_request:
|
|
291
|
+
scenario: "force_account_status"
|
|
292
|
+
params:
|
|
293
|
+
account_id: "{{account_id}}"
|
|
294
|
+
status: "payment_required"
|
|
295
|
+
|
|
296
|
+
validations:
|
|
297
|
+
- check: field_value
|
|
298
|
+
path: "success"
|
|
299
|
+
allowed_values:
|
|
300
|
+
- true
|
|
301
|
+
description: "Transition to payment_required succeeds"
|
|
302
|
+
|
|
303
|
+
- id: restore_account_active
|
|
304
|
+
title: "Restore account to active"
|
|
305
|
+
requires_tool: comply_test_controller
|
|
306
|
+
narrative: |
|
|
307
|
+
Restore the account to active state after the payment_required test.
|
|
308
|
+
task: comply_test_controller
|
|
309
|
+
comply_scenario: deterministic_account
|
|
310
|
+
stateful: true
|
|
311
|
+
expected: |
|
|
312
|
+
Account restored to active state.
|
|
313
|
+
|
|
314
|
+
sample_request:
|
|
315
|
+
scenario: "force_account_status"
|
|
316
|
+
params:
|
|
317
|
+
account_id: "{{account_id}}"
|
|
318
|
+
status: "active"
|
|
319
|
+
|
|
320
|
+
validations:
|
|
321
|
+
- check: field_value
|
|
322
|
+
path: "success"
|
|
323
|
+
allowed_values:
|
|
324
|
+
- true
|
|
325
|
+
description: "Account restored to active"
|
|
326
|
+
|
|
327
|
+
- id: deterministic_media_buy
|
|
328
|
+
title: "Deterministic media buy state machine"
|
|
329
|
+
narrative: |
|
|
330
|
+
Creates a media buy through the normal flow, then uses the controller to force
|
|
331
|
+
it through status transitions: active, completed (terminal). Verifies that
|
|
332
|
+
terminal states reject further transitions.
|
|
333
|
+
|
|
334
|
+
steps:
|
|
335
|
+
- id: create_media_buy
|
|
336
|
+
title: "Create media buy for state machine test"
|
|
337
|
+
requires_tool: comply_test_controller
|
|
338
|
+
narrative: |
|
|
339
|
+
Create a media buy through the standard create_media_buy task. The resulting
|
|
340
|
+
media_buy_id is used for controller-driven state transitions.
|
|
341
|
+
task: create_media_buy
|
|
342
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
343
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
344
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
345
|
+
comply_scenario: deterministic_media_buy
|
|
346
|
+
stateful: true
|
|
347
|
+
context_outputs:
|
|
348
|
+
- name: media_buy_id
|
|
349
|
+
path: "media_buy_id"
|
|
350
|
+
expected: |
|
|
351
|
+
Create a media buy and return a media_buy_id for state machine testing.
|
|
352
|
+
|
|
353
|
+
sample_request:
|
|
354
|
+
account:
|
|
355
|
+
brand:
|
|
356
|
+
domain: "acmeoutdoor.com"
|
|
357
|
+
operator: "pinnacle-agency.com"
|
|
358
|
+
brand:
|
|
359
|
+
domain: "acmeoutdoor.com"
|
|
360
|
+
start_time: "2026-04-01T00:00:00Z"
|
|
361
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
362
|
+
packages:
|
|
363
|
+
- product_id: "test-product"
|
|
364
|
+
budget: 5000
|
|
365
|
+
pricing_option_id: "test-pricing"
|
|
366
|
+
|
|
367
|
+
validations:
|
|
368
|
+
- check: response_schema
|
|
369
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
370
|
+
|
|
371
|
+
- id: force_media_buy_active
|
|
372
|
+
title: "Force media buy to active"
|
|
373
|
+
requires_tool: comply_test_controller
|
|
374
|
+
narrative: |
|
|
375
|
+
Use the controller to force the media buy into active state.
|
|
376
|
+
task: comply_test_controller
|
|
377
|
+
comply_scenario: deterministic_media_buy
|
|
378
|
+
stateful: true
|
|
379
|
+
expected: |
|
|
380
|
+
Return a successful state transition to active.
|
|
381
|
+
|
|
382
|
+
sample_request:
|
|
383
|
+
scenario: "force_media_buy_status"
|
|
384
|
+
params:
|
|
385
|
+
media_buy_id: "{{media_buy_id}}"
|
|
386
|
+
status: "active"
|
|
387
|
+
|
|
388
|
+
validations:
|
|
389
|
+
- check: field_value
|
|
390
|
+
path: "success"
|
|
391
|
+
allowed_values:
|
|
392
|
+
- true
|
|
393
|
+
description: "Media buy activation succeeds"
|
|
394
|
+
- check: field_value
|
|
395
|
+
path: "current_state"
|
|
396
|
+
allowed_values:
|
|
397
|
+
- "active"
|
|
398
|
+
description: "Media buy is now active"
|
|
399
|
+
|
|
400
|
+
- id: verify_media_buy_active
|
|
401
|
+
title: "Verify media buy status via get_media_buys"
|
|
402
|
+
requires_tool: comply_test_controller
|
|
403
|
+
narrative: |
|
|
404
|
+
Call get_media_buys to confirm the controller-forced status is reflected
|
|
405
|
+
in the standard API.
|
|
406
|
+
task: get_media_buys
|
|
407
|
+
schema_ref: "media-buy/get-media-buys-request.json"
|
|
408
|
+
response_schema_ref: "media-buy/get-media-buys-response.json"
|
|
409
|
+
doc_ref: "/media-buy/task-reference/get_media_buys"
|
|
410
|
+
comply_scenario: deterministic_media_buy
|
|
411
|
+
stateful: true
|
|
412
|
+
expected: |
|
|
413
|
+
Return the media buy with status: active.
|
|
414
|
+
|
|
415
|
+
sample_request:
|
|
416
|
+
account:
|
|
417
|
+
brand:
|
|
418
|
+
domain: "acmeoutdoor.com"
|
|
419
|
+
operator: "pinnacle-agency.com"
|
|
420
|
+
media_buy_ids:
|
|
421
|
+
- "{{media_buy_id}}"
|
|
422
|
+
|
|
423
|
+
validations:
|
|
424
|
+
- check: response_schema
|
|
425
|
+
description: "Response matches get-media-buys-response.json schema"
|
|
426
|
+
- check: field_present
|
|
427
|
+
path: "media_buys[0].status"
|
|
428
|
+
description: "Media buy has a status field"
|
|
429
|
+
|
|
430
|
+
- id: force_media_buy_completed
|
|
431
|
+
title: "Force media buy to completed (terminal)"
|
|
432
|
+
requires_tool: comply_test_controller
|
|
433
|
+
narrative: |
|
|
434
|
+
Force the media buy to completed, a terminal state. No further transitions
|
|
435
|
+
should be allowed.
|
|
436
|
+
task: comply_test_controller
|
|
437
|
+
comply_scenario: deterministic_media_buy
|
|
438
|
+
stateful: true
|
|
439
|
+
expected: |
|
|
440
|
+
Return a successful transition to completed.
|
|
441
|
+
|
|
442
|
+
sample_request:
|
|
443
|
+
scenario: "force_media_buy_status"
|
|
444
|
+
params:
|
|
445
|
+
media_buy_id: "{{media_buy_id}}"
|
|
446
|
+
status: "completed"
|
|
447
|
+
|
|
448
|
+
validations:
|
|
449
|
+
- check: field_value
|
|
450
|
+
path: "success"
|
|
451
|
+
allowed_values:
|
|
452
|
+
- true
|
|
453
|
+
description: "Transition to completed succeeds"
|
|
454
|
+
- check: field_value
|
|
455
|
+
path: "current_state"
|
|
456
|
+
allowed_values:
|
|
457
|
+
- "completed"
|
|
458
|
+
description: "Media buy is now completed"
|
|
459
|
+
|
|
460
|
+
- id: invalid_transition_from_terminal
|
|
461
|
+
title: "Reject transition from terminal state"
|
|
462
|
+
requires_tool: comply_test_controller
|
|
463
|
+
narrative: |
|
|
464
|
+
Attempt to force the completed media buy back to active. The controller
|
|
465
|
+
should reject this with INVALID_TRANSITION.
|
|
466
|
+
task: comply_test_controller
|
|
467
|
+
comply_scenario: deterministic_media_buy
|
|
468
|
+
stateful: true
|
|
469
|
+
expected: |
|
|
470
|
+
Return an error response:
|
|
471
|
+
- success: false
|
|
472
|
+
- error: INVALID_TRANSITION
|
|
473
|
+
|
|
474
|
+
sample_request:
|
|
475
|
+
scenario: "force_media_buy_status"
|
|
476
|
+
params:
|
|
477
|
+
media_buy_id: "{{media_buy_id}}"
|
|
478
|
+
status: "active"
|
|
479
|
+
|
|
480
|
+
validations:
|
|
481
|
+
- check: field_value
|
|
482
|
+
path: "success"
|
|
483
|
+
allowed_values:
|
|
484
|
+
- false
|
|
485
|
+
description: "Terminal state rejects transition"
|
|
486
|
+
- check: field_value
|
|
487
|
+
path: "error"
|
|
488
|
+
allowed_values:
|
|
489
|
+
- "INVALID_TRANSITION"
|
|
490
|
+
description: "Error code is INVALID_TRANSITION"
|
|
491
|
+
|
|
492
|
+
- id: deterministic_creative
|
|
493
|
+
title: "Deterministic creative state machine"
|
|
494
|
+
narrative: |
|
|
495
|
+
Syncs a creative, then uses the controller to force it through status
|
|
496
|
+
transitions: approved, archived (terminal). Verifies terminal state rejection
|
|
497
|
+
and rejection with reason.
|
|
498
|
+
|
|
499
|
+
steps:
|
|
500
|
+
- id: sync_creative_for_state
|
|
501
|
+
title: "Sync creative for state machine test"
|
|
502
|
+
requires_tool: comply_test_controller
|
|
503
|
+
narrative: |
|
|
504
|
+
Push a test creative via sync_creatives. The creative_id is captured
|
|
505
|
+
for controller-driven transitions.
|
|
506
|
+
task: sync_creatives
|
|
507
|
+
schema_ref: "creative/sync-creatives-request.json"
|
|
508
|
+
response_schema_ref: "creative/sync-creatives-response.json"
|
|
509
|
+
doc_ref: "/creative/task-reference/sync_creatives"
|
|
510
|
+
comply_scenario: deterministic_creative
|
|
511
|
+
stateful: true
|
|
512
|
+
context_outputs:
|
|
513
|
+
- name: creative_id
|
|
514
|
+
path: "results[0].creative_id"
|
|
515
|
+
expected: |
|
|
516
|
+
Accept the creative and return a creative_id for state machine testing.
|
|
517
|
+
|
|
518
|
+
sample_request:
|
|
519
|
+
account:
|
|
520
|
+
brand:
|
|
521
|
+
domain: "acmeoutdoor.com"
|
|
522
|
+
operator: "pinnacle-agency.com"
|
|
523
|
+
creatives:
|
|
524
|
+
- creative_id: "comply-state-test-creative"
|
|
525
|
+
name: "Comply State Test Creative"
|
|
526
|
+
format_id:
|
|
527
|
+
agent_url: "https://your-platform.example.com"
|
|
528
|
+
id: "display_300x250"
|
|
529
|
+
assets:
|
|
530
|
+
- asset_id: "image"
|
|
531
|
+
asset_type: "image"
|
|
532
|
+
url: "https://via.placeholder.com/300x250"
|
|
533
|
+
mime_type: "image/png"
|
|
534
|
+
|
|
535
|
+
validations:
|
|
536
|
+
- check: response_schema
|
|
537
|
+
description: "Response matches sync-creatives-response.json schema"
|
|
538
|
+
|
|
539
|
+
- id: force_creative_approved
|
|
540
|
+
title: "Force creative to approved"
|
|
541
|
+
requires_tool: comply_test_controller
|
|
542
|
+
narrative: |
|
|
543
|
+
Use the controller to force the creative into approved state.
|
|
544
|
+
task: comply_test_controller
|
|
545
|
+
comply_scenario: deterministic_creative
|
|
546
|
+
stateful: true
|
|
547
|
+
expected: |
|
|
548
|
+
Successful transition to approved.
|
|
549
|
+
|
|
550
|
+
sample_request:
|
|
551
|
+
scenario: "force_creative_status"
|
|
552
|
+
params:
|
|
553
|
+
creative_id: "{{creative_id}}"
|
|
554
|
+
status: "approved"
|
|
555
|
+
|
|
556
|
+
validations:
|
|
557
|
+
- check: field_value
|
|
558
|
+
path: "success"
|
|
559
|
+
allowed_values:
|
|
560
|
+
- true
|
|
561
|
+
description: "Creative approval succeeds"
|
|
562
|
+
- check: field_value
|
|
563
|
+
path: "current_state"
|
|
564
|
+
allowed_values:
|
|
565
|
+
- "approved"
|
|
566
|
+
description: "Creative is now approved"
|
|
567
|
+
|
|
568
|
+
- id: force_creative_archived
|
|
569
|
+
title: "Force creative to archived (terminal)"
|
|
570
|
+
requires_tool: comply_test_controller
|
|
571
|
+
narrative: |
|
|
572
|
+
Force the creative to archived, a terminal state.
|
|
573
|
+
task: comply_test_controller
|
|
574
|
+
comply_scenario: deterministic_creative
|
|
575
|
+
stateful: true
|
|
576
|
+
expected: |
|
|
577
|
+
Successful transition to archived.
|
|
578
|
+
|
|
579
|
+
sample_request:
|
|
580
|
+
scenario: "force_creative_status"
|
|
581
|
+
params:
|
|
582
|
+
creative_id: "{{creative_id}}"
|
|
583
|
+
status: "archived"
|
|
584
|
+
|
|
585
|
+
validations:
|
|
586
|
+
- check: field_value
|
|
587
|
+
path: "success"
|
|
588
|
+
allowed_values:
|
|
589
|
+
- true
|
|
590
|
+
description: "Transition to archived succeeds"
|
|
591
|
+
|
|
592
|
+
- id: invalid_creative_transition
|
|
593
|
+
title: "Reject archived to processing"
|
|
594
|
+
requires_tool: comply_test_controller
|
|
595
|
+
narrative: |
|
|
596
|
+
Attempt to force the archived creative back to processing. The controller
|
|
597
|
+
should reject this with INVALID_TRANSITION.
|
|
598
|
+
task: comply_test_controller
|
|
599
|
+
comply_scenario: deterministic_creative
|
|
600
|
+
stateful: true
|
|
601
|
+
expected: |
|
|
602
|
+
Return error with INVALID_TRANSITION.
|
|
603
|
+
|
|
604
|
+
sample_request:
|
|
605
|
+
scenario: "force_creative_status"
|
|
606
|
+
params:
|
|
607
|
+
creative_id: "{{creative_id}}"
|
|
608
|
+
status: "processing"
|
|
609
|
+
|
|
610
|
+
validations:
|
|
611
|
+
- check: field_value
|
|
612
|
+
path: "success"
|
|
613
|
+
allowed_values:
|
|
614
|
+
- false
|
|
615
|
+
description: "Terminal state rejects transition"
|
|
616
|
+
- check: field_value
|
|
617
|
+
path: "error"
|
|
618
|
+
allowed_values:
|
|
619
|
+
- "INVALID_TRANSITION"
|
|
620
|
+
description: "Error code is INVALID_TRANSITION"
|
|
621
|
+
|
|
622
|
+
- id: force_creative_rejected
|
|
623
|
+
title: "Force fresh creative to rejected with reason"
|
|
624
|
+
requires_tool: comply_test_controller
|
|
625
|
+
narrative: |
|
|
626
|
+
Sync a fresh creative, force it to pending_review, then reject it with a
|
|
627
|
+
reason string. Verifies the controller supports rejection reasons.
|
|
628
|
+
task: comply_test_controller
|
|
629
|
+
comply_scenario: deterministic_creative
|
|
630
|
+
stateful: true
|
|
631
|
+
expected: |
|
|
632
|
+
Successful transition to rejected with reason preserved.
|
|
633
|
+
|
|
634
|
+
sample_request:
|
|
635
|
+
scenario: "force_creative_status"
|
|
636
|
+
params:
|
|
637
|
+
creative_id: "{{creative_id}}"
|
|
638
|
+
status: "rejected"
|
|
639
|
+
rejection_reason: "Brand safety policy violation (comply test)"
|
|
640
|
+
|
|
641
|
+
validations:
|
|
642
|
+
- check: field_value
|
|
643
|
+
path: "success"
|
|
644
|
+
allowed_values:
|
|
645
|
+
- true
|
|
646
|
+
description: "Creative rejection succeeds"
|
|
647
|
+
|
|
648
|
+
- id: deterministic_session
|
|
649
|
+
title: "Deterministic SI session state machine"
|
|
650
|
+
narrative: |
|
|
651
|
+
Initiates an SI session, then uses the controller to force session timeout.
|
|
652
|
+
Verifies that messaging on a terminated session fails appropriately.
|
|
653
|
+
|
|
654
|
+
steps:
|
|
655
|
+
- id: initiate_session
|
|
656
|
+
title: "Initiate SI session"
|
|
657
|
+
requires_tool: comply_test_controller
|
|
658
|
+
narrative: |
|
|
659
|
+
Create an SI session via si_initiate_session. The session_id is captured
|
|
660
|
+
for controller-driven termination.
|
|
661
|
+
task: si_initiate_session
|
|
662
|
+
comply_scenario: deterministic_session
|
|
663
|
+
stateful: true
|
|
664
|
+
context_outputs:
|
|
665
|
+
- name: session_id
|
|
666
|
+
path: "session_id"
|
|
667
|
+
expected: |
|
|
668
|
+
Return a session with a session_id.
|
|
669
|
+
|
|
670
|
+
sample_request:
|
|
671
|
+
identity:
|
|
672
|
+
user_type: "consumer"
|
|
673
|
+
supported_capabilities:
|
|
674
|
+
response_formats:
|
|
675
|
+
- "text"
|
|
676
|
+
|
|
677
|
+
validations:
|
|
678
|
+
- check: field_present
|
|
679
|
+
path: "session_id"
|
|
680
|
+
description: "Session has a session_id"
|
|
681
|
+
|
|
682
|
+
- id: force_session_terminated
|
|
683
|
+
title: "Force session timeout"
|
|
684
|
+
requires_tool: comply_test_controller
|
|
685
|
+
narrative: |
|
|
686
|
+
Use the controller to force the session into terminated state with
|
|
687
|
+
termination_reason: session_timeout.
|
|
688
|
+
task: comply_test_controller
|
|
689
|
+
comply_scenario: deterministic_session
|
|
690
|
+
stateful: true
|
|
691
|
+
expected: |
|
|
692
|
+
Successful transition to terminated.
|
|
693
|
+
|
|
694
|
+
sample_request:
|
|
695
|
+
scenario: "force_session_status"
|
|
696
|
+
params:
|
|
697
|
+
session_id: "{{session_id}}"
|
|
698
|
+
status: "terminated"
|
|
699
|
+
termination_reason: "session_timeout"
|
|
700
|
+
|
|
701
|
+
validations:
|
|
702
|
+
- check: field_value
|
|
703
|
+
path: "success"
|
|
704
|
+
allowed_values:
|
|
705
|
+
- true
|
|
706
|
+
description: "Session termination succeeds"
|
|
707
|
+
|
|
708
|
+
- id: verify_terminated_session
|
|
709
|
+
title: "Verify messaging fails on terminated session"
|
|
710
|
+
requires_tool: comply_test_controller
|
|
711
|
+
narrative: |
|
|
712
|
+
Attempt to send a message on the terminated session. The agent should
|
|
713
|
+
return an error or terminated status.
|
|
714
|
+
task: si_send_message
|
|
715
|
+
comply_scenario: deterministic_session
|
|
716
|
+
stateful: true
|
|
717
|
+
expected: |
|
|
718
|
+
The request should fail or return session_status: terminated. The agent
|
|
719
|
+
must not accept messages on a terminated session.
|
|
720
|
+
|
|
721
|
+
sample_request:
|
|
722
|
+
session_id: "{{session_id}}"
|
|
723
|
+
message: "comply test — session should be terminated"
|
|
724
|
+
|
|
725
|
+
validations:
|
|
726
|
+
- check: field_value
|
|
727
|
+
path: "success"
|
|
728
|
+
allowed_values:
|
|
729
|
+
- false
|
|
730
|
+
description: "Message on terminated session fails"
|
|
731
|
+
|
|
732
|
+
- id: deterministic_delivery
|
|
733
|
+
title: "Deterministic delivery simulation"
|
|
734
|
+
narrative: |
|
|
735
|
+
Creates a media buy, simulates delivery data via the controller, then verifies
|
|
736
|
+
the simulated metrics are reflected in get_media_buy_delivery.
|
|
737
|
+
|
|
738
|
+
steps:
|
|
739
|
+
- id: create_media_buy_for_delivery
|
|
740
|
+
title: "Create media buy for delivery test"
|
|
741
|
+
requires_tool: comply_test_controller
|
|
742
|
+
narrative: |
|
|
743
|
+
Create a media buy to receive simulated delivery data.
|
|
744
|
+
task: create_media_buy
|
|
745
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
746
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
747
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
748
|
+
comply_scenario: deterministic_delivery
|
|
749
|
+
stateful: true
|
|
750
|
+
context_outputs:
|
|
751
|
+
- name: delivery_media_buy_id
|
|
752
|
+
path: "media_buy_id"
|
|
753
|
+
expected: |
|
|
754
|
+
Create a media buy and return a media_buy_id.
|
|
755
|
+
|
|
756
|
+
sample_request:
|
|
757
|
+
account:
|
|
758
|
+
brand:
|
|
759
|
+
domain: "acmeoutdoor.com"
|
|
760
|
+
operator: "pinnacle-agency.com"
|
|
761
|
+
brand:
|
|
762
|
+
domain: "acmeoutdoor.com"
|
|
763
|
+
start_time: "2026-04-01T00:00:00Z"
|
|
764
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
765
|
+
packages:
|
|
766
|
+
- product_id: "test-product"
|
|
767
|
+
budget: 5000
|
|
768
|
+
pricing_option_id: "test-pricing"
|
|
769
|
+
|
|
770
|
+
validations:
|
|
771
|
+
- check: response_schema
|
|
772
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
773
|
+
|
|
774
|
+
- id: simulate_delivery
|
|
775
|
+
title: "Simulate delivery data"
|
|
776
|
+
requires_tool: comply_test_controller
|
|
777
|
+
narrative: |
|
|
778
|
+
Inject simulated delivery metrics (impressions, clicks, spend) into the
|
|
779
|
+
media buy via the controller.
|
|
780
|
+
task: comply_test_controller
|
|
781
|
+
comply_scenario: deterministic_delivery
|
|
782
|
+
stateful: true
|
|
783
|
+
expected: |
|
|
784
|
+
Return success with simulated delivery metrics acknowledged.
|
|
785
|
+
|
|
786
|
+
sample_request:
|
|
787
|
+
scenario: "simulate_delivery"
|
|
788
|
+
params:
|
|
789
|
+
media_buy_id: "{{delivery_media_buy_id}}"
|
|
790
|
+
impressions: 10000
|
|
791
|
+
clicks: 150
|
|
792
|
+
reported_spend:
|
|
793
|
+
amount: 150.00
|
|
794
|
+
currency: "USD"
|
|
795
|
+
|
|
796
|
+
validations:
|
|
797
|
+
- check: field_value
|
|
798
|
+
path: "success"
|
|
799
|
+
allowed_values:
|
|
800
|
+
- true
|
|
801
|
+
description: "Delivery simulation succeeds"
|
|
802
|
+
|
|
803
|
+
- id: verify_delivery
|
|
804
|
+
title: "Verify delivery via get_media_buy_delivery"
|
|
805
|
+
requires_tool: comply_test_controller
|
|
806
|
+
narrative: |
|
|
807
|
+
Call get_media_buy_delivery and verify the simulated metrics are reflected
|
|
808
|
+
in the response. Expect at least 10000 impressions.
|
|
809
|
+
task: get_media_buy_delivery
|
|
810
|
+
schema_ref: "media-buy/get-media-buy-delivery-request.json"
|
|
811
|
+
response_schema_ref: "media-buy/get-media-buy-delivery-response.json"
|
|
812
|
+
doc_ref: "/media-buy/task-reference/get_media_buy_delivery"
|
|
813
|
+
comply_scenario: deterministic_delivery
|
|
814
|
+
stateful: true
|
|
815
|
+
expected: |
|
|
816
|
+
Return delivery metrics reflecting the simulated data:
|
|
817
|
+
- impressions >= 10000
|
|
818
|
+
- clicks and spend data present
|
|
819
|
+
|
|
820
|
+
sample_request:
|
|
821
|
+
account:
|
|
822
|
+
brand:
|
|
823
|
+
domain: "acmeoutdoor.com"
|
|
824
|
+
operator: "pinnacle-agency.com"
|
|
825
|
+
media_buy_ids:
|
|
826
|
+
- "{{delivery_media_buy_id}}"
|
|
827
|
+
|
|
828
|
+
validations:
|
|
829
|
+
- check: response_schema
|
|
830
|
+
description: "Response matches get-media-buy-delivery-response.json schema"
|
|
831
|
+
- check: field_present
|
|
832
|
+
path: "media_buys"
|
|
833
|
+
description: "Response contains delivery data"
|
|
834
|
+
|
|
835
|
+
- id: deterministic_budget
|
|
836
|
+
title: "Deterministic budget simulation"
|
|
837
|
+
narrative: |
|
|
838
|
+
Creates a media buy, then uses the controller to simulate budget spend at 95%
|
|
839
|
+
and 100%. Verifies the agent handles near-depletion and full depletion.
|
|
840
|
+
|
|
841
|
+
steps:
|
|
842
|
+
- id: create_media_buy_for_budget
|
|
843
|
+
title: "Create media buy for budget test"
|
|
844
|
+
requires_tool: comply_test_controller
|
|
845
|
+
narrative: |
|
|
846
|
+
Create a media buy with a known budget for spend simulation.
|
|
847
|
+
task: create_media_buy
|
|
848
|
+
schema_ref: "media-buy/create-media-buy-request.json"
|
|
849
|
+
response_schema_ref: "media-buy/create-media-buy-response.json"
|
|
850
|
+
doc_ref: "/media-buy/task-reference/create_media_buy"
|
|
851
|
+
comply_scenario: deterministic_budget
|
|
852
|
+
stateful: true
|
|
853
|
+
context_outputs:
|
|
854
|
+
- name: budget_media_buy_id
|
|
855
|
+
path: "media_buy_id"
|
|
856
|
+
expected: |
|
|
857
|
+
Create a media buy and return a media_buy_id.
|
|
858
|
+
|
|
859
|
+
sample_request:
|
|
860
|
+
account:
|
|
861
|
+
brand:
|
|
862
|
+
domain: "acmeoutdoor.com"
|
|
863
|
+
operator: "pinnacle-agency.com"
|
|
864
|
+
brand:
|
|
865
|
+
domain: "acmeoutdoor.com"
|
|
866
|
+
start_time: "2026-04-01T00:00:00Z"
|
|
867
|
+
end_time: "2026-06-30T23:59:59Z"
|
|
868
|
+
packages:
|
|
869
|
+
- product_id: "test-product"
|
|
870
|
+
budget: 10000
|
|
871
|
+
pricing_option_id: "test-pricing"
|
|
872
|
+
|
|
873
|
+
validations:
|
|
874
|
+
- check: response_schema
|
|
875
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
876
|
+
|
|
877
|
+
- id: simulate_budget_95
|
|
878
|
+
title: "Simulate 95% budget spend"
|
|
879
|
+
requires_tool: comply_test_controller
|
|
880
|
+
narrative: |
|
|
881
|
+
Simulate 95% of the media buy budget being spent. The agent should
|
|
882
|
+
handle near-depletion state.
|
|
883
|
+
task: comply_test_controller
|
|
884
|
+
comply_scenario: deterministic_budget
|
|
885
|
+
stateful: true
|
|
886
|
+
expected: |
|
|
887
|
+
Return success with budget spend simulated to 95%.
|
|
888
|
+
|
|
889
|
+
sample_request:
|
|
890
|
+
scenario: "simulate_budget_spend"
|
|
891
|
+
params:
|
|
892
|
+
media_buy_id: "{{budget_media_buy_id}}"
|
|
893
|
+
spend_percentage: 95
|
|
894
|
+
|
|
895
|
+
validations:
|
|
896
|
+
- check: field_value
|
|
897
|
+
path: "success"
|
|
898
|
+
allowed_values:
|
|
899
|
+
- true
|
|
900
|
+
description: "95% budget simulation succeeds"
|
|
901
|
+
|
|
902
|
+
- id: simulate_budget_100
|
|
903
|
+
title: "Simulate 100% budget depletion"
|
|
904
|
+
requires_tool: comply_test_controller
|
|
905
|
+
narrative: |
|
|
906
|
+
Simulate complete budget depletion. The agent should handle the fully
|
|
907
|
+
spent state.
|
|
908
|
+
task: comply_test_controller
|
|
909
|
+
comply_scenario: deterministic_budget
|
|
910
|
+
stateful: true
|
|
911
|
+
expected: |
|
|
912
|
+
Return success with budget fully depleted.
|
|
913
|
+
|
|
914
|
+
sample_request:
|
|
915
|
+
scenario: "simulate_budget_spend"
|
|
916
|
+
params:
|
|
917
|
+
media_buy_id: "{{budget_media_buy_id}}"
|
|
918
|
+
spend_percentage: 100
|
|
919
|
+
|
|
920
|
+
validations:
|
|
921
|
+
- check: field_value
|
|
922
|
+
path: "success"
|
|
923
|
+
allowed_values:
|
|
924
|
+
- true
|
|
925
|
+
description: "100% budget depletion simulation succeeds"
|