feat(testing): signals/creative-delivery/creative-features seeded bridges (#1755 phase 3)#1772
Merged
Merged
Conversation
…-features seeded bridges (#1755 phase 3) Extends TestControllerBridge with three opt-in callbacks for platform-proxy sellers to seed signal + creative read-path fixtures into conformance storyboards without driving real upstream calls: - getSeededSignals → get_signals (append-merge, canonical signal_id dedup across catalog/agent discriminator) - getSeededCreativeDelivery → get_creative_delivery (append-merge by creative_id, pagination.total drift) - getSeededCreativeFeatures → get_creative_features (oneOf-aware: merge CreativeFeatureResult[] into success-arm results by feature_id; no-op on error arm; preserves handler envelope fields) list_audiences and list_targeting_categories deliberately not added: neither tool exists in AdCP 3.0.11 (audience discovery folds into sync_audiences; targeting capabilities surface via get_adcp_capabilities). No fabricated bridges. BridgeFromSessionStoreOptions gains matching selectSeededSignals / selectSeededCreativeDelivery / selectSeededCreativeFeatures. 28 new wiring tests covering: seeded-only, handler-only, append-merge, collision dedup, mixed-collision (handler [A,B] + bridge [B,C] → [A,B-seeded,C]), source-discriminator preservation (catalog/agent signal_id with same id stay distinct), pagination.total drift on creative_delivery, oneOf error-arm pass-through and envelope-field preservation on creative_features, sandbox-gating refusal, validation drop, plus bridgeFromSessionStore selector wiring. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 16, 2026
- Correct getSeededSignals / mergeSeededSignalsIntoResponse JSDoc: PaginationResponse.total_count exists but is intentionally not recomputed on partial-page merges (cross-page total context lives outside the seeded fixture). - Stamp sandbox: true on mergeSeededCreativeDeliveryIntoResponse for symmetry with mergeSeededSignalsIntoResponse and the other list-merge bridges. - Trim changeset summary to the bridges that actually ship (signals, creative-delivery, creative-features); audiences/targeting were deliberately skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
Review nits addressedThree small fixes from the code-review + protocol-expert reviews:
|
This was referenced May 16, 2026
bokelley
added a commit
that referenced
this pull request
May 16, 2026
…1779) * docs(bridge): name resolveAccount trust boundary + multi-tenant keying as adopter responsibility Adds two paragraphs to the top-of-file JSDoc on TestControllerBridge: 1. Scope of verification — a storyboard pass through this bridge proves wire conformance against fixture data, not adapter health against the real upstream. Sellers must still exercise adapters against a live-OAuth sandbox runner separately. Cross-references the runner-visible-bridge-marker ask at #1775. 2. Adopter responsibilities — names two patterns the SDK can't enforce: (a) resolveAccount is the trust boundary; production bindings MUST configure it or the request-signal check is the only line of defense, because the dispatcher gate falls through to permissive when ctx.account === undefined. (b) Multi-tenant keying is the adopter's job; the SDK does no defensive cross-check between fixture-entry account IDs and the resolved ctx.account. No code change. Security-review-driven during the post-merge review of #1754 — main shipped the bridge surface (#1753 + phases #1759/#1761/ #1772) but no public-surface warning about either trust pattern. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(bridge): docs-expert tightenings on JSDoc PR review - "bypassed by the post-handler merge" → "shadowed by the post-handler merge" (more accurate: the upstream is called, then its response is overridden). - "request-signal check is the only line of defense" → "buyer-supplied sandbox marker is the only gate" (flatter, more accurate). - Drop the "Snap, Meta, TikTok, Google Ads" brand list → "social / search / programmatic inventory APIs" (illustrative without pulling toward a specific adopter or violating fictional-names-only convention). - Echo a one-paragraph trust-boundary note on createAdcpServer's testController config field — that's where a wiring author lands when they hit autocomplete, and the last chance to warn before resolveAccount gets omitted. Cross-references the top-of-file JSDoc on TestControllerBridge. All four changes from the docs-expert review of PR #1779. No code behavior change; pure JSDoc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
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.
Phase 3 of #1755 — extends
TestControllerBridgewith the next batch of read-path bridges so platform-proxy sellers can seed signal + creative fixtures into compliance storyboards without driving real upstream calls.Summary
Bridges shipped (3)
getSeededSignalsget_signalssignal_id(canonical)signal-marketplace,signal-owned(one bridge handles both —signal_typeis the per-entry discriminator)getSeededCreativeDeliveryget_creative_deliverycreative_id,pagination.totaldriftcreative-ad-server,creative-template,creative-generative(delivery readback)getSeededCreativeFeaturesget_creative_featuresresults[]byfeature_id(oneOf-aware no-op on error arm)creative-*governance feature evaluationBridges skipped (2 — schemas don't exist in 3.0.11)
list_audiences— not a 3.0.11 tool. Audience discovery is folded intosync_audiences(the discovery-only call omits the requestaudiencesarray but still returnsaudiences[]). Seesrc/lib/testing/storyboard/default-invariants.ts:725-727and the absence of anyaudiences/directory underschemas/cache/3.0.11/bundled/.list_targeting_categories— not a 3.0.11 tool. Targeting capabilities surface viaget_adcp_capabilities. Nolist-targeting-*.jsonschemas exist underschemas/cache/3.0.11/.Schema citations
schemas/cache/3.0.11/bundled/signals/get-signals-response.json—signals: [{ signal_id, ... }], dedup keysignal_id(discriminated union:{source:'catalog', data_provider_domain, id}or{source:'agent', agent_url, id}— canonical dedup key is${source}|${origin}|${id}).schemas/cache/3.0.11/bundled/creative/get-creative-delivery-response.json—creatives: [{ creative_id, ... }], optionalpagination.total(field nametotal, distinct fromtotal_countelsewhere).schemas/cache/3.0.11/bundled/creative/get-creative-features-response.json—oneOfenvelope. Success arm:results: CreativeFeatureResult[](dedup keyfeature_id); error arm:errors: Error[]. No top-level entity id.Implementation notes
get_creative_featuresis the first nested-array bridge. The seeded array (CreativeFeatureResult[]) merges into a property of the success arm (results), not the top-level response. The handler computes everything else; the bridge just augments per-feature evaluations. Error arm is a no-op (the seeded results array can't be grafted onto an error envelope without producing a wire-incorrect mixed shape).SignalIDis{source:'catalog', data_provider_domain, id}or{source:'agent', agent_url, id}— two signals with the sameidfrom different sources are distinct, so dedup keys on the full tuple. Validation drops entries with malformed source/origin/id triples.get_creative_featuresenvelope fields preserved.context,ext,detail_url,pricing_option_id,vendor_cost,currency,consumptionround-trip from the handler verbatim — onlyresultsis augmented.bridgeFromSessionStore selectors added
selectSeededSignalsselectSeededCreativeDeliveryselectSeededCreativeFeaturesOmitted selectors leave the corresponding bridge callback unset (opt-in by presence, same pattern as existing selectors).
Documentation
docs/guides/VALIDATE-YOUR-AGENT.md"Platform-proxy sellers" table extended with the three new entries, plus a new bullet documentingget_creative_features'soneOf-aware nested-array merge semantics.Test plan
test/lib/seed-per-tool-wiring.test.js:npm run typecheckcleannpm run format:checkcleannpm testfrom root: 8745 pass, 3 skipped, 0 fail (+ eslint-plugin workspace 30/30 pass)