Repository navigation
Description
What kind of change?
Change a normative requirement (MUST / SHOULD / MAY)
Which section?
Whole document / more than one section
Current text
| `status` | Enum | derived | `draft` \| `published` \| `under_review` \| `agreed` \| `withdrawn` \| `expired` |§ 5.1 adds sold_out.
Proposed text
### 4.3 Lifecycle
A proposal with no `buyer` is *shared*; one with a `buyer` is *issued* to that
buyer. Asks, `under_review`, holds, and assent live on an issued proposal. A
shared proposal, or any other record more than one buyer can read (§ 5.8), carries
none of them.
A buyer `request` (a `requestable` value, not a hold) or `commit` (§ 5.6.1) is an
*ask*. It names a `version` and stays *open* until answered or withdrawn, or until
it goes stale (§ 4.1.3) or void. Holds change neither `status` nor
`negotiation_history[]`.
#### 4.3.2 Line-item status transitions
These transitions are exhaustive:
- `draft` → `draft` at a new `version`: seller `publish`.
- `draft` → `published`: seller `publish`. In a frozen version this changes only
`status`, so it makes no new `version` and no entry (§ 4.1.3).
- `draft` → `withdrawn`: seller.
- `published` → `published` at a new `version`: seller `publish`.
- `published` → `under_review`: buyer ask.
- `under_review` → `under_review`: an act that leaves an ask open.
- `under_review` → `published`: the last open ask ends by seller `grant`,
`counter`, or `decline`, by buyer `withdraw`, or by going stale (rule 2).
- `under_review` → `agreed`: seller `accept` of a `commit` (§ 4.1.2); open asks
are void.
- `published` | `under_review` → `sold_out`: seller, never while `hold.status` is
`held`; open asks are void.
- `published` | `under_review` | `sold_out` → `withdrawn`: seller, never while
`hold.status` is `held` or a firm entry holds; open asks are void.
- `sold_out` → `published`: seller, when quantity returns, with no new `version`.
- `published` | `under_review` | `sold_out` → `expired`: `offer_window.end` passes.
A *firm entry* is a `pricing[]` entry with a `price_valid_until`. It holds until
that date or `offer_window.end`, whichever comes first. While it holds, a seller
revision MUST NOT change that entry, `pricing_id` included, and MUST NOT end it
sooner by moving `offer_window.end`. A `grant` or `counter` of a `request` on
that entry MAY lower its `list_rate` or widen its `unit_bounds`. A revision that
narrows who may commit (§ 5.8) does not apply, while the entry holds, to a buyer
that was eligible when the entry was first offered.
The seller of an issued proposal MUST answer a resolved `commit` under a firm
entry that:
- arrives while the entry holds, on or after `offer_window.start`; and
- passes the checks of § 5.6.1 and any authority check the seller applies (§ 5.8).
The seller accepts the `commit`, or declines it for lack of availability, an
exclusivity conflict (§ 5.6.7), or a ground stated in the `terms_refs[]` in force
when the entry was first offered.
Rules:
1. A stale ask (§ 4.1.3) is not open and not evaluated. The seller rejects it
with `stale_version` (§ 2.4).
2. A seller MAY revise a line item while an ask is open or a hold runs. The
revision is a new `version`. An ask it makes stale ends, and the seller MUST
release a `held` hold it makes stale or re-offer it at the new `version`. A
`commit` MUST NOT carry a `requestable` ask.
#### 4.3.3 Proposal status
A proposal's `status` is the first of the following that applies:
1. `draft` when every line item is `draft`.
2. `under_review` when any line item is.
3. `published` when any line item is `draft`, `published`, or `sold_out`.
4. `agreed` when any line item is `agreed`.
5. Otherwise `expired` when any line item is `expired`, else `withdrawn`.
#### 4.3.4 Expiry
| Instant | Effect when passed |
| :--- | :--- |
| `offer_window.end` | Every `published`, `under_review`, or `sold_out` line item is `expired`; open asks are void |
| `pricing[].price_valid_until` | `status` unchanged; a later `commit` under that entry is rejected with `expired`, and the seller SHOULD `publish` or `withdraw` |
| `hold.valid_until` | `hold.status` becomes `expired` |
`hold.valid_until` MUST NOT exceed `offer_window.end` or the earliest
`pricing[].price_valid_until`.Why
The draft lists status values but never says whose act moves a line item between them, so two implementations can answer differently.
agreed rests on assent. A resolved commitment is an offer to buy (our commitment acceptance change request (#67)). A line item is agreed only when assent[] holds a matching commitment and acceptance (our binding-record change request (#63)). A commit can't carry an ask: accept makes no new version, so the asked value would sit outside the version the buyer named.
Rule 1 applies #24's stale test per line item (§ 4.1.3), as our reply on #24 asks. Rule 2 lets the seller change any term before agreed, at the cost of a new version. The buyer never commits to terms it hasn't seen. BCN's dated inventory change request (#105), filed by @matthew-iabtechlab for Carsten Sander (BCN), surfaced a moved issue date.
A firm entry is the exception, as @EvgenyAndroid proposed. The text closes the four exits of their answer to open question 1. A revision of other terms keeps the entry, so the buyer re-commits at the new version and the same rate.
Our lifecycle PR carries this text. The rules issue lists the rules we left out.
Knock-on effects
- § 3
seller-set: the gate reads thestatusof the object that carries the field (our seller-set gate change request (#60)). This filing addsunder_reviewto it, and § 4.3.2 says what the revision does. - § 4.1:
negotiation_history[].actionbecomespublished|requested|granted|countered|declined|withdrawn, on the versions of our versioning change request (#64). Acommitand its answers areassent[]entries, which our signing PR defines. - § 5.6.2: a hold is on a
version, which [Change] § 4.1 — Freeze a version's offered terms; changes create version n+1 and a revised entry #64 freezes, so held terms need no rule. Our hold states change request (#66) adds the seller's release and re-offer. With [Change] § 4.1 — Freeze a version's offered terms; changes create version n+1 and a revised entry #64 and rule 2, that answers our held-terms follow-up. - [Change] § 5.2, § 5.6 — Generic insertion_schedule, placement_options and space fields for dated, discrete inventory #105: if
insertion_schedulelands, the earliestbooking_closeorprice_valid_untilof the included and selected insertions joins the cap onhold.valid_until(our reply on #105). - #26: each issued proposal has its own
status,version, and history (our issued proposals reply).
Open questions for the working group:
- Answered by @EvgenyAndroid, in our lifecycle PR. Should a firm rate also bar the other ways a seller can end the offer before
price_valid_until? Under rule 2, it can moveoffer_window.endearlier or narrow who may commit, such aseligible_buyers[]. It can also withdraw the line item, or leave acommitunanswered until it lapses (our binding-record change request (#63)). Yes to all four. While a firm entry holds, the seller can't end it by movingoffer_window.endor withdraw the line item. While it holds, a narrowing doesn't apply to a buyer that was eligible at first offer. A resolvedcommitthat arrives after the offer opens must be answered.sold_outstays. - Should a seller have to issue a proposal while a firm entry on its shared proposal holds, and carry the entry over unchanged? Otherwise, declining to issue is a fifth exit. The rules issue lists it.
- Should a seller answer a live
commitmententry within a stated time, and under a firm entry beforeprice_valid_until? As proposed, the duty to answer has no deadline, and the entry stays live untiloffer_window.end. The rules issue lists it. - While a firm entry holds, should a revision also be barred from raising what an eligible buyer pays through
deltasorincluded[]? Should it be barred from removing the mechanism the entry prices? The rules issue lists it.
Would this break an implementation already built to this draft?
Yes — breaking
You are commenting as
Other — IAB Tech Lab member (Postindustria).
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.
Details and examples: Lifecycle: full rationale and examples
Revised 2026-11-03: Rewritten to match our lifecycle PR, with a firm entry per pricing[] entry, and our signing PR, where assent[] decides agreed. Open question 1 is answered in the lifecycle PR, and questions 2 to 4 are new.
Analyzed and generated with the help of Claude, fully reviewed by me.
Activity
EvgenyAndroid commentedon Oct 27, 2026
Two cases the transition table should cover:
publishedwithhold_status.state: held. That only works if a hold freezes the offered terms, which is the addition on [Change] § 5.6.2 — hold_status needs refused and re-entry to requested #66. It would help if § 4.3 said that this is the intended representation.withdrawfor its own ask, andwithdrawnis the seller's status. A buyer turning down a seller's offer, as opposed to withdrawing an ask, has no action. Today the only reading is "no ask", with nothing recorded. If a decline should be recordable, for audit or to release a hold early, it needs an action; if not, saying so would settle it.EvgenyAndroid commentedon Oct 27, 2026
Thanks @KonstantinMirin. The decline sentence settles my second point.
On the firm offer, one mismatch. § 5.6 defines
pricing[].price_valid_untilas "How long the posted rate holds", and a buyer will read that as a promise. #66's open question 4 now says the date "bars a late acceptance (#65); it doesn't promise one (#67)". Rule 2 here also lets the seller revise the rate before that date, which makes acommitat the earlier version stale. So a firm offer as § 4.3 defines it promises nothing that anypublishedline item with aprice_valid_untildoesn't. My reply on #66 assumed the date was a promise.Two ways to resolve it:
price_valid_untilas the last moment the seller may accept acommitat that rate, and § 4.3 drops "firm".price_valid_until, a seller revision MUST NOT change thatpricing[]entry, and the seller MUST NOT decline acommitunder it except for lack of availability. Nothing is reserved, so the availability decline stays ([Change] § 3, § 5.6.1, Appendix B — A resolved commitment is an offer until the seller accepts #67), and so does marking the line itemsold_out.I'd take 2. It's the terms-only guarantee a seller means when it sets
hold_available: false, without a hold. If the group prefers 1, the § 5.6 wording still needs to change, because "holds" reads as 2.KonstantinMirin commentedon Oct 28, 2026
Thank you, @EvgenyAndroid. Postindustria (IAB Tech Lab member) takes your second option in § 4.3 above, with one change. The seller may still decline on a ground the line item already states, such as
eligible_bidders[]orterms_acceptance_required. Beforeprice_valid_until, rule 2 keeps thatpricing[]entry and itspricing_id(#94) in every new version. After a revision of other terms, the buyer re-commits at the same rate. #67 adds the decline limit, and #66 open question 4 follows. New open question 1 above asks whether a seller may still end a firm offer early.Analyzed and generated with the help of Claude, fully reviewed by me.
EvgenyAndroid commentedon Oct 28, 2026
Thanks @KonstantinMirin. I'd answer open question 1 yes. Each of those exits lets a seller walk away from the rate without changing it:
valid_untilearlier. Untilprice_valid_until, a revision MUST NOT setvalid_untilbefore it.eligible_bidders[], or setsterms_acceptance_requiredtotrue, shouldn't create a new ground against a buyer that already qualified.price_valid_until,withdrawnshould be barred.sold_outstays, since lack of availability is the one exit the offer keeps.commitunanswered. [Change] § 4.1 — Define record_digest and assent[]; defer signer identity to the AAMP profile #63 voids an unmatchedcommitmentonceprice_valid_untilpasses, so silence works as a decline on no ground. Acommitthat arrives before the date should need an answer: accept, or decline on an allowed ground.