Skip to content

fix(compliance): return the held proposal ID in simulated, not forced (#8501 entry 1) - #8765

Closed
bokelley wants to merge 2 commits into
mainfrom
fix/8501-controller-forced-proposal-id
Closed

bokelley wants to merge 2 commits into
mainfrom
fix/8501-controller-forced-proposal-id

Conversation

@bokelley

@bokelley bokelley commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

What this changes

force_hold_unavailable is the experimental comply_test_controller scenario (media_buy.hold_policy) that makes the next refine_proposals finalize of a draft fail with hold_unavailable. In the 3.3 betas, registering it returned the forced-directive response with a new unable value for forced.arm and a new forced.proposal_id echo. The forced object is closed, and a minor release does not add to a closed schema (DR-0036).

This PR removes both values. The controller now returns the draft's ID in simulated.proposal_id. simulated is the open object for "values injected or applied by this call", and simulate_later_proposal already returns a proposal_id there.

  • Schema: ForcedDirectiveSuccess goes back to its 3.2 shape: arms submitted, completed, input-required and rejected, and no proposal_id. The SimulationSuccess description now names the scenario, and the schema example moves to simulated.
  • Storyboard: hold_unavailable_batch reads simulated.proposal_id and drops its forced.arm: "unable" check.
  • Training agent: returns simulated: { proposal_id }.
  • Docs: the controller reference page and the media_buy.hold_policy row on the experimental-status page.
  • Release guidance: the 3.2 to 3.3 migration guide (closed-schema section) and the 3.3 beta page each show the old and new shapes, forced: { arm: "unable", proposal_id } → simulated: { proposal_id }, for beta conformance-runner authors.
  • Additive-minor baseline: drops the forced.proposal_id entry (37 entries remain).
  • Changeset: minor, following the withdraw-commercial-terms-features-to-4-0 precedent. Both values shipped in 3.3.0-beta.0 through 3.3.0-beta.4 (checked against dist/schemas), so the changeset tells beta adopters what to change.

Nothing else about the scenario changes. Its request, its errors, and what the next finalize returns stay the same.

Refs #8501 (entry 1)

Merge timing

This merges only after the Nov 13 consent window closes.

Tests run

  • npm run build:schemas and npm run build:compliance
  • ADCP_ADDITIVE_MINOR_BASELINE_REF=origin/main npm run test:additive-minor: 92 tests pass; lint reports 37 recorded changes and 0 new
  • node --test tests/hold-policy.test.cjs tests/hold-policy-vectors.test.cjs: 135 pass
  • npx vitest run --config server/vitest.config.ts tests/unit/training-agent-hold-vectors.test.ts tests/unit/proposal-negotiation-profiles.test.ts: 28 pass
  • npm run test:schemas: all pass
  • Storyboard lints: validations-paths, response-schema, context-output-paths, check-enum, controller-requires, contradictions: all pass
  • npm run typecheck: clean
  • Hold storyboards against the local training agent, current surface, candidate-version mode on. Every result matches the CI exact pin:
    • /sales: hold_unavailable_batch 12P/0S, hold_policy_terms_only 19P/4S, hold_extension 22P/10S, hold_policy_bounds 18P/0S, hold_policy_version_gate 11P/0S, hold_ranking 11P/0S
    • /sales/profiles/finalization-failure: hold_unavailable_batch 12P/0S
  • Changeset gates: check-changeset-protocol-scope.cjs origin/main and changeset status --since=origin/main both pass

Local hooks

CI is the gate. Locally, the two hooks went like this:

  • Pre-commit: passed, nothing skipped. It ran the root and server unit suites and the typecheck. The commit was made from a /tmp checkout of the same base with its own npm ci, and its tree is identical to the working branch. Earlier attempts from the agent worktree failed for reasons unrelated to this diff:
    • Environmental and reproducible. server/tests/unit/training-agent-creative33-buyer.test.ts gets a 404 for its fixture video in any checkout under a dot-directory, such as .claude/worktrees/. The creative 3.3 router serves the file with res.sendFile(path.resolve(...)), and Express refuses paths with a dot segment. A five-line Express script reproduces it, and the test passes from a path without one.
    • Load timeouts. tests/addie/compliance-sdk-rc-transport.test.ts takes about 8.5s inside the full root suite against a 10s limit, with or without this diff, so it fails intermittently on a loaded host. It passes alone, and the full root suite passes 1282/1282 with a 30s timeout.
    • Load timeouts. A cold-worker test in tests/unit/addie/matched-pair-ni/exact-inference.test.ts failed once under load and passed 34/34 on rerun.
    • Run by hand while diagnosing. Before the hooked commit succeeded, I ran each step of the hook chain by hand: dynamic-imports, format-identity-boundaries, callapi-state-change, the four server-unit shards, and the typecheck. Their only failures were the items above.
  • Follow-up docs commit: pre-commit skipped. The release-guidance commit touches only two .mdx files, and the pre-commit hook fails deterministically in the agent worktree because of the dot-directory 404 above. It was committed with HUSKY=0. lint:schema-links, test:docs-nav (58/58), and test:docs-error-handling-copy were run by hand and pass. Its pre-push hook ran in full: version sync, the changeset check, and the docs checks all passed, and the storyboard matrix didn't apply.
  • Pre-push on the first commit: storyboard matrix skipped. Version sync, the changeset check, and the docs checks passed. The local storyboard matrix was skipped with the hook's documented ADCP_SKIP_STORYBOARD_MATRIX=1. A first run passed /signals, then ran past 40 minutes on /sales on the shared host. The hold storyboards listed above were run separately, and CI's training-agent-storyboards workflow is authoritative.

Left unchanged

The What's new, 3.3 beta, and release-notes pages mention force_hold_unavailable but not its response shape, so none of them were wrong and this PR leaves them alone.

🤖 Generated with Claude Code

…#8501 entry 1)

force_hold_unavailable registered its directive on ForcedDirectiveSuccess
with a new `unable` arm and a `forced.proposal_id` echo. `forced` is
closed, and a minor does not add to a closed schema (DR-0036), so both
are withdrawn and ForcedDirectiveSuccess goes back to its 3.2 shape.

The scenario now answers on SimulationSuccess with
`simulated.proposal_id`, the value the call applied. The
hold_unavailable_batch storyboard reads it there, the training agent
returns it there, and the additive-minor baseline drops the
`forced.proposal_id` entry.

Refs #8501

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e 3.3 guides

Beta conformance-runner authors read the migration guide and the beta
page, not the changeset. Both now show the old and new shapes:
`forced: { arm: "unable", proposal_id }` in 3.3.0-beta.0 through
beta.4, `simulated: { proposal_id }` after.

Refs #8501

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 7, 2026
…erimental, and inventory the rest

Adds scripts/audit-schema-bounds.cjs and its inventory: every unbounded array and string in the schema source, by stability, request or response side and proposed limit, plus every property or collection list carried inline. Bounds the arrays and strings that are new in 3.3 or experimental: 646 maxItems/maxLength keywords in 152 schemas, written by `node scripts/audit-schema-bounds.cjs --apply`, which is idempotent and is the one command for regenerating the slice after a conflict. Stable fields are proposed for 4.0 in specs/collection-bounds-proposal.md and registered as schema_bounds_required_in_4_0.

Not bounded: get_adcp_capabilities and its referenced types (#8198), inline property and collection lists, five nodes the SDK generators cannot carry a bound on, and seven 3.3 beta fields that the #8501 withdrawal PRs (#8765, #8762, #8758, #8767) remove.

The script now compares with the highest 3.2.x release (3.2.8), the base lint-additive-minor uses. Build Check runs its --check-unreleased guard as npm run lint:schema-bounds, so every new 3.3 or experimental array or string arrives with a bound. The MCP parity compile limit moves from 1,376,000 to 1,378,000 bytes (the controller closure measures 1,377,055).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 7, 2026
…erimental, and inventory the rest

Adds scripts/audit-schema-bounds.cjs and its inventory: every unbounded array and string in the schema source, by stability, request or response side and proposed limit, plus every property or collection list carried inline. Bounds the arrays and strings that are new in 3.3 or experimental: 646 maxItems/maxLength keywords in 152 schemas, written by `node scripts/audit-schema-bounds.cjs --apply`, which is idempotent and is the one command for regenerating the slice after a conflict. Stable fields are proposed for 4.0 in specs/collection-bounds-proposal.md and registered as schema_bounds_required_in_4_0.

Not bounded: get_adcp_capabilities and its referenced types (#8198), inline property and collection lists, five nodes the SDK generators cannot carry a bound on, and seven 3.3 beta fields that the #8501 withdrawal PRs (#8765, #8762, #8758, #8767) remove.

The script now compares with the highest 3.2.x release (3.2.8), the base lint-additive-minor uses. Build Check runs its --check-unreleased guard as npm run lint:schema-bounds, so every new 3.3 or experimental array or string arrives with a bound. The MCP parity compile limit moves from 1,376,000 to 1,378,000 bytes (the controller closure measures 1,377,055).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 8, 2026
…erimental, and inventory the rest

Adds scripts/audit-schema-bounds.cjs and its inventory: every unbounded array and string in the schema source, by stability, request or response side and proposed limit, plus every property or collection list carried inline. Bounds the arrays and strings that are new in 3.3 or experimental: 648 maxItems/maxLength keywords in 152 schemas, written by `node scripts/audit-schema-bounds.cjs --apply`, which is idempotent and is the one command for regenerating the slice after a conflict. Stable fields are proposed for 4.0 in specs/collection-bounds-proposal.md and registered as schema_bounds_required_in_4_0.

Not bounded: get_adcp_capabilities and its referenced types (#8198), inline property and collection lists, five nodes the SDK generators cannot carry a bound on, and seven 3.3 beta fields that the #8501 withdrawal PRs (#8765, #8762, #8758, #8767) remove.

The script now compares with the highest 3.2.x release (3.2.8), the base lint-additive-minor uses. Build Check runs its --check-unreleased guard as npm run lint:schema-bounds, so every new 3.3 or experimental array or string arrives with a bound. The match_keys arrays #8446 added on product identity and TMP provider registration get maxItems 64, the cap media_buy.supported_match_keys already carries. The MCP parity compile limit moves from 1,384,000 to 1,386,000 bytes (the controller closure measures 1,385,040).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 8, 2026
…erimental, and inventory the rest

Adds scripts/audit-schema-bounds.cjs and its inventory: every unbounded array and string in the schema source, by stability, request or response side and proposed limit, plus every property or collection list carried inline. Bounds the arrays and strings that are new in 3.3 or experimental: 648 maxItems/maxLength keywords in 152 schemas, written by `node scripts/audit-schema-bounds.cjs --apply`, which is idempotent and is the one command for regenerating the slice after a conflict. Stable fields are proposed for 4.0 in specs/collection-bounds-proposal.md and registered as schema_bounds_required_in_4_0.

Not bounded: get_adcp_capabilities and its referenced types (#8198), inline property and collection lists, five nodes the SDK generators cannot carry a bound on, and seven 3.3 beta fields that the #8501 withdrawal PRs (#8765, #8762, #8758, #8767) remove.

The script now compares with the highest 3.2.x release (3.2.8), the base lint-additive-minor uses. Build Check runs its --check-unreleased guard as npm run lint:schema-bounds, so every new 3.3 or experimental array or string arrives with a bound. The match_keys arrays #8446 added on product identity and TMP provider registration get maxItems 64, the cap media_buy.supported_match_keys already carries. The MCP parity compile limit moves from 1,384,000 to 1,386,000 bytes (the controller closure measures 1,385,040).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 8, 2026
…erimental, and inventory the rest

Adds scripts/audit-schema-bounds.cjs and its inventory: every unbounded array and string in the schema source, by stability, request or response side and proposed limit, plus every property or collection list carried inline. Bounds the arrays and strings that are new in 3.3 or experimental: 648 maxItems/maxLength keywords in 152 schemas, written by `node scripts/audit-schema-bounds.cjs --apply`, which is idempotent and is the one command for regenerating the slice after a conflict. Stable fields are proposed for 4.0 in specs/collection-bounds-proposal.md and registered as schema_bounds_required_in_4_0.

Not bounded: get_adcp_capabilities and its referenced types (#8198), inline property and collection lists, five nodes the SDK generators cannot carry a bound on, and seven 3.3 beta fields that the #8501 withdrawal PRs (#8765, #8762, #8758, #8767) remove.

The script now compares with the highest 3.2.x release (3.2.8), the base lint-additive-minor uses. Build Check runs its --check-unreleased guard as npm run lint:schema-bounds, so every new 3.3 or experimental array or string arrives with a bound. The match_keys arrays #8446 added on product identity and TMP provider registration get maxItems 64, the cap media_buy.supported_match_keys already carries. The MCP parity compile limit moves from 1,384,000 to 1,386,000 bytes (the controller closure measures 1,385,040).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bokelley

bokelley commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Closing as moot after the WG decision of 2026-11-09. 3.x opens the schemas that were meant to be open, and this withdrawal existed only because its schema was closed. forced opens in #8866, so the feature stays. See the re-triage on #8501.

@bokelley bokelley closed this Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant