Skip to content

§ 5.2, § 5.9 — Video and audio: programs, break position, and the audio feed (#99, #100, #101) - #150

Open
KonstantinMirin wants to merge 267 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-video-audio
Open

KonstantinMirin wants to merge 267 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-video-audio

Conversation

@KonstantinMirin

@KonstantinMirin KonstantinMirin commented Nov 4, 2026 •

Copy link
Copy Markdown

What this changes

Draft 1 can't say where in a break an ad plays, or which show or game it runs in. Nor can it name the audio feed, or say if the ad is recorded into the content.

  • placement gets a Placement key table (§ 5.2.2), with feed and ssai. It is REQUIRED on a video or audio line item, and plcmt on video.
  • New § 5.2.3 sells pre-roll, mid-roll, and pod slots as priced break_position options, which availability recomputes against (§ 3.3).
  • New § 5.2.9 makes programs and live events selectable, with AdCOM Content and a LEAP EventSchedule. It says what happens when an event doesn't air.
  • content_detail is removed. episodes is its own field, REQUIRED on a podcast or catch-up radio feed.
  • § 5.9 defines dai, scheduled, and embedded for every channel, and the rules for an embedded line item. A buyer can ask for an embedded line item's retention, from @jaanijuk and CRA.
  • § 4.1: RequestedValue gains retention, so a request can carry the retention it asks for.
  • creative_delivery.protocols[] takes AdCOM Creative Subtypes codes, and other_protocols[] takes terms. They replace protocol and third_party_tags.
  • ProductionOption loses cost, since deltas prices a build, and build_owner becomes built_by.
  • § 1.1 maps a ctv line item that carries plcmt to adtypes 2. New § 6.10 and § 6.11 show an embedded podcast and a live event series.

Related issue

Closes #99. Closes #100. Closes #101.

Refs #89, #120, and #121.

Builds on

This PR builds on our placement PR (#120), which merges first, and our DOOH PR. It builds on our settlement PR, our pricing PR, our handoff PR, our post-agreement PR, and our holds PR. Those build on our signing PR, buyer writes PR, lifecycle PR, parties PR, errors and extensions PR, and shared types PR. Through them it carries #18, #70, #71, and #72 by @Sirajmx, #73 to #76 by @Kishore-2572, and #117 and #118 by @aleksUIX. Review the commits "Define video and audio placement, programs, and break position", "Name the advertiser in the embedded podcast example", "Let a buyer ask for a retention", "Count retention among the requestable fields", "Let a request carry the retention it asks for", and "Record the video and audio changes the changelog left out".

Type

  • Editorial — no normative effect
  • Normative — changes what the spec requires
  • Breaking — would break an implementation already built to this draft
  • Examples / schema / docs only

Checklist

  • The body section is updated — § 1.1, § 2.1, § 2.6, § 3.3, § 4.1, § 4.1.1, § 5.2, § 5.2.2, new § 5.2.3, new § 5.2.9, § 5.4, § 5.6.4, § 5.7, § 5.7.1, § 5.9, § 6.3, § 6.4, § 6.7, new § 6.10 and § 6.11, and § 7
  • Appendix A (field index) matches the body — rows for programs, episodes, break_position, and retention; content_detail and third_party_tags removed; placement and controlling_measurement rows updated. scripts/check_appendix.py passes
  • Appendix B (fields by marker, and the counts) matches the body. selectable goes from 14 to 16, and the field count from 97 to 99. seller-set goes from 47 to 46: episodes in, content_detail and third_party_tags out. requestable goes from 5 to 6 with retention.
  • Any affected example in examples/ is updated and still parses — new line-item-podcast-embedded.yaml (§ 6.10) and line-item-ctv-live-series.yaml (§ 6.11). line-item-rewarded-video.yaml (§ 6.7) uses the current field names. The CTV examples gain placement.ssai and serving_mode: dai, § 6.3 gains priced break_position options, and the audio example gains placement.feed. Both record_digest values are recomputed, and manifest.json is regenerated. scripts/check_examples.py checks tentative events and the embedded rules, and passes. scripts/check_pricing_fixtures.py passes 60 of 60
  • RFC 2119 keywords used deliberately — MUST / SHOULD / MAY are not synonyms
  • The no-inheritance rule (§ 2) still holds — every new field sits on the line item
  • Anything selectable declares available[] and included[]; anything settable declares bounds (§ 3.1, § 3.2) — programs and break_position declare both; no new settable fields
  • No confidential or commercially sensitive content

Knock-on effects

Open questions

  1. [Change] § 5.2 — Sell break position and pod slot as priced options: pre-roll, mid-roll, first in pod #99 questions 1 to 5, [Change] § 5.2 — Make programs and live events selectable, and say what happens when one doesn't air #100 questions 1 to 4, and [Change] § 5.2, § 5.9 — Audio: name the feed, and say when an ad is recorded into the content #101 questions 1, 2, 4, 6, and 7 stay open. § 6.4 answers [Change] § 5.2, § 5.9 — Audio: name the feed, and say when an ad is recorded into the content #101 question 5 as proposed, with Music streaming service (1).
  2. final_after is OPTIONAL. Without it, § 5.9 sets no end to post-flight counting on an embedded line item, and § 5.7.1 leaves that to terms_refs[]. Should embedded require final_after? This extends [Change] § 5.2, § 5.9 — Audio: name the feed, and say when an ad is recorded into the content #101 question 4.
  3. Without placement.feed, as on a video line item, every copy the seller distributes counts toward delivery under retention. Should an embedded video line item name which copies count?
  4. What does a seller promise by writing ssai: 0, which AdCOM defines as status unknown?

Contribution Terms

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

KonstantinMirin and others added 30 commits October 24, 2026 23:23
Read the media condition from the ad served when an impression accepts
several media, name the seller as the party that serves, place linear TV
outside the table, and state environments as (distribution channel,
device type) pairs. Insert environments.available[] into the summary
list without rewrapping it, shorten the changelog entry and drop
audio_streaming from OQ-7 in docs/open-questions.md.

Refs IABTechLab#90
Move the summary rule out of the § 2.1 key list, drop skip from the CTV example, and mark the CHANGELOG entry as breaking.
time_zone is the line item's clock for daypart windows and
frequency_cap.period: an IANA time zone name or viewer_local. A window
is { days[], start, end } in civil time with an exclusive end later
than start, up to 24:00; a window that crosses midnight is two windows.
List the `days[]` values once in the `daypart` row, as `monday` | ... |
`sunday`. Write HH:MM, America/New_York, and UTC as plain text, since
they're a format and examples, not field names. The meaning is
unchanged.
"At least one of" an empty list is never satisfied, so the bonus line
would fail a literal check. An absent key sets no condition. Only the
examples change; the any_of[] row and the rules stay as filed in IABTechLab#23.

Refs IABTechLab#23
The floor row now says it "neither constrains nor describes the
downstream auction floor", as IABTechLab#16 asked, and names that floor: the
per-impression floor the exchange applies at auction time (OpenRTB 2.6
Imp.bidfloor).

Refs IABTechLab#16
From the Postindustria review on IABTechLab#73:
- a replay matches on the same body, every value the buyer sent except
  idempotency_key, and returns the stored result whether an acceptance
  or a rejection; a retry against a new version uses a new key;
- version increments on each revision of the proposal, not only while
  published, so a counter under review also moves it;
- "deterministic" now says what the checks depend on: the stored
  proposal and the time the seller receives the attempt;
- the price check names the pricing[] entry the commitment is priced
  against.

Refs IABTechLab#24
Give each repeated concept one type in section 2.2, and state the table,
presence, type, key, and value rules in section 2.6. Add Type and
Required columns to every field and key table. Add the lifecycle,
recorded, asserted, and mixed markers, and a line_items[] field. Define
the Summary as a strict path subset, with manifest key tables.

Delete catalog_ref. Rename the time, reference, delta, cap, and path
fields to use the shared types. Number every heading, and keep issue
citations and edit history out of normative text. Update the examples,
the manifest, the appendices, and the docs.

Teach check_appendix.py the new columns and a closed layout list, and add
check_examples.py, which checks the examples against the spec's tables.
Add section 2.4: a rejection returns errors[], one or more ErrorObjects
with an open code list, retry values that read for any request, and
informative HTTP fits. Name the code each rejection in sections 5.5,
5.6.1, and 5.6.3 returns, and drop the requires cycle ban.

Add the Ext type and section 2.5: ext on the proposal and each line
item, keyed by owner domain, ignored and kept when not understood, and
frozen at agreed. Make spec_version a required proposal field, and ask
in section 8 how a receiver reads a later release.

Add informative security considerations in section 2.7. Word the open
questions without a count. Update the examples and appendices, and
teach check_examples.py the Ext type and the open ErrorObject.
Make seller a Party in section 4.1, with a required legal_name, and add
buyer and commitment.advertisers[]. Move the registry_id rules to Party
in section 2.2, and scope proposal_id to seller.domain.

Add section 1.2 with the three identity layers. In section 5.8, require
visibility, define each value, and separate who may read from who may
commit. Eligibility is a resolve step that returns not_eligible, and an
unreadable line item returns not_found. A required credential is
{ credential_type, issuer }, and eligible_bidders[] splits into
eligible_buyers[] and eligible_seats[].

Give buyer_requirements, billing, and agreement key tables, and convert
the rows the terms and agreement change added. In section 2.3, drop the
manifest seller_id and filter on status, and ask in section 8 whether a
manifest needs both validators. Update the examples, appendices, and
checkers.
# Conflicts:
#	examples/proposal.yaml
#	spec/openproposal-3.0.md
Separate shared and issued proposals, and add issued_from. Define the
binding record, record_digest, and assent[] entries, freeze a version's
offered terms, and state one staleness rule for asks and holds.

Give each act one history action, name the status types, make the
line-item transitions exhaustive, define a firm entry per pricing entry,
and list the allowed decline grounds once. State agreed once.

Remove buyer state from the shared examples, add an issued, partly
agreed example, and recompute its record_digest in the checker.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants