Skip to content

§ 2.4, § 2.5, § 2.7 — Errors, extensions, and forward compatibility (#130) - #138

Open
KonstantinMirin wants to merge 23 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-errors-extensions
Open

KonstantinMirin wants to merge 23 commits into
IABTechLab:mainfrom
KonstantinMirin:op30-errors-extensions

Conversation

@KonstantinMirin

@KonstantinMirin KonstantinMirin commented Nov 4, 2026 •

Copy link
Copy Markdown

What this changes

Draft 1 doesn't say what a rejection carries, or what a reader does with a key the draft doesn't define. This PR answers both.

  • § 2.4 defines errors[], one or more ErrorObjects, with ten core codes and a retry value. HTTP fits are informative. A decline isn't an error.
  • § 5.5, § 5.6.1, and § 5.6.3 name the code each rejection returns. § 5.6.3 drops the requires cycle ban; our packages PR replaces requires.
  • § 2.2 adds Ext, and § 2.5 states its rules. The proposal (§ 4.1) and each line item (§ 5.1) MAY carry ext.
  • spec_version is a REQUIRED proposal field (§ 4.1). § 8 question 8 asks how a receiver reads a later release.
  • § 2.7 adds informative security considerations.
  • The docs word the open questions without a count.
  • scripts/check_examples.py checks Ext, and treats ErrorObject as open.

Related issue

Closes #130, a change request from Postindustria (IAB Tech Lab member).

Refs #131, our extensions change request. This PR carries its text, and OQ-8 keeps tracking its question there.

Refs #33, #71, #73, #70.

Builds on

This PR builds on our shared types PR. It carries #71 by @Sirajmx and #73 by @Kishore-2572, at their heads. The merges give their new rows Type and Required cells. #71 drops its catalog_ref clause, and #73's valid_until reads offer_window.end. Review the last commit and the merges of #71 and #73.

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, § 2.2, § 2.4, § 2.5, § 2.7, § 4.1, § 5.1, § 5.5, § 5.6.1, § 5.6.3, § 8
  • Appendix A (field index) matches the body — three rows: spec_version, and ext on the proposal and the line item; scripts/check_appendix.py passes
  • Appendix B (fields by marker, and the counts) matches the body — seller-set 33 → 36; 76 → 79 fields
  • Any affected example in examples/ is updated and still parses — proposal.yaml gains spec_version and ext, line-item-display.yaml gains ext; scripts/check_examples.py passes
  • RFC 2119 keywords used deliberately — MUST / SHOULD / MAY are not synonyms
  • The no-inheritance rule (§ 2) still holds — it names spec_version among what the proposal supplies; each object carries its own ext
  • Anything selectable declares available[] and included[]; anything settable declares bounds (§ 3.1, § 3.2) — no new selectable or settable fields
  • No confidential or commercially sensitive content

Knock-on effects


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 23 commits October 22, 2026 15:56
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 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
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
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
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
"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
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.
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] § 2, § 5.5, § 5.6 — One error object for rejections: code, pointer, current version, retry

4 participants