Skip to content

ci(adcp): add storyboard CI job for seller_agent.py compliance checks#309

Merged
bokelley merged 3 commits intomainfrom
claude/issue-305-storyboard-ci-job
Apr 30, 2026
Merged

ci(adcp): add storyboard CI job for seller_agent.py compliance checks#309
bokelley merged 3 commits intomainfrom
claude/issue-305-storyboard-ci-job

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #305

Adds a storyboard CI job that boots examples/seller_agent.py on port 3001 and runs the @adcp/client storyboard suite against it on every PR. The job catches end-to-end response-shape, status-enum, and capability-declaration regressions that unit tests and import smoke checks cannot see — exactly the class of breakage that silently broke #295/#296.

The job is continue-on-error: true (informational, non-blocking) because examples/seller_agent.py on current main has known content gaps (#304) that produce partial results. Once those are fixed and the job goes green, remove continue-on-error to promote it to a required check.

What's tested

  • YAML syntax validated with python3 -c "import yaml; yaml.safe_load(...)"
  • No Python source changes; pytest, mypy, ruff not applicable to this diff

Implementation notes

  • Readiness check: curl polls http://localhost:3001/mcp (any non-000 HTTP code means uvicorn is accepting HTTP); 30s timeout with PID-alive-check to fail fast if the agent crashes on startup
  • @adcp/client@latest: intentionally unpinned — this is AdCP's own CI running AdCP's own canonical storyboard runner. Tracking latest surfaces protocol drift immediately, which is the purpose of this job. (The supply-chain risk vs. npx playwright treatment question was the only blocker/nit split in the prior triage; /triage execute resolved it.)
  • Artifact: always uploaded as storyboard-result-${{ github.run_attempt }} (suffixed to avoid v4 conflict on re-runs), with if-no-files-found: warn so a startup failure doesn't add a second noisy annotation

Pre-PR review

  • code-reviewer: approved after fixes — caught 'pass''passing' enum mismatch (would have made the job permanently red) and d[k] KeyError in diagnostic print; both fixed
  • dx-expert: approved after fixes — caught upload-artifact@v4 hard-error on missing file; fixed with if-no-files-found: warn; noted run_attempt suffix for re-run safety; applied

Nits noted (not fixed):

  • Agent process not explicitly torn down between steps (fine for single-scenario job; AGENT_PID is process-local to the step, VM exits clean it up)
  • Timeout message "30s" is technically ~29.5s; not operationally significant

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout 306
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_01SSje6ebBHD85TWdQbEig9m


Generated by Claude Code

claude and others added 3 commits April 29, 2026 21:00
Adds a non-blocking storyboard CI job (continue-on-error: true) that
boots examples/seller_agent.py and runs the @adcp/client storyboard
suite on every PR. Uses curl-based HTTP readiness polling instead of
lsof, bounds the wait with a 30s timeout + PID-alive-check, and guards
json.load with a file-existence check. Artifact always uploaded.

Non-blocking until seller-agent content gaps in #304 are resolved.

Closes #305

https://claude.ai/code/session_01SSje6ebBHD85TWdQbEig9m
- overall_status check: 'pass' → 'passing' (actual runner enum value)
- Assert step: dump full JSON on failure instead of d[k] (avoids KeyError)
- Artifact upload: add if-no-files-found: warn and run_attempt suffix
- Comment: document @latest intent and 405-ok readiness check rationale

https://claude.ai/code/session_01SSje6ebBHD85TWdQbEig9m
Acting on dx-expert review of this PR:

On dual-stack hosts (and Ubuntu runners since actions/runner 2.300+),
``localhost`` resolves to ``::1`` first. uvicorn's default bind is
IPv4-only, so the readiness probe and runner invocation each eat a
connection-refused round-trip on ``::1`` before falling back to
``127.0.0.1``. Curl falls back automatically (so it still works), but
it's wasteful and slightly fragile.

Pin both call sites to ``127.0.0.1`` directly. The agent's bind address
is unchanged (still ``0.0.0.0`` via ``ADCP_HOST`` default in #296);
only the client-side address resolution changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley marked this pull request as ready for review April 30, 2026 01:00
@bokelley bokelley force-pushed the claude/issue-305-storyboard-ci-job branch from ad17812 to 60375a9 Compare April 30, 2026 01:00
@bokelley bokelley merged commit f02ea79 into main Apr 30, 2026
9 of 11 checks passed
@bokelley bokelley deleted the claude/issue-305-storyboard-ci-job branch April 30, 2026 01:01
bokelley added a commit that referenced this pull request Apr 30, 2026
…) (#322)

End-to-end against npx @adcp/client adcp storyboard run now reports
overall_status: passing with 47/47 individual steps passing and
controller_detected: true (was 36/47 partial after #317).

Three fixes against examples/seller_agent.py:

1. Add four runner-fixture products to PRODUCTS — outdoor_display_q2,
   outdoor_video_q2, sports_preroll_q2, lifestyle_display_q2. The
   @adcp/client storyboard YAMLs reference these by ID without an
   explicit seed_product setup step; the seller is expected to know
   them out of the box. Pricing option IDs (cpm_standard,
   cpm_guaranteed) match what the compliance YAMLs send.

2. Validate measurement_terms in create_media_buy — reject with
   TERMS_REJECTED when max_variance_percent < 5 or measurement_window
   is not in (c3, c7). Source-of-truth is the
   measurement_terms_rejected.yaml storyboard which probes with
   c30 + 0% (rejected path) then retries with c7 + 10% (accepted
   path). Acceptance threshold matches the runner's relaxed shape.

3. Persist targeting_overlay (and friends) on packages — both
   create_media_buy and update_media_buy now preserve
   targeting_overlay, creative_assignments, creatives, and
   measurement_terms on the persisted package state, then surface
   them on get_media_buys. Storyboard
   inventory_list_targeting/verify_create_persisted round-trips
   property_list.list_id; the swap variant exercises the update
   parity check.

Once this lands, the storyboard CI job (#309, currently
continue-on-error: true) is promotable to required.

Closes #319

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: run AdCP storyboard suite against examples/seller_agent.py on every PR

2 participants