Skip to content

§ 5.2.4 to § 5.2.8 — Property option: seller relationship, app identity, and screens (#88) - #149

Open
KonstantinMirin wants to merge 65 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-property-option
Open

KonstantinMirin wants to merge 65 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-property-option

Conversation

@KonstantinMirin

Copy link
Copy Markdown

What this changes

Draft 1 lets a seller list any domain without saying by what right it sells it. Its property keys sit in prose. This PR gives the property option one key table, and each part of it a numbered section.

  • § 5.2.4: PropertyOption has one key table. Each property states seller_relationship and child_audience, and carries domains[], apps[], or both. When properties is absent, the seller promises no property.
  • § 5.2.5: AppId is { store, bundle }, and App adds store_url and developer_domain. store, a VocabularyTerm, names the app store.
  • § 5.2.6: a buyer can check the seller relationship against the governing ads.txt or app-ads.txt. SellerAccount names the accounts it checks. An app's governing developer domain comes from its store listing.
  • § 5.2.7: child-directed status, and what it means for audiences and buyer-supplied data.
  • § 5.2.8: the DOOH keys move into Screen, Loop, and SyncGroup tables.
  • § 5.5: a block list's app_bundle[] becomes apps[] of AppId.
  • § 2.6: a key table follows a bold lead-in that names its type, and the type of an object option ends Option. scripts/check_appendix.py lints both.
  • § 2.1: a summary lists each property's apps, child_audience, and seller_relationship. § 2.7 covers store_url as an author-chosen URL.

Related issue

Closes #88.

Refs #15, #17, #96, #97, and #71.

Builds on

This PR builds on our DOOH PR and, through it, on these PRs of ours:

It merges #17 by @Sirajmx. Through our PRs it carries #18, #70, #71, and #72 by @Sirajmx, #73, #74, #75, and #76 by @Kishore-2572, and #117 and #118 by @aleksUIX. Review the last commit; the earlier ones belong to the PRs it builds on.

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 — § 2.1, § 2.6, § 2.7, § 5.2, new § 5.2.4 to § 5.2.8, § 5.5, § 5.6, and § 5.6.4
  • Appendix A (field index) matches the body — no field is added or removed, and properties keeps Selectable[PropertyOption]; scripts/check_appendix.py passes
  • Appendix B (fields by marker, and the counts) matches the body — no marker or count changes
  • Any affected example in examples/ is updated and still parses. Each property gains seller_relationship, child_audience, and seller_accounts[]. platform: roku becomes store: roku_channel_store, and the audio example names a property. manifest.json is regenerated, and both proposal examples carry a recomputed record_digest. scripts/check_examples.py reads the new tables and passes. scripts/check_pricing_fixtures.py passes 60 of 60
  • RFC 2119 keywords used deliberately — MUST / SHOULD / MAY are not synonyms. The MUST and SHOULD sentences are those filed in [Change] § 5.2 — State the seller's relationship to each property, checkable against ads.txt #88, [Change] § 5.2, § 5.5 — DOOH properties: venue type, screens, operating hours, and loop #96, and [Change] § 5.2, § 5.3 — Disclose audience taxonomy, data label, sensitive categories, and child-directed properties #97. The block list rejects an entry whose store the seller doesn't know.
  • The no-inheritance rule (§ 2) still holds — every key sits on its property option; nothing comes from the proposal
  • Anything selectable declares available[] and included[]; anything settable declares bounds (§ 3.1, § 3.2) — properties keeps both; no new selectable or settable fields
  • No confidential or commercially sensitive content

Knock-on effects

Open questions

  1. [Change] § 5.2 — State the seller's relationship to each property, checkable against ads.txt #88's questions 1, 2, 3, and 5 carry over to this PR. It follows the filed proposal on 2 and 3: seller_relationship is REQUIRED, and inventory_partner_domain sits on the property. Question 4 is settled here: this PR merges § 5.2 — App identity on properties (#15) #17 and makes developer_domain informative.
  2. properties is OPTIONAL, so a line item with no property states no seller relationship or child-directed status. Should properties be REQUIRED, so that every line item states a seller relationship and a child-directed status?

By opening this pull request I agree my contribution may be published under this
repository's licence, as set out in CONTRIBUTING.md.

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

Sirajmx and others added 30 commits October 6, 2026 16:28
§ 5.2 properties can carry apps[] (platform, bundle, storeurl, domain),
keyed as the OpenRTB 2.6 app object where one exists. Each property
must carry domains, apps or both. The CTV example carries an app.

Refs IABTechLab#15
§ 5.6 defines floor as the seller's offer floor at proposal time, not
the downstream auction floor and not a guarantee that bids will clear.
Editorial: the meaning of the field is unchanged.

Refs IABTechLab#16
Without apps[].domain a buyer has nothing to run the app-ads.txt check
against. RECOMMENDED (SHOULD) rather than a conditional REQUIRED, as the
object has no field in which a seller claims app-ads.txt authorisation.

Refs IABTechLab#15
A proposal can say its line items must be bought together
(linked_execution, § 4.1), and a line item can name the line items or
spend that must be in the same commitment (requires, § 5.6.3). A bonus
line is a line item with requires and its own price. The § 2 "binding
terms" hook now points at a field, and the Summary Representation
carries has_requires and linked_execution.

Adds a CTV bonus line example (§ 6.5) and linked_execution: none to the
proposal example.

Refs IABTechLab#23
The seller declares which exclusion types it accepts and how it
enforces each (exclusions_accepted); the buyer supplies its lists
(exclusions). Blocked apps carry their store, { platform, bundle },
so one store id is never applied across stores. Exclusions are
recompute inputs (§ 3.3) and are never disclosed to other parties
(§ 5.8). The display example declares and supplies lists.

Refs IABTechLab#25
A line item whose rate differs by market can declare geo with the
selectable structure of § 3.1: available[], included[], pricing deltas
and max_select. A geo that declares only allowed[] stays settable, so
existing payloads are unchanged. When several priced markets are
selected, the highest delta applies. The audio example is priced by
market.

Refs IABTechLab#14
A commitment names the proposal and version it was priced against
(§ 5.6.1). The seller rejects a new attempt on a stale version, or past
valid_until or price_valid_until, and returns the current version. An
authenticated replay with the same idempotency_key and terms returns the
stored result without re-running those checks; the same key with
different terms is a conflict. Keys are opaque and scoped to one buyer
and seller pair. § 4.1 states that each revision while published
increments version.

The display, CTV and audio examples carry proposal_id and version.

Refs IABTechLab#24
§ 4.1 adds an optional, immutable proposal_template_id linking an
issued proposal to the seller's template. Each issued proposal has its
own status, version and negotiation_history[], and buyers never need
the template id to transact. § 7 adds a non-normative note separating
seller-side templates from the issued proposals buyers commit against.

Appendix A gains one row; Appendix B counts immutable 6 → 7 and
72 fields. The proposal example carries a proposal_template_id.

Refs IABTechLab#26
§ 5.8 adds terms_ref ({ url, sha256, version }), REQUIRED when
terms_acceptance_required is true, hash-pinned and frozen at agreed, so
assent binds to an exact document. § 5.10 adds agreement_ref, an
informative pointer to the master or annual agreement a line item is
priced under, and documents the io and agreement roles on
external_references[]. IO generation is stated to be a connector
concern, and § 7 adds a non-normative note on relationships.

agreement_ref is seller-set; a buyer-held agreement id travels as an
external_references[] entry with role: agreement, so the field keeps
one marker (§ 3).

Appendix A gains two rows; Appendix B counts seller-set 29 → 31 and
73 fields. The display example carries terms_ref.

Refs IABTechLab#27
A new § 2.3 lets a seller publish its public standard line items at
/.well-known/openproposal.json: seller_id, generated_at, spec_version
and, per proposal, proposal_id, version, the Summary Representation of
each line item and a full_url. ETag / Last-Modified are required, only
line items with visibility public appear, and entries must match the
current version. Buyers discover from the manifest, then fetch the Full
Representation of shortlisted line items.

Adds examples/manifest.json (§ 6.5) and visibility: public to the CTV
and audio examples; the registry_gated display line item is not listed.

Refs IABTechLab#29
The specification does not define authentication yet (WS1; see IABTechLab#62),
so the replay rule now applies to a replay from the same buyer rather
than an authenticated replay.

Refs IABTechLab#24
agreement_ref.parties used buyer_id, which the specification does not
define. parties[] now names the seller by its seller_id and the buyer
by the id it holds in eligible_bidders[] (section 5.8).

Refs IABTechLab#27
The rule that a hold on a linked_execution: all proposal uses
hold_scope: proposal came from a comment on IABTechLab#23, not the change request
as filed. It moves to the PR description as a point for the working
group, so this PR carries only the filed change.

Refs IABTechLab#23
IABTechLab#25 names the content-category list iab_content_category[], a list of
IAB Content Taxonomy ids. The earlier commit renamed it content_category
with a version-pinned taxonomy_ref, which nobody proposed. This restores
the filed name and shape; which taxonomy version to reference is left
to the working group.

Refs IABTechLab#25
IABTechLab#14 doesn't say how deltas combine when a buyer selects more than one
priced market, and neither did any comment on it. The earlier commit
said the highest delta applies; that is a design choice nobody
proposed, so it moves to the PR description as a question.

Refs IABTechLab#14
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
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
- Rename apps[].domain to developer_domain, as IABTechLab#15 filed it. It is the
  developer domain from the store listing that app-ads.txt uses, not
  OpenRTB 2.6 app.domain, which is the domain of the app.
- Define platform as the store that issued bundle, since a bundle is
  unique only within its store.
- List apps[].platform and apps[].bundle in the Summary Representation
  (section 2.1), as IABTechLab#15 asked.

Refs IABTechLab#15
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
# 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.
Keep record_digest only on assent entries, and state the exact digest
bytes. Cut the record to terms: min_rate, the advisory fields, segments,
and the suppression list leave it, and seller_rate and deal_id_issuance
go. Give AssentEntry a key table with four roles, so only assent[]
decides agreed, and move idempotency_key onto the entry.

Name the Commit and its CommitResult. The seller recomputes the digest
over the line items as they stand, and rejects in a stated order. A
commitment entry stops being live when its commit goes stale or void.

Carry entries in messages signed under the OpenProposal profile of Web
Bot Auth, as optional evidence. Add HttpsUrl, and replace terms_ref with
terms_refs[] of DocumentRef. Add the agreed record example, and teach
the checker the assent rules.
Add selected[] as the complete set of options in effect and value as the
one buyer key on a settable field, with an explicit default. An envelope's
value narrows allowed[], and the bare-value fallbacks go. Every object
option has an id, unique in its field. Name BuyerWrites, LineItemWrites,
and the availability read.

Give agreed_rate one formula, on the committed entry only, rounded once.
Rename gross_rate to list_rate, floor to min_rate, a hint, and delta_pct
to delta_fraction, a fraction. Make list_rate and commitment_bounds
requestable, mark commitment mixed, and give transaction_mechanism
max_select 1.

Split geo into a settable geo and a selectable markets over GeoCode, type
device as AdCOM codes and daypart as ClockWindow, and delete
supported_formats. Update the examples, the issued record_digest, the
appendices, and the example checker.
Split what a request or response carries from the message envelope in
section 1.2, and resolve its placeholders. The wire contract governs only
once it is on a standards track. Name the baseline as the VersionRef of
the agreed line item at the version of its agreed record.

Add change_requests[] in section 4.4 with the OpenDirect 2.1
ChangeRequest fields except webhook, plus baseline, actor, at, and
cancellation. Require orderid only when the line item has an order
reference. Remove correlation_id, give ExternalReference a key table,
rename role to reference_type, and replace io with order and line.

Let an entry carry ext outside the record, and ask in section 8 how an
entry states a change other than a cancellation. CancellationNotice stays
pending until its key table lands. Retitle sections 5.10 and 6.8, and
update the agreed example, the appendices, the issue templates, and the
checkers.

Refs IABTechLab#59, IABTechLab#68
Put one table of transaction_mechanism values in section 5.9. It states
which are deal mechanisms and which delivery_type each allows. Key
section 1.1 on those values, with each one's reference type and change
path. An option is { id, delivery_type }, and sov_basis and sov_share
describe a share of voice. Remove open_auction, because with no deal ID
no bid request can name a line item.

Map a line item agreed under a deal mechanism to a Deals API 1.0 Deal
that deal_origin pushes, with price_type saying how agreed_rate clears.
Map a direct_io line item, and a programmatic guaranteed reservation, to
an OpenDirect 2.1 Order and Line, and state what the record doesn't hold.

Define each creative_delivery.method as a creative path. Remove
buying_route and supported_order_systems, and type serving_platform as a
Domain. Update the examples, digests, manifest, appendices, and checkers.

Refs IABTechLab#132, IABTechLab#133, IABTechLab#93, IABTechLab#109
Replace hold_status with hold_terms, a seller-set offer inside the binding
record, and hold, live state outside it, so the removal path has no
exception. Rename state and hold_expires_at to status and valid_until, add
position, the order in which holds are granted, and leave hold absent until
the buyer first asks.

Close the hold machine: add declined, re-entry to requested, and the
re-offer as listed transitions, and state the cap on valid_until. Give hold
a version and two optional keys, requested_terms as LineItemWrites and
held_availability as Availability, which stays pending until its key table
lands. Remove hold_scope: under linked_execution all, holds move as a unit.

Stop the CTV example offering a hold on private_auction, show a full hold in
the issued example, and recompute its digest. Drop the checker's handling of
exceptions in removal paths, and check the keys of LineItemWrites.

Refs IABTechLab#66
Open the cost_method vocabulary, with a unit and a rate per for each
core term in section 5.6.5. Make pricing entries alternatives named by
pricing_id. Read every Amount in the committed entry's CurrencyCode,
remove commitment.currency, and ask in section 8 what basis a money
value is on.

Replace min_spend and the budget keys with commitment_bounds.spend, and
the impression keys with pricing[].unit_bounds. Give Availability,
CommitmentBounds, and MinCommitment key tables, and point the section
1.1 totals at the seller total. Define cancellation options, the notice
a change request records, and exclusivity options.

Teach the example checker the commitment arithmetic, the bounds, and the
cancellation checks. Have it check that an array whose row says MUST be
non-empty holds an entry. Align the pricing vectors with these names,
and update the examples, digests, manifest, and appendices. Replace the
PG and PMP floor example in CONTRIBUTING.md and the comment template,
since pricing entries can name their mechanisms.

Refs IABTechLab#94, IABTechLab#98, IABTechLab#117, IABTechLab#127, IABTechLab#115, IABTechLab#30, IABTechLab#70, IABTechLab#125, IABTechLab#121
Settlement reads the terms in force: the agreed record plus any change
the applying system has applied. Section 5.7.1 names what no downstream
standard states, and states the shortfall and remedy rules once.

controlling_measurement names whose count is invoiced and when it is
final. measured_by and counted_by are a Measurer, with a qualifier for a
product or method. CommittedMetric gets a key table with level and
direction, and basis and seller_reported go. metric gets a core table of
rate terms that cite their standards. shortfall_remedy becomes a
ShortfallRemedy with RemedyTerms, and section 8 gains question 10.
verification[] holds domains, viewability_standard gains mrc, feed_type
and delivery_mechanism become report_type and delivery_method, and
guaranteed covers a FLAT entry.

The examples name the measurement vendors by domain, and the checkers
read the metric table and type the new keys.
When channel is dooh, a property is a set of screens of one venue type,
with venue_type, allocation, min_screens, screens[], slots_per_loop, and
sync_groups[]. frequency_cap.per gains the screen term, and a loop_time
share derives from the loop.

Section 5.6.4 defines a play and an impression. delivery_counting,
REQUIRED on a dooh line item, holds the play tolerance, a keyed
proof_of_performance, partial_play_credit, and a nested
impression_multiplier that only a line item counting impressions needs.
The committed quantity is in the committed entry's unit, and the
multiplier's source controls the count of impressions.

Add the DOOH example. The example checker reads the new paths and checks
the counter against the multiplier's source.
# Conflicts:
#	spec/openproposal-3.0.md
PropertyOption has one key table in section 5.2.4, and a screen has its
own in section 5.2.8, with Loop and SyncGroup. App identity, seller
relationship, child-directed status, and DOOH screens each get a
numbered section.

Each property states the seller's relationship and the accounts a buyer
checks, and declares whether it is directed to children. AppId is
{ store, bundle }, and App adds store_url and developer_domain. The
platform key becomes store, an open vocabulary of store names. A block
list's app_bundle[] becomes apps[] of AppId.

A key table follows a lead-in that names its type, and an object
option's type ends Option. The table lint enforces both, and the example
checker reads the property, screen, and app tables.

Closes IABTechLab#88
Refs IABTechLab#15, IABTechLab#17, IABTechLab#96, IABTechLab#97, IABTechLab#71
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Change] § 5.2 — State the seller's relationship to each property, checkable against ads.txt

4 participants