Skip to content

docs: add property_list_exclude spec proposal#5773

Merged
nastassiafulconis merged 7 commits into
mainfrom
property-list-exclude-spec
Jul 1, 2026
Merged

docs: add property_list_exclude spec proposal#5773
nastassiafulconis merged 7 commits into
mainfrom
property-list-exclude-spec

Conversation

@nastassiafulconis

@nastassiafulconis nastassiafulconis commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Why

Property lists are the last list construct following the include/exclude pair convention that lacks its exclude twin (device_platform and language also lack _exclude, but those are scalar dimensions — geo ×4, audience, device_type, and collection_list all expose the paired convention). The collection-lists spec already says "a future protocol evolution may add property_list_exclude for symmetry" — this formalizes that.

The gap is narrower than it looks. The property-lists specialism already covers inclusion and exclusion. A property list is polarity-neutral — polarity is assigned by which targeting field references it, so a buyer can host the 65k blocklist today. The only missing piece is a targeting-overlay field to attach it to a media buy.

What

Spec-only (no code change in this PR). Proposes one field property_list_exclude in core/targeting.json, mirroring collection_list_exclude, reusing property-list-ref.json. Covers exclude-wins semantics, the resolve-cache-enforce model, explicit per-direction capability entries in get_adcp_capabilities, and the property_targeting_allowed edge case.

Open questions resolved in follow-up commit: capability granularity (Q1 → explicit targeting table entries, not specialism), precedence wording (Q3 → lifted verbatim from collection lists). Remaining items requiring WG sign-off: property_targeting_allowed reject/requote trigger condition (Q2) and coverage receipt shape (Q4 — blocker before field ships).

Property lists are the last targeting dimension without an exclude
counterpart. The governance layer already supports exclusion (the
property-lists specialism covers "inclusion and exclusion lists" and
create_property_list accepts an exclude purpose); only a targeting-overlay
field to reference an exclude list is missing. The collection-lists spec
already anticipates adding property_list_exclude for symmetry.

Proposes a single field mirroring collection_list_exclude, reusing
property-list-ref.json, with exclude-wins semantics and the existing
resolve-cache-enforce model. Captures the brand-safety failure mode
(silent ignore must be a hard reject) and the property_targeting_allowed
divergence (exclusion is a safety control, not gated by it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aao-release-bot[bot]
aao-release-bot Bot previously approved these changes Jun 30, 2026

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. A Draft spec proposal that adds no wire surface — it documents a future field and reasons about it correctly. Right call to land the thinking before the schema.

Things I checked

  • No wire change. Single file, specs/property-list-exclude.md, 138 additions. No static/schemas/source/** touched, so no changeset required. The field is proposed in prose, not added to core/targeting.json.
  • Lineage claims hold. The specialism quote matches enums/specialism.json:48 verbatim ("curated inclusion and exclusion lists for targeting and delivery compliance"). The collection-lists rationale is reproduced accurately from specs/collection-lists.md:338. property-list-ref.json exists and is reused unchanged.
  • Mirror is faithful. Proposed shape tracks the live collection_list_exclude at core/targeting.json:166 — same ref type, same "Seller must declare support in get_adcp_capabilities" language, same exclude-wins ordering.
  • Fail-loud asymmetry is sound (principle 4). For an include list a silent miss over-restricts (safe); for an exclude list it under-restricts (unsafe), so MUST-reject on an undeclared property_list_exclude is the right default. fail-closed beats fail-open on a brand-safety control.
  • The one real divergence is flagged, not buried. Principle 3 — exclusion ungated by property_targeting_allowed, unlike property_list (core/targeting.json:160) — is the load-bearing design decision here, and it's correctly surfaced as Open Question #2 for WG sign-off rather than asserted as settled. That's the right altitude for a Draft.

Follow-ups (non-blocking — file as issues)

  • Open Question #1 (capability granularity) is the one that determines wire shape when this graduates: rely on the property-lists specialism alone, or add an explicit targeting capability distinct from get_products property_list_filtering. The proposal correctly notes the existing property_list_filtering boolean is discovery-scoped, not an enforcement signal — resolve this before the schema PR so the capability story ships with the field, not after.

Minor nits (non-blocking)

  1. Status line. Mark it Status: Draft — pending WG review so the three open questions don't read as settled when this is linked from a future schema PR. (specs/property-list-exclude.md:3)

LGTM. Follow-ups noted below.

@mintlify

mintlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
adcp 🟢 Ready View Preview Jun 30, 2026, 5:41 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviewed this closely (thanks @nastassiafulconis) — the vehicle choice is right and the field should land. Summary: ship the field, but the three enforcement rules bundled in aren't "just mirroring collection_list_exclude" — they're new invariants that need sell-side sign-off. Details below, with a direct answer to Open Q1 up front since that's the one blocking the safety story.

Vehicle: correct, and complementary to content-standards (not a substitute)

The property-vs-content-standards boundary this draws is verbatim the one specs/collection-lists.md:52 already blessed: "if it can be decided from the collection's declared metadata alone, it's a list filter; if it requires evaluating actual content, it's content standards." A 65k domain+app do-not-run list is 100% identifier-decidable → property layer. Routing it through content-standards would be a category error — that's a per-impression, calibration-based evaluator for ephemeral/AI/CTV content that can't leave publisher walls, and it's statistical (fail-unsafe) for a hard blocklist. They compose as different layers; they don't compete. One point worth adding to the proposal in its favor: a property blocklist maps cleanly to seller-side badv/bapp deny-lists (GAM/Kevel/DSPs all support this); content-standards has no clean OpenRTB block-list equivalent.

Open Q1 (capability granularity) — reco: explicit, per-direction capability

Don't rely on the property-lists specialism, and don't reuse property_list_filtering (that's scoped to get_products discovery — get_adcp_capabilities.mdx:224, media-buy-features.json:14 — not serve-time targeting-overlay enforcement). Concretely:

  1. Add property_list and property_list_exclude as entries in the get_adcp_capabilities targeting table (get_adcp_capabilities.mdx:284–293), following the keyword_targets/negative_keywords precedent (each direction declared explicitly, :292–293) rather than the implicit audience/device precedent (:295).
  2. Generalize the existing fail-loud MUST at get_adcp_capabilities.mdx:298 from "a geographic targeting level" to "any targeting-overlay dimension, including property and collection lists."

Why per-direction and explicit: exclusion fails unsafe (silent drop = you run on the blocklist), so pre-submit detectability is the safety property. An agent-level specialism can't give a buyer a per-field signal — the buyer would only discover non-support via rejection, or worse, silent ignore. This also turns Principle 4 from a fresh assertion into an application of settled spec text (:298), which is the right way to give the MUST a normative home instead of leaving it in a schema description string.

Two factual corrections

  1. "Last targeting dimension without an exclude counterpart" is overstateddevice_platform and language also lack _exclude. Accurate framing: the only list construct / paired-convention dimension missing its exclude twin (geo ×4, audience, device_type, collection_list all have it).
  2. "create_property_list already accepts an exclude purpose" is inaccurate — there's no purpose field on the list object; the exclude_identifiers filter is within-list refinement, not list polarity. A property list is polarity-neutral — it's just a set of properties, and polarity is assigned by which targeting field references it. This actually strengthens the case: the hosting side needs zero changes, Gold Peak can host the 65k list today, and the only missing piece is the reference field.

Needs sell-side / WG sign-off before build (not an author nod)

  1. Ungating from property_targeting_allowed (Principle 3). Well-motivated — the flag is about subsetting for optimization (product.json:182), not safety. But it diverges from the gated include twin and can silently shrink an all-or-nothing / roadblock / sponsorship product below its fulfillment commit. Resolution: exclusion is honored where honorable, but the seller MUST be able to reject or requote when the drop breaks fulfillment or empties the buy — there's a signal_targeting_groups → REQUOTE_REQUIRED precedent already in targeting.json:144. Define that edge; otherwise "ungated" just moves the silent failure to the deliverability side.
  2. Fail-loud MUST-reject + the capability signal that backs it — see Q1. The MUST is sound (and worth retro-applying to collection_list_exclude), but it's a new seller obligation, not parity.
  3. Per-buy coverage receipt (I'd call this a blocker). collection_list_exclude's flow already returns matched_count/unmatched_entries/filtered_count at buy creation (specs/collection-lists.md:356–361); this proposal drops it. For a 65k list where the seller carries few entries, the buyer can't tell "enforced my list" from "matched 0, ran everywhere" — the exact under-restriction fail-loud is meant to prevent. Add an exclusion coverage summary at create/update_media_buy.

Companion: collection_list_exclude has the identical latent hole → #5788

The field this claims to mirror carries neither the fail-loud MUST-reject nor a capability-table entry today, so a seller can silently accept-and-ignore a collection do-not-air list right now. As written, property_list_exclude would ship a stronger contract than collection_list_exclude. Filed #5788 — let's fix both together under one enforcement/detectability contract.

Smaller items

  • Stale/unreachable exclude cache: for an exclude list, keep enforcing last-known-good (fail-closed toward the blocklist); REFERENCE_NOT_FOUND / unreachable governance agent → reject the buy, don't proceed-without-exclusion. One sentence in Enforcement.
  • Zero-delivery edge: define behavior when the exclude empties the buy (reject / warn, not silent no-fill).
  • Scale: 65k is a different order of magnitude than the small approved-inclusion sets property lists were built for — a word on cache footprint / refresh on property_list_changed / matching cost.
  • Single-ref vs array-of-refs (brand + agency + desk layering): shared open question with collection lists (collection-lists.md:570) — acknowledge, don't solve here.
  • Precedence: lift the "include applies first, then exclude removes matches" sentence verbatim from collection lists (your Open Q3) and add one line on subtraction from the effective served set.
  • Versioning: additive/minor field, target 3.2 alongside the other targeting-overlay work; flag the compliance-storyboard update under the property-lists specialism for the new MUST.

@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Issue #5788 proposes collection_list_exclude capability signal + generalized fail-loud MUST — same surface as this PR (core/targeting.json, get_adcp_capabilities); consider folding before merge or confirm follow-up.


Generated by Claude Code

@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Issue #5788 proposes adding collection_list / collection_list_exclude to the get_adcp_capabilities targeting table and generalizing the fail-loud MUST-reject rule to all targeting-overlay list dimensions — same surface as this PR. Consider folding before merge or confirm follow-up.


Generated by Claude Code

@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Re: fold or follow-up on #5788fold the capability-table entries and MUST generalization; defer the coverage receipt.

Fold into this PR:

  • Add collection_list / collection_list_exclude to the targeting table alongside property_list / property_list_exclude — same paragraph, get_adcp_capabilities.mdx:284–293
  • Generalize the fail-loud MUST at :298 from geo-scoped to "any targeting-overlay list dimension"@bokelley's Q1 recommendation already calls for this exact text

These are single-sentence edits at the same location this PR is already touching. Writing the generalized MUST once is cleaner than adding a property-list-scoped MUST here and widening it in a follow-up, and it closes the asymmetry @bokelley flagged ("otherwise property_list_exclude would ship a stronger contract than the field it claims to mirror").

Leave on #5788:

  • Per-buy coverage receipt for collection_list_exclude (matched/unmatched/filtered counts at create/update_media_buy) — non-trivial flow addition beyond the doc-only scope of this PR; better as a standalone follow-up.

(Side note: this fold suggestion was posted twice in quick succession — 17:03:37 and 17:03:54. The second is a triage dedup miss; one is sufficient.)


Generated by Claude Code

…tions, enforcement gaps

- Fix "last targeting dimension" → "last list construct following the
  include/exclude pair convention" (device_platform and language also
  lack _exclude but are scalar dimensions)
- Fix create_property_list characterization: property lists are
  polarity-neutral; polarity is assigned by the targeting field
- Resolve Open Q1: replace specialism-based capability with explicit
  per-direction entries in get_adcp_capabilities targeting table,
  following keyword_targets/negative_keywords precedent
- Resolve Open Q3: lift "include applies first, then exclude removes
  matches from the effective served set" verbatim from collection lists
- Principle 3: add reject/requote edge case for fulfillment-emptying
  exclusions (REQUOTE_REQUIRED precedent); flag for WG sign-off (Q2)
- Principle 4: anchor fail-loud MUST to get_adcp_capabilities.mdx:298
  generalization rather than a standalone schema description assertion
- Enforcement: add stale/unreachable cache (fail-closed), zero-delivery
  edge (reject, not silent no-fill), scale note, coverage receipt
  placeholder (blocker, Q4)
- Relationship to content standards: add OpenRTB badv/bapp mapping note
- Schema Changes Summary: add get_adcp_capabilities.mdx doc change
- Open Questions: resolve Q1/Q3, update Q2 with proposed resolution,
  add Q4 (coverage receipt blocker), add Q5 (single-ref vs array)

Refs #5773, #5788
@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Follow-up commit 89aed6d applies the actionable feedback from @bokelley's review. Summary of what changed and what still needs WG sign-off:

Applied:

  • Factual correction 1: "last targeting dimension" → "last list construct following the include/exclude pair convention that lacks its exclude twin" (device_platform/language also lack _exclude but are scalar, not paired-convention dimensions)
  • Factual correction 2: Removed the create_property_list "exclude purpose" claim — property lists are polarity-neutral; polarity is assigned by the targeting field. The buyer-can-host-today point stands and is strengthened.
  • Q1 resolved: Capability Declaration section rewritten to require explicit per-direction entries in the get_adcp_capabilities targeting table, following the keyword_targets/negative_keywords precedent. Specialism-only and property_list_filtering reuse are both ruled out with rationale.
  • Q3 resolved: Principle 2 now reads "include applies first, then exclude removes matches from the effective served set" — lifted verbatim from collection lists.
  • Principle 3: Added reject/requote edge case when exclusion breaks a fulfillment commitment or empties the buy (REQUOTE_REQUIRED precedent). Flagged as Q2 pending WG confirmation.
  • Principle 4: Anchors fail-loud MUST to the get_adcp_capabilities.mdx:298 generalization rather than a standalone schema description assertion.
  • Enforcement additions: Stale/unreachable cache (fail-closed, MUST reject); zero-delivery edge (reject, not silent no-fill); scale note; coverage receipt placeholder flagged as Q4 blocker.
  • Relationship to content standards: Added OpenRTB badv/bapp mapping note.
  • Schema Changes Summary: Added get_adcp_capabilities.mdx as a required doc change.
  • PR description: Corrected both factual errors.

Still needs WG sign-off (not applied as normative text):

  • Q2property_targeting_allowed reject/requote trigger: exact condition when exclusion empties the buy. Proposed resolution in Q2 text: align with REQUOTE_REQUIRED precedent.
  • Q4 — Coverage receipt shape at create/update_media_buy. Blocked: without it, buyer can't distinguish "enforced and matched 0" from "matched 0 and ran everywhere." Mirror of collection_list_exclude receipt proposed; needs spec before field ships.
  • Q5 — Single-ref vs array-of-refs (acknowledged, not solved here; carry to broader list-ref resolution).

Generated by Claude Code

aao-release-bot[bot]
aao-release-bot Bot previously approved these changes Jul 1, 2026

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Spec-only proposal doc, no wire surface touched — and every load-bearing citation in it checks out, which is the only thing that matters for a proposal whose whole value is fidelity to the settled spec.

Things I checked

  • Not a wire change. Adds one file, specs/property-list-exclude.md. No static/schemas/source/**, no docs/reference/**, no build-script change. The schema block at L58-L66 is proposed, not applied — nothing lands on the wire, so no changeset is required and none of the schema-drift blocks apply.
  • targeting.json:144 REQUOTE_REQUIRED precedent is real. L144 (signal_targeting_groups) does carry MAY reject changes that require repricing with REQUOTE_REQUIRED. Principle 3 and Open Q2 anchor to an actual precedent, not a wished-for one.
  • The mirror target exists and matches. collection_list_exclude at targeting.json:166 uses collection-list-ref.json with exclude-wins brand-safety semantics — the proposed property_list_exclude (reusing property-list-ref.json, which exists at core/property-list-ref.json) is the faithful twin it claims to be.
  • Specialism quote is verbatim. enums/specialism.json:48 reads "curated inclusion and exclusion lists" — the polarity-neutral argument in Problem holds; the exclusion capability already exists at the governance layer.
  • The "future evolution" quote is real. collection-lists.md:338 says a future evolution "may add `property_list_exclude` for symmetry." This PR is formalizing an anticipated gap, not inventing one.
  • The get_adcp_capabilities.mdx line refs land. :224 is property_list_filtering, :292-293 are keyword_targets/negative_keywords, and :298 is exactly the geo "SHOULD support both inclusion and exclusion / MUST return a validation error" rule the proposal wants to generalize. Principle 4's "normative home" argument points at settled text that actually says what's claimed.

Follow-ups (non-blocking — file as issues)

  • Q4 is correctly self-marked a blocker. The coverage-receipt shape (matched_count/unmatched_entries/filtered_count) must be specced before the field ships — a 65k exclude list that can't distinguish "enforced, matched 0" from "ran everywhere" is the failure mode. The proposal says this; the implementation PR must honor it, not this one.
  • The generalization at :298 retroactively covers collection_list_exclude. Broadening the fail-loud MUST from "a geographic targeting level" to all targeting-overlay list dimensions closes the same silent-ignore gap for collection lists (the proposal flags #5788). Worth tracking that the doc edit and the field edit land together, not drift apart.

Minor nits (non-blocking)

  1. Precedent asymmetry in Principle 3/4. The proposal leans on :298 as a "MUST" — accurate for the validation-error half, but "support both directions" is a SHOULD there. Principle 4's phrasing ("generalized fail-loud MUST") is right about the reject-on-unsupported MUST; just keep that distinction crisp when the normative text is actually written, so the implementation doesn't over-claim a MUST the base spec states as SHOULD.

Clean proposal. Safe to merge — it commits nothing to the wire and marks its own blocker before it could.

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec proposal is clean. The PR also silently deletes the entire get_adcp_capabilities documentation page — that's the block. Fail-closed beats fail-open, and shipping a "spec-only" PR that destroys 953 lines of load-bearing protocol docs fails open.

The blocker — content destruction

docs/protocol/get_adcp_capabilities.mdx goes from 1122 lines to 7. I confirmed the head blob directly (not just the diff): the file now ends after the intro sentence — every section (Tool-Based Discovery, the auth <Note>, schema references, the entire targeting capability table at :284–293, the fail-loud MUST at :298) is gone.

The PR body says "Spec-only (no code change in this PR)." The diff says 953 deletions, 1 addition on a core protocol page. Those don't reconcile. This is an accidental truncation — almost certainly a bad rebase or editor mishap — not an intended edit.

What breaks for adopters: get_adcp_capabilities is the first call a buyer makes. Its reference page is now a stub, so anyone reading the docs to integrate discovery loses the auth model, schema links, and the full capability surface.

The internal evidence that this is unintended is in your own new file. specs/property-list-exclude.md cites get_adcp_capabilities.mdx:284–293, :298, :292–293, :224, and :144 as normative anchors — line numbers in a file this same PR truncates to 7 lines. The spec's "Required doc change" section literally asks to add entries to a targeting table that this PR deletes. The two halves of the PR contradict each other.

Fix: restore docs/protocol/get_adcp_capabilities.mdx to its base content. Keep specs/property-list-exclude.md as-is. Re-push with the mdx unchanged (or, if you meant to make the doc changes the spec calls for, make those additive edits — not a wholesale delete).

Things I checked

  • Fetched the head blob of get_adcp_capabilities.mdx via API — 7 lines, gutted. Base is 1122. Not a diff-rendering artifact.
  • specs/property-list-exclude.md — spec-only, proposes property_list_exclude in core/targeting.json but makes no schema change in this PR. No static/schemas/source/** touched, so no schema-vs-docs drift and no changeset required for the proposal itself.
  • Line-number citations in the spec (targeting.json:144 REQUOTE_REQUIRED precedent, collection-lists.md:356–361 receipt shape) — internally consistent with the proposal's argument.
  • No do-not-auto-approve/security/breaking-change labels; the block is on merits.

On the spec proposal (once the mdx is restored)

The proposal is the right shape. Polarity-neutral property lists, exclude-wins semantics mirroring collection_list_exclude, reuse of property-list-ref.json, and the fail-closed stance on a stale/unreachable exclude cache are all correct — for a brand-safety blocklist, under-restricting is the unsafe failure and last-known-good is the right default. Principle 3 (exclusion ungated by property_targeting_allowed) is well-reasoned and correctly flagged as needing WG sign-off (Q2). Q4 (coverage receipt) is correctly marked a blocker before the field ships — a 65k-entry list with no receipt can't distinguish "enforced, matched 0" from "matched 0, ran everywhere."

Nothing to change in the spec. It just can't ride in on a commit that deletes the page it depends on.

Restore the doc and re-request review. Happy to approve the spec on its own once the deletion is reverted.

@bokelley

bokelley commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Folded per @bokelley's direction (commit 7a072fc):

  • Added collection_list, collection_list_exclude, property_list, and property_list_exclude rows to the targeting capability table in get_adcp_capabilities.mdx.
  • Generalized the fail-loud MUST from geo-scoped to "any targeting-overlay list dimension" (geo, collection_list, or property_list), with the explicit note that silently dropping a brand-safety exclusion list is an unsafe failure mode.

Coverage receipt for collection_list_exclude left on #5788 as directed.


Triaged by Claude Code. Session: https://claude.ai/code/${CLAUDE_CODE_REMOTE_SESSION_ID}


Generated by Claude Code

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposal is sound; the live-doc change ships ahead of the wire. Strip the two property_list_exclude entries from get_adcp_capabilities.mdx (or land the schema field in this PR) and this approves.

The specs/property-list-exclude.md draft is the right shape — reuses property-list-ref.json unchanged, mirrors collection_list_exclude (core/targeting.json:166) verbatim, and the exclude-wins ordering matches specs/collection-lists.md exactly. Principle 3 (exclusion ungated from property_targeting_allowed because a blocklist is a safety control, not subsetting-for-optimization) is a genuinely new semantic, and the PR flags it as Open Q2 for WG sign-off rather than asserting it silently. Right call. The badv/bapp mapping is accurate. No objection to the proposal itself.

Blocker

Live capability reference documents a field the wire cannot carry. docs/protocol/get_adcp_capabilities.mdx is the settled capability reference, not a proposal doc. This PR adds two entries there for a field that does not exist in static/schemas/source/core/targeting.json:

  • Table row (after property_list): property_list_exclude | boolean | ... Presence indicates support for targeting_overlay.property_list_exclude.
  • Bullet: media_buy.execution.targeting.property_list_exclude: true -> Buyer can send targeting_overlay.property_list_exclude (brand-safety blocklists), seller MUST honor them

core/targeting.json has property_list (L158), collection_list (L162), collection_list_exclude (L166) — and no property_list_exclude. So the normative reference now tells a seller to declare a capability, and a buyer to send a targeting_overlay.property_list_exclude that fails schema validation because the field is not on the wire. Docs leading the schema on a MUST-honor field is spec drift in a published reference. ad-tech-protocol-expert: sound-with-caveats overall, but named this exact divergence a spec-drift blocker.

The proposal's own Q4 marks the coverage receipt a pre-ship blocker — the field is explicitly not ready to ship, which is precisely why the live reference should not advertise it yet.

To unblock, pick one:

  1. Remove the property_list_exclude table row and bullet from get_adcp_capabilities.mdx. Keep them in specs/property-list-exclude.md where the draft belongs. Or
  2. Add property_list_exclude to core/targeting.json in this PR so doc and schema land together (with the changeset that a targeting.json change then requires).

Things I checked

  • Schema state: property_list, collection_list, collection_list_exclude present in core/targeting.json; property_list_exclude absent — matches the proposal's claim that only a targeting-overlay field is missing.
  • The collection_list/collection_list_exclude/property_list rows are correct additions — those fields exist in schema and were absent from the capability table before this PR. These close a real gap and should ship.
  • Fail-loud generalization at get_adcp_capabilities.mdx:298 (geo-only -> any targeting-overlay list dimension) is a sound generalization for the fields that exist.
  • No changeset required: the change is to docs/protocol/**, not docs/reference/** / mintlify-docs/reference/** / static/schemas/source/**. If you take unblock option 2, that changes.

Minor nits (non-blocking)

  1. EOF newline stripped. The last hunk drops the trailing newline at end of get_adcp_capabilities.mdx. Restore it.
  2. Two unrelated cosmetic table-border edits (~L718, ~L910) — border-pipe realignment with no content change. Harmless, but they are noise in a spec-proposal diff.

Once the property_list_exclude live-doc entries come out (or the schema field lands here), this is a clean approve.

…e spec

targeting.json:144 is daypart_targets, and there is no
signal_targeting_groups -> REQUOTE_REQUIRED link there. The actual
reject/requote precedent is the REQUOTE_REQUIRED error code
(enums/error-code.json), documented on update_media_buy for when a change
alters the parameter envelope the quote was priced against
(update_media_buy.mdx:603).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposal is right, and it mirrors collection_list_exclude faithfully — exclude-wins ordering, property-list-ref.json reused unchanged, fail-closed on a stale exclude cache, coverage-receipt gated as a blocker. Ungating exclusion from property_targeting_allowed is the correct boundary: that flag gates subsetting-for-optimization, and a brand-safety block is not that. Solid spec.

The mdx is where it lands wrong. docs/protocol/get_adcp_capabilities.mdx now publishes a normative MUST-honor obligation for a field that does not exist on the wire.

static/schemas/source/core/targeting.json defines property_list (:158), collection_list (:162), and collection_list_exclude (:166) — but there is no property_list_exclude. Yet the doc adds:

  • table row: property_list_exclude | boolean | Property list exclusion targeting (brand-safety blocklists)...
  • contract bullet: media_buy.execution.targeting.property_list_exclude: true → ... seller MUST honor them

An agent reading the capability contract generates targeting_overlay.property_list_exclude and it fails schema validation, because the field isn't there. The PR's own companion specs/property-list-exclude.md is Status: Draft, lists the schema addition as proposed, and gates it behind unresolved WG items (Q2, Q4 — Q4 marked "Blocker before the field ships"). So the PR ships a MUST into settled reference text for a field the same PR says isn't ready. ad-tech-protocol-expert: sound-with-caveats — proposal sound, but the doc publishes a MUST-honor row for a schema field that doesn't exist. docs-expert: lands-wrong — same finding.

What flips this to approve — pick one:

  • Drop the two property_list_exclude lines (the table row and the capability bullet) from the mdx. Keep the three schema-backed rows (collection_list, collection_list_exclude, property_list) and the generalized fail-loud MUST — those are good and retroactively close the collection_list_exclude doc gap. Hold property_list_exclude in the Draft spec until the field lands. Or:
  • Land the one-field targeting.json addition in this PR — the spec already writes it verbatim — so doc and wire stay coherent. Splitting them is the defect.

Things I checked

  • targeting.json:158–169 — confirmed property_list_exclude is absent; the other three rows map to live fields.
  • Exclude-wins ordering and property-list-ref.json reuse match collection_list_exclude (targeting.json:166–168). No new schema, additive shape.
  • property_targeting_allowed gating: SHOULD-reject exists for property_list inclusion (targeting.json:160); ungating exclusion is the defensible read.
  • Generalized fail-loud MUST at :298 reads correctly for the fields that exist; the "silently dropping a brand-safety exclusion list is an unsafe failure mode" clause is load-bearing and worth keeping.
  • The capability rows for the three existing fields are semantically accurate against their schema descriptions.

Follow-ups (non-blocking — file as issues)

  • Changeset. This PR adds new normative MUST requirements to a protocol surface. Per the normative-doc rule that's a minor changeset, not "just docs." Add one — or, if the WG prefers to hold the whole thing behind the Draft, that's a defensible reason to omit it. State the call.
  • Q2 citation. specs/property-list-exclude.md Open Q2 cites the REQUOTE_REQUIRED precedent as targeting.json:144 — line 144 is signal_targeting_groups, not a list field. The precedent is real; point it at the clause it actually quotes.
  • Coverage receipt (Q4). Correctly flagged as a blocker before the field ships. A 65k-entry exclude with no matched_count/unmatched_entries can't distinguish "enforced, matched 0" from "ran everywhere." Keep it gating.

Minor nits (non-blocking)

  1. Number agreement. The new property_list_exclude bullet ends "seller MUST honor them"; the sibling property_list/collection_list bullets say "honor it." Make it "it" if the row survives.
  2. Incidental churn. Two table-separator rows changed dash counts for no rendered effect (:718, :910), and the EOF trailing newline was dropped (:968, now "No newline at end of file"). Revert all three so the diff carries only the content change.

Held at comment rather than approve for one reason: a settled reference doc should describe the present wire, not stage a MUST for a field that isn't in the schema. Remove the two lines or land the field, and this is an approve.

nastassiafulconis and others added 2 commits July 1, 2026 20:55
Lands the wire field behind the property_list_exclude capability-table
entry so the docs no longer publish a normative MUST for a field absent
from the schema (the aao-release-bot blocker). Mirrors
collection_list_exclude, reuses property-list-ref.json. Additive/minor;
enforcement rules stay in the spec doc as WG-pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aao-release-bot aao-release-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additive optional field, correctly typed minor, right shape. This is the exclude twin collection_list_exclude already established — same $ref to property-list-ref.json, same adjacency, same exclude-wins story — so it inherits a convention rather than inventing one.

Things I checked

  • Wire impact. New optional property on an open object (additionalProperties tolerant); no required flip, no enum narrowing, no discriminator touch. Purely additive → minor is correct, not major. ad-tech-protocol-expert: sound, "land it."
  • Shape. property_list_exclude (static/schemas/source/core/targeting.json:162) reuses /schemas/core/property-list-ref.json unchanged and mirrors collection_list_exclude at :166 exactly. Closes the asymmetry the collection-lists spec explicitly promised ("a future protocol evolution may add property_list_exclude for symmetry").
  • oneOf. No top-level discriminator in targeting.json; the only oneOf is nested in geo_proximity and is untouched. No audit regression.
  • Changeset. .changeset/property-list-exclude.md present, minor, prose matches the wire impact. Not a missing-changeset block.
  • Bundle artifact. Only static/schemas/source/** is tracked; bundled/ is generated by scripts/build-schemas.cjs at build time. No stale artifact missing from the PR.
  • Capability table. The four new rows and four new dot-notation bullets in get_adcp_capabilities.mdx are internally consistent, and the fail-loud MUST generalization at :298 broadens the prior geo-only rule without weakening it — and retroactively closes the same silent-drop gap for the already-shipped collection_list_exclude (#5788). Load-bearing, and worth flagging that it changes a normative MUST for a released field, not just the new one.

Follow-ups (non-blocking — file as issues)

  • Schema description asserts an unratified semantic. The field description states exclusion "applies regardless of the product's property_targeting_allowed flag" as settled, but the spec doc itself marks that as Open Q2 (WG sign-off needed). The sibling property_list description hedges with SHOULD. Either soften the shipped description to defer gating until Q2 resolves, or land the WG decision first. Non-blocking because the field is additive and the spec doc is explicit that it's a Draft proposal — but the schema text shouldn't read as more settled than the design.
  • REQUOTE_REQUIRED scope. The code exists (enums/error-code.json), but its description scopes it to update_media_buy. The spec proposes using it at create_media_buy time on the zero-delivery edge. Broaden the enum description or resolve via WG when Q2 lands.
  • Coverage receipt (Q4). The spec correctly calls this a blocker before the field ships in anger: without a matched_count/unmatched_entries receipt, a 65k blocklist that matches zero is indistinguishable from one that ran everywhere — the exact unsafe under-restriction the doc warns about. Track it before sellers are told to honor the field.

Minor nits (non-blocking)

  1. Wrong line citation. specs/property-list-exclude.md:56 cites update_media_buy.mdx:603 for the REQUOTE_REQUIRED precedent; :603 is Python example code. The normative text is at :658, the error-table entry at :744. Fix the ref.
  2. Dropped EOF newline. docs/protocol/get_adcp_capabilities.mdx loses its trailing newline. Restore it. (The two markdown table-separator realignments in the same file are valid GFM and harmless — just unrelated to the stated change.)

LGTM. Follow-ups noted below.

@nastassiafulconis nastassiafulconis merged commit e75f12f into main Jul 1, 2026
31 of 32 checks passed
@nastassiafulconis nastassiafulconis deleted the property-list-exclude-spec branch July 1, 2026 19:14
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.

2 participants