Skip to content

[Change] § 5.3 — Machine-readable attestations for buyer_supplied data provenance and diligence #116

Open

Description

@peterduhon

What kind of change?

Add a new field

Which section?

5.3 — Audience reach

Current text

| `buyer_supplied` | Object | supplied | `{ segments_allowed, suppression_allowed, match_rate_expected, segments[], suppression_list }`. `match_rate_expected` is the seller's stated expectation; `segments[]` and `suppression_list` are buyer-populated |

Proposed text

"buyer_supplied": {
  "segments_allowed": true,
  "suppression_allowed": true,
  "match_rate_expected": 0.65,
  "segments": [],
  "suppression_list": [],
  "diligence_ref": {
    "type": "audience_diligence",
    "issuer": "diligence.example",
    "ref": "12345@2",
    "digest": "sha256:..."
  }
}

Why

Issue #108 rightly addresses the mechanics of the data-sharing handoff (how data moves via S3, Snowflake, clean rooms, etc.). However, the current OpenProposal object model describes the transport without capturing the authorization or attestation that must logically precede it.

In an agentic workflow, a seller's automated compliance agents cannot safely execute a match count or a data ingestion without verifying that the buyer agent is authorized to provide those segments. While AAMP 2.3 integrated the IAB Diligence Platform into the execution layer, OpenProposal (§ 5.3) lacks a mechanism for the buyer to assert this diligence at the proposal stage.

This proposal is not asking OpenProposal to define privacy semantics, consent frameworks (TCF/GPP), or data lineage standards. It is simply asking the protocol to provide a standardized "trust boundary" pointer (diligence_ref).

If the spec lacks an attestation model, the RFP workflow becomes a compliance bottleneck. A buyer agent might optimize for reach/CPM and commit to an RFP, only for the seller to reject the subsequent data handoff because the buyer cannot attest to the provenance of the audience. Providing a generic attestation reference ensures:
Lineage and Trust: The agreed proposal object becomes a self-contained record that the buyer asserted the right to transact.

Protocol Extensibility: Today this pointer references audience diligence; tomorrow it could reference healthcare certification (HCP scenarios), geographic data residency requirements, or political advertising approvals.

Scope Preservation: It preserves flexibility and interoperability without forcing the OpenProposal WG to become a privacy standard-setting body.

diligence_ref (optional, string): A reference to external diligence, consent, or audience provenance documentation maintained outside OpenProposal. This serves as a machine-readable attestation by the buyer agent that prerequisite conditions for the requested data handoff (as configured via activation_route or Issue #108 mechanisms) have been satisfied.

Knock-on effects

  • Downstream Standards (OpenDirect / Deals API): Binding diligence_ref into the resulting Deal object — so that the execution layer inherits the trust boundary established at the proposal stage — is the desired end state, but it is out of scope for this change request. It will require a corresponding change request to OpenDirect (and, where relevant, the Deals API), covering the contract generation phase and the Deal object's field surface. This issue flags that knock-on effect rather than asserting it. Until such a change lands, OpenProposal's guarantee is limited to preserving the attestation in the agreed proposal record, where it remains available for out-of-band diligence and audit.

  • OpenRTB 2.6: At the bid-request level, OpenRTB does not need to carry the diligence_ref directly. The deal.id in the OpenRTB request implicitly resolves back to the OpenProposal object where the attestation lives, maintaining separation between commercial discovery (OpenProposal) and transactional execution (OpenRTB).

  • Examples in § 6: The HCP (healthcare) and clean-room examples from Issue [Comment] § 5.3 — Buyer-supplied audience match: reachable count, avails, and data-sharing handoff #108 would simply include "diligence_ref": "uri:iab-diligence:12345" to demonstrate how a buyer agent signals compliance before the seller agent executes the match.

  • "Resolves without a round trip" guarantee (§ 3): Because this is an optional string reference (URI/ID) rather than a nested object requiring recursive validation, it preserves the lightweight parsing guarantees of the spec. The actual resolution of the diligence assertion happens asynchronously out-of-band, mirroring how catalog_ref resolutions are handled.

  • No-inheritance rule: The diligence_ref remains strictly scoped to the buyer_supplied object. It asserts authority over the buyer's inputs (segments/suppressions) and does not inappropriately inherit into the seller's catalog, pricing, or environments.

Would this break an implementation already built to this draft?

No — additive or editorial

Alternatives you considered and rejected

1. Embedding the full privacy/consent payload (e.g., full TCF string, SafeGuard object) directly in the proposal:
Rejected: This bloats the proposal object massively and violates the separation of concerns. A proposal should remain a lightweight commercial menu. Embedding nested consent graphs would break the lightweight parsing guarantees of the spec.

2. Handling diligence strictly out-of-band with no machine-readable footprint in the proposal:
Rejected: While the actual data lives out-of-band, the assertion of authority must be machine-readable for agentic workflows. If buyer and seller agents negotiate at machine speed, a lack of a machine-readable signal forces agents to blindly attempt data matches, resulting in automated compliance failures, wasted compute, and broken execution SLAs. The protocol needs a machine-readable trust boundary.

3. Defining normative privacy semantics within OpenProposal (e.g., adding hipaa_compliant or gdpr_tcf booleans/fields):
Rejected: Scope creep. OpenProposal is a commercial protocol, not a privacy standard. Hardcoding regulatory frameworks (GDPR, CCPA, PIPL) into the object model would make the spec brittle to future legal changes. A generic pointer (diligence_ref) future-proofs the protocol against regulatory evolution.

You are commenting as

Individual, no organisational position

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

  1. peterduhon commented on Oct 24, 2026

    @peterduhon
    Author

    Editorial revision to the Knock-on effects section: the OpenDirect bullet now flags the binding of diligence_ref into Deal contract generation as requiring a companion change request to OpenDirect, rather than asserting it as part of this proposal. No change to the proposed § 5.3 normative text.

  2. KonstantinMirin commented on Oct 25, 2026

    @KonstantinMirin

    Thank you, @peterduhon. Postindustria (IAB Tech Lab member) supports a provenance reference. As proposed, diligence_ref is a string the buyer agent writes, with no issuer or signature to check: a claim, not an attestation. We ask for an opaque reference in buyer_supplied (§ 5.3):

    "diligence_ref": { "type": "audience_diligence", "issuer": "https://diligence.example", "ref": "12345" }
    • type is an open vocabulary: a core list plus domain-namespaced terms. Your healthcare, data-residency, and political-advertising cases then need no spec revision.
    • issuer is the https origin of the party that did the diligence and signs the record.
    • ref identifies that record at the issuer.

    The proposal carries the reference, and its meaning stays with the issuer. Nothing resolves while parsing. Our AAMP identity proposal (AAMP #3) applies the same principle to agents: "A signature proves the signer, never the authority."

    Our binding-record change request (#63) already keeps every buyer_supplied field except match_rate_expected under record_digest, so both assents name the reference.

    Open questions:

    1. Which party issues a diligence record that a seller can verify? The buyer reference agent's IAB Diligence Platform integration records the buyer's approval of sellers, scoped to the buyer's own tenant.
    2. Should the reference also carry a digest of the signed record, so the assents bind its content and not only its location?

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

  3. peterduhon commented on Nov 10, 2026

    @peterduhon
    Author

    Accepted. The issuer anchored shape is a superior design, and your framing names the flaw precisely. A bare string lets the buyer assert, while the structured reference lets the seller see who stands behind the claim before deciding whether and how to verify it. I am updating the proposed text below.

    Two alignment notes with the existing object model, then answers to your open questions.

    Alignment. Using an https origin for the issuer matches the semantics already used by required_credentials[].issuer in § 5.8. This maintains one concept of issuer across the spec. Furthermore, the namespaced open vocabulary for type follows the same pattern as the catalog_ref and channel namespaced format identifiers. Core terms cover common cases, while domain terms extend without requiring a spec revision. This lands the extensibility case from the original proposal much more cleanly.

    On Q1. Who issues a diligence record a seller can verify. Issuance should follow the authority chain of the data. For first party segments, the authority is the compliance function of the buyer. The buyer issues the record, and trusting it becomes a policy decision for the seller against a named origin. For third party segments, the natural issuer is the provider that granted transmission rights in the first place, since the diligence question of whether the buyer may hand these segments to the seller is ultimately for the provider to answer. Neutral venues like clean rooms can also issue records where both parties already trust the operator. I would not have OpenProposal enumerate or prefer any of these. The spec simply requires a resolvable origin and nothing more. Per your AAMP #3 principle, the signature proves the signer. Whether the authority of the signer matters is strictly a policy decision for the counterparty. Verification semantics belong in the identity workstream, not the proposal object.

    On Q2. A digest of the signed record. Yes, but it should be optional and recommended rather than strictly required, because it supplies the content pinning this reference otherwise lacks. Without it, the reference simply points at a live document. The issuer can reissue, rescope, or supersede after agreement, and the meaning of the committed artifact silently drifts. That is the exact hazard that the version pinning in § 2.2 exists to prevent for catalog_ref. A diligence record is a fact about a specific moment in time, just like a catalog entry. A digest object containing the algorithm and value binds the assents to what was attested rather than merely where it lives. Given that #63 already places buyer_supplied fields under record_digest, the structural reference is named by both assents, and the digest extends that binding to the external record itself. Where an issuer does not sign, a version suffixed reference is the fallback. Algorithm choice should follow the scheme of the issuer rather than the spec.

    Consolidated proposed text for § 5.3 in the buyer_supplied object:

    "diligence_ref": {
      "type": "audience_diligence",
      "issuer": "https://diligence.example",
      "ref": "12345@2",
      "digest": {
        "alg": "sha256",
        "value": "..."
      }
    }
    • type is an open vocabulary with a core list plus domain namespaced terms.
    • issuer is the https origin of the party that performed the diligence and signs the record, using origin semantics consistent with § 5.8.
    • ref identifies the record at the issuer and is version suffixed where the issuer versions records.
    • digest is optional and recommended, binding assent to content rather than location.

    Nothing resolves while parsing (§ 3). The reference remains opaque to OpenProposal and freezes into the committed artifact at agreed. The alternatives rejected section of the original issue stands unchanged, as issuer anchoring strengthens the scope preservation argument rather than altering it.


  4. KonstantinMirin commented on Nov 11, 2026

    @KonstantinMirin

    Thanks, @peterduhon. Three details against our open PRs. The second changes my own example.

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

  5. changed the title [-][Question] § 5.3 — Machine-readable attestations for buyer_supplied data provenance and diligence[/-] [+][Change] § 5.3 — Machine-readable attestations for buyer_supplied data provenance and diligence[/+] on Nov 11, 2026
  6. peterduhon commented on Nov 11, 2026

    @peterduhon
    Author

    @KonstantinMirin

    All three accepted. The first two are your #157 rule — one type per concept — applied to this proposal, and each removes a type form the proposal was inventing. The third changes what the signature protects, and it lands in the proposal's favor.

    1. digest as the Digest string (#137). Agreed. An { alg, value } object re-derives a type the spec already carries, and since the value itself carries the algorithm, the "algorithm follows the issuer" caveat from my last comment can be deleted rather than qualified. sha256-only in this version (§2.2) is fine — nothing about diligence needs a hash the rest of the record doesn't already use. Q2's optional-and-recommended standing is unchanged.

    2. issuer as a Domain, host form (#139, #142). Agreed — and since the correction retires your example and mine in the same stroke, the merged form inherits the fix cleanly. It also completes the alignment argument rather than weakening it: I anchored diligence_ref.issuer on required_credentials[].issuer (§5.8), that field is a Domain, so the https:// prefix was a deviation from my own anchor — and it stays a Domain whichever array carries it after #139's split into eligible_buyers[] and eligible_seats[]. The host form also composes cleanly with the Q1 answer: first-party data puts the buyer's host in issuer, third-party segments put the provider's — one form covering both branches of the authority chain.

    3. The binding record under #142. Understood, and the reduced scope lands in the proposal's favor. With buyer_supplied.segments and suppression_list leaving the record as deliveries (§4.1.1), the record_digest on the assents no longer covers the payloads the buyer asserts provenance over. That promotes the in-record pointer from convenience to the load-bearing element: diligence_ref is not among the paths that leave the record, so it stays in, and both assents still name it. The signature covers the claim where it no longer covers the payload; the optional digest extends that one step further — from where the referenced record lives to what it said. The seller's check path is unchanged: assents → resolve ref → the diligence record speaks for the data at its origin.

    Consolidated form against #137 / #139 / #142:

    "diligence_ref": {
      "type": "audience_diligence",
      "issuer": "diligence.example",
      "ref": "12345@2",
      "digest": "sha256:…"
    }

    Every element is now an existing spec type: a namespaced vocabulary term for type (the catalog_ref / format-id pattern), a Domain for issuer, a version-suffixed ref, a Digest string for the content pin. diligence_ref introduces no new type forms — which is where I wanted it to land for disposition.

    I've folded this into the issue body's Proposed text and retitled to [Change], since the question has converged into a concrete change request.

  7. KonstantinMirin commented on Nov 12, 2026

    @KonstantinMirin

    Thanks, @peterduhon. One naming detail against #137: it reserves the suffix _ref for a DocumentRef or an EntryRef (§ 2.6), so an object with your four keys needs a name without it, such as diligence. My earlier example used that name too. To keep diligence_ref, it could be one EntryRef string (§ 2.2), "diligence.example/audience_diligence/12345@2", when the issuer versions its records, with type as its own VocabularyTerm key. An EntryRef carries no digest, so that pin is #129's question.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions