Skip to content

feat(creative): declare tracker execution contracts - #6786

Open
bokelley wants to merge 48 commits into
mainfrom
tracker-execution-contract
Open

feat(creative): declare tracker execution contracts#6786
bokelley wants to merge 48 commits into
mainfrom
tracker-execution-contract

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Summary

  • add a format-option-scoped AdCP 3.2 production contract for first-class pixel_tracker, vast_tracker, and daast_tracker assets
  • distinguish complete unsupported sets from incomplete/undeclared behavior, with exact event, actor, path, target, offset, and standards-version matching
  • pin the effective product/placement contract, exact VAST/DAAST execution version, and RFC 8785 digests in immutable package format snapshots
  • keep seller production authority out of creative-agent capability and legacy projection surfaces
  • compose tracker initiation separately from feat(creative): define delivery representations and macro resolution #6767 macro processing and representation selection

Preview observation sessions and runtime evidence are intentionally excluded and remain AdCP 3.3 work in #6782. URL-slot tracker selectors are the independent 3.3 extension in #6784.

Stack

This PR is stacked on #6767 because tracker compatibility participates in representation-set selection. Retarget to main after #6767 merges.

Validation

  • npm run build:schemas — 106 bundled schemas, zero failures
  • npm run test:schemas
  • npm run test:json-schema
  • npm run test:compliance-snippets
  • npm run test:error-code-drift
  • npm run test:oneof-discriminators
  • npm run test:schema-links
  • node --test tests/tracker-execution-contracts.test.cjs tests/tracker-execution-package-integration.test.cjs tests/tracking-event-enums.test.cjs tests/creative-delivery-contracts.test.cjs tests/docs-nav-validation.test.cjs
  • node scripts/check-changeset-protocol-scope.cjs origin/vast-creative-delivery-rules
  • ad-tech, protocol, and code whole-diff review

Closes #6207
Related: #6775, #6783, #6782, #6784, #6767

Comment thread static/schemas/source/core/assets/vast-tracker-asset.json Outdated
Comment thread static/schemas/source/core/canonical-format-option.json

@aao-secretariat aao-secretariat 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.

Ladon verdict: Request changes

Request changes — 1 blocking finding.

Blocking findings

  • static/schemas/source/core/assets/vast-tracker-asset.json:34 — GA-published vast_tracker/daast_tracker assets are narrowed against 3.1.19 (offset ignored→forbidden, new event/target matrix) via the new constraints files. This is a breaking wire change shipped under a minor changeset, which violates the repo's changeset-scope rule (breaking wire changes require major, not minor/patch). Either scope the changeset as major or avoid tightening validation on the already-published assets.

Medium findings

  • static/schemas/source/core/canonical-format-option.json:45 — canonical-format-option adds a publisher_domain→format_option_id requirement (accept→reject), a validation tightening worth confirming is intended and non-breaking for existing payloads.

Row 1 of the decision table fires on the high finding, producing request-changes. Note: this PR touches gated paths under static/schemas/source/** with review_decision unknown/not APPROVED, and the reviewer flags a breaking-class change — both of which independently require human/CODEOWNERS review before merge. The schema modeling itself (discriminated tracker-execution-selector oneOf, immutable PackageFormatSnapshot with RFC 8785 digests, authority-stripping on projection surfaces) is clean and well tested; the blocker is the changeset-type/wire-compatibility mismatch on the GA-published tracker assets.

Blocking findings

  • static/schemas/source/core/assets/vast-tracker-asset.json:34 — vast_tracker/daast_tracker GA assets narrowed (offset ignored→forbidden, new event/target matrix): breaking wire change vs 3.1.19 shipped under a minor changeset; requires major changeset or reverted tightening

Medium findings

  • static/schemas/source/core/canonical-format-option.json:45 — canonical-format-option adds publisher_domain->format_option_id requirement (accept->reject)

@aao-secretariat aao-secretariat 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.

Ladon verdict: Escalate to human review

Escalate — gated paths not yet satisfied by human/CODEOWNERS review.

This is a subsequent pass. The prior request-changes blocking finding (vast/daast tracker assets narrowed against 3.1 GA under a minor changeset) has been resolved: the delta drops the whole-file constraints allOf and keeps only a local progress→offset requirement, restoring legacy-asset permissiveness, and new tests prove legacy assets/packages validate. The prior medium (canonical-format-option.json) file is out of the current delta and correctly skipped. No new blocking or medium findings this run.

However, this PR touches many files under static/schemas/source/**, which is a deterministic hard approval gate (gated_paths: true), and review_decision is CHANGES_REQUESTED — not APPROVED. Per decision rule row 2, the outcome must be escalate until a human/CODEOWNERS approval lifts the gate. No critical/high findings exist, so this is not request-changes; it is held for required human review only.

Escalation reasons:

  • Gated paths touched (protocol schema source under static/schemas/source/**) and review_decision is CHANGES_REQUESTED, not APPROVED. Human/CODEOWNERS approval is required before merge.

Why human review

  • Gated paths under static/schemas/source/** are modified/added and review_decision is CHANGES_REQUESTED (not APPROVED) — human/CODEOWNERS approval required to lift the hard approval gate (decision rule row 2).
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/assets/daast-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/pixel-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/assets/vast-tracker-asset.json (modified) matches static/schemas/source/**; static/schemas/source/core/canonical-format-option.json (modified) matches static/schemas/source/**; static/schemas/source/core/daast-tracker-constraints.json (added) matches static/schemas/source/**; static/schemas/source/core/format.json (modified) matches static/schemas/source/**; static/schemas/source/core/package-format-snapshot.json (added) matches static/schemas/source/**; static/schemas/source/core/package.json (modified) matches static/schemas/source/**; static/schemas/source/core/product-format-declaration.json (modified) matches static/schemas/source/**; static/schemas/source/core/representation-destination.json (modified) matches static/schemas/source/**; static/schemas/source/core/representation-rejection.json (modified) matches static/schemas/source/**; static/schemas/source/core/representation-selection.json (modified) matches static/schemas/source/**; static/schemas/source/core/requirements/daast-asset-requirements.json (modified) matches static/schemas/source/**; static/schemas/source/core/tracker-execution-contract.json (added) matches static/schemas/source/**; static/schemas/source/core/tracker-execution-selector.json (added) matches static/schemas/source/**; static/schemas/source/core/transformer.json (modified) matches static/schemas/source/**; static/schemas/source/core/vast-tracker-constraints.json (added) matches static/schemas/source/**; static/schemas/source/core/x-entity-types.json (modified) matches static/schemas/source/**; static/schemas/source/enums/pixel-tracking-event.json (added) matches static/schemas/source/**; static/schemas/source/enums/tracker-execution-actor.json (added) matches static/schemas/source/**; static/schemas/source/enums/tracker-firing-path.json (added) matches static/schemas/source/**; static/schemas/source/formats/canonical/audio_daast.json (modified) matches static/schemas/source/**; static/schemas/source/index.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-media-buys-response.json (modified) matches static/schemas/source/**; static

…(truncated)…

@bokelley
bokelley dismissed aao-secretariat[bot]’s stale review August 24, 2026 12:17

Resolved in 3eae83b: legacy VAST/DAAST asset validation was restored while strict constraints remain scoped to the new selector. The subsequent Ladon pass confirms no blocking findings; human/CODEOWNER approval remains required.

…6767)

* feat(creative): define delivery and macro resolution contracts

* docs(creative): gate tracker firing on product capabilities

* fix(creative): preserve URL compatibility and type error details

* feat(creative): define complete VAST technical requirements

* fix(creative): keep VAST requirements extensible

* fix(creative): close delivery contract review gaps

* fix(creative): satisfy canonical VAST gates

* fix(compliance): version CTV VAST fixtures

* feat(creative): model equivalent representation sets

* fix(creative): satisfy representation CI gates

* fix(creative): keep VAST version requirement additive

* docs(creative): clarify representation set format scoping and add localization migration warning

Per @pkras review on #6767:
- state explicitly that a representation set is scoped to one format_kind
- add a Warning callout documenting the destructive, non-atomic path for
  migrating an existing localized creative to representation selection

* docs(creative): pin accepted representation selections

* fix(creative): clarify representation review guarantees

---------

Co-authored-by: Claude <noreply@anthropic.com>
Base automatically changed from vast-creative-delivery-rules to creative-revision-identity August 24, 2026 21:30
…ract

# Conflicts:
#	docs/contributing/x-entity-annotation.md
#	docs/creative/canonical-formats.mdx
#	docs/creative/representation-sets.mdx
#	docs/creative/universal-macros.mdx
#	package.json
#	static/compliance/source/test-vectors/creative-representation-resolution.json
#	static/compliance/source/test-vectors/macro-processing.json
#	static/schemas/source/core/canonical-format-option.json
#	static/schemas/source/core/creative-representation-set.json
#	static/schemas/source/core/macro-declaration.json
#	static/schemas/source/core/product-format-declaration.json
#	static/schemas/source/core/representation-destination.json
#	static/schemas/source/core/representation-rejection.json
#	static/schemas/source/core/representation-selection.json
#	static/schemas/source/core/x-entity-types.json
#	static/schemas/source/index.json
#	tests/creative-delivery-contracts.test.cjs
#	tests/docs-nav-validation.test.cjs
…ntity

# Conflicts:
#	docs.json
#	tests/docs-nav-validation.test.cjs
…ract

# Conflicts:
#	docs.json
#	tests/docs-nav-validation.test.cjs
@bokelley

Copy link
Copy Markdown
Contributor Author

Ready for fresh CODEOWNER review on the repaired stack. The head now descends from current #6781 and preserves all parent representation/macro guarantees. Follow-up fixes require matching first-class format slots, enforce complete-parent narrowing over atomic version/actor/path tuples without treating incomplete parents as ceilings, and keep DAAST close legacy-compatible while excluding it from standards selectors. Focused combined schema/compliance tests are green. @ohalushchak-exadel @bmilekic, please review when available.

… tracker-execution-contract

# Conflicts:
#	static/schemas/source/core/canonical-format-option.json
#	static/schemas/source/core/product-format-declaration.json
@bokelley
bokelley requested a review from pkras August 25, 2026 05:58
@bokelley

Copy link
Copy Markdown
Contributor Author

Pushed the latest parent integration and CI/resource fix at a049687a99.

  • preserves both root-level macro_resolution_capabilities and tracker_execution_contract
  • keeps macro processing metadata out of canonical creative params
  • restores the exact GA VAST/DAAST asset validation envelope while retaining strict matrices for new tracker selectors
  • removes avoidable schema-graph expansion; measured MCP contexts are 398.08 KiB (media-buy, 400 KiB budget) and 405.39 KiB (creative, scoped 410 KiB budget)
  • full schema suite passed: 34 schema checks, 160 Node tests, 10 premium-display tests, and 6 geo tests
  • focused combined suite passed 54/54; two independent protocol/ad-tech reviews found no blocker/high issues

Fresh human/CODEOWNERS review is requested for the exact pushed head. #6781 remains the dependency and should merge first.

@pkras pkras left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. closeLinear is missing VAST 4.0 (blocker or needs a note).
    In vast-tracker-constraints.json, closeLinear allows ["3.0","4.1","4.2","4.3"] but not 4.0, even though every neighboring event covers 4.0–4.3 and closeLinear exists in 4.0. As written it reads like a typo, and a seller building a 4.0 tag can’t declare it. Please either add 4.0 or add a $comment explaining why the gap is intentional.

  2. The “preservation” rule is described but not enforced.
    The docs/spec say a child contract preserves parent commitments “unless narrower inventory genuinely excludes them,” but the actual matching only checks that the child is a subset of the parent — nothing enforces preservation, and “genuinely excludes” has no concrete definition. As-is, one seller could trim the list freely and another couldn’t, and both would pass. Can we either define this precisely or drop the sentence so implementations don’t diverge?

  3. Fix the IAB citations (doc-only, but worth doing here).
    Two provenance claims are off: audible_video_complete is labeled “IAB type 500,” but in OpenRTB Native 1.2 the 500+ range is exchange-specific, not a defined event; and viewable_video_50 is described as requiring “audio on,” which type 4 doesn’t (audio-on is what distinguishes the audible metric). The enum values are fine — just the descriptions.

Smaller items:

The per-version VAST event rules are almost entirely untested — only loaded+4.0 is exercised. A wrong enum in any of the other branches would ship silently; a positive/negative vector per rule would close that.
Minor doc contradiction: package.json says pending items carry the digest unconditionally, while get-media-buys-response.json says “when present” — ID-less snapshots have no digest, so “when present” is the correct phrasing in both.
Heads-up that the new if publisher_domain → require format_option_id rule in canonical-format-option.json is an additional constraint beyond trackers; worth confirming no existing publisher_domain-only options would break under a minor bump.

Base automatically changed from creative-revision-identity to main August 25, 2026 10:42
…tract

# Conflicts:
#	docs/contributing/x-entity-annotation.md
#	docs/creative/canonical-formats.mdx
#	docs/creative/representation-sets.mdx
#	docs/creative/universal-macros.mdx
#	package.json
#	static/schemas/source/core/canonical-format-option.json
#	static/schemas/source/core/product-format-declaration.json
#	static/schemas/source/core/representation-destination.json
#	static/schemas/source/core/representation-rejection.json
#	static/schemas/source/core/representation-selection.json
#	static/schemas/source/core/x-entity-types.json
#	tests/mcp-schema-projection.test.cjs
#	tests/tracking-event-enums.test.cjs
@bokelley
bokelley requested a review from pkras August 25, 2026 11:31
@bokelley

Copy link
Copy Markdown
Contributor Author

Retargeted to main after #6781 merged and pushed clean ancestry reconciliation at f85d9e80ac.

Verification on the exact combined tree:

  • main is an ancestor; PR diff is limited to the intended 45 tracker-contract files
  • schema build: 106/106 bundles
  • focused MCP/tracker/package/representation/revision/event suite: 55/55
  • MCP contexts: media-buy 398 KiB (400 KiB budget), creative 405 KiB (410 KiB budget)
  • confidential-name scan and diff checks clean
  • local pre-push matrix passed schema/compliance authority, /signals, and required exact sales lifecycle gates; two unrelated existing creative storyboards (creative/native_in_feed, creative/policy_backed_rejections) hit the workstation's 120s isolation timeout, so the remaining local tenant pass was stopped rather than changing unrelated coverage. Required GitHub CI is running on the exact head.

All review threads remain resolved. Fresh CODEOWNERS approval is requested for this head.

@bokelley
bokelley enabled auto-merge (squash) August 25, 2026 11:31
@bokelley

Copy link
Copy Markdown
Contributor Author

CI follow-up: current main added a conformance-freshness gate that correctly found three uncatalogued versioned vector sets. Head 865848d6c1 catalogs creative-representation-resolution, macro-processing, and tracker-execution-contracts. The exact failing command (npm run test:doc-compliance-drift) now passes 21/21 including release instrumentation; docs navigation passes 43/43. Exact-head CI has restarted.

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

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: Measurement capability declaration (tracking_capabilities, attribution methodologies, TMP exposure data)

3 participants