Skip to content

fix(schemas): open schemas that were closed by accident (3.2.x backport) - #8864

Merged
bokelley merged 12 commits into
3.2.xfrom
fix/open-closed-schemas-3-2-x
Nov 12, 2026
Merged

bokelley merged 12 commits into
3.2.xfrom
fix/open-closed-schemas-3-2-x

Conversation

@bokelley

@bokelley bokelley commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The 3.2.x backport of the working group decision of 2026-11-09: 3.x opens the schemas that were meant to be open. A 3.2 validator should not reject a newer 3.x payload just because a schema was closed.

Source of truth: #8866 (3.3, merged into main as 2dc672e316) owns the classification and the named rejections, including Konstantin Mirin's review of it. This PR mirrors #8866's final state node by node.

Approval: Brian approved the keep-closed (b) list as the 3.3 inventory had it on 2026-11-09, relayed by the release-planning agent. The review changes below were decided on #8866 and mirrored here.

Important

Ready for review. Brian merges (gated schema paths). No auto-merge. Hold the 3.2.11 Version Packages PR #8942 until this PR has merged and release.yml has regenerated #8942 to include this changeset.

Classification on 3.2.x

The tree was inventoried with the same inventory.py/classify.py as 3.3 and classified by the same rules.

Count
Closed locations on 3.2.x before this PR 775 in 342 files
Opened (class a) 674
Kept closed (class b) 101 in 48 files
Locations shared with #8866 (747 open / 112 closed) 772: every one has the same class
oneof_risk pairs on 3.2.x 4 (a2ui/bound-value 0/4 and 3/4, brand.json 1/3 and 2/4), all inside the kept-closed set

Kept closed, by reason:

Reason Locations Files
oneOf disjointness 9 a2ui/bound-value.json, brand.json
Join keys (metric qualifiers, forecast dimensions) 21 canonical-metric-qualifier, the qualifier objects, forecast-dimension-*
Signature envelope 1 response-payload-jws-envelope
Privacy boundary 20 TMP identity-match-request / context-match-request, catalog-item-reference-not-found-error, agent-permission-denied, billing-not-permitted-for-agent, get-principal-response (recognized, unconfigured, failed), sync-principal-response (failed), get-reporting-status-response (unavailable lookup)
Credential-free reporting destinations 10 agent-reporting-destination, reporting-write-destination, reporting-dataset-share-destination
No free text to agents 1 agent-reporting-destination-state setup
No key material or markup 8 placement-presentation
Maps keyed by identifier (patternProperties) 5 creative-asset, creative-manifest, creative-localization, creative-localization-readback, list-creatives-response
Held closed until 4.0 (commercial terms; a hold, not a structural reason) 26 commercial-terms, product-purchase, change-term, change-term-constraints, sla-window, canonical-measurement-terms, canonical-performance-standard, canonical-reporting-commitment, canonical-pricing-option, canonical-budget-allocation, bidding-policy, proposal-budget-constraint

Named rejections

Of #8866's 64 not clauses (unchanged through its merge as 2dc672e316), 46 apply on 3.2.x and are present at the same pointers with the same value. The other 18 target schemas or nodes that 3.2.x does not have: media-buy issues, reporting subscriptions, proposal webhooks, signal-delivery-method, canonical-installment, proposal holds, asset sizes, the merge assignment op, the vendor_metric goal, capabilities implementation, and timezone_cutovers. No rejection on 3.2.x is absent from #8866.

They cover only names the protocol defines elsewhere or forbids there. Following the #8866 review, step, gpc_honored, political, threshold_rate and per_ad_spend are not rejected, and list-application receipts reject auth_token alone. access_token on the delivery-ready webhook stays as a credential clamp.

Key-presence unions. Each branch rejects its sibling's keys by name:

  • account-ref and canonical-account-ref: account_id vs the natural key (brand, operator, operator_unit, currency, timezone, sandbox);
  • geo-region requirement and support countries: all_values vs values;
  • image bleed: uniform vs per-side;
  • postal-area: the deprecated fused-system form has no country;
  • sync_reporting_receipts results: receipt vs adjustment_receipt, and a failed result neither.

Descriptions. Every node or union with a named rejection says what it rejects and why. Two sentences are worded for 3.2.x:

  • the sync_creatives assignment one, because 3.2.x has no merge op;
  • the closed lookup_unavailable branch's statement of its clamp.

