Skip to content

[Change] § 5.6 — Give the buyer's counter a field (requested_rate), state how agreed_rate is derived, and say who can read floor and seller_rate #30

Description

@VJAlkimi

What kind of change?

Add a new field

Which section?

5.6 — Commercial terms

Current text

§ 5.6, pricing[] rows:

pricing[].gross_rate · Number · seller-set · The list rate the buyer pays
pricing[].agreed_rate · Number · derived · The transacted rate after selections and any agreed request
pricing[].seller_rate · Number · seller-set · What the publisher receives
pricing[].floor · Number · seller-set · OPTIONAL. The lowest rate the seller will consider. Enables a requestable counter to be evaluated without a round trip

As revised by draft PR #18 (for #16), floor reads:

pricing[].floor · Number · seller-set · OPTIONAL. The seller's offer floor: the lowest rate it will consider at proposal time, so a requestable counter can be evaluated without a round trip. Not the downstream auction floor, and not a guarantee that bids at or above it will clear

§ 3.1, selectable pricing key:

pricing · OPTIONAL · Delta per option beyond those included, as { option_id: { delta_cpm | delta_flat | delta_pct } }

§ 5.6.1:

derived_units · derived · Computed from amount, agreed_rate and cost_method. Informative, not binding

examples/line-item-display.yaml, line 56:

agreed_rate: 24.00          # derived: no priced options included

Proposed text

Add to § 5.6, pricing[]:

pricing[].requested_rate · Number · requestable · OPTIONAL. The rate the buyer proposes in place of the composed rate (gross_rate plus selected deltas). When floor is declared and requested_rate is greater than or equal to floor, the request MUST resolve without seller assent. When floor is absent, the seller has not offered a counter mechanism and any requested_rate is a requestable ask. When floor is absent, or requested_rate is less than floor, the request requires explicit seller assent, recorded in negotiation_history[] as accepted or declined.

Replace the agreed_rate row with:

pricing[].agreed_rate · Number · derived · The transacted rate. MUST be computed as follows, by either party, from the document alone: (1) start from requested_rate if present and resolved, otherwise gross_rate; (2) add the delta_cpm of every option in selected[] that is not in included[], across all selectable fields on the line item; (3) apply the delta_pct of every option in selected[] that is not in included[], multiplicatively and in document order, where delta_pct is a decimal fraction (0.20 means twenty percent); (4) delta_flat values MUST NOT alter agreed_rate; they accumulate into commitment.flat_charges. An option in both included[] and pricing carries a zero delta. An option in available[] with no pricing entry carries a zero delta.

Add to § 5.6.1:

flat_charges · derived · The sum of delta_flat for every selected option not in included[], in commitment.currency. Informative, not binding.

