fix(training-agent): event_source validation + cost_per_acquisition for performance_buy_flow#4654
Merged
Conversation
…or performance_buy_flow Close the two gaps that prevent the `media_buy_seller/performance_buy_flow` storyboard scenario (#4642) from passing against the training agent. - `handleCreateMediaBuy` validates `optimization_goals[].event_sources[].event_source_id` against the session's registered sources (via `findEventSourceInSession`, which falls back to a global scan to match `log_event` lookup semantics). Phantom ids are rejected with INVALID_REQUEST and `error.field` set to the literal JSONPath-lite shape (`packages[0].optimization_goals[0].event_sources[0].event_source_id`) the scenario asserts on. Silent acceptance would let a seller advertise `conversion_tracking` without being able to actually optimize against the event source the buyer thinks is bound. - `get_media_buy_delivery` totals now carry `conversions` and `cost_per_acquisition = spend / conversions` when `simulate_delivery` injected both — matching the delivery contract for performance buys. Sellers that don't compute conversion metrics simply omit the fields (no conversions injected => no fields emitted). Unit tests assert the rejection path with the literal JSONPath, the success path against a registered source, and CPA emission / omission in delivery reporting. Refs #4569 (capability gating), #4637, #4642 (scenario PR). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 17, 2026
Merged
bokelley
added a commit
that referenced
this pull request
May 17, 2026
…ed scenarios (#4637) (#4664) * feat(compliance): audience_buy_flow + event_dedup_flow scenarios + TA audience validation (#4637) Two new capability-gated scenarios in the contract pattern (#4637), added to sales-non-guaranteed.requires_scenarios: - media_buy_seller/audience_buy_flow — gated on media_buy.audience_targeting presence. Certifies sync_audiences → bound audience_id in targeting → unbound id rejected → delivery against an audience-targeted buy. Sibling to performance_buy_flow on the audience side; the unbound-id rejection is the discriminating assertion. The literal error.field path on packages[0].targeting_overlay.audience_include[0] mirrors the event_source_id contract from #4642. - media_buy_seller/event_dedup_flow — gated on media_buy.conversion_tracking.multi_source_event_dedup equals true. Certifies that the same event_id from two registered event sources attributes to one conversion, not two. Sellers without multi_source_event_dedup grade not_applicable — the bit gates the scenario; the cumulative-count assertion (1, not 2) is the contract. The training agent does not declare this bit, so it grades not_applicable here; no training-agent fix is needed for this scenario. Training-agent fix: create_media_buy now rejects targeting_overlay.audience_include / audience_exclude entries whose audience_id was never registered via sync_audiences, with INVALID_REQUEST and error.field set to the literal JSONPath-lite path. Mirrors the event_source_id validation pattern from #4654. sync_audiences itself is now wired through the training agent (legacy /mcp HANDLER_MAP and v6 /sales/mcp via AudiencePlatform) so adopters can run the audience scenario against the reference implementation. Four unit tests cover the four contract paths (accept/reject × include/exclude). Three sibling product-level scenarios (reach, clicks, completed_views) remain blocked on #4651 product-level capability gating RFC. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(training-agent): register sync_audiences in /sales tenant catalog (PR 4664 CI fix) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
5 tasks
bokelley
added a commit
that referenced
this pull request
May 19, 2026
…ompleted_views scenarios (#4766) * feat(training-agent): metric-mode capability + validation + derived delivery for clicks/reach/completed_views Declares seller-level `media_buy.supported_optimization_metrics` (honest union across catalog products), validates `reach_unit` / `view_duration_seconds` against product capabilities on create_media_buy, and emits `cost_per_click` plus goal-gated `reach + frequency` / `completed_views + completion_rate` on get_media_buy_delivery. Flips three capability-gated storyboards from `not_applicable` to applicable: clicks_buy_flow, reach_buy_flow, completed_views_buy_flow. Same forcing-function shape as #4654 and #4664. Manual rollup pending adcp-client#1818 (SDK seller-level field exposure). Refs: #4637, #4642, #4654, #4664, #4722. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(training-agent): add completed_views delivery emission + cost_per_click negative tests (PR 4766 review) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Close the two gaps that prevent the
media_buy_seller/performance_buy_flowstoryboard scenario (#4642) from passing against the training agent. The training agent already advertisesmedia_buy.conversion_tracking, so the scenario runs against it (notnot_applicable) — without these fixes the newrejection_unbound_event_sourceandattributed_delivery_reportingphases fail.handleCreateMediaBuyvalidatesoptimization_goals[].event_sources[].event_source_idagainst the session's registered sources. Phantom ids reject withINVALID_REQUESTanderror.fieldset to the literal JSONPath-lite shapepackages[i].optimization_goals[j].event_sources[k].event_source_idthe scenario asserts on. Silent acceptance would let a seller advertiseconversion_trackingwithout being able to actually optimize against the event source the buyer thinks is bound — a façade.get_media_buy_deliverytotals now emitconversionsandcost_per_acquisition = spend / conversionswhensimulate_deliveryinjected both. Sellers that don't compute conversion metrics simply omit the fields (no conversions injected → no fields emitted).Lookup uses a new exported helper
findEventSourceInSession(sessionKey, id)(session-local lookup with global fallback) incatalog-event-handlers.ts— same fallback semantics thatlog_eventalready relies on so the test-controller seeding path stays consistent.Test plan
npx vitest run server/tests/unit/training-agent.test.ts— 372 tests pass, including three new assertions covering the rejection path, the success path against a registered source, and CPA emission/omission in delivery reporting.npx vitest run server/tests/unit/comply-test-controller.test.ts— 42 tests pass; delivery simulation totals stay backwards-compatible for non-conversion buys.npx vitest run server/tests/unit/training-agent(all 12 training-agent unit suites) — 503 tests pass.npm run build— full schema build, compliance build, tarball build all clean.Refs
What is NOT in this PR
static/compliance/source/**— the storyboard ships in feat(compliance): performance_buy_flow scenario for capability-gated CPA buys (closes #4569) #4642.by_creative[].conversionsper-creative attribution — that scenario assertion is being dropped from feat(compliance): performance_buy_flow scenario for capability-gated CPA buys (closes #4569) #4642.🤖 Generated with Claude Code