#8866's description cleanups are ported too, so opened schemas no longer claim to be closed.

sync_plans reserved names. The opened plan item rejects version, status, syncedAt, revisionHistory, committedBudget and committedByType. They are the governance agent's bookkeeping names, which the plan_hash profile strips from its preimage, so a buyer value under one of them would sit outside the hash. The list matches 3.2's closed "Excluded fields" list. This is ported from #8866 fa7aefacfe, with tests/sync-plans-reserved-names.test.cjs.

Principal results. The get_principal current branch and the sync_principal applied and validated branches open, as on #8866. The validated (dry-run) branch rejects destination_ref and configuration_version.

3.2.x-only deltas

Location On 3.2.x Why
media-buy/get-reporting-status-response.json /oneOf/1/oneOf/0 (unavailable lookup) stays closed Its caller-isolation text requires one identical lookup_unavailable shape for unknown and unauthorized identifiers. On 3.2.x the branch is closed with the envelope redeclared, because the envelope-composition backport was reverted in #8612. 3.3 enforces the same clamp differently: under #8547's envelope rule the branch is open there, with a closed adcp_error/errors[], a const message, and named rejections of ledger_snapshot_id, ledger_as_of and account_id.
media-buy/get-reporting-status-response.json /oneOf/1/oneOf/1 (operational failure) opens Not a privacy shape. The required failure_kind const keeps the two branches disjoint. Already open on main.
brand.json /definitions/identity_relying_party opens An inline object on 3.2.x. On main it is a $ref alias to core/identity-relying-party.json, which is class (a).
core/targeting-overlay-requirements.json description partial port Only the "request shape" → "request schema" wording is ported. The boolean-demographics deprecation (x-deprecated-in: 3.3.0) and the gender-targeting wording in #8866 are 3.3 content and stay out.
core/canonical-installment-ref.json, trust/v1/trust.json n/a Not present on 3.2.x. They are kept closed on 3.3.

Other changes

  • MCP model-context projection. stripModelContextAnnotations now drops boolean additionalProperties, true as well as false. This is the projector change from f5c56db on main. It also omits a named rejection beside declared properties, as it omits bounds, which comes from fix(schemas): open the 3.3 schemas that were meant to be open #8866. Model-context budgets are unchanged. PARITY_COMPILE_LIMIT is also unchanged on 3.2.x; it does not trip.
  • training-agent. The product-discovery tools/list schemas omit additionalProperties: true inside bundled definitions (9c1c52d). Its sync_principal part does not apply, because the 3.2 training agent does not implement sync_principal.
  • Tests mirror fix(schemas): open the 3.3 schemas that were meant to be open #8866's edits for the test files 3.2.x has, citing DR-0009 because DR-0036 is not on 3.2.x:
    • generic unknown-key probes, including those for the dropped rejections, now expect the key to validate;
    • account-ref, canonical-account-ref and image-bleed tests are wired into test:schemas. They load the source schemas, as 3.2.x tests do, because scripts/built-schemas.cjs is not on 3.2.x;
    • the MCP legacy-graph check walks the parsed schema and skips not and descriptions;
    • product-discovery-schema-parity compares openness rather than the literal keyword.

Verification

Head 600458f51d, base 8558eef55d:

Docs. Two separate docs commits correct the closure statements:

  • the refine[] scope branches (refinement.mdx, with the error the opened schema actually gives) and governance policy entries (content-standards/index.mdx) are described as open;
  • the sync_plans plan item (governance/campaign/specification.mdx) is open, so the governance agent's bookkeeping fields are simply undeclared there;
  • the AccountRef variants (protocol/calling-an-agent.mdx) are told apart by named rejections rather than additionalProperties: false.

The wording matches #8866's.

🤖 Generated with Claude Code

bokelley added a commit that referenced this pull request Nov 10, 2026
…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>
@bokelley
bokelley force-pushed the fix/open-closed-schemas-3-2-x branch from 7d52566 to d00f0ad Compare November 10, 2026 16:28
bokelley added a commit that referenced this pull request Nov 12, 2026
* 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>
bokelley and others added 12 commits November 12, 2026 15:11
The WG decided on 2026-11-09 that 3.x opens the schemas that were meant
to be open, so a 3.2 validator does not reject a newer 3.x payload just
because a schema was closed. This is the 3.2.10 backport of the 3.3
opening. additionalProperties goes from false to true at 671 of the 775
closed locations in the 3.2 source tree.

104 locations stay closed, by the keep-closed list approved for 3.3;
every file/pointer the two lines share has the same class: oneOf
branches told apart only by key presence, the signed commercial terms
and the must-understand proposal budget constraint, metric qualifiers
and forecast dimensions (join keys), the JWS response envelope, privacy
boundaries (TMP match requests, the not-found error, permission-denied
and billing-not-permitted details, get_principal and sync_principal
results, the get_reporting_status unavailable lookup), the
credential-free reporting destinations and their setup action,
placement-presentation (no key material or markup), and
patternProperties maps keyed by IDs.

The get_reporting_status unavailable-lookup branch stays closed on 3.2.x
with the envelope redeclared; 3.3 opens it under #8547's envelope rule
and enforces the same clamp with named rejections.

The MCP model-context projection drops boolean additionalProperties,
true as well as false (ported from f5c56db on main), so the opening
does not inflate the prompt view. Tests that pinned closure now assert
the opened behavior or compare against the source schema.

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

Ports #8866's named rejections to 3.2.x for every node that exists
there: where closure was the only thing rejecting a specific field the
protocol defines elsewhere or forbids, the opened schema rejects it by
name in `not`, next to additionalProperties: true. 31 of #8866's 51
named rejections apply on 3.2.x; the rest target schemas or nodes that
3.2.x does not have.

Also ports #8866's description cleanups: opened schemas no longer say
they are closed, and the metric-qualifier descriptions say new keys
ship in a major release. The 3.3-only boolean-demographics deprecation
and gender-targeting wording are not ported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports #8866's test edits for the test files 3.2.x has: generic
unknown-key assertions now expect the key to validate, citing DR-0009
(DR-0036 is not on 3.2.x), and the training agent test shows an unknown
hard overlay requirement still matches no product.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports #8866's 9bda16d and 32768d4 to 3.2.x. Opening exposed
anyOf unions whose branches were told apart only by which keys are
present; each branch now rejects its sibling's keys by name: geo-region
requirement and support countries (all_values vs values), the canonical
account ref (account_id vs brand + operator), the deprecated
fused-system postal area (no country), and sync_reporting_receipts
results (receipt vs adjustment_receipt). Also names `step` on frequency
cap impression constraints and `mode` on list-application receipts.

Tests: adds canonical-account-ref.test.cjs (loading source schemas, as
3.2.x tests do), strips the format-key prohibitions from the MCP
legacy-graph check, and flips the generic unknown-key vectors, citing
DR-0009. PARITY_COMPILE_LIMIT is unchanged on 3.2.x; it does not trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…finitions on 3.2.x

