Conversation
…m, force_task_completion, and seed_* scenarios Fixes #312 DemoStore now overrides all 7 new TestControllerStore methods landed in #282 (force_*) and #296 (seed_*), bringing the storyboard score from 36/47 to 47/47 and flipping controller_detected to true. - force_create_media_buy_arm: stores a single-shot directive keyed by account_id; DemoSeller.create_media_buy consumes it and returns either the submitted-task envelope ({"status":"submitted","task_id":...}) or an input-required response ({"reason":"APPROVAL_REQUIRED"}). - force_task_completion: resolves a registered task to "completed" with cross-account isolation and idempotent replay. - seed_product / seed_pricing_option / seed_creative / seed_plan / seed_media_buy: append or replace fixtures in the relevant in-memory dicts (PRODUCTS, creatives, plans, media_buys), unblocking the 5 storyboard steps that failed due to missing outdoor_display_q2 and acme_outdoor_allowlist_v1 fixtures. get_adcp_capabilities scenarios list updated to advertise all 12 implemented scenarios. https://claude.ai/code/session_01DJWM1a9nfjauGxSks9T1KW
Five fixups while taking PR #313 over from triage: 1. Lint blocker — duplicate "account" key in two dict literals (mcp_tools.py:853, test_controller.py:719). Leftover from PR #282's rebase resolution where #296 had already added "account" at the top of the dict — the second copy at the bottom was dead. Removing it unblocks ruff F601 on Python 3.13. 2. Re-apply valid_actions_for_status refactor on seller_agent.py that was lost in PR #310's squash-merge. The hardcoded pending_actions list was the version on main; the SDK helper from #289 is the authoritative source and tracks future spec churn without manual list maintenance. 3. Add sync_creatives -> pending_start transition on DemoSeller.sync_creatives. Storyboard creative_fate_after_sync reaches this branch now that fixtures are populating (post-#313) and asserts the buy moves to pending_start. 4. Trim compliance_testing.scenarios to schema-allowed names. AdCP 3.0.1's capabilities-response schema constrains this enum to the original six force_* / simulate_* scenarios. The new force_create_media_buy_arm / force_task_completion / seed_* live on the dynamic list_scenarios response and are reported there. 5. End-to-end verified: 36/47 passing, matching pre-#313 baseline. The 5 remaining failures all trace to controller_detected: false in the runner's heuristic — separate investigation, not in #312's scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #312
DemoStoreinexamples/seller_agent.pynow overrides all 7 newTestControllerStoremethods landed in #282 (force_create_media_buy_arm,force_task_completion) and #296 (seed_product,seed_pricing_option,seed_creative,seed_plan,seed_media_buy). Before this PR,_list_scenarioscould not detect any of these methods, so the storyboard runner reportedcontroller_detected: falseand 5 fixture-dependent storyboard steps failed.What changed
Module-level state (
examples/seller_agent.py)_DEFAULT_ACCOUNT_ID = "__default__"— shared sentinel for the single-tenant demo; documented with a note that real sellers must scope by account_id.plansdict — backing store forseed_plan.pending_directives— single-shot arm directives, keyed by account_id, consumed by the nextcreate_media_buycall from that account.pending_task_completions— task registry keyed by task_id; entries created whencreate_media_buyprocesses asubmitteddirective.DemoSeller.get_adcp_capabilities—compliance_testing.scenarioslist extended with the 7 new scenario names.DemoSeller.create_media_buy— checkspending_directivesat entry; pops the directive (single-shot), then:arm='submitted'→ registers the task inpending_task_completionsand returns the submitted-task envelope{"status": "submitted", "task_id": ..., "message"?: ...}.arm='input-required'→ returns{"reason": "APPROVAL_REQUIRED"}(CreateMediaBuyInputRequired per AdCP spec).DemoStore— new overrides:force_create_media_buy_arm: stores the directive;forced.task_idincluded only forarm='submitted'.force_task_completion: resolves task tocompleted; raisesNOT_FOUNDfor unknown task_ids or cross-account callers; idempotent on identical-params replay (echoes originalprevious_state); raisesINVALID_TRANSITIONon diverging-params replay against an already-completed task.seed_product: append or replace inPRODUCTSlist;create_media_buy'svalid_idsset is computed fresh per call so new products are immediately available.seed_pricing_option: attach to specified product (or first product whenproduct_id=None); raisesNOT_FOUNDwhen the specified product doesn't exist.seed_creative: upsert intocreativesdict.seed_plan: upsert intoplansdict.seed_media_buy: upsert intomedia_buysdict; stampsmedia_buy_idinto the stored dict (consistent withseed_creative/seed_plan).What was tested
pytest tests/ -q -m "not integration" --ignore=tests/conformance/signing/test_ip_pinned_transport.py: 2321 passed, 22 skipped, 1 xfailed — no regressions. (The ignored test hitsexample.comover the network and fails with 403 in this sandbox; it's pre-existing and unrelated to this diff.)examples/is excluded fromruff,mypy, andpytestinpyproject.toml— no linting or type-check applies to the example file itself.Pre-PR review
force_task_completionnow detects diverging-params replay on completed tasks and raisesINVALID_TRANSITION; (2)seed_media_buynow stampsmedia_buy_idinto the stored dict (consistent with all otherseed_*methods). 1 nit noted:seed_pricing_optionerror message whenproduct_id=NoneandPRODUCTSis empty readsProduct 'None' not found._DEFAULT_ACCOUNT_IDextracted to module-level constant (was duplicated 3×); arm-dispatch branches increate_media_buyannotated with spec shape; idempotent-replayprevious_statenow echoes the original value from first completion. Remaining nits surfaced below.Nits surfaced (not fixed — follow-up candidates)
seed_pricing_optionreportsProduct 'None' not foundwhenproduct_id=NoneandPRODUCTSis empty. Low-severity; the storyboard always passes a product_id.seed_pricing_optionsilently attaches to the first product whenproduct_id=None; a comment noting this behavior would help copiers.SCENARIOSintest_controller.py;force_session_statusabsence not annotated.contextkwarg on newDemoStoremethods is accepted but unused; a comment would clarify it's an optional SDK hook.Session: https://claude.ai/code/session_01DJWM1a9nfjauGxSks9T1KW
Generated by Claude Code