Skip to content

[Change] § 2, § 4.1, § 5.1 — Name the line-item container (line_items[]) and carry proposal_id and seller_id on every line item representation #31

Open

Description

@VJAlkimi

What kind of change?

Add a new field

Which section?

Whole document / more than one section

Current text

§ 2, Object shape:

Proposal          → the merchandising pitch, identity, lifecycle state and assent
Line Items[]      → fully self-contained buyable units, each in exactly one channel

§ 2.1, Summary Representation:

plus, from the parent proposal: proposal_id · seller_name · description · valid_from · valid_until.

§ 2.1, Full Representation:

every field, with all catalog_ref values resolved. A full fetch MUST return it.

§ 4.1: no row names the array that holds line items. Appendix A lists 71 fields and does not include it.

§ 5.1 Identity:

line_item_id · String · immutable · Identity within the proposal
status · Enum · derived · ... Independent of the proposal's status
channel · Enum · immutable · ...

§ 7:

A buying agent can hand a single line item to a downstream system without resolving proposal-level defaults or cross-channel ambiguity.

Proposed text

§ 4.1, new row:

line_items[] · Array[Object] · seller-set · The line items beneath this proposal, each conforming to § 5. MUST contain at least one entry while status is published or later. Order carries no meaning.

§ 5.1, two new rows:

proposal_id · String · immutable · The containing proposal's proposal_id. MUST equal it. Present in every representation of the line item, including the Full Representation returned by a full fetch and any line item transported on its own.
seller_id · String · immutable · The containing proposal's seller_id. MUST equal it. Present in every representation of the line item.

§ 2, add after the no-inheritance rule:

proposal_id and seller_id on a line item are the sole exception to the no-inheritance rule. They are not inherited: they are stated on the line item and MUST be validated equal to the parent. They exist so that a line item fetched, signalled or handed off on its own still identifies its proposal and its seller.

§ 2.1, Full Representation, replace with:

every field of the line item, including proposal_id and seller_id, with all catalog_ref values resolved. A full fetch MUST return it.

§ 2, replace "Line Items[]" in the shape diagram with "line_items[]".

Appendix A: add line_items[] (4.1, Array[Object], seller-set), proposal_id (5.1, String, immutable), seller_id (5.1, String, immutable). Appendix B: seller-set 29 → 30; immutable 6 → 8.

examples/: publish one complete nested document, examples/proposal-full.yaml, showing the omni proposal with its three line items under line_items[], each carrying proposal_id and seller_id. Keep the four existing files as excerpts of it.

Why

Field(s) involved

