Skip to content

Add IMPRESSION_ID universal macro for impression dedup#5020

Merged
bokelley merged 3 commits into
mainfrom
BaiyuScope3/tmpy-context-match-macro
May 26, 2026
Merged

Add IMPRESSION_ID universal macro for impression dedup#5020
bokelley merged 3 commits into
mainfrom
BaiyuScope3/tmpy-context-match-macro

Conversation

@BaiyuScope3

Copy link
Copy Markdown
Collaborator

Summary

  • Adds IMPRESSION_ID to the universal-macro enum as a general-purpose per-impression identifier — usable by buyers, measurement vendors, verification services for impression dedup, cross-vendor reconciliation, pixel-retry detection, and (in TMP) cross-identity exposure dedup.
  • Closes the gap where TMP context-only impressions had no impression_id available (no {TMPX} → no buyer-side decode-time mint).
  • Defines a three-layer minting hierarchy: (1) publisher first-party code, (2) ad-decision layer (Prebid TMP module, ad server, SSP), (3) buyer impression tracker at {TMPX} decode (TMP-specific fallback). Format is implementation choice — UUID, ULID, snowflake, or equivalent.

Why not TMPY

An earlier proposal added a TMPY macro carrying a buyer-minted opaque blob from the context-match response. Rejected because (a) it would have bridged TMP's structural identity↔context separation when rendered alongside {TMPX} on the same pixel, (b) it un-deprecates the AXEM pattern the protocol already moved away from, and (c) industry convention is for the ad-decision layer to mint and downstream trackers to consume via macro substitution. Publisher/decision-layer mint via {IMPRESSION_ID} solves the underlying need without any of those costs.

Files changed

  • static/schemas/source/enums/universal-macro.json — adds IMPRESSION_ID to enum + description map
  • docs/creative/universal-macros.mdx — new ### Impression Identification section with use cases, format flexibility, three-source hierarchy
  • docs/trusted-match/impression-tracker-implementation.mdx — rule Welcome to adcp Discussions! #1 (format-agnostic), rule Remove targeting_template and add pluggable product catalog system #2 (three valid sources), updated write-path to handle context-only pixels
  • docs/trusted-match/surfaces/web.mdx — new ### Impression ID Substitution subsection with tmp_impression_id GAM targeting KV, enableTIDs reuse, ULID code example
  • specs/prebid-tmp-proposal.md — three-layer resolveImpressionId() in prose and reference adapter
  • .changeset/impression-id-universal-macro.md — patch-level changeset

Test plan

  • npm run build:schemas succeeds, IMPRESSION_ID lands in dist/schemas/latest/enums/universal-macro.json
  • npm run test:schemas — 8/8 pass
  • npm run test:examples — 36/36 pass
  • CI green
  • Spec review by @brkylem to confirm this resolves the rtss-thread TMPY need

🤖 Generated with Claude Code

BaiyuScope3 and others added 2 commits May 25, 2026 17:11
Closes the gap where TMP context-only impressions have no impression_id
available for cross-identity dedup (no TMPX → no decode-time mint).
Positions {IMPRESSION_ID} as a general-purpose impression key — used
by buyers, measurement vendors, verification services, and TMP — with
a three-layer minting hierarchy: publisher first-party code, then the
ad-decision layer (Prebid TMP module, ad server, SSP), then the buyer
at TMPX decode time as a TMP-specific fallback. Format is implementation
choice (UUID, ULID, snowflake, or equivalent). Documents the Prebid TMP
module pattern using `tmp_impression_id` targeting KV with optional
`enableTIDs` reuse. No router changes; preserves the identity↔context
structural separation by keeping minting at the publisher/decision-layer
join, not in TMPY or any new context-match response field.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
aao-release-bot[bot]
aao-release-bot Bot previously approved these changes May 25, 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.

LGTM. Follow-ups noted below. The three-layer minting hierarchy is the right shape — publisher → decision layer → buyer-at-decode preserves TMP's identity↔context separation while closing the context-only gap that motivated the rejected TMPY proposal. Schema change is purely additive; description-map parity preserved.

Things I checked

  • Schema change at static/schemas/source/enums/universal-macro.json:62,134 is additive only — enum array and enumDescriptions map both updated; no reorder, no field changes elsewhere.
  • resolveImpressionId() reference adapter at specs/prebid-tmp-proposal.md:421-440 correctly propagates the value through both code paths — Phase 1 sets unit.tmpImpressionId at line ~454; identity-bearing join at line ~502 emits it; applyContextOnly at line ~526 emits it. No path silently drops the id.
  • "MUST NOT reuse TMPX nonce" clause at docs/trusted-match/impression-tracker-implementation.mdx:33 closes the obvious foot-gun — the nonce is per-IM-evaluation and would silently merge distinct impressions if reused.
  • enableTIDs/transactionId reuse optimization is correctly gated on the Prebid config flag (specs/prebid-tmp-proposal.md:432) — won't break when enableTIDs is the opt-out default in PBJS 8+.
  • GAM substitution pattern %%PATTERN:tmp_impression_id%% at docs/trusted-match/surfaces/web.mdx:218 is a real GAM substitution, not invented.

Follow-ups (non-blocking — fix in this PR or as issues)

  • Broken anchor links. Two link sites point at #tmp-impression-identification but the heading is ### Impression Identification — slug is #impression-identification. Sites: docs/trusted-match/impression-tracker-implementation.mdx:33 and docs/trusted-match/surfaces/web.mdx:187. Either fix both anchors or rename the heading to ### TMP Impression Identification (the latter would also match the sibling ### TMP Exposure Tracking pattern in the same file).
  • Changeset bump. Prior universal-macro additions in CHANGELOG.md are minor — TMPX at line ~4384 and APP_ITEM_ID at line ~4893 both shipped under Minor sections. A new public enum value is a feature add that downstream SDK regeneration picks up. Bump .changeset/impression-id-universal-macro.md:2 from patch to minor for consistency, or note in the PR body why this one is patch.
  • Oversized enum description. The new IMPRESSION_ID description in static/schemas/source/enums/universal-macro.json:134 is ~1200 chars; peer entries are 5–200 chars (TMPX is ~190). This map surfaces in generated SDK tooltips and OpenAPI clients where multi-paragraph blobs render poorly. Trim to peer length; the prose page already carries the full hierarchy.
  • Rule #2 density. docs/trusted-match/impression-tracker-implementation.mdx:33 now packs source priority, buyer consumption rule, context-only failure mode, degraded-mode behavior, and the TMPX-nonce caveat into one ~250-word bullet. Split — the SHOULD clause currently gets buried.
  • Required-vs-SHOULD drift. Schema description and docs/creative/universal-macros.mdx:181 both say IMPRESSION_ID is "Required for TMP context-only impressions". impression-tracker-implementation.mdx:33 says trackers SHOULD treat its absence as an integration error with a fallback path. Producer-side MUST and consumer-side SHOULD are reconcilable but should be stated symmetrically.

Minor nits (non-blocking)

  1. applyContextOnly implicit dependency. specs/prebid-tmp-proposal.md:526 reads unit.tmpImpressionId that's set in Phase 1 at line ~454. A one-line comment in the function would keep a reader from reordering and silently producing undefined.

Two follow-ups would have been one if the heading slug had matched the link target — worth a docs-build link-checker in CI as a separate item.

Approving.

@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. Additive enum value, the wire surface is clean, and the three-layer minting hierarchy (publisher → decision-layer → buyer-at-decode) is structurally cleaner than the rejected TMPY blob — minting happens upstream of the identity↔context join, so the value is opaque-by-construction by the time it reaches a pixel.

Things I checked

  • static/schemas/source/enums/universal-macro.json:62 and :134enum and enumDescriptions stay in parity, no oneOf surface touched, no router/error-code schema needs to land alongside.
  • .changeset/impression-id-universal-macro.md:2 — frontmatter is minor. That's the right call for an additive enum value; the PR body's "patch-level" phrasing is just sloppy prose, the shipped artifact is correct.
  • Three-layer hierarchy reads consistently across docs/creative/universal-macros.mdx, docs/trusted-match/impression-tracker-implementation.mdx, docs/trusted-match/surfaces/web.mdx, and specs/prebid-tmp-proposal.md. "Lower layers MUST defer" is stated the same way in each.
  • resolveImpressionId() is functionally equivalent in docs/trusted-match/surfaces/web.mdx:201 and specs/prebid-tmp-proposal.md:434 — one uses pbjs.getConfig, the other getGlobal().getConfig. Both idiomatic for their context.
  • Build/test plan: schemas + examples pass; the unchecked items in the PR test plan are CI and this review itself, not feature validation.

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

  1. Rule #4 contradicts Rule #6. docs/trusted-match/impression-tracker-implementation.mdx:35 says the degraded fallback for missing {IMPRESSION_ID} on context-only is "skip the exposure write or fall back to a one-shot identifier per pixel fire." A one-shot-per-pixel-fire fallback directly violates rule #6 at :37 — every retry mints a fresh id and double-counts. Tighten #4 to "skip the exposure write" only, or carve out an explicit exception for the degraded path.
  2. Stale cross-reference in write-path rule #3. docs/trusted-match/impression-tracker-implementation.mdx:113 says "on context-only impressions, see rule #2 in the rules section above for the degraded-mode behavior." Rule #2 is the three-sources rule; the degraded-mode text is in rule #4. Re-point.
  3. Pre-existing prose at :79 drifted under the rewrite. The bullet still reads "impression_id — generated at TMPX decode." Under the new hierarchy the value is more often minted upstream and consumed at decode. Worth a single edit so a reader following the table back to the rules doesn't get a contradiction.
  4. adcp_* convention claim doesn't match the KV name. docs/trusted-match/surfaces/web.mdx:223 says tmp_impression_id "mirrors the adcp_* convention used elsewhere on this page" — but the page itself uses adcp_pkg/adcp_seg at :153-154. Either rename to adcp_impression_id for consistency, or fix the prose to say the KV deliberately uses a tmp_* namespace.
  5. MUST in a non-normative page. Rule #4 at :35 adds "Publishers and decision layers MUST include {IMPRESSION_ID} for TMP context-only impressions," but the page footnote at :37 reaffirms the page is non-normative and points conformance at identity-match-implementation.mdx. If the requirement is load-bearing, lift it onto the normative page; if not, downgrade to SHOULD here.

Minor nits (non-blocking)

  1. PR body vs. changeset type. The summary calls this a "patch-level changeset" but the file is minor. The file is right; the PR description is wrong — worth fixing for log hygiene since the body is what gets read alongside the merged commit. The series of follow-up commits ("Address IMPRESSION_ID review follow-ups") apparently didn't reach the PR description itself.

Safe to merge once the contradiction in #1 is filed as a follow-up.

@bokelley bokelley merged commit 5015802 into main May 26, 2026
19 checks passed
@bokelley bokelley deleted the BaiyuScope3/tmpy-context-match-macro branch May 26, 2026 01:44
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