feat(media-buy): add targeting-aware product discovery - #6203
Conversation
c93aa6c to
91d362a
Compare
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated-path change requires human/CODEOWNERS review.
This PR modifies/adds ~15 files under static/schemas/source/**, which are under a hard, deterministic approval gate (gated_paths: true). The current review_decision is REVIEW_REQUIRED, not APPROVED, so decision-table row 2 fires and the outcome cannot be approve or plain comment.
Independent of the gate, this is a Breaking-class-eligible protocol change (new AdCP 3.2 targeting-aware product-discovery contract) touching published wire surface. Under the repo's "Breaking-class changes are never auto-approved" hard gate, ratification is a human act.
The reviewer found no Critical/High/Medium findings: schema↔docs coherence verified (product.json overlay_support / targeting_resolution / is_custom / expires_at match get_products.mdx and targeting.mdx), the demographic_targeting_resolution→targeting_resolution.demographics rename is on an unreleased 3.2-beta field (absent from dist/**) so the minor changeset is correct, both new oneOf schemas carry discriminators (mode/operation), and released dist artifacts are untouched. Clean diff, but the deterministic gate stands until a human/CODEOWNERS approval lands.
Escalation reasons
- Modifies/adds ~22 files under
static/schemas/source/**(gated path) withreview_decision: REVIEW_REQUIRED— human/CODEOWNERS approval required before merge. - New published protocol contract (AdCP 3.2 targeting-aware discovery) requires human ratification per the Breaking-class hard gate.
No blocking code findings; escalation is procedural (approval gate), not a defect.
Why human review
- Modifies/adds ~22 files under static/schemas/source/** (gated path) while review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required (row 2).
- New AdCP 3.2 published protocol contract requires human ratification per the repo's Breaking-class hard gate.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/creative-assignment.json (modified) matches
static/schemas/source/**; static/schemas/source/core/package-targeting-resolution.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/package.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/placement-selection.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/placement.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/product-filters.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/product-targeting-resolution.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/product.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-modification.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-requirements.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-support.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/targeting.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-media-buys-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-products-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-products-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/get-products-targeting-resolution.json (added) matchesstatic/schemas/source/**; static/schemas/source/media-buy/package-request.json (modified) matches `static
…(truncated)…
|
Ladon cannot review this PR until merge conflicts are resolved. |
Summary
This proposes the AdCP 3.2 targeting-aware product-discovery contract:
filtersare offer filters and work consistently in brief, wholesale, and refine modestargeting_overlaycarries exact targeting known during discovery, so availability, price, and forecast reflect itrequired_overlay_supportasks for targeting dimensions that must remain selectable on packages lateroverlay_supportand sparsetargeting_resolution.modificationsonly when applied targeting differstargeting_resolution.brief_targetingcan confirm hard targeting inferred from prose once per result setdevice_platform_excludeuses the canonical platform enum, exclusion-wins semantics, reject-rather-than-drop enforcement, and independently declared product supportThe implementation includes schemas, normative design, migration guidance, task/reference docs, buyer education, the media-buy skill, Addie curriculum guidance, compliance storyboards, test vectors, and regression tests.
Important semantics
device_platformdoes not implydevice_platform_exclude.custom,key_value_pairs, and equivalent raw targeting maps are explicitly out of scope; sellers compile typed fields and signals into backend controls internally.PRODUCT_EXPIRED; unknown IDs returnPRODUCT_NOT_FOUND.Training rollout
Live training-agent behavior is intentionally deferred until the 3.2 beta schemas have generated SDK support. Tracking issue: #6199.
Until then, the curriculum separates the current live buying workflow from 3.2 schema-fixture validation so ignored preview fields cannot look like success.
Expert review
The final diff received explicit merge-ready approval from three independent review passes focused on:
Their findings drove the separate request/support shapes, configured-product expiry rules, fixed/selectable placement model, atomic creative-routing behavior, lifecycle-specific resolutions, deterministic refinement semantics, and training-runtime deferral.
Community feedback requested
brief_targetingconfirmation the right scope for a curated result set?required_overlay_supportcorrectly promise independent selection, and should future versions express cross-dimension combinations or numeric minima?is_customthe right marker for all request-bound configured offers?Validation
npm test— passed, including 358 server test files and 5,153 tests (30 skipped)main$reflinks — passed before rebase; post-rebase schema build, bundled schemas, MCP projection, and generated skill schemas passed on the 3.1.10 baselineproduct_filter_behaviorlive run — 9/9 graded checks passed across brief, wholesale, and refine modes/sales: 91 clean storyboards, 500 passing steps)The pre-commit hook's duplicate server-unit invocation hit its 240-second wrapper timeout after the complete suite had already passed; the commit bypassed that redundant hook. No test failed.
Related work
Closes #6132. The design document records the intentional changes from the issue proposal: placement selection is unified under
targeting_overlay, authorized byupdate_targeting, and governed by complete-overlay replacement semantics.Behavioral filter conformance (#2902)
This PR now absorbs the deterministic
get_products.filtersportion of #2902. The normative contract requires every returned product to satisfy every supplied filter predicate inbrief,wholesale, andrefinemodes. A new independent storyboard seeds one matching product plus separate channel-only and delivery-only negative controls, so full and partial filter no-ops fail by membership and field assertions rather than by assuming two responses must differ.#2902 intentionally remains open for
get_media_buy_delivery,get_media_buys, andlist_creativesbehavioral coverage. Natural-language brief relevance remains outside its mechanical filter track. The targeting-aware storyboard separately books and reads back concrete platform exclusion, placement, property, and collection targeting.Grounded lifecycle readback (#4291 / #6173)
This PR also absorbs the configured-product lifecycle slice of #6173: after creating and updating a buy, the targeting readback now uses
field_equals_contextto prove bothmedia_buy_idandpackage_idmatch the identities captured during creation. This prevents an unrelated but correctly shaped buy from satisfying the targeting assertions.The remainder of #6173 stays independent: delivery identity, creative-delivery membership, and generic
list_*round trips. The async lifecycle (#6174), rights lifecycle (#6175), and HTTP creative-approval harness (#6176) are unrelated to targeting-aware discovery and remain separate.