Repository navigation
fix(schemas): open the capability blocks and containers 3.3 extends, against DR-0019 (#8501) - #8772
Conversation
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
…e register DR-0036 states the rule and its departures: a closed schema stays closed for the major, a minor changes a schema only by addition, and the only departures are corrections and named exceptions. A correction either opens a schema that the published text keeps open or applies a bound or required name that the published text already sets. The record no longer lists corrections location by location. scripts/lint-additive-minor-corrections.json is the register. The additive-minor check no longer parses correction tables from the decision record; it still requires the register to name an existing decision record, verifies each quoted source, and accepts exactly the listed changes. Each reason names its kind of correction in place of a correction letter. DR-0019's amendment note, the 3.3 release docs, the migration guides and the versioning page describe corrections by kind.
4a3dba7 to
6440784
Compare
| // The requirements container is open (a correction under DR-0036). An unknown | ||
| // hard requirement still isn't ignored: matching fails closed on it. | ||
| assert.equal( | ||
| validate({ future_unknown_dimension: true }), | ||
| false, | ||
| true, | ||
| errors(validate) |
There was a problem hiding this comment.
Medium: Opening targeting-overlay-requirements.json drops the schema-level rejection of unknown hard requirements, and this test swaps the functional guarantee for a prose check. Before, validate({ future_unknown_dimension: true }) returned false — the schema itself fail-closed. Now it returns true and the only remaining assertion is assert.match(...description..., /Missing or unknown required fields do not match\./). That tests the wording, not the matcher. The fail-closed guarantee now rests entirely on the reference matcher, and no functional test in this PR exercises an unrecognized requirement dimension actually failing to match. If the matcher ever fails open on an unknown key, a buyer's hard requirement is silently ignored and non-conforming inventory matches — the exact failure the "do not match" rule exists to prevent. Add a matcher-level case that an unknown requirement dimension matches no product.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema paths require human/CODEOWNERS approval.
This PR modifies five files under static/schemas/source/**, which is a hard, deterministic approval gate (gated_paths: true). The current review_decision is REVIEW_REQUIRED, not APPROVED, so the gate is not satisfied (decision table row 2). Human/CODEOWNERS review is required before this can merge.
Gated files requiring approval:
- static/schemas/source/core/canonical-reporting-capabilities.json
- static/schemas/source/core/daypart-target.json
- static/schemas/source/core/spot-reporting-capability.json
- static/schemas/source/core/targeting-overlay-requirements.json
- static/schemas/source/core/targeting-overlay-support.json
Medium findings:
- tests/targeting-aware-discovery.test.cjs:2016 — Opened requirements container shifts fail-closed behavior to a matcher with no functional test covering the now-reachable fail-open path.
The reviewer confirmed schema↔docs coherence holds, changeset types are correct (minor for additive openings, no breaking wire change, no dist/ edits, no oneOf regression), and the lint governance redesign is deliberate and documented. The sole substantive concern is the Medium test-coverage gap above — not blocking on its own, but it lands on a modified high-risk schema path and warrants a human eye alongside the gate review.
Medium findings
- tests/targeting-aware-discovery.test.cjs:2016 — Opened requirements container shifts fail-closed to matcher with no functional test
Why human review
- Gated paths touched (static/schemas/source/**) with review_decision=REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required on: canonical-reporting-capabilities.json, daypart-target.json, spot-reporting-capability.json, targeting-overlay-requirements.json, targeting-overlay-support.json
- Medium finding on a modified high-risk schema path: opened requirements container shifts fail-closed to matcher with no functional test (tests/targeting-aware-discovery.test.cjs:2016)
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/canonical-reporting-capabilities.json (modified) matches
static/schemas/source/**; static/schemas/source/core/daypart-target.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/spot-reporting-capability.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-requirements.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-support.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.
|
Thanks, that's fair: the assertion here only checked the wording. a7f7f7f adds a functional case in |
…against DR-0019 (adcontextprotocol#8501) 3.2 published these schemas closed. DR-0019 keeps capability blocks and container objects open, and calls a class B row without an escape hatch a defect. No record explains the closure. Open them as corrections under DR-0036, which allows opening a schema that the published text keeps open: - core/daypart-target.json, a row with no ext. The root oneOf still rejects a window that mixes start_hour/end_hour with start_time/end_time. - core/targeting-overlay-requirements.json, with its structured daypart and demographics requirement branches. An unknown requirement still matches no product. - the structured daypart support branch of core/targeting-overlay-support.json. - core/spot-reporting-capability.json and core/canonical-reporting-capabilities.json. Each change sets additionalProperties to true at the listed pointer and nothing else. No 3.2.x patch opens them: their 3.2 closure rejects nothing a conforming 3.2 peer sends. Register the sync_creatives assign branch as a named exception under DR-0036. It is a discriminated oneOf branch (DR-0019 class A), so it stays closed and takes only trackers and landing_page_url. Each requires a creative capability the seller declares, and buyers must not send it otherwise. Add the nine entries to scripts/lint-additive-minor-corrections.json and drop the 11 baseline rows they cover (38 to 27). Update the four tests that asserted closure on the opened schemas, extend the list of 3.3 corrections in the migration guide, add correction notes to the migration guide and versioning page, and add a patch changeset.
… { age: true }
The boolean branch of demographics on targeting-overlay-support and
targeting-overlay-requirements is deprecated in 3.3 and removed in 4.0
(adcontextprotocol#8778). It is defined as the 3.2 shorthand for { age: true }. Senders
MUST send the object form, which every 3.2 release accepts; receivers
MUST accept true and read it as { age: true }, so it satisfies an age
requirement and never a gender requirement.
Mark both boolean branches x-removed-in 4.0.0 and list them in the 4.0
compatibility registry under schema_removals_not_checked. Product
support is seller-emitted and observable on get_products but isn't
graded yet; requirements are buyer-sent.
Document the deprecation in the get_products matching rules, the 3.2 to
3.3 migration guide, and the 4.0 compatibility guide. The changeset
becomes minor because the deprecation adds a sender requirement.
… no product The requirements container is open, so an unknown required_overlay_support key passes schema validation. Assert that list_products and get_products still return no product for it, against a control request that differs only by that key: missing or unknown required fields do not match.
a7f7f7f to
b3e9767
Compare
|
|
||
| Every payload that was valid stays valid. The 3.3 fields on these schemas go only to 3.3 peers, because a strict 3.2 validator still rejects them. No 3.2.x patch opens them. | ||
|
|
||
| The boolean form of `demographics` is deprecated on both `core/targeting-overlay-support.json` and `core/targeting-overlay-requirements.json`, and removed in 4.0 (#8778). `demographics: true` is the 3.2 shorthand for `{ "age": true }`, and every 3.2 release accepts the object form. Senders MUST send the object form. Receivers MUST accept `true` and read it as `{ "age": true }`, so it satisfies an age requirement and never a `gender` requirement. |
There was a problem hiding this comment.
Medium: This states boolean demographics "satisfies an age requirement and never a gender requirement." The reference matcher doesn't implement that. overlaySupportContains (server/src/training-agent/task-handlers.ts:8054) treats boolean true as a wildcard — its own doc comment says "true means unrestricted protocol-valid support." So product support demographics: true + requirement { gender: true } matches at L8059-8068, and a demographics: true requirement is satisfied by gender-only support at L8070. Neither reads true as { age: true }. No functional test covers the boolean→age matching claim — the new targeting-aware-discovery.test.cjs case only asserts schema validation. Same shape as the prior container finding: a semantic matcher claim shipped without a functional test.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema paths require human/CODEOWNERS approval.
This PR opens 3.2 capability blocks/containers to additionalProperties: true (DR-0036 corrections) and deprecates boolean demographics, touching protocol source of truth under static/schemas/source/**. Per the decision table, row 2 fires: gated_paths: true and review_decision is not APPROVED (unknown/none). Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
Iteration credit: the prior Medium finding (missing functional test for the opened requirements container) has been resolved by the new fail-closed functional test in server/tests/unit/training-agent.test.ts:409-445. Schema↔docs↔changeset are coherent, the minor changeset is correct (additive opens + still-functional deprecation), the daypart root oneOf still rejects mixed forms, and lint baseline→corrections moves are consistent.
Medium findings
- .changeset/open-capability-blocks-and-containers.md:16 — Boolean demographics age-only claim ("{age:true} never satisfies a gender requirement") not honored by the reference matcher (overlaySupportContains treats boolean true as a wildcard both directions); no functional test for the age-only semantics.
Escalation reasons
- Gated paths touched (static/schemas/source/**) with review_decision not APPROVED — human/CODEOWNERS approval required on: canonical-reporting-capabilities.json, daypart-target.json, spot-reporting-capability.json, targeting-overlay-requirements.json, targeting-overlay-support.json.
- Fresh medium finding still present on this run, sustaining the prior escalation.
Medium findings
- .changeset/open-capability-blocks-and-containers.md:16 — Boolean demographics age-only claim not honored by reference matcher; no functional test
Why human review
- Gated paths touched (static/schemas/source/**) with review_decision not APPROVED — human/CODEOWNERS approval required on: canonical-reporting-capabilities.json, daypart-target.json, spot-reporting-capability.json, targeting-overlay-requirements.json, targeting-overlay-support.json
- Fresh medium finding present on this run (.changeset/open-capability-blocks-and-containers.md:16 — boolean demographics age-only claim not honored by reference matcher; no functional test), sustaining prior escalation
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/canonical-reporting-capabilities.json (modified) matches
static/schemas/source/**; static/schemas/source/core/daypart-target.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/spot-reporting-capability.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-requirements.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/targeting-overlay-support.json (modified) matchesstatic/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.
|
@KonstantinMirin, thank you for this. It's superseded by #8866, which folds it in with credit, so I'm leaving this PR for you to close. On Nov 9 the WG decided that 3.x opens the schemas that were meant to be open, as DR-0036 is being rewritten in #8858. #8866 makes that change for 3.3:
The rest of #8866 opens 744 of the 859 closed locations. 115 stay closed for a structural reason that Brian approved, and the additive-minor lint changes to match. 🤖 Generated with Claude Code |
Brings over the schema, test and doc changes of #8772 by Konstantin Mirin: the daypart window, the overlay requirement and support containers, spot reporting and canonical reporting capabilities open; boolean demographics becomes the deprecated 3.2 shorthand for { age: true }, so only gender support satisfies a gender requirement. The DR-0036 register entries and the named exception from #8772 are left out: the next commits open these schemas under the WG decision of 2026-11-09, which needs neither. Co-authored-by: Konstantin Mirin <konstantin.mirin@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I'd recommend closing this as superseded by #8866, which carries every schema change, test and the registry entry from here. Thanks for the credit, Brian. Two doc hunks didn't come across, the |
Brings over the schema, test and doc changes of #8772 by Konstantin Mirin: the daypart window, the overlay requirement and support containers, spot reporting and canonical reporting capabilities open; boolean demographics becomes the deprecated 3.2 shorthand for { age: true }, so only gender support satisfies a gender requirement. The DR-0036 register entries and the named exception from #8772 are left out: the next commits open these schemas under the WG decision of 2026-11-09, which needs neither. Co-authored-by: Konstantin Mirin <konstantin.mirin@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unks From Konstantin Mirin's review of #8866: - The commercial terms and proposal-budget-constraint are held closed until 4.0, not closed for a structural reason. terms_digest covers every member at every depth, open ones included, so the docs no longer claim that closure stops a 3.2 buyer accepting a term it ignored. - The boolean demographics deprecation reaches the 3.2 to 3.3 summary and Deprecations list, and the 4.0 guide's removal count and seller-emitted list, as #8772 had them. - target_audiences sits beside audience_evidence_requirements because one names which audience and the other the evidence quality, not because the requirements object was closed. - 3.2.10 opens all but one of 3.2's locations: it keeps the lookup_unavailable branch closed. The get_principal current and sync_principal applied and validated results open, so 747 locations open and 112 stay closed. - The lint hint points to the corrections register again and says a correction sets a bound or a required name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(schemas): fold in #8772's capability-block and container openings Brings over the schema, test and doc changes of #8772 by Konstantin Mirin: the daypart window, the overlay requirement and support containers, spot reporting and canonical reporting capabilities open; boolean demographics becomes the deprecated 3.2 shorthand for { age: true }, so only gender support satisfies a gender requirement. The DR-0036 register entries and the named exception from #8772 are left out: the next commits open these schemas under the WG decision of 2026-11-09, which needs neither. Co-authored-by: Konstantin Mirin <konstantin.mirin@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): open the 3.3 schemas that were meant to be open The WG decided on 2026-11-09 that 3.x opens the schemas that were meant to be open: closing a schema only breaks hard-coded validators, so opening one is not a protocol break. additionalProperties goes from false to true at 784 of the 859 closed locations in the source tree. Nothing else in those schemas changes. 75 locations stay closed for a structural reason: oneOf branches told apart only by key presence (a2ui bound-value, brand.json), the signed commercial terms that terms_digest binds, metric qualifiers and forecast dimensions (join keys), the canonical installment identity, the JWS response envelope, the TMP match requests and the not-found error (privacy boundaries), the reporting-destination setup action, and patternProperties maps keyed by IDs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep the privacy clamps closed; drop closure claims from opened schemas The per-agent PERMISSION_DENIED details and the failed and unconfigured get_principal results stay closed: their descriptions make the closed shape the clamp against an existence or commercial-state oracle. Descriptions of schemas that are now open no longer say they are closed or reject unknown members. The metric qualifiers stay closed, so their descriptions now say new keys ship in a major release, not in a minor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(lint): flag additions only to schemas that stay closed Under the WG decision of 2026-11-09 and the rewritten DR-0036, schemas are open by default and a schema stays closed only for a structural reason. The additive-minor lint now matches: - property-added-to-closed fires only where the schema is closed in both the base and the candidate. Opening a schema, and adding to one the candidate opens, passes. - The closed-anywhere-in-the-major rule goes: closedInEarlierReleases, the "(closed in X)" findings and the released exemption. - Corrections only tighten a bound or require a name the published text already set. The 24 whole-schema reopen entries go; an entry that lets in a property is an error. - Openings print one notice line with the count. - Removals, renames, retypes, enum removals, bound tightening, new required names and closing an open schema still fail. The baseline drops the 34 entries this resolves and keeps 4, each with its resolution: metric_id and the two sla-window fields sit on schemas that stay closed (signed commercial terms), and evaluator is restored. Also ports the DR-0036 cross-check removal from #8858 (from Konstantin Mirin's #8777): the corrections list names its decision record, which no longer lists entries. Co-authored-by: Konstantin Mirin <konstantin.mirin@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(lint): cover the open-by-default additive-minor rule Drops the tests of the earlier-release closure, the released exemption and the reopen and property corrections, moves the correction checks onto bound fixtures, and adds cases for additions to schemas closed on both sides, opened, or open, for closing an open schema, and for a correction that lets in a property. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep the reporting-status and billing-permission clamps closed The 3.2.10 backport found two more privacy clamps: - get_reporting_status's Unavailable lookup failure is closed in every 3.2 release; #8547 opened it during the 3.3 betas. Its caller isolation text requires unknown and unauthorized identifiers to use one identical lookup_unavailable shape, so it closes again with the envelope fields redeclared as 3.2.8 does. The Operational failure branch stays open; its failure_kind const keeps the two apart. - BILLING_NOT_PERMITTED_FOR_AGENT details stay closed, as PERMISSION_DENIED's per-agent details do: their description calls extra keys commercial-state oracles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: say schemas are open by default; restate the closed ones' reasons The 3.2 to 3.3 migration guide's "Closed schemas stay closed within a major" section becomes "Schemas are open by default": what opened, the structural reasons the rest stay closed, and what it means for validators, generated types and 3.2 peers. The 3.3 beta page, What's new, the release notes and the 4.0 compatibility guide follow. Pending changesets that cited "a minor never changes a closed schema" or a lettered DR-0036 correction now cite the structural reason (commercial_terms is signed) or DR-0024. Adds the changeset for the opening. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep trust.json and placement-presentation closed Both are security-sensitive documents whose closure keeps out an open-ended class of content that no list of names could cover: - trust.json sits on the signature-verification fetch path, and signing keys are published only in the key directory, so its records, agents, grants and acknowledgements carry no key material (jwks_uri, key pins, signing profiles) and no undeclared authority. - placement-presentation is a declarative, non-executable frame that consumers render, so it carries no markup or script. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: count the 100 locations that stay closed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep principal results, reporting destinations and hard budget bounds closed - get_principal and sync_principal results keep their closed branches: no branch may become an oracle for another principal's existence or state, and a dry run issues no durable identifier. - Reporting destinations are credential-free by contract, and closure rejects credentials under any name. - proposal-budget-constraint is the strict peer of budget-range: a seller that ignored an unknown member of a hard constraint would violate a constraint it never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: count the 116 locations that stay closed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep the reporting-status lookup_unavailable branch open Every response root and status branch accepts every envelope field (#8547), so the Unavailable lookup branch can't close without redeclaring the envelope, which the composition rule forbids. main's shape already carries the caller-isolation clamp: the error objects stay closed, the message is a const, and the ledger and account fields are rejected by name. The branch goes back to that shape; only its nested error objects stay closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(security): count the capability blocks 3.3 opens as open positions The worst-case capabilities document is unchanged at 99,100,981 bytes; its open positions go from 108 to 190. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): name the fields closure used to reject in opened schemas Where a closed schema also rejected a specific field the protocol defines elsewhere, or one its text forbids there, the opened schema now rejects it by name in a not/anyOf/required clause, as #8531 did for canonical-product. Examples: trackers, landing_page_url and weight stay off unassign, replace and merge; hold entries carry no expires_at; a reporting revision carries no destination_ref; delivery-ready webhooks carry no access_token; SDK metadata carries no self-asserted approval; an attestation presentation carries no evaluator decision; requirement branches reject seller maxima. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: expect opened schemas to accept unknown keys Tests that asserted generic closure (an undeclared key is rejected, or additionalProperties is false) now assert the opened behaviour. Tests that reject a named field are unchanged and pass through the schema's named rejection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): keep key-presence anyOf unions apart by name Opening the branches of an anyOf that was told apart only by which keys are present lets one payload carry both forms. Each branch now rejects the other's keys by name: - canonical-account-ref: the account_id form rejects brand and operator, and the natural-key form rejects account_id; - geo-region requirement and support: all_values and values exclude each other per country; - the deprecated fused-system postal area rejects country; - a sync_reporting_receipts result carries a receipt or an adjustment receipt, not both. Also names step on frequency-cap impression constraints and mode on list application receipts, matching the 3.2.10 backport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: finish the open-schema test fallout - mcp-schema-projection: PARITY_COMPILE_LIMIT 1,384,000 -> 1,385,000, measured (the named rejections add 395 bytes to the comply-test-controller closure); the list_products legacy-graph check strips the new format_ids and v1_format_ref prohibitions as it strips canonical-product's. - Unknown-key cases that are now accepted: entries_total on list receipts, an unknown geo_countries support key, response_due_at and completion_due_at on issue receipts, the bucket_completness typo, and an unexpected publisher targeting key-value config key. - New canonical-account-ref test: account_id and the natural key exclude each other, and an unknown key is accepted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(training-agent): keep tools/list within budget and ignore unknown declarations - tools/list discovery schemas omit `additionalProperties: true` inside bundled definitions. It is JSON Schema's default and carries no information, and dropping it keeps the four-tool surface under its 162 KiB budget once the named rejections land. The root keeps the keyword, which the parity test compares with the source. - The parity test compares openness instead of the literal keyword. - sync_principal keeps only the declaration axes the seller reads, so an unknown declarations member is ignored rather than stored and read back. An unknown section is still refused (UNSUPPORTED_FEATURE). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): address review on named rejections and key-presence guards From Konstantin Mirin's review of #8866: - Key-presence guards on two more unions: account-ref's account_id and natural-key forms exclude each other (as canonical-account-ref does), and image bleed's uniform and per-side forms exclude each other. canonical-account-ref's account_id form also rejects operator_unit, currency, timezone and sandbox, and a failed receipt result carries no receipt. A rescan of every oneOf and anyOf finds no other key-presence union. - Named rejections now cover only names the protocol defines elsewhere or forbids there. Dropped: step, covered (two nodes), gpc_honored, political, threshold_rate, per_ad_spend, verified (two nodes) and mode on list receipts. access_token on the delivery-ready webhook stays as a credential clamp. - Every node or union with a named rejection says in its description what it rejects and why, since generated types can't express not. - The get_principal current branch and the sync_principal applied and validated branches open: they return the caller's own configuration and are dispatched by kind. The validated branch rejects destination_ref and configuration_version, because a dry run issues no durable identifier. recognized, unconfigured and failed stay closed. - The reporting-status lookup_unavailable branch states its clamp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: call the commercial terms a hold until 4.0; carry #8772's doc hunks From Konstantin Mirin's review of #8866: - The commercial terms and proposal-budget-constraint are held closed until 4.0, not closed for a structural reason. terms_digest covers every member at every depth, open ones included, so the docs no longer claim that closure stops a 3.2 buyer accepting a term it ignored. - The boolean demographics deprecation reaches the 3.2 to 3.3 summary and Deprecations list, and the 4.0 guide's removal count and seller-emitted list, as #8772 had them. - target_audiences sits beside audience_evidence_requirements because one names which audience and the other the evidence quality, not because the requirements object was closed. - 3.2.10 opens all but one of 3.2's locations: it keeps the lookup_unavailable branch closed. The get_principal current and sync_principal applied and validated results open, so 747 locations open and 112 stay closed. - The lint hint points to the corrections register again and says a correction sets a bound or a required name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: flip probes for dropped rejections; add account-ref and bleed guards From Konstantin Mirin's review of #8866: - Probes for names the protocol never defines (step, mode on receipts, covered, gpc_honored, political, threshold_rate, per_ad_spend, verified) now expect the opened schema to accept them. - New tests: account-ref and image bleed key-presence guards, and the extended canonical-account-ref guard. - The list_products legacy-graph check skips not subtrees and descriptions structurally, instead of matching serialized strings. - The model-context projection omits named rejections beside declared properties, as it omits bounds: they are validation, and the descriptions carry them. A bare not branch of a union stays. The media-buy budget is unchanged; PARITY_COMPILE_LIMIT is 1,386,000, measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(lint): prune the additive-minor baseline to base 3.2.9 The 3.2.9 forward-merge makes 3.2.9 the default base. The 4 recorded entries are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: point the backport to the next 3.2.x patch; drop stale closure claims 3.2.10 shipped without the open-schemas backport, so the changeset and the migration guide now say the next 3.2.x patch (#8864) opens 3.2's locations, all but one. Docs that still called opened objects closed now match the schemas: the refine scope branches (a stray id fails on the missing product_id), policy entries, sync_plans plan items, and the account-ref variants. Where the reason was the commercial terms, the docs say they are held closed until 4.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: regenerate compliance symbol links on get_products Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: describe the account-ref guard errors, not additionalProperties Merged variants now fail on the named rejection (not) or a missing required name, and a budget object fails on type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(schemas): reserve the plan_hash bookkeeping names on sync_plans plans The opened sync_plans plan item accepted the governance agent's bookkeeping names: version, status, syncedAt, revisionHistory, committedBudget and committedByType. The plan_hash profile strips exactly those names from its preimage, so a buyer value under one of them would sit outside the hash and could collide with state the agent manages. The plan item now rejects them by name, and its description says they are reserved and a buyer MUST NOT send them. The list matches the profile's closed "Excluded fields" list. No storyboard, fixture or request example sends them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(3.3): say the commercial terms are held closed until 4.0 whats-new and the release notes no longer give the signed commercial_terms as the example of a structural reason: the rest stay closed where closure enforces something, and commercial_terms is held closed until 4.0. experimental-status no longer calls the buy_products purchase input and the list_products offer_filters closed; both are open in 3.3 and gain target_audiences in 4.0, with the accepted product-purchase snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(lint): describe the commercial terms as held closed until 4.0 The withdrawn-to-4-0 test comment, the additive-minor baseline $comment and the lint header drop the structural-reason framing for the commercial terms. All four baseline entries sit in commercial-terms schemas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(refinement): match the troubleshooting heading to the error it shows The heading quoted "must NOT have additional properties" while the body shows the missing product_id error. The body no longer says every scope branch requires its own identifier: the request scope requires ask. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Konstantin Mirin <konstantin.mirin@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Depends on #8777, which states DR-0036 as a decision; this PR adds only register entries under it.
Summary
This PR opens the 3.2 capability blocks and containers that 3.3 adds fields to. It adds them to
scripts/lint-additive-minor-corrections.jsonas register entries for openings (correction kind 1 in DR-0036: opening a schema that the published text keeps open). It also adds register entries for one named exception: the closedassignoperation onsync_creativestakestrackersandlanding_page_url, and nothing else. It makes no edits to DR-0036.It covers entries 7 to 10 and 13 to 19 of the disposition table on #8501 (issuecomment-6601730525).
Part of #8501.
Why
DR-0019 says:
and:
3.2 published these schemas closed anyway, and no record explains why. It's the same defect that #8531 fixed for the proposal flow, so I record it the same way. Each register entry cites the DR-0019 sentence that requires the location to be open.
What opens
additionalPropertiesgoes fromfalsetotrueat exactly these locations, and nothing else in the schema changes:core/daypart-target.jsonextcore/targeting-overlay-requirements.jsoncore/targeting-overlay-requirements.json/definitions/daypartRequirement/anyOf/1core/targeting-overlay-requirements.json/properties/demographics/anyOf/1core/targeting-overlay-support.json/definitions/daypartSupport/anyOf/1core/spot-reporting-capability.jsoncore/canonical-reporting-capabilities.jsonWhat closure did, and what does it now:
oneOfstill rejects a window that mixesstart_hour/end_hourwithstart_time/end_time.max_values_per_packageare still rejected there.canonical-reporting-capabilitiesgets no new field here. It opens so thatavailable_installment_statusescan move into it, as agreed on #8501. That move is in a separate PR, and this PR doesn't touch the field.Each opening's register reason begins "Opens a schema closed in 3.2 against DR-0019.", followed by the kind of schema and what still rejects.
The named exception
The
assignbranch ofassignment_operations[]is a discriminatedoneOfbranch, and DR-0019 lists those under class A. So it stays closed and takes onlytrackersandlanding_page_url. Any other property is still rejected.DR-0036's Named exceptions section, as #8777 states it, covers this case: the schema validates a request, so the receiver is the validator; each name requires a capability the receiver declares; and a sender MUST NOT send the name to a receiver that doesn't declare it. Both fields qualify. They require
creative.supports_assignment_trackersandcreative.supports_assignment_landing_page, and no 3.2 release defines either one. A conforming buyer never sends them to a seller whose validator rejects them.The register lists both as named-property entries, which the check already supports. Each reason begins "Named exception:". The source quote for each one is the field's own "buyers MUST NOT send this field otherwise" sentence.
Entry 17: the boolean form of
demographicsis deprecatedIn 3.2, age was the only demographic dimension, and
demographics: truewas the shorthand for{ "age": true }. Every 3.2 release, 3.2.0-beta.0 through 3.2.8, also accepts the object form{ "age": true }on both schemas. 3.3 deprecates the boolean form ontargeting-overlay-support.jsonandtargeting-overlay-requirements.json, and 4.0 removes it (#8778). Senders MUST send the object form. Receivers MUST accepttrueand read it as{ "age": true }.demographicson both schemas carriesdeprecated: true,x-deprecated-in: "3.3.0", andx-removed-in: "4.0.0", with the description "Deprecated in 3.3. The 3.2 shorthand for { age: true }. Senders MUST send the object; receivers MUST accept true."targeting-overlay-requirements.json, root: "For demographics, true on either side is the deprecated shorthand for { age: true } and matches as that object." Support satisfies a requirement for a dimension only if it supports that dimension, and the shorthand counts as age.genderrequirement: "Experimental in AdCP 3.3 (media_buy.gender_targeting). Only product support with gender: true satisfies it." Thegendersupport property drops "AdCP 3.2 core remains age-only."get_products.mdxstates the same matching rule. The 3.2 to 3.3 migration guide lists the deprecation under Deprecations.static/compliance/source/universal/v4-compatibility.yamllists both branches inschema_removals_not_checkedunder issue 4.0: remove the boolean form of demographics in overlay support and requirements #8778. Product support is seller-emitted and observable onget_products, but isn't graded yet; requirements are buyer-sent. The 4.0 compatibility guide's count of marked fields goes from 46 to 48.Baseline
scripts/lint-additive-minor-baseline.jsondrops these 11 rows, from 38 to 27:core/daypart-target.json:start_time,end_time(entries 7, 8)core/targeting-overlay-requirements.json/definitions/daypartRequirement/anyOf/1:time_granularity(9)core/targeting-overlay-support.json/definitions/daypartSupport/anyOf/1:time_granularity(10)core/spot-reporting-capability.json:available_statuses,supports_break_position(13, 14)core/targeting-overlay-requirements.json:collection_lists,collection_lists_exclude(15, 16)core/targeting-overlay-requirements.json/properties/demographics/anyOf/1:gender(17)creative/sync-creatives-request.json/properties/assignment_operations/items/oneOf/0:landing_page_url,trackers(18, 19)No 3.2.x patch
The proposal-flow reopening shipped in 3.3.0 and in a 3.2.x patch (#8532). These openings ship in 3.3.0 only.
In 3.2, closing these schemas rejects nothing a conforming 3.2 peer sends. Every field the opening lets in is a 3.3 field, and 3.3 fields go only to 3.3 peers. The proposal-flow reopening had a 3.2 reason that these schemas lack: the closed proposal-flow responses rejected the
adcp_versionecho that the 3.2 versioning page requires (#8518). The named exception can't go to 3.2.x at all, because its fields and capabilities are 3.3.Other changes
daypart-time-of-day,targeting-aware-discovery,spot-delivery-reporting-contract, andmcp-schema-analysis. They now expect the schemas to be open. The requirements test also checks that the description keeps the rule that unknown requirements don't match. A newtargeting-aware-discoverytest checks that both schemas acceptdemographics: trueand the object forms, and that the boolean branch is marked deprecated and removed in 4.0 in the source and the built schema.demographics, and the 4.0 compatibility guide lists it among the seller-emitted removals that aren't graded yet.minorchangeset foradcontextprotocol, because the deprecation adds a sender requirement.Compatibility impact
demographics: truestays valid on both schemas and reads as{ "age": true }. So it never satisfies a gender requirement, and ademographics: truerequirement isn't satisfied by gender-only support.Expected conflicts
core/daypart-target.json. Each is a short manual merge. This PR no longer edits DR-0036, so the two PRs don't meet there.assignrows this PR drops.Test plan
ADCP_ADDITIVE_MINOR_BASELINE_REF=origin/main npm run test:additive-minor: 89 tests pass. The lint reports 27 recorded changes and 0 new, with 7 notices, each marked as a correction listed in the register.trackersandlanding_page_url. With a made-uprotation_modeonassign, it fails on that name only.npm run test:v4-compatibility-registry(the source tree passes the registry lint, with bothdemographicssites listed) andtests/schema-deprecation-metadata.test.cjs: pass.test:schemas,test:json-schema,test:examples,test:composed,test:extension-schemas,test:sdk-response-conformance,test:targeting-aware-discovery,test:mcp-schema-projection: pass.npm run build:compliance -- --check,test:docs-nav,check:owned-links,lint:schema-links: pass.tests/changeset-protocol-scope.test.cjs,tests/capabilities-structural-bounds.test.cjs, andnode scripts/check-changeset-protocol-scope.cjs origin/main: pass.maineach one rejects it. The daypart window still rejectsstart_hourwithend_time,start_timewithend_hour, and both forms together.assignacceptstrackersandlanding_page_urland still rejects any other property. The metro requirement, which stays closed, still rejects one.