Skip to content

examples/seller_agent.py: DemoStore needs overrides for force_create_media_buy_arm, force_task_completion, and seed_* scenarios #312

@bokelley

Description

@bokelley

Context

PR #282 just landed the SDK base-class methods for `force_create_media_buy_arm` + `force_task_completion`, and PR #296 landed stubs for the 5 `seed_*` scenarios (AdCP 3.0.1). The SDK's `_list_scenarios` helper introspects which methods the store overrides — only overridden ones get advertised in `list_scenarios` and only those count toward the JS storyboard runner's controller-detection probe.

`DemoStore` in `examples/seller_agent.py` overrides 5 of the older scenarios (`force_creative_status`, `force_account_status`, `force_media_buy_status`, `simulate_delivery`, `simulate_budget_spend`) but none of the new ones. Result: `controller_detected: false` in the storyboard runner, and 5 step failures cascade because storyboards depending on seeded fixtures (`outdoor_display_q2` product, `acme_outdoor_allowlist_v1` property list) can't run.

Current storyboard score: 36/47 passing, 5 failed, 6 skipped, `controller_detected: false`.

Proposal

Override the following in `DemoStore`, mutating the example's in-memory `PRODUCTS` / `media_buys` / `creatives` dicts:

Required for `controller_detected: true`

  1. `force_create_media_buy_arm(arm, task_id, message, account)` — store a single-shot directive on the seller (e.g. `pending_directives[account_id] = {"arm": arm, "task_id": task_id, "message": message}`); the next `create_media_buy` from the same account checks for and consumes the directive.

  2. `force_task_completion(task_id, result, account)` — record a completion payload to deliver to the buyer's `push_notification_config.url` on the next polling tick (or synchronously if the example doesn't model webhooks).

Required to unblock the 5 fixture-dependent storyboards

  1. `seed_product(fixture, product_id)` — append/replace in the example's `PRODUCTS` list. Closes the `Product 'sports_preroll_q2' not found` and `Product 'outdoor_display_q2' not found` failures.

  2. `seed_media_buy(fixture, media_buy_id)` — pre-populate the example's `media_buys` dict with `targeting_overlay` populated. Closes the `acme_outdoor_allowlist_v1` / `acme_outdoor_no_match_v1` validation failures in the `inventory_list_targeting` storyboard.

Optional (nice-to-have for completeness)

  1. `seed_pricing_option`, `seed_creative`, `seed_plan` — same pattern, append to the appropriate dict.

Verification

Once these overrides land, re-run:

```
ADCP_PORT=3001 python examples/seller_agent.py &
sleep 2
npx -y -p @adcp/client@latest adcp storyboard run \
http://127.0.0.1:3001/mcp media_buy_seller --json --allow-http \
| jq '{overall_status, controller_detected, summary}'
```

Target: `overall_status: pass`, `controller_detected: true`, `summary.steps_passed: 47`. The storyboard CI job from #305 (currently `continue-on-error: true`) can be promoted to required.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions