Add GAM cohort attribution for Trusted Server traffic - #1034
Conversation
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
Approved after a thorough review of the GAM cohort-attribution implementation. I found no actionable correctness, security, compatibility, or test-coverage findings.
Several required GitHub Actions jobs are currently red because runner setup could not download actions from GitHub codeload (429/503); rerun those checks before merge.
aram356
left a comment
There was a problem hiding this comment.
Summary
Tightly scoped implementation of the default-off gam_attribution_enabled marker. The risky surfaces check out: attribution is queued before the adInit guard and any display()/refresh(), the bundle fallback fails closed on document.currentScript (duplicate-ID decoys and cloned tags covered), the default path is byte-for-byte unchanged, creative documents keep the unmarked unified tag, streaming emits both activation signals in the first head chunk, and no cleanup path touches the page-level ts key. The double setConfig application (bootstrap + bundle) is intentional and idempotent per the design doc.
No correctness bugs found; the requested changes below are hardening and consistency items on the new surfaces.
CI Status
- fmt: PASS
- clippy (fastly/axum/cloudflare/cloudflare-wasm/spin-native/spin-wasm): PASS
- rust tests (fastly/axum/cloudflare/spin/parity/CLI): PASS
- js tests (vitest, browser integration): PASS
- formats (typescript/docs), CodeQL: PASS
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review at bbadec3: all seven findings from the previous review are resolved — first-wins attribute dedupe with a conflict test, debug-build charset guards on publisher tag attributes with WASM-safe panic tests, guarded ts.log.warn in the bootstrap attribution catch with test coverage, quote normalization synchronized with the Rust ordering test, dead mock member removed, and capability-based overlay wording. Approving; the two inline comments below are optional polish.
Both inline comments carry a one-click GitHub
suggestion— use Commit suggestion (or Add suggestion to batch) to apply them as commits on the PR branch.
Non-blocking
♻️ refactor
- Warn when a conflicting duplicate attribute value is dropped — see inline at
crates/trusted-server-core/src/integrations/registry.rs:1064
⛏ nitpick
- Example-TOML overlay comment reads circularly — see inline at
trusted-server.example.toml:107
CI Status
All 19 checks PASS: cargo fmt (required), cargo test (required), format-typescript (required), format-docs (required), cargo test (axum native), cargo test (cross-adapter parity), cargo test (ts CLI, native), cargo check (cloudflare native + wasm32-unknown-unknown), cargo check/build/test (spin native + wasm32-wasip1), vitest, browser integration tests, integration tests, integration tests (Fastly EC lifecycle), prepare integration artifacts, Analyze (actions), Analyze (javascript-typescript) ×2, Analyze (rust), CodeQL.
First-wins dedupe silently dropped a conflicting duplicate value. Log a warning naming the integration and attribute when a later injector emits a different value for an already-claimed attribute name, matching the registry's existing skip warnings. Identical duplicates stay silent.
The prior wording read circularly: the environment overlay can never create a missing configuration leaf. State the intent directly — keep the leaf so the override can apply.
Brings in the squashed #1034 (GAM cohort attribution) and #1025 (GPT diagnostics attribution docs), whose implementation branches were already merged here. Conflict resolutions keep main's post-review versions: attribute-name/value debug assertions and duplicate-attribute dedup in the registry, the GAM attribution warn log, and the reworded docs. Kept rc-only work where main's squash would have regressed it: the `getConfig` mock surface in the bootstrap test, and the deleted `tsjs_unified_helpers_use_all_module_ids` test, which contradicts the hashless unified script source introduced by the cache header policy work on this branch.
Summary
gam_attribution_enabledGPT option that applies fixed page-levelts=truetargeting to eligible publisher documents whose rewritten head is emitted by Trusted Server, allowing GAM to describe treatment delivery while the production/control path remains unmarked.document.currentScriptattribute-gated TSJS fallback that fails closed and isolatessetConfigfailures.ts_initiallifecycle, and publisher/Prebid targeting while documenting the collision audit, reporting contract, rollout, monitoring limits, and drain-safe rollback sequence.Changes
crates/trusted-server-cli/tests/config_env_overlay.rscrates/trusted-server-core/src/creative_opportunities.rststargeting remains forwarded unchanged.crates/trusted-server-core/src/html_processor.rscrates/trusted-server-core/src/integrations/gpt.rscrates/trusted-server-core/src/integrations/gpt_bootstrap.jsts=truebefore the existingadInitguard and isolate attribution failures from later GPT commands.crates/trusted-server-core/src/integrations/registry.rscrates/trusted-server-core/src/publisher.rscrates/trusted-server-core/src/tsjs.rscrates/trusted-server-integration-tests/browser/tests/shared/script-injection.spec.tscrates/trusted-server-integration-tests/fixtures/configs/trusted-server.integration.tomlcrates/trusted-server-js/lib/src/integrations/gpt/index.tscrates/trusted-server-js/lib/test/integrations/gpt/ad_init.test.tstskey.crates/trusted-server-js/lib/test/integrations/gpt/gpt_bootstrap.test.tssetConfig, and bootstrap continuity.crates/trusted-server-js/lib/test/integrations/gpt/index.test.tscrates/trusted-server-js/lib/test/integrations/prebid/index.test.tststargeting across refreshes.docs/guide/integrations/gpt.mddocs/superpowers/plans/2026-07-15-gam-ts-cohort-attribution.mddocs/superpowers/specs/2026-07-15-gam-ts-cohort-attribution-design.mdtrusted-server.example.tomlLaunch gates
This PR completes the repository implementation. Starting the cohort remains gated on target-network GAM provisioning, cross-system collision and privacy/CSP audits, a paired-report dry run, and router-controlled treatment validation described in the design.
GAM results are descriptive delivery attribution, not causal treatment-effect estimates.
Closes
Closes #1027
Test plan
cargo test-fastly && cargo test-axumcargo clippy-fastly && cargo clippy-axumcargo fmt --all -- --checkcd crates/trusted-server-js/lib && npx vitest run(44 files, 847 tests)cd crates/trusted-server-js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute serve: confirmed the inline flag, activation attribute, GPT page targeting, and decodedcust_paramscontainingts=trueon a real GAM requestChecklist
unwrap()added to production code