Replace the floor row (as revised by PR #18) with:

pricing[].floor · Number · seller-set · OPTIONAL. The seller's offer floor at proposal time: the lowest requested_rate that resolves without seller assent. Visible to the buyer in the full representation. Not the downstream auction floor, and not a guarantee that bids at or above it will clear.

Replace the seller_rate row with:

pricing[].seller_rate · Number · seller-set · OPTIONAL. What the publisher receives. Informative to the seller's own systems. MUST NOT be returned in the summary or full representation to a buyer.

§ 2.1: add seller_rate to the fields a representation returned to a buyer MUST omit.

Appendix A: add pricing[].requested_rate (5.6, Number, requestable) and commitment.flat_charges (5.6.1, Number, derived). Appendix B: requestable count 3 → 4; derived count 11 → 12. examples/: add one line item with a selected[] that includes a priced option, so agreed_rate differs from gross_rate, and one with a requested_rate between floor and gross_rate.

Why

Field(s) involved

pricing[].gross_rate, pricing[].agreed_rate, pricing[].floor, pricing[].seller_rate, pricing deltas on selectable fields (§ 3.1: delta_cpm, delta_flat, delta_pct), commitment.derived_units

The draft defines every price key on a line item as seller-set or derived. Not one is settable or requestable. Yet floor is described, in both the current text and the PR #18 revision, as existing "so a requestable counter can be evaluated without a round trip." The counter it refers to has no field. A buyer's agent reading the display example (gross_rate 24.00, floor 21.00) is told that a figure down to 21.00 will be considered, and has nowhere in the object to write 22.00. The only way to make the counter is outside the document, which is the natural-language exchange § 3 and § 7 exist to remove. #16 fixed what floor means; this filing gives the thing it enables a place to live.

The second gap is that agreed_rate is marked derived, and the derivation is not written anywhere. The example comment ("derived: no priced options included"), the names delta_cpm and gross_rate, and the phrase "after selections" together imply gross_rate plus the sum of selected deltas. No sentence in the body states it. Three questions follow that two implementers will answer differently:

  • What does delta_pct apply to, and in what order relative to delta_cpm? With gross_rate 24.00, one option at delta_cpm 4.00 and one at delta_pct 0.15, percentage-then-add gives 31.60 and add-then-percentage gives 32.20. Across the display example's 3.3 million derived units that is roughly 2,000 USD of disagreement on one line item.
  • Is delta_pct written as 15 or 0.15? The key appears once in the repository, in the § 3.1 grammar, with no field using it, no example exercising it and no unit stated.
  • Where does delta_flat land? The display example prices log-level reporting at delta_flat 2500.00 and the audio example prices seller-built production at 12000.00. A flat amount cannot enter a per-unit rate, and the draft does not say what it enters instead.

#14 part 1, which the maintainer has welcomed, states that "agreed_rate derivation adds the geo delta, same mechanics as the audience delta." Those mechanics are about to be extended to a fourth dimension without having been written down for the first three.

The third point is about who can read two fields. seller_rate reveals the gap between what the buyer pays and what the publisher receives, which is the intermediary's margin. floor reveals the lowest figure the seller will accept. Both sit in the same object the buyer composes against. The draft neither says these are intended to be buyer-visible nor provides a seller-private view. This filing does not take a position on whether a seller ought to disclose either; it asks the specification to say what the object does. For floor, the PR #18 text already treats buyer visibility as the design, since a counter can only be evaluated without a round trip if the buyer can see the bound. The proposal makes that explicit. For seller_rate, nothing in the buyer's composition depends on it, so the proposal is that it is omitted from any representation returned to a buyer. A later attestation over the agreed record (§ 4.1 assent) will cover whatever the record contains, so what the object exposes should be decided now rather than discovered at signing.

The draft's own markers point the same way. floor is OPTIONAL: a seller may withhold its reservation price, and a seller that does so is offering no counter mechanism at all, which is a legitimate take-it-or-leave-it position the proposed requested_rate text preserves. seller_rate carries no OPTIONAL marker, so it reads as always present. That is the asymmetry inverted: the figure the draft lets a seller keep private is the one that matters only if the buyer counters, and the figure it appears to require is the one that exposes the intermediary's margin and plays no part in composition. Making seller_rate OPTIONAL and seller-only, and stating that an absent floor means no counter, aligns the two markers with what each field is for.

The fourth point is small. #15 (selectable rules) and #9 (catalog option ids) both touch how included[] and pricing interact. The two zero-delta sentences in the proposed derivation settle the pricing half of that: absence from pricing is zero, and presence in both included[] and pricing is zero. Without them a reader of the display example's formats block cannot tell whether 728x90, which is available and unpriced, is free or unlisted.

Concrete scenario

From examples/line-item-display.yaml:

pricing:
  - cost_method:  CPM
    gross_rate:   24.00
    agreed_rate:  24.00     # derived: no priced options included
    seller_rate:  20.40
    floor:        21.00

A buyer agent composes the line item with ep:hnw-investors (+4.00 delta_cpm), clean_room activation (+1.50) and the 970x250 format (+3.00), and adds log-level reporting (delta_flat 2500.00). It wants to offer 30.00 against a composed 32.50.

Under the current text:

  1. The agent cannot record 30.00 anywhere. gross_rate is seller-set, agreed_rate is derived, and no price key is requestable. It has to send a message.
  2. The agent cannot tell whether 30.00 is acceptable. floor is 21.00 and the text says a counter above it "can be evaluated without a round trip", but no rule says a counter above floor is accepted.
  3. The agent cannot know whether the seller's agent will compute 32.50. The derivation is unwritten. If any option had a delta_pct the two sides could legitimately differ.
  4. The agent cannot know whether the 2500.00 changes the rate, the total, or nothing.

Four round trips on a line item the draft counts as needing none.

With the proposed text the agent writes:

pricing:
  - cost_method:    CPM
    gross_rate:     24.00
    requested_rate: 30.00   # ≥ floor 21.00: resolves without assent
    agreed_rate:    38.50   # derived: 30.00 + 4.00 + 1.50 + 3.00
    floor:          21.00
commitment:
  amount:         80000.00
  flat_charges:   2500.00   # derived
  derived_units:  2077922   # derived: 80000 / 38.50 × 1000

Both agents compute 38.50 and 2,077,922 from the document, the 2500.00 sits in flat_charges, seller_rate is not in the buyer's copy, and nothing is sent. If the agent had written requested_rate 20.00 instead, below floor, that single ask would need the seller's assent and would be logged in negotiation_history[], which is the one round trip § 3 intends.

Knock-on effects

Would this break an implementation already built to this draft?

No — additive or editorial

Alternatives you considered and rejected

  • Mark gross_rate itself requestable. Loses the list price the moment a buyer counters, so the record no longer shows what was offered versus what was asked.
  • Collapse floor into gross_rate and publish one number. Removes the counter mechanism [Comment] § 5.6 — pricing[].floor is the offer floor, not the downstream auction floor #16 chose to keep, and makes PR § 5.6 — pricing[].floor is the offer floor, not the auction floor (#16) #18 moot.
  • Leave the derivation to the schema. The README says schemas follow the first revision and that the body is normative. A formula is normative text.
  • Define delta_pct as additive (15 + 10 = 25 percent). Simpler, but every pricing system we know of compounds percentage adjustments, and additive stacking produces negative rates at large discounts. Multiplicative in document order is deterministic and matches practice.
  • Put delta_flat into agreed_rate by dividing across derived_units. Circular: derived_units depends on agreed_rate.
  • Drop delta_pct from 3.0 entirely. Acceptable to us if the working group prefers it; a grammar production with no semantics and no example is worse than no production. The proposed text keeps it because cost_method may be flat or CPC, where a percentage is the only proportional form.
  • Keep seller_rate buyer-visible and say so. Also acceptable, if that is the intent. The filing asks for the choice to be written down; omission is the proposal because nothing in composition needs it.

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

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

    change-requestProposes specific normative wordingnormativeChanges what the spec requires

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions