Skip to content

[Change] § 2, § 4.1, § 5.6 — Line-item dependencies and bonus lines (linked_execution, requires) #23

Open

Description

@Sirajmx

What kind of change?

Add a new field

Which section?

Whole document / more than one section

Current text

§ 2, Object shape:

**Subsettable proposals.** A buyer MAY select and commit a subset of a
proposal's line items, unless the proposal explicitly mandates linked execution
through its binding terms.

§ 4.1 and § 5.6: n/a, new fields.

Proposed text

§ 2, replace the subsettable paragraph:

**Subsettable proposals.** A buyer MAY select and commit a subset of a
proposal's line items, unless the proposal sets `linked_execution` to `all`
(§ 4.1). A line item that declares `requires` (§ 5.6) may be committed only
when its conditions are met.

§ 4.1, new row:

| `linked_execution` | Enum | seller-set | `none` (default, subsettable) \| `all` (all published line items must be committed together) |

§ 5.6, new row:

| `requires` | Object | seller-set | OPTIONAL. Conditions that must hold in the same commitment for this line item to be committable. See 5.6.3 |

New § 5.6.3:

#### 5.6.3 requires

| Key | Meaning |
| :--- | :--- |
| `all_of[]` | Line items that MUST all be in the same commitment |
| `any_of[]` | Line items of which at least one MUST be in the same commitment |
| `min_commitment[]` | Purchase-level thresholds: `{ line_item_id, basis, amount, currency }` |

A bonus line item is a line item with `requires` and its own pricing, such as
a discounted `gross_rate` or `cost_method: flat` at 0. A conditional discount
is modelled as a separate line item that `requires` unlocks, not as a price
that changes according to the other line items selected. Every price remains
self-contained.

- References in `requires` MUST point to line items in the same proposal and
  version.
- A seller MUST reject a commitment that includes a line item whose `requires`
  is unmet. This check MUST be deterministic.
- If a line item referenced in `requires` becomes `sold_out` or `withdrawn`
  before commitment, the dependent line item becomes non-committable. After
  `agreed`, cancellation of a referenced line item is governed by the
  dependent line item's `cancellation_policy`.
- A seller MUST reject a proposal at publication if `requires` references
  form a cycle.

Example:

requires:
  all_of:  ["li-display-a", "li-video-b"]      # these lines must be in the basket
  any_of:  []                                  # at least one of these
  min_commitment:                              # purchase-level thresholds
    - { line_item_id: "li-display-a", basis: spend, amount: 50000, currency: USD }

§ 2.1, Summary Representation: add a boolean has_requires per line item, and linked_execution from the parent proposal, so screening agents do not recommend a line item that cannot be bought on its own.

Why

Sellers merchandise bonus line items and line items that are available only with, or at a price that depends on, a purchase elsewhere in the proposal. Attendees at the 24 September 2026 Agentic Bootcamp raised this twice: "Bonus line items need to be handled in the spec. You cannot pick and choose all lines from a pub-submitted proposal; some lines are linked to purchase levels." The multi-channel bundling discussion (display and video with conditional pricing) raised the same need.

§ 2 anticipates this with "linked execution through its binding terms", but no field defines binding terms, so the hook cannot be implemented as written. There is no way to say that line C is available, or available at a given price, only if lines A and B are bought at or above a given level. OQ-5 (#6) covers only the all-or-nothing case.

The proposal keeps the draft's design principles:

  • No-inheritance rule (§ 2): every line item stays self-contained and fully priced. A dependency is an eligibility constraint that references sibling ids, not inherited values.
  • Resolution without a round trip (§ 3): a buyer agent can validate a basket against the rules from the published proposal alone.
  • One channel per line item: cross-channel bundles are expressed as linked line items, not multi-channel line items.

Knock-on effects

  • § 2: the subsettable paragraph references the new fields.
  • § 2.1: has_requires and linked_execution added to the Summary Representation.
  • Appendix A / B: new rows for linked_execution and requires, and the marker counts.
  • § 6: a bonus line item added to examples/, for example a CTV bonus unlocked by display and video spend.
  • OQ-5 (OQ-5 — Is a min_line_items field needed? #6): linked_execution: all covers the case min_line_items was intended for. We propose closing OQ-5 into this change request.

Would this break an implementation already built to this draft?

No — additive or editorial

Alternatives you considered and rejected

  • min_line_items on the proposal (OQ-5): covers only all-or-nothing.
  • Multi-channel line items: would break the one-channel-per-line-item rule.
  • A price that changes according to the other line items selected: would break self-contained, auditable pricing.

You are commenting as

Standards body / working group participant

Activity

  1. Kishore-2572 commented on Oct 8, 2026

    @Kishore-2572

    The version rules this change relies on ("References in requires MUST point to line items in the same proposal and version") are proposed in #24

  2. bhillman-TelevisaUnivision commented on Oct 15, 2026

    @bhillman-TelevisaUnivision

    Publisher support for this change, and for closing OQ-5 (#6) into it.

    Event sponsorships, such as a major sports tournament or an awards show, are commonly sold as a must-buy package across platforms, often with added-value lines available only with the package. The draft can't express either rule today without prose. Two small asks:

    1. Holds on bundles. When linked_execution is all, a hold MUST use hold_scope: proposal. Otherwise a buyer can hold the anchor line, let the rest of the package sell, and the seller is left holding a fragment that cannot be bought on its own.
    2. Mark added value explicitly. To a screening agent, a bonus line at cost_method: flat and 0 looks the same as a pricing error. A boolean such as added_value: true on the line item (and in the summary, next to has_requires) would stop buyer agents from ranking a seller on a zero-cost line out of context, and would let reporting separate paid delivery from added-value delivery.
  3. KonstantinMirin commented on Oct 22, 2026

    @KonstantinMirin

    PR #70 checks requires "in the same commitment", but commitment belongs to one line item, so nothing names the line items a buyer commits together. Postindustria (IAB Tech Lab member) proposes a commitment set as that referent, holding the terms those line items share.

    The buyer writes a commitment_sets[] entry, { set_id, line_item_ids[], currency, max_total, frequency_cap, total }, on the proposal issued to it. The set constrains its line items and never supplies a value, so the § 2 no-inheritance rule holds. Our binding-record filing groups the same line items for assent, but a signing record can't carry shared terms.

    1. Referent. "The same commitment" means the same set. The seller checks all_of[], any_of[], and min_commitment[] against it. linked_execution: all means one set of every published line item, answering the min_line_items question (#6) and the indivisible package (#50).
    2. One currency. A set has one currency, like an OpenDirect 2.1 Order. Each line item's committed pricing[] entry, its commitment.currency, and each min_commitment[].currency equal it. Nothing converts: lines in different currencies go in separate sets.
    3. max_total, the IO maximum. The derived total, flat charges included (#30), MUST NOT exceed it. It isn't the principal's mandate (our reply on #57).
    4. A shared frequency cap. One counter on top of each line item's own cap, inside a group the seller declares.
    5. frequency_groups[], seller-set: { group_id, line_item_ids[], max: { min, max }, period, basis, time_zone }, with period, basis, and time_zone as in our targeting-values reply on #58. The group has its own clock, since its lines' clocks can differ. A seller counts only exposures it serves; other cross-line caps belong in the buyer's DSP.
    6. Whole acceptance (our acceptance filing). The seller rejects a set that breaks a rule, naming the rule, and accepts or declines a set whole.

    As drafted (§ 2, § 5.6.1):

    stateDiagram-v2
        state "line item A: commitment resolved" as A
        state "line item B: commitment resolved" as B
        [*] --> A : buyer composes
        [*] --> B : buyer composes
        A --> agreed : ? undefined
        B --> agreed : ? undefined
        note right of agreed : nothing names A and B as one commitment
    
    Loading

    Proposed:

    stateDiagram-v2
        state "commitment set" as S
        [*] --> S : buyer composes
        S --> resolved : requires met, one currency, total within max_total, cap inside a group
        S --> rejected : rule broken, seller names it
        rejected --> S : buyer recomposes
        resolved --> agreed : seller accepts the whole set
        resolved --> declined : seller declines the whole set
        declined --> S : buyer recomposes
    
    Loading

    Open questions:

    1. Should "the same commitment" in the line-item dependency rules of PR #70 name a commitment set, as proposed, or the buyer commitment entry of assent[] in our binding-record filing (#63), with the shared terms held elsewhere?
    2. Should commitment_sets[] be settable, with § 3.2 Settable bounds naming its bounds, or supplied with total marked derived, given that no seller bound applies to max_total?
    3. Should total count a selected flat charge inside commitment.amount or on top of it, and should that choice wait for the agreed_rate derivation (#30) to define flat_charges?
    4. Should a cross-line cap require a seller-declared frequency_groups[] entry, as proposed, or should OpenProposal carry no plan cap and leave every cross-line cap to the buyer's DSP?
    5. Should the seller record a rejected set as a declined entry in negotiation_history[] that names the rule, as a new rejected action, or not at all?

    Details: Commitment set: full rationale and examples

    Analyzed and generated with the help of Claude, fully reviewed by me.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions