Summary
Every adopter of `adcp-client-python` who wants to run the compliance storyboard against their own seller in CI has to invent the same harness:
- Mount the full ASGI app via `build_app()` (or whatever entry point the seller exposes)
- Drive requests through `httpx.ASGITransport` to exercise the real wire envelope (MCP and A2A)
- Parse the response, extract `adcp_error` from `structuredContent` (MCP) or `Task.artifacts[0].parts[0].data` (A2A)
- Run scenarios from the bundled compliance cache against this harness
- Aggregate pass/fail
This is reinvented in every salesagent test file we've added today (see PR #330's `tests/integration/test_delegate_wire_envelope_cross_transport.py`). It's tedious and prone to drift across adopters.
Proposed surface
```python
from adcp.server.testing import StoryboardHarness
@pytest.fixture
def harness():
return StoryboardHarness(app=build_app(), seller_config=...)
def test_create_media_buy_compliance(harness):
result = harness.run_scenario(
"media_buy_seller/refine_products",
transport="mcp", # or "a2a", or "both"
)
assert result.passed, result.failures
def test_typed_error_translates(harness):
response = harness.invoke(
tool="update_media_buy",
payload={"media_buy_id": "does-not-exist", ...},
transport="a2a",
)
assert response.adcp_error.code == "MEDIA_BUY_NOT_FOUND"
```
The harness:
- Wraps the ASGI app and provides MCP/A2A transport adapters
- Reads compliance scenarios from the bundled cache
- Handles wire-shape envelope unpacking per transport
- Reports per-scenario pass/fail with the same JSON shape as `adcp storyboard run --json`
Why this matters
- Adopters get compliance testing for free — no harness to maintain
- Cross-transport contract tests become trivial — single fixture covers both transports
- Spec drift detection — when the SDK bumps to a new spec version, every adopter's CI catches behavioral regressions automatically
- Onboarding friction drops — "how do I test my seller against AdCP compliance?" has a one-line answer
Reference implementation
PR #330 in bokelley/salesagent (`tests/integration/test_delegate_wire_envelope_cross_transport.py`) is a working version for a single tool. Extending to scenario-level execution is the obvious next step.
Related
Summary
Every adopter of `adcp-client-python` who wants to run the compliance storyboard against their own seller in CI has to invent the same harness:
This is reinvented in every salesagent test file we've added today (see PR #330's `tests/integration/test_delegate_wire_envelope_cross_transport.py`). It's tedious and prone to drift across adopters.
Proposed surface
```python
from adcp.server.testing import StoryboardHarness
@pytest.fixture
def harness():
return StoryboardHarness(app=build_app(), seller_config=...)
def test_create_media_buy_compliance(harness):
result = harness.run_scenario(
"media_buy_seller/refine_products",
transport="mcp", # or "a2a", or "both"
)
assert result.passed, result.failures
def test_typed_error_translates(harness):
response = harness.invoke(
tool="update_media_buy",
payload={"media_buy_id": "does-not-exist", ...},
transport="a2a",
)
assert response.adcp_error.code == "MEDIA_BUY_NOT_FOUND"
```
The harness:
Why this matters
Reference implementation
PR #330 in bokelley/salesagent (`tests/integration/test_delegate_wire_envelope_cross_transport.py`) is a working version for a single tool. Extending to scenario-level execution is the obvious next step.
Related