@adcp/client 4.21.0 → 4.22.1

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.
Files changed (160) hide show
  1. package/AGENTS.md +278 -0
  2. package/README.md +96 -61
  3. package/bin/adcp.js +342 -4
  4. package/dist/lib/agents/index.generated.d.ts +9 -1
  5. package/dist/lib/agents/index.generated.d.ts.map +1 -1
  6. package/dist/lib/agents/index.generated.js +12 -0
  7. package/dist/lib/agents/index.generated.js.map +1 -1
  8. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.d.ts +2 -1
  10. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  11. package/dist/lib/core/SingleAgentClient.js +10 -1
  12. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  13. package/dist/lib/discovery/property-crawler.d.ts +4 -0
  14. package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
  15. package/dist/lib/discovery/property-crawler.js +10 -2
  16. package/dist/lib/discovery/property-crawler.js.map +1 -1
  17. package/dist/lib/index.d.ts +4 -4
  18. package/dist/lib/index.d.ts.map +1 -1
  19. package/dist/lib/index.js +6 -4
  20. package/dist/lib/index.js.map +1 -1
  21. package/dist/lib/protocols/index.d.ts.map +1 -1
  22. package/dist/lib/protocols/index.js +8 -6
  23. package/dist/lib/protocols/index.js.map +1 -1
  24. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  25. package/dist/lib/protocols/mcp.js +24 -11
  26. package/dist/lib/protocols/mcp.js.map +1 -1
  27. package/dist/lib/server/index.d.ts +2 -0
  28. package/dist/lib/server/index.d.ts.map +1 -1
  29. package/dist/lib/server/index.js +3 -1
  30. package/dist/lib/server/index.js.map +1 -1
  31. package/dist/lib/server/serve.d.ts +73 -0
  32. package/dist/lib/server/serve.d.ts.map +1 -0
  33. package/dist/lib/server/serve.js +94 -0
  34. package/dist/lib/server/serve.js.map +1 -0
  35. package/dist/lib/testing/client.d.ts.map +1 -1
  36. package/dist/lib/testing/client.js +1 -0
  37. package/dist/lib/testing/client.js.map +1 -1
  38. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  39. package/dist/lib/testing/compliance/comply.js +48 -63
  40. package/dist/lib/testing/compliance/comply.js.map +1 -1
  41. package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
  42. package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
  43. package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
  44. package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
  45. package/dist/lib/testing/compliance/types.d.ts +1 -1
  46. package/dist/lib/testing/compliance/types.d.ts.map +1 -1
  47. package/dist/lib/testing/index.d.ts +1 -0
  48. package/dist/lib/testing/index.d.ts.map +1 -1
  49. package/dist/lib/testing/index.js +23 -1
  50. package/dist/lib/testing/index.js.map +1 -1
  51. package/dist/lib/testing/orchestrator.d.ts +8 -0
  52. package/dist/lib/testing/orchestrator.d.ts.map +1 -1
  53. package/dist/lib/testing/orchestrator.js +8 -0
  54. package/dist/lib/testing/orchestrator.js.map +1 -1
  55. package/dist/lib/testing/storyboard/context.d.ts +34 -0
  56. package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
  57. package/dist/lib/testing/storyboard/context.js +257 -0
  58. package/dist/lib/testing/storyboard/context.js.map +1 -0
  59. package/dist/lib/testing/storyboard/index.d.ts +15 -0
  60. package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
  61. package/dist/lib/testing/storyboard/index.js +48 -0
  62. package/dist/lib/testing/storyboard/index.js.map +1 -0
  63. package/dist/lib/testing/storyboard/loader.d.ts +53 -0
  64. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
  65. package/dist/lib/testing/storyboard/loader.js +114 -0
  66. package/dist/lib/testing/storyboard/loader.js.map +1 -0
  67. package/dist/lib/testing/storyboard/path.d.ts +29 -0
  68. package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
  69. package/dist/lib/testing/storyboard/path.js +121 -0
  70. package/dist/lib/testing/storyboard/path.js.map +1 -0
  71. package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
  72. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
  73. package/dist/lib/testing/storyboard/request-builder.js +410 -0
  74. package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
  75. package/dist/lib/testing/storyboard/runner.d.ts +24 -0
  76. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
  77. package/dist/lib/testing/storyboard/runner.js +280 -0
  78. package/dist/lib/testing/storyboard/runner.js.map +1 -0
  79. package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
  80. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
  81. package/dist/lib/testing/storyboard/task-map.js +84 -0
  82. package/dist/lib/testing/storyboard/task-map.js.map +1 -0
  83. package/dist/lib/testing/storyboard/types.d.ts +156 -0
  84. package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
  85. package/dist/lib/testing/storyboard/types.js +10 -0
  86. package/dist/lib/testing/storyboard/types.js.map +1 -0
  87. package/dist/lib/testing/storyboard/validations.d.ts +17 -0
  88. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
  89. package/dist/lib/testing/storyboard/validations.js +166 -0
  90. package/dist/lib/testing/storyboard/validations.js.map +1 -0
  91. package/dist/lib/testing/types.d.ts +2 -0
  92. package/dist/lib/testing/types.d.ts.map +1 -1
  93. package/dist/lib/types/core.generated.d.ts +2 -2
  94. package/dist/lib/types/core.generated.d.ts.map +1 -1
  95. package/dist/lib/types/core.generated.js +1 -1
  96. package/dist/lib/types/schemas.generated.d.ts +193 -34
  97. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  98. package/dist/lib/types/schemas.generated.js +87 -5
  99. package/dist/lib/types/schemas.generated.js.map +1 -1
  100. package/dist/lib/types/tools.generated.d.ts +280 -3
  101. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  102. package/dist/lib/utils/response-schemas.d.ts.map +1 -1
  103. package/dist/lib/utils/response-schemas.js +34 -3
  104. package/dist/lib/utils/response-schemas.js.map +1 -1
  105. package/dist/lib/utils/validate-user-agent.d.ts +8 -0
  106. package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
  107. package/dist/lib/utils/validate-user-agent.js +15 -0
  108. package/dist/lib/utils/validate-user-agent.js.map +1 -0
  109. package/dist/lib/version.d.ts +6 -0
  110. package/dist/lib/version.d.ts.map +1 -1
  111. package/dist/lib/version.js +7 -1
  112. package/dist/lib/version.js.map +1 -1
  113. package/docs/README.md +42 -0
  114. package/docs/guides/BUILD-AN-AGENT.md +294 -0
  115. package/docs/llms.txt +634 -0
  116. package/examples/README.md +106 -0
  117. package/examples/adcp.config.json +30 -0
  118. package/examples/basic-a2a.ts +76 -0
  119. package/examples/basic-mcp.ts +50 -0
  120. package/examples/batch-preview-test.ts +266 -0
  121. package/examples/conversation-client.ts +291 -0
  122. package/examples/debug-preview-response.ts +73 -0
  123. package/examples/debug-preview-with-logging.ts +50 -0
  124. package/examples/easy-config-demo.ts +242 -0
  125. package/examples/env-config.ts +51 -0
  126. package/examples/error-compliant-server.ts +237 -0
  127. package/examples/generative-creative-demo.ts +205 -0
  128. package/examples/inspect-card-formats.ts +161 -0
  129. package/examples/logger-usage.ts +165 -0
  130. package/examples/oauth-cli-example.ts +154 -0
  131. package/examples/pr78-async-patterns-demo.ts +247 -0
  132. package/examples/signals-agent.ts +163 -0
  133. package/examples/simple-getting-started.ts +225 -0
  134. package/examples/simple-protocol-demo.ts +75 -0
  135. package/examples/test-helpers-demo.ts +239 -0
  136. package/examples/zod-validation-example.ts +126 -0
  137. package/package.json +12 -2
  138. package/skills/adcp/SKILL.md +13 -2
  139. package/storyboards/audience_sync.yaml +199 -0
  140. package/storyboards/behavioral_analysis.yaml +244 -0
  141. package/storyboards/brand_rights.yaml +131 -0
  142. package/storyboards/creative_ad_server.yaml +171 -0
  143. package/storyboards/creative_sales_agent.yaml +169 -0
  144. package/storyboards/creative_template.yaml +306 -0
  145. package/storyboards/deterministic_testing.yaml +925 -0
  146. package/storyboards/error_compliance.yaml +231 -0
  147. package/storyboards/governance_content_standards.yaml +213 -0
  148. package/storyboards/governance_property_lists.yaml +372 -0
  149. package/storyboards/media_buy_catalog_creative.yaml +457 -0
  150. package/storyboards/media_buy_governance_escalation.yaml +467 -0
  151. package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
  152. package/storyboards/media_buy_non_guaranteed.yaml +288 -0
  153. package/storyboards/media_buy_proposal_mode.yaml +369 -0
  154. package/storyboards/media_buy_seller.yaml +560 -0
  155. package/storyboards/media_buy_state_machine.yaml +254 -0
  156. package/storyboards/schema.yaml +65 -0
  157. package/storyboards/schema_validation.yaml +166 -0
  158. package/storyboards/si_session.yaml +384 -0
  159. package/storyboards/signal_marketplace.yaml +283 -0
  160. 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"