line_items[] (new, § 4.1), proposal_id and seller_id on the line item (new, § 5.1), § 2 object shape, § 2.1 Full Representation, requires (#23), source_ref (#28), commitment.proposal_id (#24)

Two things hold the two-level tree together and neither is written down: the key that contains the children, and the fields that let a child identify its parent.

The container has no name. "Line Items[]" appears once, in the § 2 shape diagram, and nowhere else. No field table defines the key, its cardinality, or whether an empty array is valid. Appendix A, which claims to index every field, omits it. Two implementers serialising a proposal will name the array differently and their documents will not interoperate. Three change requests filed this week assume the container exists without naming it: #23's requires references sibling line items by id, #28's source_ref points at a line item in another seller's proposal, and #24's commitment.proposal_id names the proposal a line item belongs to. All three reference members of an array that has no key.

A line item on its own does not know its seller. Containment is the only link between a line item and seller_id, and the draft defines three situations where a line item leaves its container:

  • § 2.1 says "a full fetch MUST return" the Full Representation of a line item. That is one line item returned alone, defined as "every field" of the line item. seller_id is not a field of the line item.
  • § 5.1 says line item status is "independent of the proposal's status, so one line item may sell out while the rest of the shelf stays live." A status that changes alone is signalled alone.
  • § 7 says a buying agent "can hand a single line item to a downstream system." The receiving system has no seller to attach it to.

The Summary Representation already concedes the point: § 2.1 requires it to carry proposal_id and seller_name "from the parent proposal." The Full Representation, the one handed downstream, is not required to. The thinner form carries parent identity and the richer form does not.

#24 proposes proposal_id and version inside commitment. That solves the stale-version problem and we support it. It does not solve this one: commitment is "absent on a published standard proposal" (§ 5.6.1), so a line item fetched before composition, or signalled as sold_out, still carries nothing. And commitment is the buyer's object; seller_id is the seller's identity and belongs on the seller's side of the line item.

#28 makes the gap visible from another angle. An aggregator's line item will carry source_ref.seller_id, the original publisher, while the line item itself still has no seller_id of its own. A downstream system receiving that line item alone sees who originally sold it and not who is selling it now.

The example files never show the join. A proposal and its line items are one document; § 2's shape diagram, § 2.1's "from the parent proposal", and #29's manifest all assume it. The four files in examples/ are excerpts of that one document, split for readability under § 6.1 to § 6.4. The split itself is fine. What is missing is any example of the nesting: the proposal excerpt has no line_items key, so the container's name never appears, and the line-item excerpts carry no proposal_id, so an implementer working from the examples, which the README says are "the best reference for shape" until schemas exist, has to guess both the key and the back-reference. One nested example alongside the excerpts closes that.

This is not inheritance. The no-inheritance rule forbids a line item taking a field's value from the parent. Stating proposal_id and seller_id explicitly on the line item and validating them equal to the parent is a reference, the same way requires in #23 references sibling ids. The proposed text names it as the sole, deliberate exception so nobody reads it as a loophole.

Concrete scenario

A buyer agent screens the summary of examples/line-item-ctv.yaml and fetches its Full Representation. Under § 2.1 the response is every field of the line item with catalog refs resolved:

line_item_id: "weather-app-ctv"
status:       published
channel:      ctv
...
correlation_id: "ep-q4-2026-commitment/weather-app-ctv"

The agent holds a fully priced, fully specified line item and cannot say which seller is offering it, which proposal it belongs to, or which offer window applies. If it hands the line item to its DSP as a private-auction deal per § 1.1, the DSP has no seller to key the deal to. If the line item later signals status: sold_out, the signal carries no proposal_id for the agent to update.

With the proposed text the same fetch returns:

proposal_id:  "examplepub-us-q4-2026-omni"
seller_id:    "reg:examplepub-digital"
line_item_id: "weather-app-ctv"
status:       published
channel:      ctv
...

and the published proposal reads:

proposal_id: "examplepub-us-q4-2026-omni"
seller_id:   "reg:examplepub-digital"
...
line_items:
  - proposal_id:  "examplepub-us-q4-2026-omni"
    seller_id:    "reg:examplepub-digital"
    line_item_id: "business-daily-display"
    ...
  - proposal_id:  "examplepub-us-q4-2026-omni"
    seller_id:    "reg:examplepub-digital"
    line_item_id: "weather-app-ctv"
    ...

Every representation of the line item now identifies its proposal and seller, a validator can check the two ids against the parent, and #23's requires, #24's commitment.proposal_id and #28's source_ref all have a named container to index.

Knock-on effects

Would this break an implementation already built to this draft?

Yes — breaking

Alternatives you considered and rejected

  • State that a line item is never valid outside its proposal. Clean, but contradicts § 2.1's standalone full fetch, § 5.1's independent status, and § 7's handoff claim. Removing those three would be a larger change than adding two ids.
  • Put the ids only in commitment, as [Change] § 4.1, § 5.6.1 — Commitments must carry proposal_id and version; stale versions are rejected #24 does. Covers composed line items only; a published or sold-out line item still carries nothing. We support [Change] § 4.1, § 5.6.1 — Commitments must carry proposal_id and version; stale versions are rejected #24 as the version-pinning half and propose this as the identity half.
  • Carry seller_name instead of seller_id. seller_id is the registry key; seller_name is display text. The Summary carries seller_name for screening; the Full Representation should carry the key a downstream system can resolve.
  • Leave the container key to the schema. The schema cannot name what the prose does not, and the body is normative.
  • Use correlation_id prefixes as the link. They are informal, buyer-assigned at commitment time, and absent on a published line item.

You are commenting as

AdTech Provider

Before you submit

  • I have read CONTRIBUTING.md and agree my contribution may be published under this repository's licence.
  • This contains no confidential or commercially sensitive information.

Activity

  1. Sirajmx commented on Oct 21, 2026

    @Sirajmx
    Contributor

    Thank you for filing this. It has been triaged and labelled for the working group, and will be considered at adjudication after the comment period closes on 22 October 2026. Related: #23, #24, #28.

  2. EvgenyAndroid commented on Oct 27, 2026

    @EvgenyAndroid

    Supporting this, with implementation evidence. I couldn't parse a proposal and its line items as one document without inventing a wrapper, because no field table names the container. line_items[] plus proposal_id/seller_id on each line item is the shape I ended up needing. One addition: a line item handed off on its own should also say which proposal version it was taken from, which #24 asks for on the commitment.

  3. KonstantinMirin commented on Nov 4, 2026

    @KonstantinMirin

    Agreed on the version, @EvgenyAndroid. Our shared types PR names line_items[] in § 4.1 and adds a VersionRef type: proposal_id, version, and an optional line_item_id. A system that holds a line item outside its proposal can name it with a VersionRef and keeps the proposal's seller.domain beside it. A proposal_id is unique only within that domain (our parties PR, from #61).

    Neither PR copies these keys onto the line item. Without version on the line item, a revision to another line item leaves asks and holds on this one current (our lifecycle PR). After agreed, downstream execution names the agreed line item by the same VersionRef (our post-agreement PR, from #68).

    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