Skip to content

Minor releases sometimes break older buyers, and our versioning rules disagree about whether that's allowed #8501

Open

Description

@KonstantinMirin

The problem

We say a minor release only adds things, so a buyer built for 3.0 keeps working against a 3.2 seller. In practice it sometimes doesn't.

Some of our schemas are published as closed. A closed schema tells a validator to reject any field it doesn't recognize. When a later minor adds a field to a closed schema, a buyer that validates against its own release rejects the newer response. That's a breaking change, even though the field is optional.

This has happened in every minor so far. Two examples:

  • The brand reference was closed in 3.0. It gained brand_kit_override in 3.1 and countries in 3.2.
  • The account reference (the brand + operator form) was closed in 3.0. It gained currency, timezone and operator_unit in 3.2.

A check that compares each release with the previous one (#8502) counts the changes that aren't additive. Experimental features are left out, because they're allowed to change:

From → to Changes that aren't additive
3.0 → 3.1 79
3.1 → 3.2 70
3.2 → 3.3 beta 41

Why it keeps happening: two rules that disagree

Each rule makes sense on its own. Together they allow minor releases that break older buyers, and implementers can't tell which rule to rely on. The cost shows up elsewhere. Sellers have to shape responses to each buyer's release (DR-0024). Requests that only say "version 3" now get the oldest release (DR-0034). And DR-0032 proposes translation code in every SDK.

Proposal

  1. One rule: a minor release never breaks a buyer that validates against its own release. A closed schema stays as it is until the next major. New fields go into an open schema, a new schema, or the next major.
  2. Update DR-0019 to match. Its idea of closed schemas can stay; closed just means frozen within a major.
  3. Check it in CI (build(schemas): fail CI when a minor release makes a non-additive schema change #8502). The changes already made are listed in a baseline that can only shrink, so nothing fails today and nothing new slips in.
  4. Before 3.3 is final, decide what to do with each field 3.3 adds to a closed schema: move it, send it only to buyers on 3.3, or leave it for 4.0.

I'm happy to do the follow-up work.

Activity

  1. bokelley commented on Oct 26, 2026

    @bokelley
    Contributor

    WG Session C (2026-10-26) accepted the problem. Adding a property to a schema published with additionalProperties: false breaks older strict validators, exactly as removing a field does.

    • One rule: a minor never adds a property to, or removes one from, a closed schema. A closed schema is frozen until the next major.
    • DR-0019 is to be updated to match.
    • CI check: build(schemas): fail CI when a minor release makes a non-additive schema change #8502, with a baseline that can only shrink.
    • New schemas default to open (DR-0009) unless there's a stated reason to close them.
    • Owner: @KonstantinMirin owns the triage of the 3.3 additions to closed schemas (move it, send it only to 3.3 buyers, or defer it to 4.0), due before 3.3 GA.

    DR-0032 and DR-0033 are parked until this is settled.

  2. KonstantinMirin commented on Oct 26, 2026

    @KonstantinMirin
    CollaboratorAuthor

    Thanks for taking this up at Session C. Here's the triage I owe for the 3.3 additions to closed schemas.

    The rule I applied: a minor release only adds, and it never adds to a closed schema (additionalProperties: false). A closed schema stays exactly as it is until 4.0. I didn't make exceptions for fields sent only to 3.3 peers, or for experimental fields, because either one would still break a strict 3.2 validator.

    For each of the 57 new fields on closed schemas there are two outcomes. Either the field moves to the nearest open object that contains its closed parent, keeping its meaning, or it waits for 4.0. 15 move and 42 wait. The evaluator value removed from the x-entity registry comes back.

    Most of the 42 share one cause. In 3.2, list_products, request_proposals, refine_proposals, buy_products, accept_proposal, decline_proposals and control_media_buy were published closed from the request or response object down. So proposals, purchases and commercial terms have no open place to grow in 3.x. DR-0019 asks for roots and containers to stay open, so I'd treat that as something to reopen in 4.0, together with declared extension points, rather than as anyone's mistake today.

    Feature 3.3 outcome
    Minute dayparts (#8025) Moves: a new daypart_windows on targeting, with the granularity on overlay_support and get_products
    Exact package forecast (#8468) Moves: package_forecasts[] and package_forecast_results[] on get_products
    Spot lifecycle capability (#8017) Moves: onto reporting_capabilities
    Collection-list and gender requirements (#8061, #7925) Move: onto the get_products request
    Review SLAs (#8417) Narrowed: business time moves to the product's creative policy; per-action SLAs wait
    DOOH summary, collection cards, lineage, expected_confirmation_at, the creative start policy, metric_id, assignment landing page and trackers, webhook signing_profile Narrowed: these ship where their schemas are open, and the copies on closed schemas wait
    Seller offers (#8103) Ships; later-proposal consent waits
    Holds, installment selection, purchase rights, definition pins, the list_products version echo, product_ids_exclusive Wait for 4.0

    The full per-field list, with the open object each field moves to and the reason for each deferral, is in this gist.

    Follow-ups I'll open:

    • DR-0036: a minor adds only to open schemas; a closed schema stays as it is until the next major, including its closedness, so opening it doesn't allow later additions; new schemas default to open. It replaces DR-0019's "additions to closed schemas are minor" and keeps its two classes.
    • A fix to the build(schemas): fail CI when a minor release makes a non-additive schema change #8502 check: treat a schema as closed if any stable release of the major closed it. Today the check compares only with 3.2.7, which is how one case slipped through: the capabilities identity block was closed in 3.0.0, opened in 3.0.5, and gained brand_json_url in 3.1.0.
    • The changes themselves: restore evaluator, remove the deferred fields with the capability flags of the features that wait, and one PR per moved feature, agreed with its owner first.

    @bokelley, I know this costs 3.3 features the group already agreed on, and I'm sorry to bring it this late. Could you check the list before we cut 3.3.0-beta.1? Six features wait for 4.0, and the moves change the wire form of #8025 and #8468, so their owners should see it too. I'm happy to walk through any of it.

  3. bokelley commented on Oct 27, 2026

    @bokelley
    Contributor

    Thanks, Konstantin. This is careful work. I'd accept the analysis method, the 15 moves, the narrowings, the evaluator restore and the check fix (closed anywhere in the major) as written. The identity case shows why the fix matters.

    Before we accept the 42 deferrals, I'd like to question their main cause rather than live with it until 4.0. Most of them, and all six features that slip (holds, installment selection, purchase rights, definition pins, the list_products version echo, product_ids_exclusive), come from one thing: the 3.2 proposal flow was published closed from the root down. As far as I can find, nobody decided that, and it contradicts our own records.

    What the records say:

    • DR-0009: schemas are open by default, so that a minor can add optional fields.
    • DR-0019: allows additionalProperties: false only on row schemas: join-key objects, or row envelopes that keep an ext escape hatch. It also says outright that "response roots, capability blocks, and container objects stay open."

    What 3.2 shipped:

    Schema Closed ext
    request_proposals request (root) yes no
    request_proposals response (root) yes yes
    list_products request (root) yes no
    buy_products request (root) yes yes
    canonical-proposal (container) yes no
    commercial-terms yes no
    canonical-product yes yes

    The roots and containers are closed, which DR-0019 says they must not be. Several of them also lack the ext slot DR-0019 requires of a closed envelope. None carries a note explaining why. I read this as a 3.2 defect, not a deliberate design.

    One exception is deliberate in substance: commercial-terms. A buyer must not be bound by terms it can't read, and those terms are what terms_digest signs. If the object were open, a 3.2 buyer could accept a 3.3 term (rights, pins, installments) it silently ignored. Exhaustive keys there fit DR-0019's join-key class, and I'd keep it closed.

    Proposal:

    1. Fix the defect in 3.2.x and 3.3. Open the proposal-flow roots, rows and containers (the canonical discovery and proposal task roots, canonical-proposal, canonical-product, product-discovery-criteria, proposal-refinement, package-control), and keep commercial-terms closed. Loosening is non-breaking under DR-0019: anything valid before stays valid. These tasks are new in 3.2, so the strict validators that exist for them are almost all the SDKs, and we'll patch those.
    2. 3.3 fields on the opened objects go only to peers that negotiated 3.3. DR-0024 already requires responses, webhooks included, to conform to the served release. Every counterpart on these tasks must advertise supported_versions (the 3.2 grader blocks otherwise), so negotiation is reliable here. An un-updated strict 3.2.0–3.2.7 validator therefore never sees a 3.3 field from a conformant seller.
    3. Term-level 3.3 features (definition pins, purchase rights, installments in purchases[]) are offered only to buyers that negotiated 3.3. A seller never serves a pre-3.3 peer a proposal whose commercial-terms uses them. It returns VERSION_UNSUPPORTED for that proposal instead of stripping terms, which would also break terms_digest. This keeps the reason the object is closed: nobody receives terms they can't read.
    4. build(schemas): fail CI when a minor release makes a non-additive schema change #8502 treats the proposal-flow objects opened in step 1 as open from 3.3 on, applies the strict rule everywhere else, and records each property added under step 3 with an explicit negotiated-since marker, so the exception stays narrow and checkable.

    What this costs:

    • It contests the "opening a closed schema permits nothing within the major" part of the rule. That needs the group's agreement and probably an amendment to the DR-0036 you're drafting.
    • A third-party strict validator pinned to 3.2.0–3.2.7 that never takes the errata could still reject a field, but only if a non-conformant seller ignores the served release.

    What it buys:

    • All six features stay in 3.3. Definition pins matter most, because the 3.3 docs list them as required behavior.
    • The proposal flow complies with DR-0019 now instead of carrying the defect to 4.0.
    • Your M1 point still applies to everything else: a moved field on an open object is ignored rather than rejected, so negotiation-aware senders are needed either way.

    If the group prefers the strict rule without this exception, I'll take your list as is. Either way, can we settle it at the next session, or async this week, so 3.3.0-beta.1 isn't blocked? I'm happy to write the errata PR and the #8502 changes if we go this way.

  4. KonstantinMirin commented on Oct 27, 2026

    @KonstantinMirin
    CollaboratorAuthor

    Thanks, Brian. You're right about the cause. DR-0019 says roots and containers stay open, and nobody decided to close the 3.2 proposal flow. #8518 shows the same closure even blocks the version echo the versioning page requires. So I'd treat it as a defect to correct, not a rule to live with.

    Where I land on your four steps:

    1. Reopen the proposal-flow roots, rows and containers: yes, as a one-time correction. DR-0036 will record it as exactly that, with the list of reopened schemas and the reason (they contradicted DR-0019). The general rule stays as accepted on Monday: a minor adds only to open schemas, and a closed schema stays closed until the next major.
    2. 3.3 fields on the reopened objects go only to 3.3 peers: yes. DR-0024 already requires it, and DR-0034 covers requests that only say "version 3". I accept that this relies on sellers shaping responses for the reopened objects. That's the price of correcting the defect inside 3.x.
    3. Adding to commercial-terms in 3.3: no. It's the one object closed on purpose, for the reason you gave: a buyer must not be bound by terms it can't read. Adding fields to it in a minor, and relying on negotiation to keep that safe, brings back the exception we decided against on Monday, for exactly the object where it matters most. So definition pins, purchase rights, and choosing installments inside purchases[] wait for 4.0. In 4.0, commercial-terms gets a declared extension point with must-understand, which is what binding terms need.
    4. Per-field "negotiated-since" markers in build(schemas): fail CI when a minor release makes a non-additive schema change #8502: not needed. Without step 3, the check only needs two changes. It counts a schema as closed if any stable release of the major closed it, and it reads the fixed list of reopened schemas from DR-0036.

    With that, holds, the list_products version echo, product_ids_exclusive, and the installment parts on products and refinement all stay in 3.3. Pins, rights, and installment selection move to 4.0.

    I'll do the work: the reopening PR, DR-0036, and the check change. I'll link them here.

  5. KonstantinMirin commented on Oct 27, 2026

    @KonstantinMirin
    CollaboratorAuthor

    The three PRs are up:

    Two updates to my earlier comment. Installment selection waits for 4.0 as a whole: its refinement fields are checked against the installments in purchases[], which wait, so they can't ship alone. The installment fields on products stay. Later-proposal consent does ship: reopening opportunity-context lets it through. @bokelley, can you confirm you're OK with that?

    On #8523 and #8524: they implement correction (b), so they add their entries to the corrections file that #8530 introduces. Once #8531 lands, #8523 may need fewer entries, because (a) already covers the proposal-flow responses.

  6. bokelley commented on Oct 27, 2026

    @bokelley
    Contributor

    Maintainer decisions (2026-10-27): aligned with your plan, @KonstantinMirin.

    1. DR-0036 one-time correction: yes. Reopen the 3.2 proposal flow (build(schemas): keep closed schemas closed within a major, with recorded corrections #8530, fix(schemas): reopen the 3.2 proposal-flow schemas closed against DR-0019 #8531, fix(schemas): reopen the proposal-flow schemas closed against DR-0019 on 3.2.x (#8501) #8532). I'll merge them as they go green; they touch gated paths.

    2. Later-proposal consent ships in 3.3: confirmed (opportunity-context reopened).

    3. commercial-terms stays closed: agreed. Moving to 4.0, where commercial-terms gets a declared extension point with must-understand:

      Staying in 3.3, as you listed: holds, the list_products version echo, product_ids_exclusive, and the installment fields on products and in refinement.

    4. feat(media-buy): seller offers on accepted buys #8102 splits: the offer lane ships where its fields land on reopened, non-commercial-terms objects. The seller-held allowance lane (holder/purchase_index on change-term, inside commercial terms) moves to 4.0.

    5. Capabilities byte cap (Spec tension: creative.supported_formats pushes capabilities past the 64 KiB that gates signing-key discovery #8198/spec(capabilities): structural bounds are the limit; the byte cap is a deployment backstop #8526): see Spec tension: creative.supported_formats pushes capabilities past the 64 KiB that gates signing-key discovery #8198. It stays as a backstop only.

  7. bokelley commented on Oct 30, 2026

    @bokelley
    Contributor

    4.0 work list from this thread, async (the Nov 2 session is cancelled; objections and owner volunteers by Fri 2026-11-06):

    1. commercial-terms gets a declared extension point with must-understand. It brings back definition pins, purchase rights, installment selection in purchases[], and seller-held adjustable terms (holder/purchase_index). Proposed owner: @KonstantinMirin.
    2. Reopen closed roots and containers under DR-0019, beyond the DR-0036 corrections, together with declared extension points.
    3. Enforce maxItems/maxLength on stable fields from the bounds inventory. 3.3 enforces bounds only on new and experimental fields.
    4. Property and collection lists are always passed by reference, never inline.
    5. Remove the deprecated surfaces: adcp_major_version, the natural-key account reference after provisioning, the identity-rekey machinery, principal_kind, and the RFC 9421 signing profiles.

    Tracked in the v4 compatibility registry. Reply with objections or to take an item.

  8. bokelley commented on Oct 31, 2026

    @bokelley
    Contributor

    @KonstantinMirin: one ask on the GA path for 3.3 (#8600). scripts/lint-additive-minor-baseline.json still has 26 entries marked "pending WG decision". Could you post a disposition table here: each entry with one of (a) move to the nearest open parent, (b) record a DR-0036 correction, with the spec text it restores, or (c) defer to 4.0 and withdraw from 3.3? We'll approve it by consent, with objections by Fri 2026-11-13, and land the moves before the GA beta (target: week of Nov 16). Happy for you to own the PRs, or tell us which ones you'd like taken off your plate.

  9. KonstantinMirin commented on Nov 2, 2026

    @KonstantinMirin
    CollaboratorAuthor

    Happy to take item 1, thanks for offering it.

    I'd like to do it as a module, per #8359, rather than as an extension point added to a closed schema. So commercial-terms would get its own identity and version, and core would declare the extension point it attaches to, so core doesn't change when the module does.

    On must-understand, I'd read it as one thing here: a receiver that doesn't recognize a declared extension refuses the terms. That follows from what you've already set up, since terms_digest signs these terms and a buyer shouldn't be bound by terms it can't read.

    I'll put it up as its own PR so you can see how it holds together. If it works, I think it could be a template for later modules. Let me know what you think.

  10. KonstantinMirin commented on Nov 3, 2026

    @KonstantinMirin
    CollaboratorAuthor

    A correction on item 1. I said I'd do commercial-terms as a module, and I built it that way, but an audit against #8359 showed it isn't one. It's an extension point with four extensions. I don't think we can create a real module until the schemas themselves are layered, and I've written that up on #8359: #8359 (comment)

    I'm still happy to own item 1 as an extension point and four extensions, and I'd sequence it behind a clear boundary around what terms_digest covers.

  11. KonstantinMirin commented on Nov 3, 2026

    @KonstantinMirin
    CollaboratorAuthor

    Hi Brian,

    Before I post the disposition table, there's one thing I'd like to raise, because it affects most of the table.

    Deprecated surfaces are where I'd like to disagree. I don't think we should add fields to them. It keeps the old surface growing while we're asking people to move off it, and every field that exists only there is a new gap for anyone migrating. 3.3 currently adds these, compared with 3.2.8:

    Deprecated surface Added in 3.3 On a replacement?
    create_media_buy predecessor_media_buy_id, lineage_reason Yes: buy_products, accept_proposal
    create_media_buy expected_confirmation_at (response) Yes: buy_products, accept_proposal
    create_media_buy artifact_webhook.signing_profile No, and artifact_webhook itself isn't on them
    create_media_buy, update_media_buy start_requires_all_creatives_approved on packages control_media_buy yes, buy_products no
    create_media_buy, update_media_buy target_audiences on packages No
    get_products include_collections, collections (response) Yes: list_products, request_proposals, refine_proposals
    get_products filters.target_audiences No
    get_products include_execution_readiness, execution_readiness (response) No
    get_products refine[].package, refinement_applied[].result_product_id, resolved_start_time, resolved_end_time No
    sync_creatives assignments[] trackers, landing_page_url Yes: assignment_operations

    I'd suggest withdrawing all of these from the deprecated surfaces. 3.3 is still in beta, so that breaks no stable release, and the collections, readiness and target_audiences fields are experimental anyway. Where a replacement doesn't have a field yet, I'd add it there, so the new surface is where the new capability lives.

    Opening the closed 3.2 schemas is what makes this possible, and with so few 3.2 implementers so far, I don't think closure should stop us, as long as each one is recorded in DR-0036. The additive-minor guard covers this going forward, and I'd keep commercial-terms closed because terms_digest signs it. The get_products page says target_audiences waits for 4.0 on buy_products and list_products because their schemas are closed, so today closure is what pushes new capability onto the old tasks. Readiness looks straightforward: list_products already takes account and returns execution_requirements, and its root is open. The exact-package forecast is the one I can't place. I don't see an obvious home for it on the discovery tasks, so I'd really like your view on where it should go.

    I'm not asking to fork shared schemas. A field that reaches a deprecated task through a type it shares with live tasks, like core/targeting.json or core/reporting-webhook.json, should stay, because a second copy would be worse.

    3.2 and 3.3 need to stay interoperable. When I raised #7403 in September, #7444 covered most of it, and the compatibility doc now says a facade preserves a field or rejects it, but never drops it. I'd like that to stay true through 3.3. The doc doesn't mention 3.3 yet, and some fields aren't covered: filters.audience_activation_methods, for example, has no compact member and no obligation. So I'd suggest that every field a buyer can send to get_products at 3.2 or 3.3 has a stated outcome in that doc: a compact field, a facade obligation, or a rejection at its path. I also still owe you the scenarios you asked me to open as a PR on #7403, and I'll do that.

    For the GA criteria in #8600, I'd propose adding two things: no 3.3 field exists only on a deprecated surface, and the compatibility doc covers every get_products field.

    The table for the 26 entries will follow from this. Does this seem reasonable to you? Please tell me if there's a reason some of these need to stay on the deprecated surfaces.

  12. KonstantinMirin commented on Nov 3, 2026

    @KonstantinMirin
    CollaboratorAuthor

    Hi Brian,

    Here's the disposition table you asked for on Oct 31. It follows the position in my earlier comment: no new fields on deprecated tasks, and the commercial-terms root stays closed. Everything else stays in 3.3 where you put it.

    Result: 11 entries stay, 2 move, 12 are withdrawn and 1 is restored.

    I decided each entry with four rules, in this order:

    1. A published enum value that 3.3 removed comes back.
    2. A field on a deprecated task leaves it. If the need is real and no live task has the field, it goes on the replacement.
    3. A field that changes the meaning of a signed field leaves. The digest proves the bytes didn't change, but it can't stop a buyer from misreading them.
    4. Everything else stays, and DR-0036 records the reopening.

    How the 11 entries stay. Nine of them sit on schemas that DR-0019 says should be open. It says "Response roots, capability blocks, and container objects stay open", and "A Class B schema without an escape hatch is a defect." That's the same basis as the proposal-flow correction we agreed on Oct 27, so I'd record these as one more correction of the same kind. The other two are the trackers and landing_page_url fields on assign. No published text required them, and DR-0019 allows a discriminated-union branch to stay closed. So I'd keep that branch closed and record just those two names as a named exception. sync_creatives is where assignment settings belong, and #8695 builds on them.

    What differs from the triage you accepted on Oct 27:

    • Minute dayparts, the spot capability and the overlay requirement filters stay where you put them. The triage moved them to new fields, so this saves a wire change.
    • The assign fields stay. The triage withdrew them.
    • The exact-package forecast leaves get_products. Where it goes is the open question from my earlier comment.
    • Lineage, collection cards and the creative start policy leave the deprecated tasks and stay on the live ones. The triage let them ship wherever the schema was open.

    Everything else in the triage stands. All of this is in the 3.3 betas, so no stable release breaks.

    Entries 1 to 5 are narrowings you already accepted, so they go unless you'd like to keep one. Entry 1 is the one I'd give back first, because #8696 asserts on it.

    Paths are under static/schemas/source/.

    # Field Decision What happens, and why
    1 compliance/comply-test-controller-response.json, forced.proposal_id Withdraw The controller returns the proposal ID in simulated, which holds "Values injected or applied by this call". hold_unavailable_batch.yaml reads it there. forced.arm also loses the unable value 3.3 added.
    2 core/agent-notification-config.json, signing_profile Withdraw It stays on push_notification_config and reporting_webhook. A per-row profile only matters until 4.0 removes the RFC 9421 profile. This row has ext, so DR-0019 lets it stay closed.
    3 core/notification-config.json, signing_profile Withdraw Same as 2.
    4 core/canonical-media-buy-action-fields.json, review_sla Withdraw The product's creative_policy.review_sla already carries this value, and a buy doesn't change it.
    5 core/media-buy-available-action.json, review_sla Withdraw Same as 4. get_media_buys accepts either row, so 4 and 5 go together.
    6 core/canonical-performance-standard.json, metric_id Withdraw, add to the 4.0 list It selects which vendor number decides a signed performance standard. A 3.2 buyer would read the same standard differently.
    7 core/daypart-target.json, start_time Stay, schema opens DR-0019 calls a row with no ext a defect. The oneOf still rejects a window that mixes hours and minutes.
    8 core/daypart-target.json, end_time Stay, schema opens Same as 7.
    9 core/targeting-overlay-requirements.json, daypart requirement time_granularity Stay, branch opens It's part of a requirements container, and DR-0019 keeps containers open.
    10 core/targeting-overlay-support.json, daypart support time_granularity Stay, branch opens It's a capability block, and DR-0019 keeps those open.
    11 core/sla-window.json, clock Move to core/creative-review-sla.json creative_policy.review_sla keeps business time. sla-window goes back to its 3.2.8 form, and escalation-sla loses clock. The signed terms use sla-window through change_terms[].processing_sla, and 3.2.8 says "Sellers include weekends and non-working periods in the maximum."
    12 core/sla-window.json, business_calendar_id Move with 11 Same as 11.
    13 core/spot-reporting-capability.json, available_statuses Stay, schema opens It's a capability block with no ext. Canonical products keep it as well.
    14 core/spot-reporting-capability.json, supports_break_position Stay, schema opens Same as 13.
    15 core/targeting-overlay-requirements.json, collection_lists Stay, schema opens It's a container. A seller still won't match a product against a requirement it doesn't recognize.
    16 core/targeting-overlay-requirements.json, collection_lists_exclude Stay, schema opens Same as 15.
    17 core/targeting-overlay-requirements.json, demographics requirement gender Stay, branch opens One catch: in 3.2, a product's demographics: true means age, but it matches a gender requirement. The schema description needs an exception for that, and seller matching has to follow it. The training agent needs the same fix.
    18 creative/sync-creatives-request.json, assign landing_page_url Stay, named exception The branch stays closed and takes this one name. Sellers declare support with supports_assignment_landing_page.
    19 creative/sync-creatives-request.json, assign trackers Stay, named exception Same as 18, with supports_assignment_trackers.
    20 creative/sync-creatives-request.json, assignments[] landing_page_url Withdraw assignments[] is deprecated, and assign has the field. No storyboard sends it on assignments[].
    21 creative/sync-creatives-request.json, assignments[] trackers Withdraw Same as 20.
    22 media-buy/get-products-request.json, refine[].package Withdraw from get_products media-buy/package-forecast-input.json goes too, because nothing else uses it. Its home is the open question. Wherever it lands, it has to carry the goal, because #8448 says "A guaranteed forecast depends on the goal".
    23 media-buy/get-products-response.json, refinement_applied[].result_product_id Withdraw with 22 It only answers refine[].package.
    24 media-buy/get-products-response.json, refinement_applied[].resolved_start_time Withdraw with 22 Same as 23.
    25 media-buy/get-products-response.json, refinement_applied[].resolved_end_time Withdraw with 22 Same as 23.
    26 core/x-entity-types.json, value evaluator Restore It comes back as a deprecated value, with its definition. The evaluator_id removal stands. 3.2.8 says "Existing values are never removed or renamed."

    Deprecated-task fields outside the 26. The baseline doesn't list these, because their schemas are open. The same rules apply.

    Field Where Decision
    predecessor_media_buy_id, lineage_reason create_media_buy Withdraw. buy_products and accept_proposal keep them.
    artifact_webhook.signing_profile create_media_buy Withdraw. No live task has artifact_webhook.
    start_requires_all_creatives_approved create_media_buy, update_media_buy packages Withdraw. control_media_buy keeps it, and it doesn't need to be on the purchase, because it "does not change accepted commercial terms".
    target_audiences create_media_buy, update_media_buy packages Withdraw, add to the 4.0 list. The v4 registry entry purchase_target_audiences_required_in_4_0 says a purchase must record it, and the purchase is signed. My earlier comment said reopening makes room for this field. It doesn't.
    filters.target_audiences get_products Withdraw, add to the 4.0 list. The same registry already names offer_filters for 4.0. core/product-offer-filters.json has ext, so DR-0019 gives no reason to open it.
    include_collections, collections get_products Withdraw. list_products, request_proposals and refine_proposals keep them.
    include_execution_readiness, execution_readiness get_products Move to the list_products request and response, which are open.
    trackers, landing_page_url on core/creative-assignment.json create_media_buy, update_media_buy Withdraw. assign writes them, and get_media_buys reads them.
    metric_id on core/performance-standard.json and core/product-offer-filters.json create_media_buy, update_media_buy, get_products, offer filters Withdraw with entry 6. Otherwise the filter matches on a value canonical products don't carry.
    counting_mechanisms (experimental) create_media_buy, update_media_buy, get_products Withdraw. The registry already has it for 4.0 as canonical_counting_mechanisms_required_in_4_0.
    price_adjustments (experimental) get_products pricing options Withdraw, add to the 4.0 list on the canonical pricing option. It needs a registry entry.
    available_installment_statuses (experimental) get_products Move to core/canonical-reporting-capabilities.json, a capability block that opens with the other nine.

    expected_confirmation_at stays everywhere, and my earlier comment was wrong to list it. It belongs on core/task-submitted.json, which every submitted response uses, create_media_buy included.

    One definition per field. When these land, I'd give each field one definition:

    Field Defined today in One definition
    price_adjustments 7 pricing options A parent schema they all use
    trackers 5 places, 3 of them with minItems core/assignment-trackers.json, with minItems on the requests
    signing_profile 2 webhooks core/webhook-signing.json, with its rule against sending authentication too
    predecessor_media_buy_id, lineage_reason 2 tasks core/media-buy-lineage.json
    include_collections, collections 3 tasks One request and one response schema
    start_requires_all_creatives_approved 5 places core/creative-start-policy.json
    collection_lists, collection_lists_exclude 2 identical arrays on targeting core/collection-list-refs.json
    Daypart start_time, end_time 2 identical patterns core/civil-time-hhmm.json
    expected_confirmation_at 5 submitted responses core/task-submitted.json

    None of these changes what validates, except expected_confirmation_at. A task that doesn't declare it today starts rejecting a non-date value.

    A correction to my earlier comment. I said filters.audience_activation_methods has no obligation in the compatibility doc. The doc's general rule, preserve the field or reject it, does cover it. What's missing is an outcome for that specific field.

    PRs. I'll take DR-0036, the correction and the named exception, the baseline, and entries 2, 3, 6 and 26. Could you take 1, 11, 12 and 20 to 25? They touch your storyboards and the training agent.

    Objections by Fri 2026-11-13, as you proposed.

  13. bokelley commented on Nov 5, 2026

    @bokelley
    Contributor

    @KonstantinMirin: thanks for the table. Yes to the split. I'll take entries 1, 11, 12 and 20–25, and I'll also take the deprecated-task fields table, since it touches the same files.

    PRs, all drafts that reference this issue:

    1. Entry 1. forced.proposal_id and the unable arm leave comply-test-controller-response.json. hold_unavailable_batch.yaml and the training agent read the proposal ID from simulated.
    2. Entries 11–12. sla-window goes back to its 3.2.8 shape. clock and business_calendar_id move to core/creative-review-sla.json, and escalation-sla loses clock.
    3. Entries 20–25, plus the get_products rows of the deprecated-task table. This covers assignments[] trackers/landing_page_url; refine[].package, package-forecast-input.json and refinement_applied[]; filters.target_audiences; include_collections/collections; include_execution_readiness/execution_readiness moving to list_products; and the experimental price_adjustments and counting_mechanisms.
    4. The create_media_buy / update_media_buy rows. This covers lineage, artifact_webhook.signing_profile, start_requires_all_creatives_approved, target_audiences, trackers/landing_page_url on creative-assignment, and counting_mechanisms.

    Coordination:

    • metric_id on performance-standard and product-offer-filters goes with your entry 6, so I'll leave those two rows to your PR unless you'd rather I take them.
    • available_installment_statuses moves into canonical-reporting-capabilities, which opens with your capability-block set. I'll make that move once your opening has landed.
    • Each PR drops its own rows from scripts/lint-additive-minor-baseline.json. If your baseline PR lands first, I'll rebase.

    Timing: drafts up by Thu Nov 12. Nothing merges until the consent window closes Fri Nov 13.

    🤖 Generated with Claude Code

  14. bokelley commented on Nov 6, 2026

    @bokelley
    Contributor

    @KonstantinMirin: my half is up as drafts. None of them merges before the consent window closes on Fri Nov 13.

    PR Covers
    #8765 Entry 1: the held proposal ID moves to simulated; forced.proposal_id and arm: unable are withdrawn
    #8762 Entries 11–12: sla-window goes back to its 3.2.8 shape; clock and business_calendar_id move to creative-review-sla
    #8758 Entries 20–25, plus the get_products rows of the deprecated-task table (execution_readiness moves to list_products)
    #8767 The create_media_buy / update_media_buy rows, plus counting_mechanisms on the shared measurement-terms

    Entries 4 and 5 (review_sla on canonical-media-buy-action-fields and media-buy-available-action) didn't have an owner, so I'm folding them into #8762, next to the review-SLA change they depend on.

    Three things for Monday:

    1. The new creative-review-sla schema is open, by default under DR-0036. It was effectively closed before, through its $ref to the closed sla-window. If you read it as DR-0019 class A, say so on fix(schema): keep sla-window at its 3.2 shape; review SLA stays on the product (#8501 entries 4, 5, 11, 12) #8762.
    2. The feat(media-buy): forecast exact packages before booking #8468 exact-package forecast no longer has a home once refine[].package leaves get_products. Per RFC: check a proposed package's availability before create_media_buy (structured package on refine) #8448, wherever it goes has to carry the goal.
    3. fix(schema): keep 3.3 additions off the deprecated create_media_buy and update_media_buy (#8501) #8767 leaves a gap. Removing trackers and landing_page_url from update_media_buy assignments takes away the only atomic way to clear one override while keeping rotation, group, sequence and placements, because assign can't carry those settings. The PR documents a non-atomic replace-then-assign workaround. We either accept that for 3.3, or let assign carry those controls.

    Once all four land, media_buy.audience_evidence_targets and core/audience-evidence-target.json have nothing left in 3.3 that uses them. I'll remove them in whichever PR merges last.

    🤖 Generated with Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions