fix(creative): clarify preflight dry-run validation - #5791
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
Clean clarification: separates validate_input (manifest-structure preflight) from sync_creatives dry_run: true (operation-level trafficking rehearsal), and makes the training-agent reference implementation match. The boundary is drawn on the right axis — preflight validates shape, dry-run rehearses the seller's account/library/policy path.
Things I checked
- Schema changes are description-only. All four files under
static/schemas/source/creative/touch onlydescription/examples[].descriptionstrings. No field renames, type changes, enum changes, required↔optional flips, or oneOf discriminator moves.dry_runstaysboolean/default: false;validate-input-resultkeepsrequired: ["target","result_kind"]and its threeresult_kindvalues intact. Wire-compatible →patchchangeset is the correct semver call. (ad-tech-protocol-expert: sound.) - Schema-vs-docs coherence. The two-primitive narrative matches across
sync-creatives-request.json, the threevalidate-input-*.jsonfiles,canonical-formats.mdx,canonical-formats-migration.mdx, andtask-reference/sync_creatives.mdx. No drift. The renamed sectionvalidate_input vs sync_creatives dry runand its comparison table mirror the schema descriptions. - The one behavior change is correct.
task-handlers.ts:5439-5466— dry-run now enters the assignment block (was gated out by!isDryRun), validates references againstavailableCreativeIds(session creatives + non-failedresults), returnsstatus: 'error'for bad refs, and gates only the real mutation (pkg.creativeAssignments.push) behind!isDryRunat:5461. Non-dry-run path is unchanged:session.creativesalready holds every just-created creative before the loop, soavailableCreativeIdsis a superset of the oldsession.creatives.has()check — identical behavior on the happy path. - No library mutation on dry-run. Creatives stay gated by the existing
if (!isDryRun)persist block; the new test assertslist_creativesreturns[]after a dry-run sync, and that assertion is genuinely load-bearing (thecreative_idsfilter runs before the compliance fallback). (code-reviewer: clean, no blockers.) - Changeset present and typed correctly.
.changeset/clarify-creative-preflight.md—patch, wire-touching PR covered.
Minor nits (non-blocking)
- New test covers the error path only.
server/tests/unit/training-agent.test.tsasserts the dry-run missing-package case (status: 'error') but not the more load-bearing invariant: a valid ref ondry_run: truereturnsstatus: 'assigned'whilepkg.creativeAssignmentsstays empty. That's the!isDryRunguard attask-handlers.ts:5461— worth an explicit assertion. Not blocking; the mutation guard is a one-liner and the non-dry-run push is already covered attraining-agent.test.ts:4294.
LGTM. Follow-up noted.
There was a problem hiding this comment.
Schema/tool/prose reframing is sound and the dry-run server change is clean — but the new dry-run snippet in sync_creatives.mdx checks assignment errors on a field the published response schema doesn't have, so it fails open on the exact path this PR exists to teach.
The reframing itself is the right shape: validate_input = manifest-structure preflight (no trafficking gates), sync_creatives dry_run:true = non-mutating rehearsal of the actual seller operation. That boundary is now stated coherently across the four schema descriptions, both tool strings, and the three docs. ad-tech-protocol-expert: sound — the four schema touches are description-only, no wire-shape change, patch changeset is correct.
Things I checked
- Schema touches are description-only. Every changed line in the four
static/schemas/source/creative/*.jsonfiles is a-/+pair on adescriptionstring.dry_runstays{type: boolean, default: false}(sync-creatives-request.json:88);result_kindenum and theoneOfconstdiscriminators onvalidate-input-result.jsonare untouched. Not a breaking change.patchis right. - Dry-run server change leaks no state.
handleSyncCreativesnow seedsavailableCreativeIdsfromsession.creatives.keys()plus non-failedresults, validates assignment references, and gates the only mutation —pkg.creativeAssignments.push— behind!isDryRun(task-handlers.ts:204). Creative persistence at:5411was already!isDryRun. Non-dry-run is equivalent to the priorsession.creatives.has()check.code-reviewer: ready to push. - Regression test covers the new path.
training-agent.test.ts:4335asserts dry-run returnsassignments[0].status === 'error'("Package not found") andlist_creativesreturns[]. On base the block was skipped in dry-run, so this genuinely exercises new behavior. - The response schema has no top-level
assignments[].grepconfirms it exists only in the request. The success shape carries assignment outcomes per-creative viaassigned_to[]andassignment_errors{}(sync-creatives-response.json:83-100).
The question that flips this to approve
sync_creatives.mdx:113-116 (JS) and :124-127 (Python) detect assignment failures via validated.assignments?.some(a => a.status === "error") / getattr(result, 'assignments', []). That top-level assignments[] does not exist on SyncCreativesResponseSchema — a spec-conformant seller returns assignment failures in the per-creative assignment_errors map. So the branch never fires against the wire contract: creative uploads clean, package assignment fails, and the snippet prints "Validation passed! Ready to sync." The creative.action === "failed" sibling branch is correct (sync-creatives-response.json:40, creative-action.json) — only the assignment branch is wrong. Rewrite both to read assignment_errors per creative and I'll approve.
The shape the snippet checks is the one the training-agent runtime emits (task-handlers.ts:5471), not the one the published schema documents — an easy shape to reach for when the reference server is what you're testing against.
Follow-ups (non-blocking — file as issues)
- The training-agent runtime returns a top-level
assignments[]withstatus, whichsync-creatives-response.jsondoesn't model. Pre-existing divergence the snippet leaned on; worth reconciling the reference server to the published response shape (per-creativeassignment_errors). training-agent.test.ts:4335only covers the package-not-found branch. Add a dry-run happy-path case (valid media buy + package + creative) assertingpkg.creativeAssignmentsstays unmutated — the!isDryRunpush guard itself is currently untested.
Minor nits (non-blocking)
- "Dry run" doc section doesn't show where assignment errors live.
sync_creatives.mdx:816-819now promises dry-run returns "assignment errors" but never points atassignment_errors. One accurate example closes the loop the snippet above opens.
LGTM after the two snippets read assignment_errors. Everything else is clean.
* fix(creative): clarify preflight dry-run validation (#5791) * Clarify creative preflight semantics * chore: refresh PR checks * docs(get_media_buy_delivery): correct misleading "Buyer Reference Query" example (#5807) Fix a misleading get_media_buy_delivery example that implied buyers can look up delivery by their own reference. media_buy_ids are seller-assigned, so the example now uses seller-assigned mb_... IDs and points buyers to reconcile their own reference through opaque context echoed by create_media_buy / get_media_buys. * docs(compliance): document branch-set any_of peer cascade exemption (#5783) Adds `branch_set_cascade_exemption` to `cascade_rules` in runner-output-contract.yaml (parallel to `sole_stateful_step_exemption`): a stateful peer's genuine failure or `peer_branch_taken` skip MUST NOT cascade `prerequisite_failed` onto a sibling phase sharing the same `branch_set.id` under `any_of` semantics. Branch-set peers are mutually-exclusive alternatives, not a dependency chain. Scoped to `any_of`, N-ary-safe, cross-set and within-phase cascade unchanged, and explicitly `depends_on`-agnostic (fires whether the sibling's dependency is the implicit default or an explicit depends_on naming the peer). `default_cascade` gains a pointer to the new exemption; storyboard- schema.yaml's `depends_on` section gains a cross-reference. Documents-only: codifies the runner behavior shipped in adcp-client#2306 (closing adcp-client#2305), root-caused in #5337. No schema or wire change. Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * compliance(media-buy): available_actions uses a non-guaranteed fixture (runnable by sales-non-guaranteed-only sellers) (#5731) The available_actions scenario seeded a guaranteed-only product fixture, so its create_buy_from_product step failed with a terminal DELIVERY_MODE_NOT_SUPPORTED for sellers declaring only specialisms: ["sales-non-guaranteed"], cascading the whole available-actions enforcement flow (read_persisted_buy_actions + enforce_available_actions all prerequisite_failed). The allowed_actions behavior this scenario grades is delivery-type-agnostic, so the fixture switches to non_guaranteed (fixed_price → floor_price). Same fix as the base media_buy_seller flow; the create steps reference the product/pricing by id, unchanged. The packaged dist/compliance/ cache is generated from this source. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore(changeset): mark available actions fix as patch (#5906) * fix(compliance): correct creative storyboard capability assertions (#5847) - canonical_supported_formats: change hardcoded field_value for capability_id ("training_image_generation") to field_present, since capability_id is agent-local; remove field_absent on supported_formats[1] which incorrectly capped to a single advertised format; rename key: to name: in context_outputs per storyboard schema. Bump to 1.0.1. - evaluator_auth: add requires_capability guards to all six optional phases so agents declaring creative.supports_evaluator: false receive not_applicable instead of false failures; guards evaluate against the raw capabilities response, bypassing a runner-side boolean-false context accumulator bug (adcp-client); rename key: to name: in context_outputs. Bump to 1.0.1. Closes #5843. Refs #5844 (runner fix in adcp-client still required; storyboard fix stops the false failures). Claude-Session: https://claude.ai/code/session_011iWNWasRVCisU8sMy688Qx Co-authored-by: Claude <noreply@anthropic.com> * fix(compliance): correct privacy and inventory guidance (#5904) * fix(release): preserve schema release status (#5913) * fix(docs): replace phantom creative and governance error codes with canonical enum members (#5819) sync_creatives, build_creative, the creative specification, check_governance, and sync_plans documented 13 errors[].code values that do not exist in enums/error-code.json. Remap each to the existing code with matching semantics (UNSUPPORTED_FEATURE, VALIDATION_ERROR, CREATIVE_REJECTED, INVALID_STATE, INVALID_REQUEST, PERMISSION_DENIED); replace GENERATION_FAILED with task-failure guidance per the open-vocabulary rule. Also fix the one live INVALID_FORMAT emission in the training-agent reference implementation. Same failure mode as #4852 / #5307. * docs: add creative agent setup verification (#5881) Co-authored-by: Brian O'Kelley <bokelley@scope3.com> * docs(media-buy): add Budget & Pacing Controls reference to create_media_buy (#5984) Enumerates every budget-constraint field (total_budget, package budget, impressions, pacing, bid_price, flight window) in one place, documents the three pacing modes, and marks the missing daily-cap field as a known gap with the pacing-based workaround. Cross-links from update_media_buy. Closes #4429 * fix(schema): require cancellation_fee rate/amount by fee type (#5987) cancellation-policy.json documents cancellation_fee.rate as "Required when type is 'percent_remaining'" and .amount as "Required when type is 'fixed_fee'" — restated in the pricing-models reference — but cancellation_fee listed only ["type"] in required[]. A validator accepted a percent_remaining or fixed_fee cancellation term with no fee value, leaving the cancellation cost undefined for a buyer accepting the product's terms. Adds if/then conditionals enforcing the documented contract; full_commitment and none are unaffected. No prose change. Regression coverage added. Closes #5986 * fix: align retry_after with the canonical error shape (#5954) * fix(ci): preserve forward-merge branches when opening PRs (#5978) * docs: expand AgenticAdvertising.org name in backports --------- Co-authored-by: Steven Liss <stevenliss45@gmail.com> Co-authored-by: fgranata <220887501+fgranata@users.noreply.github.com> Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Aleksander Sekowski <aleksander@uixlimited.com> Co-authored-by: Bill Jung <56685007+sangilish@users.noreply.github.com> Co-authored-by: Garvit kaushik <77023388+garvitkaushik-123@users.noreply.github.com>
* fix(delivery-metrics): allow null for video-only metrics (quartile_data, completion_rate) (#5837) * fix(delivery-metrics): allow null for video-only metrics (quartile_data, completion_rate) Sellers running non-video inventory (display, audio-only, DOOH-without-video) legitimately return null for video-only metrics — the correct "not applicable" signal. The schema required type:"number"/"object" and rejected null, so receivers throw a validation error on every valid display-inventory delivery report. - delivery-metrics.json: completion_rate -> ["number","null"], quartile_data -> ["object","null"] (min/max on completion_rate still apply to non-null). - get-media-buy-delivery-response.json: aggregated_totals.completion_rate gets the same loosening so the aggregate path can't re-trigger the failure. - Docs: scope the null convention to these two fields; omission remains the canonical "not applicable" signal for every other metric. Refs Sentry AGENTIC-API-9P (87 events/5 days; PubX, BidMachine, Ozone, Vox). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(docs): escape bare < in spec-guardian so Mintlify link check parses it 'overturn <5%' parsed as a JSX tag open (< before a digit), failing the Mintlify broken-links check that runs on any docs change. Escape to <5%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> # Conflicts: # specs/spec-guardian.md * chore(ci): add 3.1.x to release and CI workflow branch filters Enables the Release workflow, Build Check, Changeset Check, and CodeQL to fire on pushes and PRs targeting the 3.1.x maintenance branch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(storyboards): port governance approval and stale date fixes to 3.1.x Cherry-picks two patch fixes from main needed for storyboard coverage to pass on 3.1.x: - Fix brand-handlers to always return REFERENCE_NOT_FOUND (removing 3.0 compat path that returned BRAND_NOT_FOUND), fixing brand_baseline failure - Move stale exclusivity/rights window dates in brand-handlers from 2026-2027 to 2099 to prevent date-expiry storyboard failures - Fix governance compliance storyboards for human approval and signal activation enforcement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(signals): port signal governance enforcement fix to 3.1.x Cherry-picks a335070 from main: signal agents now fail closed on governed accounts without a valid approval context, and governance compliance checks no longer require the signals tenant to own sync_plans. Fixes the activate_signal_denied storyboard floor failure on 3.1.x. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(deps): bump @adcp/sdk to 9.6.2 on 3.1.x The signal governance enforcement fix cherry-picked in da636b4 was validated on main under @adcp/sdk 9.6.2 (bumped there in 7a27263 the day before the fix landed). Under 9.3.0 the storyboard runner skips sync_accounts as not_applicable when require_operator_auth is true, so the governance_denied storyboard never registers a governance agent and activate_signal returns success instead of PERMISSION_DENIED, leaving the signals 3.0-compat leg at 64 clean vs the 65 floor. Verified locally: 3.0-compat matrix passes all tenants (signals 65 clean, 108 steps, matching main) and current matrix passes (signals 113 clean, 137 steps). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(deps): regenerate lockfile with npm 10 for CI compatibility The previous lockfile was regenerated by a locally wrapped npm 11 that pruned nested proxy-agent@8.0.2 entries, so npm ci on CI (node 22, npm 10) failed with a lock sync error. Restore the prior lockfile and apply only the @adcp/sdk 9.6.2 bump via npm 10, matching CI. Verified with npm@10 ci --dry-run plus a rerun of typecheck and the 3.0-compat storyboard matrix (all tenants meet floors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Version Packages (#5842) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(training-agent): backport publisher_domain filter to 3.1.x (#5868) * feat(training-agent): add publisher_domain filter to get_products (#5867) * feat(discovery): add publisher_domain filter to get_products Adds a publisher_domain filter to product-filters.json so buyers can discover which products from a seller cover a given publisher domain. A product matches when at least one publisher_properties entry targets the specified domain exactly. Implements the training-agent filter alongside schema and tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(training-agent): add publisher_domain filter to get_products Adds publisher_domain as a filter on get_products so buyers can narrow results to products whose publisher_properties cover a specific domain. - Adds publisher_domain to the source schema (static/schemas/source) so it survives schema rebuilds - Handles both publisher_domain (singular) and publisher_domains[] (plural array) forms of PublisherPropertySelector, matching the logic in adagents-manager.ts - Canonicalizes the filter value and stored values via canonicalizePublisherDomain so BBC.com / bbc.com/ / bbc.com all match - Adds typeof guard to reject non-string values passed as the filter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): revert immutable dist artifact edit The dist/schemas/3.1.0/ artifacts are released and immutable. The publisher_domain field belongs in the source schema only; the versioned dist is generated by npm run version when the changeset is processed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): downgrade to patch for 3.1.x backport --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Version Packages (#5869) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(protocol): restore the supported 3.1 contract (#5908) * Version Packages (#5909) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix: prepare 3.1.5 patch release (#6001) * fix(creative): clarify preflight dry-run validation (#5791) * Clarify creative preflight semantics * chore: refresh PR checks * docs(get_media_buy_delivery): correct misleading "Buyer Reference Query" example (#5807) Fix a misleading get_media_buy_delivery example that implied buyers can look up delivery by their own reference. media_buy_ids are seller-assigned, so the example now uses seller-assigned mb_... IDs and points buyers to reconcile their own reference through opaque context echoed by create_media_buy / get_media_buys. * docs(compliance): document branch-set any_of peer cascade exemption (#5783) Adds `branch_set_cascade_exemption` to `cascade_rules` in runner-output-contract.yaml (parallel to `sole_stateful_step_exemption`): a stateful peer's genuine failure or `peer_branch_taken` skip MUST NOT cascade `prerequisite_failed` onto a sibling phase sharing the same `branch_set.id` under `any_of` semantics. Branch-set peers are mutually-exclusive alternatives, not a dependency chain. Scoped to `any_of`, N-ary-safe, cross-set and within-phase cascade unchanged, and explicitly `depends_on`-agnostic (fires whether the sibling's dependency is the implicit default or an explicit depends_on naming the peer). `default_cascade` gains a pointer to the new exemption; storyboard- schema.yaml's `depends_on` section gains a cross-reference. Documents-only: codifies the runner behavior shipped in adcp-client#2306 (closing adcp-client#2305), root-caused in #5337. No schema or wire change. Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * compliance(media-buy): available_actions uses a non-guaranteed fixture (runnable by sales-non-guaranteed-only sellers) (#5731) The available_actions scenario seeded a guaranteed-only product fixture, so its create_buy_from_product step failed with a terminal DELIVERY_MODE_NOT_SUPPORTED for sellers declaring only specialisms: ["sales-non-guaranteed"], cascading the whole available-actions enforcement flow (read_persisted_buy_actions + enforce_available_actions all prerequisite_failed). The allowed_actions behavior this scenario grades is delivery-type-agnostic, so the fixture switches to non_guaranteed (fixed_price → floor_price). Same fix as the base media_buy_seller flow; the create steps reference the product/pricing by id, unchanged. The packaged dist/compliance/ cache is generated from this source. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore(changeset): mark available actions fix as patch (#5906) * fix(compliance): correct creative storyboard capability assertions (#5847) - canonical_supported_formats: change hardcoded field_value for capability_id ("training_image_generation") to field_present, since capability_id is agent-local; remove field_absent on supported_formats[1] which incorrectly capped to a single advertised format; rename key: to name: in context_outputs per storyboard schema. Bump to 1.0.1. - evaluator_auth: add requires_capability guards to all six optional phases so agents declaring creative.supports_evaluator: false receive not_applicable instead of false failures; guards evaluate against the raw capabilities response, bypassing a runner-side boolean-false context accumulator bug (adcp-client); rename key: to name: in context_outputs. Bump to 1.0.1. Closes #5843. Refs #5844 (runner fix in adcp-client still required; storyboard fix stops the false failures). Claude-Session: https://claude.ai/code/session_011iWNWasRVCisU8sMy688Qx Co-authored-by: Claude <noreply@anthropic.com> * fix(compliance): correct privacy and inventory guidance (#5904) * fix(release): preserve schema release status (#5913) * fix(docs): replace phantom creative and governance error codes with canonical enum members (#5819) sync_creatives, build_creative, the creative specification, check_governance, and sync_plans documented 13 errors[].code values that do not exist in enums/error-code.json. Remap each to the existing code with matching semantics (UNSUPPORTED_FEATURE, VALIDATION_ERROR, CREATIVE_REJECTED, INVALID_STATE, INVALID_REQUEST, PERMISSION_DENIED); replace GENERATION_FAILED with task-failure guidance per the open-vocabulary rule. Also fix the one live INVALID_FORMAT emission in the training-agent reference implementation. Same failure mode as #4852 / #5307. * docs: add creative agent setup verification (#5881) Co-authored-by: Brian O'Kelley <bokelley@scope3.com> * docs(media-buy): add Budget & Pacing Controls reference to create_media_buy (#5984) Enumerates every budget-constraint field (total_budget, package budget, impressions, pacing, bid_price, flight window) in one place, documents the three pacing modes, and marks the missing daily-cap field as a known gap with the pacing-based workaround. Cross-links from update_media_buy. Closes #4429 * fix(schema): require cancellation_fee rate/amount by fee type (#5987) cancellation-policy.json documents cancellation_fee.rate as "Required when type is 'percent_remaining'" and .amount as "Required when type is 'fixed_fee'" — restated in the pricing-models reference — but cancellation_fee listed only ["type"] in required[]. A validator accepted a percent_remaining or fixed_fee cancellation term with no fee value, leaving the cancellation cost undefined for a buyer accepting the product's terms. Adds if/then conditionals enforcing the documented contract; full_commitment and none are unaffected. No prose change. Regression coverage added. Closes #5986 * fix: align retry_after with the canonical error shape (#5954) * fix(ci): preserve forward-merge branches when opening PRs (#5978) * docs: expand AgenticAdvertising.org name in backports --------- Co-authored-by: Steven Liss <stevenliss45@gmail.com> Co-authored-by: fgranata <220887501+fgranata@users.noreply.github.com> Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Aleksander Sekowski <aleksander@uixlimited.com> Co-authored-by: Bill Jung <56685007+sangilish@users.noreply.github.com> Co-authored-by: Garvit kaushik <77023388+garvitkaushik-123@users.noreply.github.com> * Version Packages (#6003) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Rachit <43431004+rachitm022@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Nastassia Fulconis <nfulconis@scope3.com> Co-authored-by: aao-release-bot[bot] <280565558+aao-release-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nastassia Fulconis <nastassia.fulconis@gmail.com> Co-authored-by: Steven Liss <stevenliss45@gmail.com> Co-authored-by: fgranata <220887501+fgranata@users.noreply.github.com> Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Aleksander Sekowski <aleksander@uixlimited.com> Co-authored-by: Bill Jung <56685007+sangilish@users.noreply.github.com> Co-authored-by: Garvit kaushik <77023388+garvitkaushik-123@users.noreply.github.com>
* fix(delivery-metrics): allow null for video-only metrics (quartile_data, completion_rate) (#5837) * fix(delivery-metrics): allow null for video-only metrics (quartile_data, completion_rate) Sellers running non-video inventory (display, audio-only, DOOH-without-video) legitimately return null for video-only metrics — the correct "not applicable" signal. The schema required type:"number"/"object" and rejected null, so receivers throw a validation error on every valid display-inventory delivery report. - delivery-metrics.json: completion_rate -> ["number","null"], quartile_data -> ["object","null"] (min/max on completion_rate still apply to non-null). - get-media-buy-delivery-response.json: aggregated_totals.completion_rate gets the same loosening so the aggregate path can't re-trigger the failure. - Docs: scope the null convention to these two fields; omission remains the canonical "not applicable" signal for every other metric. Refs Sentry AGENTIC-API-9P (87 events/5 days; PubX, BidMachine, Ozone, Vox). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(docs): escape bare < in spec-guardian so Mintlify link check parses it 'overturn <5%' parsed as a JSX tag open (< before a digit), failing the Mintlify broken-links check that runs on any docs change. Escape to <5%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> # Conflicts: # specs/spec-guardian.md * chore(ci): add 3.1.x to release and CI workflow branch filters Enables the Release workflow, Build Check, Changeset Check, and CodeQL to fire on pushes and PRs targeting the 3.1.x maintenance branch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(storyboards): port governance approval and stale date fixes to 3.1.x Cherry-picks two patch fixes from main needed for storyboard coverage to pass on 3.1.x: - Fix brand-handlers to always return REFERENCE_NOT_FOUND (removing 3.0 compat path that returned BRAND_NOT_FOUND), fixing brand_baseline failure - Move stale exclusivity/rights window dates in brand-handlers from 2026-2027 to 2099 to prevent date-expiry storyboard failures - Fix governance compliance storyboards for human approval and signal activation enforcement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(signals): port signal governance enforcement fix to 3.1.x Cherry-picks a335070 from main: signal agents now fail closed on governed accounts without a valid approval context, and governance compliance checks no longer require the signals tenant to own sync_plans. Fixes the activate_signal_denied storyboard floor failure on 3.1.x. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(deps): bump @adcp/sdk to 9.6.2 on 3.1.x The signal governance enforcement fix cherry-picked in da636b4 was validated on main under @adcp/sdk 9.6.2 (bumped there in 7a27263 the day before the fix landed). Under 9.3.0 the storyboard runner skips sync_accounts as not_applicable when require_operator_auth is true, so the governance_denied storyboard never registers a governance agent and activate_signal returns success instead of PERMISSION_DENIED, leaving the signals 3.0-compat leg at 64 clean vs the 65 floor. Verified locally: 3.0-compat matrix passes all tenants (signals 65 clean, 108 steps, matching main) and current matrix passes (signals 113 clean, 137 steps). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(deps): regenerate lockfile with npm 10 for CI compatibility The previous lockfile was regenerated by a locally wrapped npm 11 that pruned nested proxy-agent@8.0.2 entries, so npm ci on CI (node 22, npm 10) failed with a lock sync error. Restore the prior lockfile and apply only the @adcp/sdk 9.6.2 bump via npm 10, matching CI. Verified with npm@10 ci --dry-run plus a rerun of typecheck and the 3.0-compat storyboard matrix (all tenants meet floors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Version Packages (#5842) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(training-agent): backport publisher_domain filter to 3.1.x (#5868) * feat(training-agent): add publisher_domain filter to get_products (#5867) * feat(discovery): add publisher_domain filter to get_products Adds a publisher_domain filter to product-filters.json so buyers can discover which products from a seller cover a given publisher domain. A product matches when at least one publisher_properties entry targets the specified domain exactly. Implements the training-agent filter alongside schema and tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(training-agent): add publisher_domain filter to get_products Adds publisher_domain as a filter on get_products so buyers can narrow results to products whose publisher_properties cover a specific domain. - Adds publisher_domain to the source schema (static/schemas/source) so it survives schema rebuilds - Handles both publisher_domain (singular) and publisher_domains[] (plural array) forms of PublisherPropertySelector, matching the logic in adagents-manager.ts - Canonicalizes the filter value and stored values via canonicalizePublisherDomain so BBC.com / bbc.com/ / bbc.com all match - Adds typeof guard to reject non-string values passed as the filter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): revert immutable dist artifact edit The dist/schemas/3.1.0/ artifacts are released and immutable. The publisher_domain field belongs in the source schema only; the versioned dist is generated by npm run version when the changeset is processed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): downgrade to patch for 3.1.x backport --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Version Packages (#5869) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(protocol): restore the supported 3.1 contract (#5908) * Version Packages (#5909) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix: prepare 3.1.5 patch release (#6001) * fix(creative): clarify preflight dry-run validation (#5791) * Clarify creative preflight semantics * chore: refresh PR checks * docs(get_media_buy_delivery): correct misleading "Buyer Reference Query" example (#5807) Fix a misleading get_media_buy_delivery example that implied buyers can look up delivery by their own reference. media_buy_ids are seller-assigned, so the example now uses seller-assigned mb_... IDs and points buyers to reconcile their own reference through opaque context echoed by create_media_buy / get_media_buys. * docs(compliance): document branch-set any_of peer cascade exemption (#5783) Adds `branch_set_cascade_exemption` to `cascade_rules` in runner-output-contract.yaml (parallel to `sole_stateful_step_exemption`): a stateful peer's genuine failure or `peer_branch_taken` skip MUST NOT cascade `prerequisite_failed` onto a sibling phase sharing the same `branch_set.id` under `any_of` semantics. Branch-set peers are mutually-exclusive alternatives, not a dependency chain. Scoped to `any_of`, N-ary-safe, cross-set and within-phase cascade unchanged, and explicitly `depends_on`-agnostic (fires whether the sibling's dependency is the implicit default or an explicit depends_on naming the peer). `default_cascade` gains a pointer to the new exemption; storyboard- schema.yaml's `depends_on` section gains a cross-reference. Documents-only: codifies the runner behavior shipped in adcp-client#2306 (closing adcp-client#2305), root-caused in #5337. No schema or wire change. Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * compliance(media-buy): available_actions uses a non-guaranteed fixture (runnable by sales-non-guaranteed-only sellers) (#5731) The available_actions scenario seeded a guaranteed-only product fixture, so its create_buy_from_product step failed with a terminal DELIVERY_MODE_NOT_SUPPORTED for sellers declaring only specialisms: ["sales-non-guaranteed"], cascading the whole available-actions enforcement flow (read_persisted_buy_actions + enforce_available_actions all prerequisite_failed). The allowed_actions behavior this scenario grades is delivery-type-agnostic, so the fixture switches to non_guaranteed (fixed_price → floor_price). Same fix as the base media_buy_seller flow; the create steps reference the product/pricing by id, unchanged. The packaged dist/compliance/ cache is generated from this source. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore(changeset): mark available actions fix as patch (#5906) * fix(compliance): correct creative storyboard capability assertions (#5847) - canonical_supported_formats: change hardcoded field_value for capability_id ("training_image_generation") to field_present, since capability_id is agent-local; remove field_absent on supported_formats[1] which incorrectly capped to a single advertised format; rename key: to name: in context_outputs per storyboard schema. Bump to 1.0.1. - evaluator_auth: add requires_capability guards to all six optional phases so agents declaring creative.supports_evaluator: false receive not_applicable instead of false failures; guards evaluate against the raw capabilities response, bypassing a runner-side boolean-false context accumulator bug (adcp-client); rename key: to name: in context_outputs. Bump to 1.0.1. Closes #5843. Refs #5844 (runner fix in adcp-client still required; storyboard fix stops the false failures). Claude-Session: https://claude.ai/code/session_011iWNWasRVCisU8sMy688Qx Co-authored-by: Claude <noreply@anthropic.com> * fix(compliance): correct privacy and inventory guidance (#5904) * fix(release): preserve schema release status (#5913) * fix(docs): replace phantom creative and governance error codes with canonical enum members (#5819) sync_creatives, build_creative, the creative specification, check_governance, and sync_plans documented 13 errors[].code values that do not exist in enums/error-code.json. Remap each to the existing code with matching semantics (UNSUPPORTED_FEATURE, VALIDATION_ERROR, CREATIVE_REJECTED, INVALID_STATE, INVALID_REQUEST, PERMISSION_DENIED); replace GENERATION_FAILED with task-failure guidance per the open-vocabulary rule. Also fix the one live INVALID_FORMAT emission in the training-agent reference implementation. Same failure mode as #4852 / #5307. * docs: add creative agent setup verification (#5881) Co-authored-by: Brian O'Kelley <bokelley@scope3.com> * docs(media-buy): add Budget & Pacing Controls reference to create_media_buy (#5984) Enumerates every budget-constraint field (total_budget, package budget, impressions, pacing, bid_price, flight window) in one place, documents the three pacing modes, and marks the missing daily-cap field as a known gap with the pacing-based workaround. Cross-links from update_media_buy. Closes #4429 * fix(schema): require cancellation_fee rate/amount by fee type (#5987) cancellation-policy.json documents cancellation_fee.rate as "Required when type is 'percent_remaining'" and .amount as "Required when type is 'fixed_fee'" — restated in the pricing-models reference — but cancellation_fee listed only ["type"] in required[]. A validator accepted a percent_remaining or fixed_fee cancellation term with no fee value, leaving the cancellation cost undefined for a buyer accepting the product's terms. Adds if/then conditionals enforcing the documented contract; full_commitment and none are unaffected. No prose change. Regression coverage added. Closes #5986 * fix: align retry_after with the canonical error shape (#5954) * fix(ci): preserve forward-merge branches when opening PRs (#5978) * docs: expand AgenticAdvertising.org name in backports --------- Co-authored-by: Steven Liss <stevenliss45@gmail.com> Co-authored-by: fgranata <220887501+fgranata@users.noreply.github.com> Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Aleksander Sekowski <aleksander@uixlimited.com> Co-authored-by: Bill Jung <56685007+sangilish@users.noreply.github.com> Co-authored-by: Garvit kaushik <77023388+garvitkaushik-123@users.noreply.github.com> * Version Packages (#6003) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(schema): backport legacy format mappings to 3.1.x (#6040) Backport the patch-eligible literal v1 canonical format mappings from #6037 for the 3.1.6 maintenance release. * fix(release): backport schema discovery status test correction (#6044) Backport #6043 so the 3.1.6 release audit accepts exact withdrawn artifacts while continuing to reject non-selectable alias targets. * Version Packages (#6041) Release adcontextprotocol 3.1.6. * fix(schema): allow canonical list_creatives identities (#6047) (#6057) * fix(schema): allow canonical list_creatives identities * chore(schema): update oneOf discriminator baseline * Version Packages (#6059) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(schema): correct legacy canonical mappings (#6061) (#6066) * fix(schema): preserve video aspect ratio mapping * fix(schema): publish AAO display mappings * Version Packages (#6067) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Rachit <43431004+rachitm022@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Nastassia Fulconis <nfulconis@scope3.com> Co-authored-by: aao-release-bot[bot] <280565558+aao-release-bot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nastassia Fulconis <nastassia.fulconis@gmail.com> Co-authored-by: Steven Liss <stevenliss45@gmail.com> Co-authored-by: fgranata <220887501+fgranata@users.noreply.github.com> Co-authored-by: Fernando Granata <fernandogranata@Host-001.homenet.telecomitalia.it> Co-authored-by: Aleksander Sekowski <aleksander@uixlimited.com> Co-authored-by: Bill Jung <56685007+sangilish@users.noreply.github.com> Co-authored-by: Garvit kaushik <77023388+garvitkaushik-123@users.noreply.github.com>
Clarifies the boundary between
validate_inputmanifest preflight andsync_creativesdry-run trafficking rehearsal across schemas, docs, and training-agent tool descriptions.Updates
sync_creativesdry-run behavior to validate assignment references without mutating package assignments, matching the new operation-level rehearsal language.Adds a regression test for invalid dry-run assignments and a patch changeset for the protocol-facing clarification.
Validated with schema/type checks, targeted docs JSON checks, changeset checks, the new Vitest regression, and the pre-push storyboard/docs gates.