Skip to content

feat(training-agent): dogfood @adcp/client 5.13 seller helpers (closes #2889)#2992

Merged
bokelley merged 3 commits into
mainfrom
bokelley/issue-2889
Apr 24, 2026
Merged

feat(training-agent): dogfood @adcp/client 5.13 seller helpers (closes #2889)#2992
bokelley merged 3 commits into
mainfrom
bokelley/issue-2889

Conversation

@bokelley

@bokelley bokelley commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adopts @adcp/client 5.11–5.13 seller helpers in the reference training agent. Three helper families used:

  • wrapEnvelope for sibling-field emission (replayed / context / operation_id) in framework-server.ts's toAdaptedResponse / serviceUnavailable / versionUnsupported.
  • Session-scoped testController.getSeededProducts callback wires comply_test_controller.seed_product fixtures through get_products on sandbox requests. New behavior — the training agent previously surfaced seeded products only in create_media_buy's product lookup, so a buyer that seeded then called get_products never saw the fixture. SEED_PRODUCT_DEFAULTS fills the response-schema required fields so sparse fixtures still validate.
  • mergeSeedProduct replaces the shallow-spread merge in overlaySeededProducts, gaining permissive-leaf semantics and by-id pricing_options overlay.

Why 5.13.0 exact (not ^5.14.0 or ^5.13.0)

Originally shipped against 5.14 but 5.14 regressed the storyboard runner — strict AJV mode promotes unresolvable $refs from lenient-warning to hard step failure, and downstream storyboards that depend on a ×-flagged step cascade into false-positive agent failures. Measured this branch + main both drop from 52/52 → 39/52 clean storyboards under 5.14.

Filed upstream as adcontextprotocol/adcp-client#866. Pinned to 5.13.0 (exact) so npm install doesn't opportunistically upgrade past the regression. Bump to ^5.14.x in a follow-up PR once #866 ships a fix; the follow-up will also adopt the three 5.14-only helpers:

  • bridgeFromSessionStore — collapses our hand-rolled session-scoped callback to a one-liner.
  • mcpAcceptHeaderMiddleware — 5.14 patches rawHeaders (adcp-client#825); 5.13's version only mutates req.headers.accept, which doesn't propagate through StreamableHTTPServerTransport's @hono/node-server-backed Fetch Request.
  • Delete conflict-envelope.ts — 5.14 ships sanitizeAdcpErrorEnvelope in the dispatcher (adcp-client#826), making the training agent's wire-layer redactor redundant.

Also deferred (not blocked on 5.14): migrating comply_test_controller off customTools onto registerTestController for its auto-emitted capabilities.compliance_testing.scenarios block.

Upstream follow-ups filed during dogfooding

Four DX-gap issues filed; all four merged upstream the same day in adcp-client#830 and #843:

Issue 5.14 resolution
adcontextprotocol/adcp-client#824 bridgeFromSessionStore(loadSession, selectSeededProducts, defaults?)
adcontextprotocol/adcp-client#825 mcpAcceptHeaderMiddleware now patches rawHeaders too
adcontextprotocol/adcp-client#826 adcpError() consults ADCP_ERROR_FIELD_ALLOWLIST; dispatcher re-applies via sanitizeAdcpErrorEnvelope
adcontextprotocol/adcp-client#827 createDefaultTestControllerStore was deleted, replaced with a worked seller example

Plus adcontextprotocol/adcp-client#866 blocking the 5.14 adoption (filed from this branch after finding the storyboard regression).

Security notes

Addressed during review:

  • Bridge sandbox gate: with no resolveAccount wired, isSandboxRequest(params) is the only fence. Sessions are keyed by brand.domain / account_id, not auth principal — cross-tenant fixture reads are possible for any authenticated caller that sends context.sandbox: true plus another caller's brand.domain. Pre-existing behavior (legacy overlaySeededProducts had the same shape); acceptable for this sandbox because fixture data is non-sensitive by design. Documented inline at the bridge wiring site.
  • Custom-tool sanitizer bypass: comply_test_controller is registered via customTools, which bypasses the dispatcher's finalize() / sanitizeAdcpErrorEnvelope. Today the handler never emits adcp_error envelopes (only { success: false, error: '<code>' }), so no live leak. Guard-rail added as a module-level comment in comply-test-controller.ts.

Test plan

  • npm run typecheck clean
  • Targeted training-agent suites — 446 tests passing
  • End-to-end HTTP smoke: verified Accept: application/json → 200, framework dispatcher serves get_products, IDEMPOTENCY_CONFLICT flow strips recovery from both structuredContent.adcp_error AND content[0].text
  • Local storyboards (legacy dispatch): 52/52 clean, 380 passed, 0 failed — matches main's baseline
  • Local storyboards (framework dispatch): 51/52 clean, 390 passed, 1 residual (known, floor = 51/378)
  • Code review (code-reviewer agent): no Must Fix / Should Fix
  • Security review (security-reviewer agent): two Should Fix items addressed as documentation

🤖 Generated with Claude Code

bokelley and others added 2 commits April 23, 2026 22:53
…#2889)

Adopts the five helper families shipped for seller authors in
`@adcp/client` 5.11–5.14:

- `wrapEnvelope` for sibling-field emission in the framework server's
  response adapters
- `bridgeFromSessionStore` wires `comply_test_controller.seed_product`
  fixtures through `get_products` on sandbox requests (new behavior —
  closes a latent gap where seeded products never reached the buyer
  tool)
- `mergeSeedProduct` replaces the shallow-spread overlay in
  `overlaySeededProducts`
- `mcpAcceptHeaderMiddleware` replaces the inline Accept header +
  rawHeaders rewrite on `/mcp` and `/mcp-strict`
- `adcpError()` + dispatcher `sanitizeAdcpErrorEnvelope` make
  `conflict-envelope.ts` and the response-body wrapper redundant —
  both deleted; a framework-path regression locks in that `recovery`
  is stripped from `IDEMPOTENCY_CONFLICT` envelopes at both transport
  layers

Follow-ups filed as adcontextprotocol/adcp-client#824, #825, #826,
#827 landed in 5.14 (closed), so the adoption is complete rather than
partial. Deferred: migrating `comply_test_controller` off the
`customTools` path to `registerTestController` for its auto-emitted
capability block.

Net `+183 / -459` — 276 lines of bespoke glue removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
#	package-lock.json
#	package.json
#	server/src/training-agent/framework-server.ts
@adcp/client 5.14 regressed the storyboard runner — with 5.14 the
training agent drops from 52/52 clean to 39/52 (confirmed against both
this branch and main, identical behavior). Filed upstream as
adcontextprotocol/adcp-client#866.

For this PR, pin to 5.13.0 and narrow the adoption to what works
there: `wrapEnvelope`, `mergeSeedProduct`, and a hand-rolled session-
scoped `testController.getSeededProducts` callback (new behavior —
seeded products now flow through `get_products`, closing a latent
gap).

Put back until the 5.14 bump resolves adcp-client#866:

- inline Accept-header + rawHeaders rewrite on `/mcp` and `/mcp-strict`
- `conflict-envelope.ts` + `wrapResponseForConflictRedaction`
- response-wrapper regression test file

Drop the framework-path regression test for `recovery`-absence on
`IDEMPOTENCY_CONFLICT` — that path exists now only at the HTTP-layer
redactor, which `dispatchTestRequest` doesn't exercise. The legacy
`conflict-envelope.test.ts` covers the redactor's unit contract.

Storyboards local verify:
- legacy (TRAINING_AGENT_USE_FRAMEWORK=0): 52/52 clean, 380 passed, 0 failed
- framework (=1): 51/52 clean, 390 passed, 1 known residual

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley changed the title feat(training-agent): dogfood @adcp/client 5.14 seller helpers (closes #2889) feat(training-agent): dogfood @adcp/client 5.13 seller helpers (closes #2889) Apr 24, 2026
@bokelley bokelley merged commit 6887801 into main Apr 24, 2026
14 checks passed
@bokelley bokelley deleted the bokelley/issue-2889 branch April 24, 2026 10:10
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.

1 participant