Skip to content

feat(media-buy): add get_products rejection outcome - #6127

Open
bokelley wants to merge 4 commits into
mainfrom
brief-diagnostics-option-a
Open

feat(media-buy): add get_products rejection outcome#6127
bokelley wants to merge 4 commits into
mainfrom
brief-diagnostics-option-a

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Adds a terminal GetProductsRejected response arm for well-formed commercial declines while keeping semantic no-match as completed products: [], partial usable responses in incomplete, and transient upstream failures in SERVICE_UNAVAILABLE.

Updates schemas, protocol and task documentation, A2A semantics, and compliance coverage with strict response-arm mutual exclusion.

Extends the training agent with account-and-principal-scoped submitted-task polling, durable completion, webhook correlation, and downstream media-buy materialization.

Validation: current-version storyboards passed across all six tenants, focused schema/A2A/controller/MCP suites passed, while the unchanged SDK safe-fetch fixture, released 3.0 signals governance-denial storyboard, and baseline otel-logs.ts type error remain failing.

Closes #6035.

Comment thread server/src/training-agent/task-handlers.ts Fixed
Comment thread server/src/training-agent/comply-test-controller.ts Fixed
@bokelley
bokelley marked this pull request as ready for review July 31, 2026 14:30
) {
throw new Error('Pending submitted task cap reached (1000)');
}
await registerSubmittedTask(directive.taskId, args, directivePrincipal, 'get_products');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: registerSubmittedTask is unguarded against a live deterministic ID. This PR newly writes the caller-supplied task_id into the task store on submit. DeterministicInMemoryTaskStore.createTaskWithId throws Task with ID … already exists (deterministic-task-store.ts:31), and a completed task lingers in the store for its full 15-min TTL before scheduleCleanup drops it. Sequence that bites: register force_get_products_arm submitted with task_id T → consume → force_task_completion T → within 15 min re-register + consume the same T for the same account+principal. The throw propagates out of handleGetProducts and is caught only by the generic dispatch try/catch, so the buyer gets an opaque tool error instead of a clean submitted envelope or a controller-level INVALID_PARAMS. Compliance storyboards use fixed task_ids, so a re-run against the same sandbox account inside the TTL window reproduces this. Same call site at task-handlers.ts:4541 for create_media_buy. Prior force_create_media_buy_arm used SDK-generated IDs and had no such collision surface.

@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Jul 31, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths require human/CODEOWNERS approval.

This PR adds the GetProductsRejected structured-decline arm to get_products: new schema, response-arm mutual exclusion (via not.anyOf across get-products-rejected/get-products-response/async-response-data), A2A/protocol-envelope/task-status semantics, a compliance scenario + controller directive, and a 3.2-beta.0 version-negotiated training-agent implementation with account+principal-scoped deterministic task polling. Reviewer confirms schema↔docs coherence holds, mutual exclusion is enforced, the changeset is present and correctly minor (additive, non-breaking), and no dist/** artifacts were touched.

No critical/high findings. One medium (non-blocking on its own).

Why escalate: this PR modifies multiple files under static/schemas/source/**, which are under the repo's deterministic hard approval gate (gated_paths: true). review_decision is not APPROVED, so per decision-table row 2 the gate is not satisfied and the outcome must be escalate. A human/CODEOWNERS approval on the gated schema files is required before this can proceed.

Medium findings

  • server/src/training-agent/task-handlers.ts:3141 — registerSubmittedTask throws opaquely on deterministic task_id reuse within the 15-min TTL window.

Medium findings

  • server/src/training-agent/task-handlers.ts:3141 — registerSubmittedTask throws opaquely on deterministic task_id reuse within TTL

Why human review

  • Gated paths: PR modifies files under static/schemas/source/** (comply-test-controller-request.json, comply-test-controller-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, get-products-response.json) plus adds get-products-rejected.json — these are under a hard approval gate and review_decision is not APPROVED. Human/CODEOWNERS review required.
  • Protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products; requires human sign-off on the schema surface even though the change is additive/minor.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/compliance/comply-test-controller-request.json (modified) matches static/schemas/source/**; static/schemas/source/compliance/comply-test-controller-response.json (modified) matches static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matches static/schemas/source/**; static/schemas/source/core/protocol-envelope.json (modified) matches static/schemas/source/**; static/schemas/source/enums/task-status.json (modified) matches static/schemas/source/**; static/schemas/source/index.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-rejected.json (added) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', 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.

@bokelley bokelley changed the title [codex] Add get_products rejection outcome feat(media-buy): add get_products rejection outcome Jul 31, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — protocol schema surface under a hard approval gate; human/CODEOWNERS review required.

Why escalate (row 2): gated_paths: true and review_decision is not APPROVED. This PR modifies eight files under static/schemas/source/** (a hard, deterministic approval gate), including a new response arm (GetProductsRejected) on get_products. Row 2 fires before any fall-through — outcome must be escalate until a human/CODEOWNERS approval is recorded.

Gated files requiring review:

  • static/schemas/source/media-buy/get-products-rejected.json (added)
  • static/schemas/source/media-buy/get-products-response.json (modified)
  • static/schemas/source/core/async-response-data.json (modified)
  • static/schemas/source/core/protocol-envelope.json (modified)
  • static/schemas/source/enums/task-status.json (modified)
  • static/schemas/source/index.json (modified)
  • static/schemas/source/compliance/comply-test-controller-request.json (modified)
  • static/schemas/source/compliance/comply-test-controller-response.json (modified)

Delta since prior pass: The prior medium finding (task-handlers.ts:3141) is out of scope this pass and does not carry forward. The two new delta items — a justified codeql[js/user-controlled-bypass] suppression and a test-only CURRENT_ADCP_VERSION bump — clear no severity bar. No current findings at medium-or-above.

Blocking findings: none.

Medium findings: none.

This remains an additive protocol wire-shape change (new response arm on get_products) that requires human sign-off on the schema surface. Once review_decision becomes APPROVED, a clean re-run can fall through to approve.

Why human review

  • Gated paths: PR modifies files under static/schemas/source/** (get-products-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, comply-test-controller-request.json, comply-test-controller-response.json) and adds get-products-rejected.json — hard approval gate, and review_decision is not APPROVED. Human/CODEOWNERS review required.
  • Protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products; requires human sign-off on the published schema surface even though the change is additive.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/compliance/comply-test-controller-request.json (modified) matches static/schemas/source/**; static/schemas/source/compliance/comply-test-controller-response.json (modified) matches static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matches static/schemas/source/**; static/schemas/source/core/protocol-envelope.json (modified) matches static/schemas/source/**; static/schemas/source/enums/task-status.json (modified) matches static/schemas/source/**; static/schemas/source/index.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-rejected.json (added) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', 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.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths require human/CODEOWNERS approval.

This PR modifies and adds files under static/schemas/source/**, which is a hard, non-overridable approval gate (gated_paths: true). The current review_decision is not APPROVED (unknown/none), so decision-table row 2 fires: outcome must be escalate.

Blocking findings: none. The reviewer surfaced no critical/high/medium findings. The only delta since the prior clean pass is a behavior-preserving hunk in server/src/training-agent/comply-test-controller.ts (hoisting the get_products-rejected version check into a const and removing a CodeQL suppression comment) — confirmed to have no runtime security impact since the account gate still runs above the sandbox scenario selector.

Escalation reasons:

  • Touches gated paths under static/schemas/source/** (get-products-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, comply-test-controller-request.json, comply-test-controller-response.json modified; get-products-rejected.json added) while review_decision is not APPROVED — human/CODEOWNERS review required.
  • Protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products. Even though additive, the published schema surface requires human sign-off per repo governance.

This is a clean diff (no blocking findings), so once a human/CODEOWNERS records an APPROVED review, the gate lifts and the PR can proceed.

Why human review

  • Gated paths: PR modifies/adds files under static/schemas/source/** (get-products-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, comply-test-controller-request.json, comply-test-controller-response.json modified; get-products-rejected.json added) and review_decision is not APPROVED — hard approval gate, human/CODEOWNERS review required.
  • Protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products; published schema surface requires human sign-off even though the change is additive.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/compliance/comply-test-controller-request.json (modified) matches static/schemas/source/**; static/schemas/source/compliance/comply-test-controller-response.json (modified) matches static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matches static/schemas/source/**; static/schemas/source/core/protocol-envelope.json (modified) matches static/schemas/source/**; static/schemas/source/enums/task-status.json (modified) matches static/schemas/source/**; static/schemas/source/index.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-rejected.json (added) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', 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.

Comment thread server/src/training-agent/comply-test-controller.ts Dismissed

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated-path approval gate is unsatisfied (and this is a breaking-class-eligible protocol wire-shape change).

Escalation reasons

  • Gated paths: this PR modifies/adds files under static/schemas/source/** (get-products-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, comply-test-controller-request.json, comply-test-controller-response.json modified; get-products-rejected.json added) and review_decision is not APPROVED. Human/CODEOWNERS approval is required before this can merge.
  • Protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products. Published-surface schema changes require human sign-off per the repo's breaking-class hard gate, even when additive.

Findings

  • No critical/high/medium findings surfaced. The delta (duplicate task_id re-registration converted from a 500 into a clean conflict response, fail-closed race handling, fully-awaited async plumbing, four new tests) reads as clean.

Notes for reviewers

  • The diff appears well-tested; the block here is purely the hard, deterministic gated-paths gate plus the breaking-class-change human-ratification requirement — not a code defect. Once a CODEOWNERS/human approval is recorded (review_decision: APPROVED), a re-run with a clean finding set can fall through to approve.
  • Prior decision was also escalate for the same gated-paths reason; this remains the correct outcome under decision-table row 2.

Why human review

  • Gated paths: PR modifies/adds files under static/schemas/source/** (get-products-response.json, async-response-data.json, protocol-envelope.json, task-status.json, index.json, comply-test-controller-request.json, comply-test-controller-response.json modified; get-products-rejected.json added) and review_decision is not APPROVED — hard approval gate, human/CODEOWNERS review required.
  • Breaking-class-eligible protocol wire-shape change: adds a new response arm (GetProductsRejected) to get_products on the published schema surface; per the repo's hard gate, ratification is a human act and cannot be auto-approved until review_decision is APPROVED.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/compliance/comply-test-controller-request.json (modified) matches static/schemas/source/**; static/schemas/source/compliance/comply-test-controller-response.json (modified) matches static/schemas/source/**; static/schemas/source/core/async-response-data.json (modified) matches static/schemas/source/**; static/schemas/source/core/protocol-envelope.json (modified) matches static/schemas/source/**; static/schemas/source/enums/task-status.json (modified) matches static/schemas/source/**; static/schemas/source/index.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-rejected.json (added) matches static/schemas/source/**; static/schemas/source/media-buy/get-products-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: seller declines have no structured outcome — add a Rejected arm (get_products first) and give task-status rejected a payload contract

2 participants