Skip to content

feat(testing): bridge participation marker (#1775)#1786

Merged
bokelley merged 2 commits into
mainfrom
bokelley/bridge-leaderboard-and-proxy
May 16, 2026
Merged

feat(testing): bridge participation marker (#1775)#1786
bokelley merged 2 commits into
mainfrom
bokelley/bridge-leaderboard-and-proxy

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Summary

Closes #1775 (SDK half — consumer half tracked in #1782 and adcontextprotocol/adcp).

When the TestControllerBridge merges seeded fixtures into a handler response, stamp a non-normative _bridge: { callback, tool, merged_count } marker on structuredContent (mirrored to content[0].text when JSON). This is the runner-visible signal that distinguishes "this pass exercised the adopter's adapter against upstream" from "this pass exercised wire conformance against fixture data merged by the SDK". Storyboard runners and compliance leaderboards read it to attribute bridge participation in run records.

Why now: the bridge surface has grown from 5 tools (PR #1754) to 13 through phases 2–4 (#1759, #1761, #1772, #1773). With 13 fixture-augmented tools, every storyboard pass through fixture-merge reads identically to one that ran through a real adapter — exactly where the gap matters most (walled-garden proxies). JSDoc disclaimers don't survive contact with a leaderboard score.

What ships

  • stampBridge helper (parallel to stampReplayed) sets _bridge on structuredContent + opportunistic JSON-text mirror.
  • 19 dispatch sites across 16 bridge callbacks — every bridge merge point in create-adcp-server.ts stamps per-tool with the originating callback name, so runners can attribute participation at the getSeededCreatives / getSeededMediaBuys / etc. granularity.
  • Append-merge tools stamp when the callback returned ≥ 1 valid entry. Singleton-replace tools (get_account_financials, get_brand_identity, si_get_offering, get_property_list, get_collection_list, get_content_standards) stamp only when a seeded fixture actually matched the request id and replaced the handler payload.
  • Marker absent on non-sandbox traffic, when the callback is omitted, and on singleton-replace tools when no fixture matched.
  • Schema-safe: verified every bridge-touching response schema sets additionalProperties: true at the top level (success arm for oneOf envelopes). Underscore prefix advertises "internal / out-of-spec" to validators that round-trip unknowns.
  • BridgeMarker type exported from @adcp/sdk/server for adopters who want to type-check marker reads.
  • Dead-code removal: dropped three unreachable duplicate dispatch blocks (get_brand_identity, get_rights, si_get_offering) that were appended below the canonical else if chain. No behavior change — only the first block ever fired in a continuous else if.

Docs

docs/guides/VALIDATE-YOUR-AGENT.md § Platform-proxy sellers gains a new bullet explaining the marker, its payload, and how to interpret a bridge-augmented pass (wire conformance against fixture data, not adapter-against-upstream health). Cross-links #1775 (cross-repo coordination) and #1782 (leaderboard policy).

Half-shipped warning

The SDK emits the signal; the runner has to surface it for the marker to do its job. Consumer side lives in adcontextprotocol/adcp (storyboard runner) and adcp-client#1782 (leaderboard policy). Without those, this PR is the inert half of the contract — landing it unblocks the cross-repo work.

Test plan

  • 23 new tests in test/lib/bridge-marker.test.js — one happy path per bridge callback + four absence cases (omitted callback, non-sandbox, singleton no-match, empty-fixture)
  • 186 existing bridge tests (seed-per-tool-wiring, seed-get-products-wiring, test-controller-bridge, seed-merge-helpers) pass unchanged
  • Full library suite: 6699 pass / 0 fail
  • tsc --noEmit clean
  • prettier --check clean
  • Build clean

🤖 Generated with Claude Code

bokelley and others added 2 commits May 16, 2026 07:44
When the TestControllerBridge merges seeded fixtures into a handler response,
stamp `_bridge: { callback, tool, merged_count }` on structuredContent so
storyboard runners and compliance leaderboards can distinguish wire conformance
against fixtures from adapter-against-upstream health.

- 19 dispatch sites across 16 bridge callbacks; append-merge stamps on ≥1
  valid entry; singleton-replace stamps only when a fixture actually matched.
- Schema-safe (AdCP 3.0 envelopes all allow additionalProperties at top level).
- Drops three unreachable duplicate dispatch blocks (get_brand_identity /
  get_rights / si_get_offering) appended below the canonical else-if chain.
- BridgeMarker type exported from @adcp/sdk/server.

Consumer side (storyboard runner / leaderboard policy) lives in
adcontextprotocol/adcp and is coordinated via #1782.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three convergent doc nudges from parallel expert review — no logic changes:

1. VALIDATE-YOUR-AGENT.md bullet now addresses the procurement reader
   directly: explains how `merged_count` distinguishes "fully fixture-
   augmented" from "bridge-supplemented real adapter call" (PM review).

2. JSDoc on `AdcpServerConfig.testController` flags the trust-boundary
   risk when registered without `resolveAccount` — caller-supplied
   `account.sandbox = true` is the only gate, so production deployments
   must either configure `resolveAccount` or omit `testController`
   outside test/staging (security review M1; pre-existing risk made
   discoverable by the marker).

3. JSDoc on `BridgeMarker` explains why the marker lives on the response
   body rather than MCP `_meta`: cross-transport parity with A2A, L2
   text-body parity, and precedent with `replayed` (protocol review).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley
Copy link
Copy Markdown
Contributor Author

Expert review pass — four reviewers, no blockers

Ran four parallel expert reviews (ad-tech-protocol, code-reviewer, adtech-product, security). Synthesis:

Convergent feedback addressed in commit 1d603ee:

  1. PM (procurement framing)docs/guides/VALIDATE-YOUR-AGENT.md bullet now speaks directly to the buyer reading a compliance score, explaining how merged_count distinguishes "fully fixture-augmented" from "bridge supplemented a real adapter call." The previous wording was SDK-adopter-only.

  2. Security M1 (trust boundary) — JSDoc on AdcpServerConfig.testController now flags that registering the bridge without resolveAccount makes caller-supplied account.sandbox = true the only gate. Pre-existing risk in createAdcpServer (the createAdcpServerFromPlatform path already enforces this via Phase 2 of feat(server): Account.mode + sandbox-account authority gate for comply controller #1435), but the marker makes the leak more discoverable, so this is the right PR to document it. Net-positive for wire honesty.

  3. Protocol (body vs MCP _meta) — JSDoc on BridgeMarker now explains the three reasons body placement won over _meta: cross-transport parity with A2A (no _meta equivalent), L2 text-body parity, and precedent with replayed.

Non-blocking, deferred:

  • Protocol: File a spec-level proposal in adcontextprotocol/adcp for the underscore-prefixed annotation convention so future framework-emitted markers have a documented home. Will open a separate spec issue — not in this PR's scope.
  • Code-review nits: merged_countseeded_count rename (touches Bridge leaderboard policy: how does a runner-visible bridge marker get consumed? #1782 runner contract; defer); test helper deepEqual strictness (current strictness is the point).
  • Security L1/L2: cache canonicalization audit for _bridge field (parallel to existing replayed hazard, no new risk); marker-on-mutating-tool future-proofing (none of the 13 bridge tools are in MUTATING_TASKS today).

Verdict from each reviewer: ship it.

CI re-running on commit 1d603ee; will admin-merge once green.

@bokelley bokelley merged commit bea09b9 into main May 16, 2026
10 checks passed
@bokelley bokelley deleted the bokelley/bridge-leaderboard-and-proxy branch May 16, 2026 11:59
bokelley added a commit that referenced this pull request May 16, 2026
…roxy sellers only (#1787)

Names the audience explicitly so state-local sellers don't wire the bridge
unnecessarily, and upstream-proxy sellers know to wire it. Cross-links the
upstream taxonomy proposal at adcontextprotocol/adcp#4593 and the leaderboard
policy at #1782.

Also collapses a duplicate trust-boundary blurb (added in #1779 alongside the
security-review note in #1786) into a single coherent section.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot mentioned this pull request May 16, 2026
bokelley added a commit that referenced this pull request May 16, 2026
…n model (#1795)

* docs: align bridge framing with revised single-dimension certification model

Maintainer walked back the two-badge proxy-vs-state-local split from #1782
and proposed a single-dimension framing (Wire Conformance / Live Integration
Verified) where every seller faces the same verifiability gap, and the bridge
is one of two mechanisms for closing the seed→read loop, not a special path
for one seller class.

JSDoc on AdcpServerConfig.testController:
- Drops "only upstream-proxy sellers" as primary framing
- "Pick by where your read handlers fetch from, not by seller class"
- "Either path earns wire-conformance credit; it is *not* a separate
  certification category"

skills/build-seller-agent/SKILL.md:
- New "Test surfaces" section frames the verifiability gap as universal
- Names the two implementations (state-local store vs TestControllerBridge)
- Hedges on certification names while #1782 settles

No SDK behavior change. Marker contract, trust-boundary docs, and dual-emit
warn from #1786/#1787/#1788 all stay as-is — they describe mechanism without
committing to certification taxonomy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(skill): fold docs-expert feedback — tighten Test surfaces section + in-repo JSDoc link

---------

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Storyboard runner: surface bridge participation in run record

1 participant