Ports the tools/list and parity-test parts of 9c1c52d (#8866):
bundled definitions in the product-discovery tools/list schemas omit
`additionalProperties: true`, which is JSON Schema's default and carries
no information. The root keeps the keyword. The parity test compares
openness rather than the literal keyword.

The sync_principal part of 9c1c52d does not apply: the 3.2 training
agent does not implement sync_principal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports cd8bc76 (Konstantin Mirin's review of #8866) for every node
3.2.x shares:

- Key-presence guards: account-ref's account_id and natural-key forms
  exclude each other, as canonical-account-ref's now do for all six
  natural-key fields; image bleed is uniform or per-side; a failed
  reporting-receipt result carries no receipt.
- Named rejections only for names the protocol defines elsewhere or
  forbids: step, gpc_honored, political, threshold_rate and
  per_ad_spend are dropped, and list-application receipts reject
  auth_token alone. access_token on the delivery-ready webhook stays as
  a credential clamp.
- Each node or union with a named rejection says in its description
  what it rejects and why. The sync_creatives sentence omits the merge
  op 3.2.x does not have, and the closed lookup_unavailable branch
  states its clamp in 3.2.x terms.
- The get_principal current branch and the sync_principal applied and
  validated branches open; the validated branch rejects destination_ref
  and configuration_version.

The changeset calls the commercial terms a hold until 4.0 rather than
a structural reason. 674 of 775 locations open; 101 stay closed.

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

Ports c01b095 (#8866) for the test files 3.2.x has: probes for the
dropped rejections expect acceptance (DR-0009); account-ref.test.cjs
and image-bleed.test.cjs are new (loading source schemas, as 3.2.x
tests do) and wired into test:schemas; canonical-account-ref covers
the extended guard. The MCP legacy-graph check walks the parsed schema
and skips `not` and descriptions, and the model-context projection
omits named rejections beside declared properties, as it omits bounds.
PARITY_COMPILE_LIMIT is unchanged on 3.2.x; it does not trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The refine[] scope branches and governance policy entries are open on
3.2.x now. A pre-rename refine entry still fails validation, because its
generic `id` doesn't supply the `product_id` or `proposal_id` its scope
requires; the troubleshooting section shows the error the opened schema
gives. A policy-entry field outside the table has no defined meaning, so
receivers ignore it; partner metadata still belongs under `ext`.

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

The sync_plans plan item is open on 3.2.x, so the governance agent's
bookkeeping fields are simply not declared there, rather than excluded
by closure. The two AccountRef variants are told apart by named
rejections: the account_id variant rejects the natural-key fields and
the natural-key variant rejects account_id, so {account_id, brand}
still fails both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aligns the refine troubleshooting, policy-entry, sync_plans and
AccountRef passages with #8866 (6c689cc), including the two
calling-an-agent error-table rows that named additionalProperties.

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

Ports fa7aefa (#8866). 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 3.2's closed "Excluded fields" list. No storyboard, fixture
or request example sends them. The test loads source schemas, as 3.2.x
tests do, and cites DR-0009.

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

Ports 7d4dd1b (#8866): the heading names the error the opened refine
branches give, and the text says which identifier each scope requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bokelley
bokelley force-pushed the fix/open-closed-schemas-3-2-x branch from e1199d3 to 600458f Compare November 12, 2026 15:15
@bokelley
bokelley marked this pull request as ready for review November 12, 2026 15:15

@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 review.

This PR is a 332-file 3.2.x backport mirroring #8866's open-closed-schema decision (ratified WG 2026-11-09), opening additionalProperties: false→true in 674 of 775 locations while keeping 101 closed. The reviewer verified the load-bearing cases hold (fail-closed privacy clamps, not-based oneOf disjointness, schema↔docs coherence, changeset present, no dist/** mutation) and surfaced no Critical/High/Medium findings.

However, the PR touches hundreds of files under static/schemas/source/**, which are under a hard, deterministic approval gate (gated_paths: true), and review_decision is unknown/none — not APPROVED. Per decision-table row 2, a gated-paths PR cannot be approved until a real human/CODEOWNERS approval satisfies the gate. Additionally, the repo's constitution treats this protocol-surface wire-shape change as a governance/ratification call (patch-eligibility and Breaking-class classification are human acts), reinforcing that a human must sign off.

No blocking code defects were found, so this is not request-changes — it is a clean diff awaiting the required human review on gated protocol-surface files.

Why human review

  • Gated paths touched (static/schemas/source/** — 332 protocol-surface schema files) and review_decision is not APPROVED; human/CODEOWNERS approval required before merge (decision-table row 2).
  • Protocol wire-shape change (open-closed-schema backport) is a governance/ratification call per the constitution's Breaking-class hard gate — ratification is a human act.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/aao/agent-publishers.json (modified) matches static/schemas/source/**; static/schemas/source/account/sync-governance-request.json (modified) matches static/schemas/source/**; static/schemas/source/account/sync-governance-response.json (modified) matches static/schemas/source/**; static/schemas/source/brand.json (modified) matches static/schemas/source/**; static/schemas/source/collection/base-collection-source.json (modified) matches static/schemas/source/**; static/schemas/source/collection/collection-list-changed-webhook.json (modified) matches static/schemas/source/**; static/schemas/source/collection/collection-list-filters.json (modified) matches static/schemas/source/**; static/schemas/source/collection/collection-list.json (modified) matches static/schemas/source/**; static/schemas/source/collection/get-collection-list-request.json (modified) matches static/schemas/source/**; static/schemas/source/collection/get-collection-list-response.json (modified) matches static/schemas/source/**; 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/content-standards/get-media-buy-artifacts-request.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-change-recorded-webhook.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-identity-change-preview.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-identity-change.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-ref.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-status-changed-webhook.json (modified) matches static/schemas/source/**; static/schemas/source/core/account-timezone-capability.json (modified) matches static/schemas/source/**; static/schemas/source/core/account.json (modified) matches static/schemas/source/**; static/schemas/source/core/agent-encryption-key.json (modified) matches static/schemas/source/**; static/schemas/source/core/agent-notification-

…(truncated)…

@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Nov 12, 2026
@bokelley
bokelley merged commit a07826a into 3.2.x Nov 12, 2026
51 checks passed
@bokelley
bokelley deleted the fix/open-closed-schemas-3-2-x branch November 12, 2026 16:00
bokelley added a commit that referenced this pull request Nov 12, 2026
…lease docs

After rebasing onto main with #8866 merged:

- Take #8866's wording for the boolean form of demographics in the
  migration guide's Deprecations section, and align the release notes and
  What's new with it (#8778 tracks the 4.0 removal).
- 3.2.10 shipped without the schema opening, so say "the next 3.2.x patch
  (#8864)" and "3.2.10 and earlier", including in #8866's
  Schemas-are-open-by-default bullet.
- Drop the dependency markers #8866 satisfied, and retarget the rest.
- Cover the other changes merged for rc.0: origin-only authorized_agents
  URLs (#8939), declared-option creative conformance (#8941), TMP cache
  isolation (#7446), creative.supports_registry_policy_enforcement
  (#8857), 3gp/mpeg/m4v containers (#8668), carousel card_image_sizes
  (#8937), and the loosened URL patterns (#8792).
- Refresh the in-review table against the 3.3.0 milestone on 2026-11-12,
  and remove the stray duplicate table header it carried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…lease docs

After rebasing onto main with #8866 merged:

- Take #8866's wording for the boolean form of demographics in the
  migration guide's Deprecations section, and align the release notes and
  What's new with it (#8778 tracks the 4.0 removal).
- 3.2.10 shipped without the schema opening, so say "the next 3.2.x patch
  (#8864)" and "3.2.10 and earlier", including in #8866's
  Schemas-are-open-by-default bullet.
- Drop the dependency markers #8866 satisfied, and retarget the rest.
- Cover the other changes merged for rc.0: origin-only authorized_agents
  URLs (#8939), declared-option creative conformance (#8941), TMP cache
  isolation (#7446), creative.supports_registry_policy_enforcement
  (#8857), 3gp/mpeg/m4v containers (#8668), carousel card_image_sizes
  (#8937), and the loosened URL patterns (#8792).
- Refresh the in-review table against the 3.3.0 milestone on 2026-11-12,
  and remove the stray duplicate table header it carried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…se docs

- #8858 merged: drop its markers on the 3.3 support window and the
  daily-budget spec.
- #8864 merged into 3.2.x, so the schema opening ships in 3.2.11: say
  "3.2.11 (#8864)" instead of "the next 3.2.x patch", with one marker per
  page on the 3.2.11 release itself (Version Packages #8942).
- target_audiences on list_products offer_filters is decided: it stays as
  it is in 3.3, and any change is 4.x, so media_buy.audience_evidence_targets
  has no 3.3 surface once the get_products and create_media_buy copies leave.
- The available_installment_statuses move is a 3.3 RC item; its markers
  now point at c4777ebd's PR, and the release-notes installment_lifecycle
  row carries a marker to move to the canonical location when it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…lease docs

After rebasing onto main with #8866 merged:

- Take #8866's wording for the boolean form of demographics in the
  migration guide's Deprecations section, and align the release notes and
  What's new with it (#8778 tracks the 4.0 removal).
- 3.2.10 shipped without the schema opening, so say "the next 3.2.x patch
  (#8864)" and "3.2.10 and earlier", including in #8866's
  Schemas-are-open-by-default bullet.
- Drop the dependency markers #8866 satisfied, and retarget the rest.
- Cover the other changes merged for rc.0: origin-only authorized_agents
  URLs (#8939), declared-option creative conformance (#8941), TMP cache
  isolation (#7446), creative.supports_registry_policy_enforcement
  (#8857), 3gp/mpeg/m4v containers (#8668), carousel card_image_sizes
  (#8937), and the loosened URL patterns (#8792).
- Refresh the in-review table against the 3.3.0 milestone on 2026-11-12,
  and remove the stray duplicate table header it carried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…se docs

- #8858 merged: drop its markers on the 3.3 support window and the
  daily-budget spec.
- #8864 merged into 3.2.x, so the schema opening ships in 3.2.11: say
  "3.2.11 (#8864)" instead of "the next 3.2.x patch", with one marker per
  page on the 3.2.11 release itself (Version Packages #8942).
- target_audiences on list_products offer_filters is decided: it stays as
  it is in 3.3, and any change is 4.x, so media_buy.audience_evidence_targets
  has no 3.3 surface once the get_products and create_media_buy copies leave.
- The available_installment_statuses move is a 3.3 RC item; its markers
  now point at c4777ebd's PR, and the release-notes installment_lifecycle
  row carries a marker to move to the canonical location when it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…lease docs

After rebasing onto main with #8866 merged:

- Take #8866's wording for the boolean form of demographics in the
  migration guide's Deprecations section, and align the release notes and
  What's new with it (#8778 tracks the 4.0 removal).
- 3.2.10 shipped without the schema opening, so say "the next 3.2.x patch
  (#8864)" and "3.2.10 and earlier", including in #8866's
  Schemas-are-open-by-default bullet.
- Drop the dependency markers #8866 satisfied, and retarget the rest.
- Cover the other changes merged for rc.0: origin-only authorized_agents
  URLs (#8939), declared-option creative conformance (#8941), TMP cache
  isolation (#7446), creative.supports_registry_policy_enforcement
  (#8857), 3gp/mpeg/m4v containers (#8668), carousel card_image_sizes
  (#8937), and the loosened URL patterns (#8792).
- Refresh the in-review table against the 3.3.0 milestone on 2026-11-12,
  and remove the stray duplicate table header it carried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…se docs

- #8858 merged: drop its markers on the 3.3 support window and the
  daily-budget spec.
- #8864 merged into 3.2.x, so the schema opening ships in 3.2.11: say
  "3.2.11 (#8864)" instead of "the next 3.2.x patch", with one marker per
  page on the 3.2.11 release itself (Version Packages #8942).
- target_audiences on list_products offer_filters is decided: it stays as
  it is in 3.3, and any change is 4.x, so media_buy.audience_evidence_targets
  has no 3.3 surface once the get_products and create_media_buy copies leave.
- The available_installment_statuses move is a 3.3 RC item; its markers
  now point at c4777ebd's PR, and the release-notes installment_lifecycle
  row carries a marker to move to the canonical location when it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…lease docs

After rebasing onto main with #8866 merged:

- Take #8866's wording for the boolean form of demographics in the
  migration guide's Deprecations section, and align the release notes and
  What's new with it (#8778 tracks the 4.0 removal).
- 3.2.10 shipped without the schema opening, so say "the next 3.2.x patch
  (#8864)" and "3.2.10 and earlier", including in #8866's
  Schemas-are-open-by-default bullet.
- Drop the dependency markers #8866 satisfied, and retarget the rest.
- Cover the other changes merged for rc.0: origin-only authorized_agents
  URLs (#8939), declared-option creative conformance (#8941), TMP cache
  isolation (#7446), creative.supports_registry_policy_enforcement
  (#8857), 3gp/mpeg/m4v containers (#8668), carousel card_image_sizes
  (#8937), and the loosened URL patterns (#8792).
- Refresh the in-review table against the 3.3.0 milestone on 2026-11-12,
  and remove the stray duplicate table header it carried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 12, 2026
…se docs

- #8858 merged: drop its markers on the 3.3 support window and the
  daily-budget spec.
- #8864 merged into 3.2.x, so the schema opening ships in 3.2.11: say
  "3.2.11 (#8864)" instead of "the next 3.2.x patch", with one marker per
  page on the 3.2.11 release itself (Version Packages #8942).
- target_audiences on list_products offer_filters is decided: it stays as
  it is in 3.3, and any change is 4.x, so media_buy.audience_evidence_targets
  has no 3.3 surface once the get_products and create_media_buy copies leave.
- The available_installment_statuses move is a 3.3 RC item; its markers
  now point at c4777ebd's PR, and the release-notes installment_lifecycle
  row carries a marker to move to the canonical location when it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant