feat(media-buy): add compact AdCP 3.2 lifecycle - #6115
Conversation
f460c71 to
60068ad
Compare
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema path change requires human/CODEOWNERS review, and this is a Breaking-class protocol change.
This PR classifies get_products as state-mutating and adds a required idempotency_key to the published request schema — an optional→required addition on a published wire surface, i.e. a Breaking-class change. It correctly carries a major changeset and schema↔docs coherence checks out (idempotency_key row: Yes, 16-255, matching pattern; manifest, examples, compliance fixtures, MCP/v5/v6 routes, and Addie tools all coherent). The idempotency.ts fencing and task-handlers recovery/natural-key reuse logic were reviewed and are sound.
Two escalation triggers apply and neither is satisfiable by the arbiter:
- Gated paths:
static/schemas/source/manifest.schema.jsonandstatic/schemas/source/media-buy/get-products-request.jsonare under the hard approval gate (gated_paths: true), andreview_decisionisREVIEW_REQUIRED(notAPPROVED). Decision-table row 2 forces escalate. - Repo hard gate: a Breaking-class protocol change is never auto-approved — ratification is a human act — unless
review_decisionisAPPROVED. It is not.
No critical/high findings were reported (a correct major changeset accompanies the breaking change, so no spec-drift/changeset finding). One Medium remains: the new per-session get_products mutex CONFLICTs concurrent pure reads.
Human/CODEOWNERS review of the gated schema files is required before this can merge.
Medium findings:
- server/src/training-agent/task-handlers.ts:3912 — get_products session mutex CONFLICTs concurrent pure reads
Medium findings
- server/src/training-agent/task-handlers.ts:3912 — get_products session mutex CONFLICTs concurrent pure reads
Why human review
- Modifies gated schema files static/schemas/source/manifest.schema.json and static/schemas/source/media-buy/get-products-request.json under the hard approval gate; review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS review required.
- Breaking-class protocol change (optional→required idempotency_key on published get_products request schema, get_products reclassified as state-mutating) — never auto-approved; ratification is a human act unless review_decision is APPROVED.
- Medium: server/src/training-agent/task-handlers.ts:3912 — get_products session mutex CONFLICTs concurrent pure reads.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/manifest.schema.json (modified) matches
static/schemas/source/**; static/schemas/source/media-buy/get-products-request.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema files require human/CODEOWNERS review; a Breaking-class protocol change is present.
Escalation reasons
- Gated path not satisfied: modifies
static/schemas/source/manifest.schema.jsonandstatic/schemas/source/media-buy/get-products-request.jsonunder the hard, non-overridable approval gate;review_decisionisREVIEW_REQUIRED, notAPPROVED. Human/CODEOWNERS approval is required before merge. - Breaking-class protocol change (optional→required
idempotency_keyon the publishedget_productsrequest schema;get_productsreclassified as state-mutating) is never auto-approved — ratification is a human act unlessreview_decisionisAPPROVED.
Iteration note
The prior medium finding (get_products session mutex CONFLICTing concurrent pure reads at server/src/training-agent/task-handlers.ts:3912) is resolved: brief/wholesale now take the mutex only for a bounded (~1s, backoff+jitter) directive-consumption preflight, release before read-only work, and no longer write lastGetProductsContext. Directive consumption is threaded through readDirectives so exactly one of N parallel reads consumes a one-shot rejection. Four concurrency tests added. No new blocking or medium findings in the delta.
The escalation persists solely because the gated-path approval gate remains unsatisfied (REVIEW_REQUIRED) and the underlying change is Breaking-class — not because of any unresolved reviewer finding. The gate lifts the moment a human/CODEOWNERS approval is recorded.
Why human review
- Gated paths not satisfied: static/schemas/source/manifest.schema.json and static/schemas/source/media-buy/get-products-request.json are under the hard approval gate and review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS review required.
- Breaking-class protocol change (optional→required idempotency_key on published get_products request schema; get_products reclassified as state-mutating) is never auto-approved unless review_decision is APPROVED — human ratification required.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/manifest.schema.json (modified) matches
static/schemas/source/**; static/schemas/source/media-buy/get-products-request.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
983fced to
d5b0a59
Compare
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — hard approval gate unsatisfied plus breaking-class protocol change.
This PR modifies published protocol source under static/schemas/source/** (manifest.schema.json, media-buy/get-products-request.json), which is a deterministic hard approval gate: gated_paths: true and review_decision: REVIEW_REQUIRED (not APPROVED). Row 2 of the decision table fires — cannot auto-approve until a human/CODEOWNERS approval is recorded.
Independently, the reviewer confirms this delta reframes the get_products idempotency contract as a 4.0 major boundary: idempotency_key is in required[] with x-mutates-state:true, an optional→required flip on a published field that reclassifies get_products as state-mutating. That is a Breaking-class protocol change under the constitution and the repo's "Breaking-class changes are never auto-approved" hard gate — ratification is a human act, escalate unless review_decision is APPROVED. It is not.
Reviewer found no Critical/High/Medium correctness findings in the delta; schema↔docs coherence holds (security.mdx, specification.mdx, get_adcp_capabilities.mdx align on the 4.0 cut), oneOf/canonical coverage preserved, deploy wiring safe. The only finding is one low-severity legacy-wire projection note, which does not block on its own. But the two hard gates above are dispositive.
Escalation reasons
- Gated paths not satisfied:
static/schemas/source/manifest.schema.jsonandstatic/schemas/source/media-buy/get-products-request.jsonare under the hard approval gate andreview_decisionisREVIEW_REQUIRED, notAPPROVED— human/CODEOWNERS review required. - Breaking-class protocol change: optional→required
idempotency_keyflip on published get_products request schema; get_products reclassified state-mutating. Never auto-approved unlessreview_decisionisAPPROVED— human ratification required.
Why human review
- Gated paths not satisfied: static/schemas/source/manifest.schema.json and static/schemas/source/media-buy/get-products-request.json are under the hard approval gate and review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS review required.
- Breaking-class protocol change: optional→required idempotency_key flip on the published get_products request schema, reclassifying get_products as state-mutating. Ratification is a human act — never auto-approved unless review_decision is APPROVED.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/manifest.schema.json (modified) matches
static/schemas/source/**; static/schemas/source/media-buy/get-products-request.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — hard approval gate not satisfied + Breaking-class protocol change requires human ratification.
Escalation reasons
- Gated paths not satisfied:
static/schemas/source/manifest.schema.jsonandstatic/schemas/source/media-buy/get-products-request.jsonare under the repo's hard, non-overridable approval gate andreview_decisionisREVIEW_REQUIRED, notAPPROVED. Human/CODEOWNERS review is required before merge (decision-table row 2). - Breaking-class protocol change: an optional→required
idempotency_keyflip on the publishedget_productsrequest schema, reclassifyingget_productsas state-mutating (x-mutates-state: true). Per repo governance, Breaking-class changes are never auto-approved even with a correctmajorchangeset — ratification is a human act. Escalate unlessreview_decisionisAPPROVED.
Findings
No critical/high/medium code findings surfaced this run. The reviewer verified schema↔docs coherence (schema requires the key + x-mutates-state:true; get_products.mdx marks Required:Yes), a correct major changeset, no oneOf/additionalProperties regressions, and confirmed the session-mutex, hash-aware fenced idempotency claim/save/release, and durable-state flush paths are safe.
This is the same posture as the prior escalate decision: the diff is clean, but the gated path + Breaking-class governance gate hold until a human/CODEOWNERS approval is recorded. Once review_decision becomes APPROVED, this PR falls through to a normal approve.
Why human review
- Gated paths not satisfied: static/schemas/source/manifest.schema.json and static/schemas/source/media-buy/get-products-request.json are under the hard approval gate and review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS review required.
- Breaking-class protocol change: optional→required idempotency_key flip on the published get_products request schema, reclassifying get_products as state-mutating (x-mutates-state:true). Ratification is a human act — never auto-approved unless review_decision is APPROVED, even with a correct major changeset.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/manifest.schema.json (modified) matches
static/schemas/source/**; static/schemas/source/media-buy/get-products-request.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated-path hard gate unsatisfied + breaking-class protocol change requires human ratification.
Why not approve: This PR touches 30+ files under static/schemas/source/**, which is a hard, deterministic approval gate (gated_paths: true). The current GitHub review_decision is REVIEW_REQUIRED, not APPROVED. Per decision-table row 2, the gate is NOT satisfied and the outcome must be escalate — regardless of how clean the diff is.
Reviewer findings: None — no critical/high/medium findings. Relationship validation (legacy_fallback/superseded_by with cycle detection), the enum-completeness ratchet, schema-path/identity checks, and the documented, changeset-backed non-breaking result loosening all pass cleanly.
Escalation reasons:
- Gated-path hard gate (row 2): 30+ files under
static/schemas/source/**modified/added whilereview_decisionisREVIEW_REQUIRED, notAPPROVED. Human/CODEOWNERS approval required before merge. - Breaking-class protocol surface change (new proposal-workflow tools/schemas: decline-proposals, refine-proposals, request-proposals; new core schemas brand-key, catalog-selection, opportunity-context, product-offer-filters; new enum values in proposal-status, proposal-decline-reason, task-type, error-code). Per the constitution's hard gate, breaking-class ratification is a human act — never auto-approved absent
review_decision: APPROVED.
The prior decision was also escalate; the gate condition still holds this run, so escalation stands. No blocking findings exist, so this is not request-changes — a human/CODEOWNERS approval simply needs to be recorded.
Why human review
- Gated-path hard gate (row 2): 30+ files under static/schemas/source/** modified/added while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required before merge.
- Breaking-class protocol change (new proposal-workflow tools/schemas, new core schemas, new enum values in proposal-status/proposal-decline-reason/task-type/error-code) — ratification is a human act and is never auto-approved absent review_decision=APPROVED.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/account-authorization.json (modified) matches
static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/brand-key.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/catalog-selection.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/opportunity-context.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/product-offer-filters.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/proposal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/tasks-get-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matchesstatic/schemas/source/**; static/schemas/source/creative/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-decline-reason.json (added) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-status.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/task-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/manifest.schema.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-response.json (modified) matchesstatic/schemas/source/**; static/schemas/
…(truncated)…
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated-path hard gate not satisfied.
This PR modifies/adds 30+ files under static/schemas/source/**, which are under a hard, non-overridable approval gate (gated_paths: true). The current GitHub review_decision is REVIEW_REQUIRED, not APPROVED, so decision-table row 2 fires: outcome must be escalate until a human/CODEOWNERS approval is recorded.
Beyond the deterministic path gate, this is a breaking-class protocol change (new proposal-workflow tools/schemas, new core schemas, new enum values in proposal-status / proposal-decline-reason / task-type / error-code). Per the repo's hard gate, breaking-class changes are never auto-approved — ratification is a human act — even with a correct major changeset.
The reviewer surfaced no critical/high/medium findings (delta since the prior run is a single editorial link-to-plain-text change in docs/building/by-layer/L3/task-lifecycle.mdx; substance unchanged). This is a clean pass on the diff itself, but the gate stands independent of diff quality.
Escalation reasons
- Gated-path hard gate (row 2): 30+ files under
static/schemas/source/**modified/added whilereview_decisionisREVIEW_REQUIRED— human/CODEOWNERS approval required before merge. - Breaking-class protocol change (new proposal-workflow tools/schemas, new core schemas, new enum values) — ratification is a human act, never auto-approved absent
review_decision=APPROVED.
No blocking correctness findings; escalation is purely to require the human approval the gate mandates.
Why human review
- Gated-path hard gate (row 2): 30+ files under static/schemas/source/** modified/added while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required before merge.
- Breaking-class protocol change (new proposal-workflow tools/schemas, new core schemas, new enum values in proposal-status/proposal-decline-reason/task-type/error-code) — ratification is a human act and is never auto-approved absent review_decision=APPROVED.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/account-authorization.json (modified) matches
static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/brand-key.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/catalog-selection.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/opportunity-context.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/product-offer-filters.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/proposal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/tasks-get-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matchesstatic/schemas/source/**; static/schemas/source/creative/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-decline-reason.json (added) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-status.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/task-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/manifest.schema.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/decline-proposals-request.json (added) matchesstatic/schemas/source/**; static/schema
…(truncated)…
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated-path hard gate unsatisfied plus breaking-class protocol change awaiting human ratification.
This PR touches 34 files under static/schemas/source/**, which are under a hard, non-overridable approval gate (gated_paths: true), and the current GitHub review_decision is REVIEW_REQUIRED — not APPROVED. Under decision-table row 2, this alone forces escalation: Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
Independently, this is a Breaking-class protocol change: new proposal-workflow tools/schemas (decline-proposals, refine-proposals, request-proposals, product-discovery-criteria, catalog-selection, etc.), new enum values (proposal-status, proposal-decline-reason, task-type, error-code), and new core schemas. Per the repo's "Breaking-class changes are never auto-approved" hard gate, ratification is a human act and must not be auto-approved absent review_decision: APPROVED.
The reviewer surfaced no critical/high/medium findings in this delta — the schema↔docs coherence, changeset scope/type, oneOf-discriminator, and released-artifact-immutability checks all passed, and the delta's fallback-grade/manifest changes are fail-closed and unit-tested. This is a net-clean diff. But both hard gates stand until a human/CODEOWNERS approval lands.
Blocking findings: none.
Escalation reasons:
- Gated path hard gate (row 2): 34 files under
static/schemas/source/**modified/added whilereview_decisionisREVIEW_REQUIRED, notAPPROVED— human/CODEOWNERS approval required before merge. - Breaking-class protocol change (new proposal-workflow tools/schemas, new enum values across proposal-status/proposal-decline-reason/task-type/error-code, new core schemas) — ratification is a human act; never auto-approved absent
review_decision: APPROVED.
Why human review
- Gated path hard gate (row 2): 34 files under static/schemas/source/** modified/added while review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required before merge.
- Breaking-class protocol change (new proposal-workflow tools/schemas, new enum values in proposal-status/proposal-decline-reason/task-type/error-code, new core schemas) — ratification is a human act; never auto-approved absent review_decision=APPROVED.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/account-authorization.json (modified) matches
static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/brand-key.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/catalog-selection.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/opportunity-context.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/product-offer-filters.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/proposal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/tasks-get-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matchesstatic/schemas/source/**; static/schemas/source/creative/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-decline-reason.json (added) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-status.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/task-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/manifest.schema.json (modified) matchesstatic/schemas/source/**; static/schemas/source/
…(truncated)…
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated-path hard gate unsatisfied (breaking-class protocol change awaiting human/CODEOWNERS approval).
Escalation reasons
- 34 files under
static/schemas/source/**are added/modified (new proposal-workflow tools & schemas: request/refine/decline-proposals, product-discovery-criteria, product-fields, brand-key, catalog-selection, opportunity-context, product-offer-filters; new enum values in proposal-status, proposal-decline-reason, task-type, error-code).gated_paths: trueandreview_decisionis notAPPROVED(unknown/none) → decision-table row 2 forcesescalate. Human/CODEOWNERS approval is required before merge. - Breaking-class protocol change per repo hard gate: ratification is a human act and is never auto-approved absent
review_decision=APPROVED, regardless of how clean the diff is.
Findings
The reviewer delta since the prior escalate is two files with no actionable findings: scripts/build-schemas.cjs (L1078-1084) replaces a TOCTOU existsSync+statSync/readFileSync with a single try/readFileSync/catch that still handles ENOENT/EISDIR — no behavior regression; and docs/building/by-layer/L3/task-lifecycle.mdx (L197) is an editorial hyperlink→plain-text swap on a non-normative page. No new critical/high/medium findings. The gated wire-schema changes belong to prior commits already under this same escalation.
This remains an escalate on the gated-path gate, not on any code defect. The gate lifts the moment a human/CODEOWNERS records review_decision=APPROVED.
Why human review
- Gated path hard gate (row 2): 34 files under static/schemas/source/** modified/added while review_decision is not APPROVED (unknown/none) — human/CODEOWNERS approval required before merge.
- Breaking-class protocol change (new proposal-workflow tools/schemas, new enum values in proposal-status/proposal-decline-reason/task-type/error-code, new core schemas) — ratification is a human act; never auto-approved absent review_decision=APPROVED.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/account-authorization.json (modified) matches
static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/brand-key.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/catalog-selection.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/opportunity-context.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/product-offer-filters.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/proposal.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/tasks-get-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matchesstatic/schemas/source/**; static/schemas/source/creative/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-decline-reason.json (added) matchesstatic/schemas/source/**; static/schemas/source/enums/proposal-status.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/task-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/manifest.schema.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/create-media-buy-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/decline-proposals-request.json (added) matchesstatic/schemas/source/**; static/schemas/source/media-buy/decl
…(truncated)…
# Conflicts: # tests/docs-nav-validation.test.cjs
|
Reviewed at 1. Blocker — The baseline enum ratified Concrete failure: a buyer sits on an unexpired committed proposal through two days of internal approval; inventory sells out; seller A rejects Ask, any of:
As written, the redefinition of a shared ratified enum value also strains the "intentionally additive" claim and should be called out in the changeset regardless of which resolution lands. 2. Concern —
Concrete failure: a buyer agent scoping "US CTV" against an aggregator must page the whole catalog — hundreds of sequential synchronous calls — or the seller must block long enough to materialize filtered pages across upstream publisher systems with no task handoff available. We consider async support here critical for aggregator-scale sellers. Ask, in preference order:
Silent inheritance of "synchronous, unscoped, 100 per page" is the worst of the three. 3. Warning — async support at These are the consultative arms — the successors of exactly the legacy modes ( Ask: state the disposition on each task page ("MAY return 4. Warning — four new normative task surfaces, zero behavioral compliance coverage. All four doc pages carry Ask: add at least a split-lifecycle happy-path storyboard (list → request → refine → buy), a decline-terminality probe (decline, then 5. Notes.
|
|
Thanks for the thorough review @lukasz-pubx. I ran protocol and product analysis on these; here is the consolidated synthesis. Finding 1 — The "Firm pricing with inventory reserved … After expires_at, the hold lapses" wording is verbatim in Minimum viable resolution in this PR is option (b): a normative rejection path in the Finding 3 — async at The "wiring half-exists" observation is verifiable: these tasks appear in The precedent is unambiguous: every async-capable task in the repo has a per-task submitted schema (7 tasks: Finding 2 — The keyword/country/property distinction from delivery targeting is correct. In the existing Option (a) — async arm — is the wrong direction. Finding 4 — compliance coverage: well-founded
Preferred resolution: add a happy-path storyboard covering Finding 5 — notes All four land correctly:
@bokelley: findings 1, 3, and 4 have clear MVRs and are actionable before merge; finding 2's fix is bounded and in scope. Happy to dig further on any of them. Generated by Claude Code |
|
Issue #6432 proposes behavioral compliance storyboards for Generated by Claude Code |
Finding 1 (blocker): Revise `committed` enumDescription to document the normative rejection path — a seller that did not reserve inventory MAY reject an unexpired committed proposal at create_media_buy via PROPOSAL_UNAVAILABLE; availability risk pre-execution is on the buyer absent a stated hold. Add PROPOSAL_UNAVAILABLE error code with correctable recovery guidance and regenerate compliance-error-codes.mdx. Add matching PROPOSAL_UNAVAILABLE note to the create_media_buy doc page. Finding 2 (well-founded): Add `countries` and `property_list` product-attribute filters to ProductOfferFilters (channels was already present). Override `incomplete` description on list-products-response to clarify it fires on result-count truncation at the page cap, not time_budget (which has no meaning for a sync task). Add dead-surface note to push_notification_config on list-products-request. Finding 3 (blocker): Create per-task async submitted schemas for request_proposals and refine_proposals, register both in the webhook union anyOf. Add one-line MAY-async statement to each doc page. Finding 4 (well-founded): Flip all four new task pages (list_products, request_proposals, refine_proposals, decline_proposals) to testable: false pending behavioral compliance storyboard work (tracked in #6432).
|
All four findings addressed in commit Finding 1 (blocker) —
Finding 2 (well-founded) —
Finding 3 (blocker) — async at
Finding 4 (well-founded) — compliance coverage
Generated by Claude Code |
…empotency' into clean-up-pr-6115 # Conflicts: # .changeset/secure-get-products-idempotency.md # docs/media-buy/task-reference/refine_proposals.mdx # static/schemas/source/enums/proposal-status.json # static/schemas/source/media-buy/list-products-request.json # static/schemas/source/media-buy/list-products-response.json # static/schemas/source/media-buy/refine-proposals-async-response-submitted.json # static/schemas/source/media-buy/request-proposals-async-response-submitted.json
What changed
list_products,request_proposals,refine_proposals,decline_proposals,buy_products,accept_proposal, andcontrol_media_buyaccept_proposalthe single commitment boundary for creating, amending, or canceling a MediaBuy from a committed proposalbuy_productsand operational controls throughcontrol_media_buyrefine_proposals(accepted_proposal_id)followed byaccept_proposal; accepted snapshots remain immutablesync_creativespath: the new purchase/control inputs do not accept inline creatives, legacy creative shapes, BrandRef payloads, or transitive provenance graphsget_products,create_media_buy, andupdate_media_buyas 3.x compatibility facades, with machine-readable fallback metadata for SDK adapterslist_productsis the synchronous bootstrap and repair readLifecycle boundaries
list_productsreads offers only and never creates proposals.request_proposalsproduces immutable committed snapshots;refine_proposalsforks new snapshots.buy_productscommits listed products without a proposal workflow.accept_proposalcreates a buy or applies an accepted amendment/cancellation proposal.control_media_buyhandles operational actions within the accepted envelope. Changes to product, flight, budget, targeting, billing/measurement, performance, or reporting terms require proposal refinement and acceptance.sync_creativesremains the only creative-management surface for this lifecycle.get_media_buysreturns the accepted proposal and canonical routed actions so clients can recover the correct next step after restart.Versioning and compatibility
This is additive in AdCP 3.2. Legacy tools remain supported throughout 3.x and map to the canonical lifecycle through declared fallback grades and operation families. Stateful calls replay only under their own canonical tool identity; exact retries converge, while reuse with different logical input conflicts.
The stricter removal of compatibility surfaces, inline creatives, and transitively inlined creative/provenance data remains 4.0 work.
Surface-area result
Additional review fixes
PROPOSAL_UNAVAILABLEfor committed offers without reserved inventorycountriesandproperty_listoffer attributes without turning discovery into delivery targetingValidation
mainand the latest remote PR branch; conflicts resolvedHuman/CODEOWNERS approval is still required because this PR changes gated protocol schema paths.