Skip to content

Design mobile ad-rendering trace endpoint - #1107

Open
prk-Jr wants to merge 18 commits into
mainfrom
spec/mobile-ad-render-trace-endpoint
Open

prk-Jr wants to merge 18 commits into
mainfrom
spec/mobile-ad-render-trace-endpoint

Conversation

@prk-Jr

@prk-Jr prk-Jr commented Sep 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • establish a reviewable design boundary before implementing the mobile ad-rendering trace requested by Create debug endpoint for mobile user to trace ad rendering #1050
  • define a mobile-first reproduction and export journey that does not require credentials, developer tools, a target URL, or a server-side report database
  • separate privacy-safe server-auction, GPT delivery, and creative-rendering evidence so the report does not claim correlations it cannot prove

Changes

File Change
docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Defines UX, routing, configuration, schemas, live auction transport, opaque slot correlation, privacy, failure handling, testing, rollout, acceptance criteria, and implementation sequencing.

Review corrections

  • Keep valid server-auction capture complete when only slot-token correlation fails or correlation sidecars are evicted; align failure handling and required regressions.
  • Make the newest-cycle-per-slot truncation floor apply to every stage, protecting referenced auctions and explicitly failing an oversized protected set.
  • Assert committed asset digests against build output and require a new URL/digest for changed bytes.
  • Name the browser Prebid bidder timeout and verified 3000 ms default, with bounded timer delays and checked expiry arithmetic.
  • Explicitly add the new onTimeout and onBidderError hooks and require testing through the actual Prebid registration path.
  • Identify the setup-request network/CookieHealth projection independently of the publisher-document capture gate.

These are design-spec corrections; endpoint implementation remains tracked by #1050.

Current validation

Validated commit 2028bc6e1 locally: Rust formatting, all eight target-matched Clippy gates, all four Rust adapter test aliases, cross-adapter parity, JS build, all 1,185 Vitest tests across 48 files, JS formatting, and docs formatting passed. The Rust suites passed 3,299 tests with 13 existing ignored cases and zero failures. Independent semantic review found no remaining issues; git diff --check passed.

Closes

Closes #1108

Implementation remains tracked by #1050. Related observability and timing follow-ups remain tracked by #1081 and #1076.

Test plan

  • cargo test-fastly && cargo test-axum && cargo test-cloudflare && cargo test-spin — passed
  • All eight target-matched Clippy gates — passed
  • cargo fmt --all -- --check
  • JS tests: cd crates/trusted-server-js/lib && npx vitest run — 48 files and 1,185 tests passed under pinned Node 24.12.0
  • JS format: cd crates/trusted-server-js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM build: cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1 — not run; documentation-only change
  • Manual testing via fastly compute serve — not applicable
  • Other: independent adversarial design review approved; git diff --check main...HEAD passed

Checklist

  • Changes follow CLAUDE.md conventions
  • No unwrap() in production code — no production code changed
  • Uses tracing macros (not println!) — no logging code changed
  • New code has tests — no code added; the spec defines the required implementation test strategy
  • No secrets or credentials committed

@prk-Jr prk-Jr self-assigned this Sep 1, 2026
@prk-Jr
prk-Jr marked this pull request as draft September 1, 2026 10:51
@aram356 aram356 added this to the 202609 milestone Sep 2, 2026
@aram356
aram356 requested a review from jevansnyc September 14, 2026 15:52
@aram356
aram356 marked this pull request as ready for review September 14, 2026 15:53

@jevansnyc jevansnyc 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.

Review of the design spec. No code changes here, so this is internal consistency plus whether the stated contracts hold against what is in the repo today (gpt_diagnostics.rs, publisher.rs, auth.rs, prebid_eids.rs, and the TS diagnostics store/types).

Seven issues inline. The first three change the design rather than the wording:

  1. The ts-auc- token shape does not match the existing producer, so correlation never joins.
  2. TraceGptDiagnosticsV1 as specified cannot satisfy acceptance criterion 8.
  3. Trace paths terminate ahead of authentication, which carves an exemption out of the ^/_ts namespace that auth.rs says should not exist.

The remaining four are bounded-scope corrections to the cookie lifetime claim, the TSJS gate, a capture_status gap, and redaction consistency.

Mechanical checks came back clean: cookie names (ts-ec, ts-eids, ts-tester, __Host-ts-console), the 8 KiB ts-eids cap (MAX_EIDS_COOKIE_BYTES), and the callback-issue reason values all match what the spec assumes.

Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
@prk-Jr
prk-Jr requested a review from jevansnyc September 19, 2026 06:06

@aram356 aram356 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.

Summary

A design-only PR adding a single 1852-line spec for a /_ts/trace mobile
diagnostics endpoint. The document is unusually well-grounded: field names,
constants, and several non-obvious hazards (the AuctionRequest.id leak, the
JA4/H2 fingerprint exclusion, bootstrap-fallback argument tolerance, the
unpopulated asn) are verbatim correct against the code. All seven findings
from the previous round are genuinely resolved in e3f371f8c, and I re-verified
each rather than re-raising it.

The blocking findings below are places where the spec mandates behavior the
pinned platform cannot express, or where it assumes adapter defaults that do the
opposite of what sections 8, 12.3, and 13 require. Because this is a design
document, each one is cheaper to fix now than after it becomes four
implementation PRs.

6 of the inline comments below carry a one-click GitHub suggestion —
use Commit suggestion (or Add suggestion to batch) to apply them. The
remaining comments describe the change in prose because the fix is a new
validation hook or spans more than one contiguous range.

Blocking

🔧 wrench

  • Two-second request-body deadline is unimplementable — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:494
  • HEAD /_ts/trace is proxied to the publisher origin — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:468
  • Router-level 405 carries no Allow and no hardening headers — see
    inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:506
  • The mandated configuration validation cannot fire — see
    Cross-cutting below

Non-blocking

🤔 thinking / 📝 note

  • AuctionSlot.ext presented as an existing type — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:908
  • Slot tokens described as existing; verbatim-comparison rule conflicts with
    normalizedAuctionId
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:819
  • Inherited and new cookie caps are presented as one list — see inline
    at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:654
  • CSP blocks the favicon, and leaves blob: and inline styles unaddressed
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1326
  • Auth contract overstates rule composition; existing JA4 route is an
    auth-bypass precedent
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1364
  • Container-nesting cap has zero headroom — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1092
  • source enum diverges from the existing AuctionSource — see inline
    at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:841
  • Deprecated /__ts/page-bids alias is uncovered — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:996
  • GPT projection prose is not a usable allowlist — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:715

Cross-cutting / body-level findings

  • 🔧 The configuration validation this spec mandates cannot fire as a
    validator rule.
    Section 8 (line 452) requires that
    “trace_page_enabled = true requires enabled = true; invalid
    combinations fail configuration validation”, and section 14.1 (line 1433)
    requires a test that configuration “rejects trace-page enablement without
    GPT diagnostics”.

    One correction first, in fairness to the design: adding trace_page_enabled
    to TOML today is already a hard error on both the enabled and disabled
    paths, because validate_disabled_schema
    (crates/trusted-server-core/src/settings.rs:247-253) forgives only errors
    beginning "missing field ", and an unknown-field error is not forgiven.
    That part is correctly fail-closed.

    The real gap is narrower but still real. Once trace_page_enabled is a
    legitimate field, IntegrationSettings::get_typed returns before validation:

    // crates/trusted-server-core/src/settings.rs:348-350
    if !config.is_enabled() {
        return Ok(None);
    }
    
    config.validate().map_err(|err| { /* :352 */ })?;

    So the exact combination the spec wants rejected — enabled omitted (serde
    default false) together with trace_page_enabled = true — resolves to
    Ok(None) and a #[validate(schema(...))] rule never runs. Note
    #[validate(schema(...))] does otherwise work in this crate
    (settings.rs:2737), so the failure mode is silent rather than obvious.

    The precedent that fits is validate_js_asset_proxy_config
    (crates/trusted-server-core/src/config.rs:280-299): it reads the raw JSON
    and calls validate() outside the enabled gate, runs from both the deploy
    (config.rs:250) and runtime (config.rs:271) paths, and is proven by
    validate_rejects_invalid_disabled_js_asset_proxy_assets
    (config.rs:1424). Naming that pattern here would keep an implementer from
    writing a rule that never fires.

    On sourcing: the “invalid enabled config must not be silently
    logged-and-disabled” rule is not actually in AGENTS.md or
    CONTRIBUTING.md. Its canonical statement is a HIGH-severity finding in
    docs/superpowers/specs/2026-03-11-production-readiness-report-design.md:217-233.
    If this spec relies on it as normative, that is worth making explicit, since
    it was never promoted into the contributor docs.

  • 📝 Section 12.4's cache invariant is already implemented, in two
    places on Fastly.
    The spec asks that “tests must prove that late
    response-header handlers cannot make traced content publicly cacheable”
    (line 1355). That guarantee exists today:
    apply_response_headers_with_cache_privacy
    (crates/trusted-server-core/src/response_privacy.rs:163-172) skips operator
    response_headers entries for Cache-Control and edge-cache header names
    whenever the response is already uncacheable. On Fastly there is a second
    layer after it — apply_terminal_response_effects
    (crates/trusted-server-adapter-fastly/src/main.rs:371-392) re-runs the
    privacy guards, because EC finalize and filter effects can add Set-Cookie
    later; the regression test is
    late_filter_effects_cannot_make_an_assembled_response_public. Citing both
    would let the implementation plan reuse the mechanism instead of rebuilding
    it. Note also that apply_finalize_headers is terminal on Axum, Cloudflare,
    and Spin but not on Fastly.

  • 📝 A reserved-namespace classifier already exists, at the fallback
    boundary.
    Section 8 requires rejecting trailing slashes, extra segments,
    repeated separators, encoded separators, and ambiguous dot segments beneath
    the reserved namespace (lines 509-514). deny_admin_diagnostic_fallback
    (crates/trusted-server-core/src/ec/admin.rs:179-196) already solves that
    shape for /_ts/admin, including a bounded percent-decode-to-fixed-point
    with MAX_PERCENT_DECODE_ROUNDS = 4. It runs first inside each adapter's
    fallback rather than at the front door, but it is the pattern to lift
    forward rather than re-derive.

  • 📝 Adapter-parity caveat for section 8. Several existing /_ts/*
    routes (/_ts/api/v1/*, /_ts/set-tester, /_ts/clear-tester,
    /_ts/debug/ja4) are registered only on Fastly. Section 8 requires the trace
    namespace on all four adapters, so trace routing cannot follow that
    precedent — worth stating, since it affects the sequencing in section 17.

CI Status

All checks passing on e3f371f8c.

  • browser integration tests: PASS
  • integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • prepare integration artifacts: PASS
  • CodeQL: PASS
  • Analyze (rust): PASS
  • Analyze (javascript-typescript): PASS
  • Analyze (actions): PASS
  • cargo fmt: PASS
  • cargo test: PASS
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native): PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • vitest: PASS
  • format-typescript: PASS
  • format-docs: PASS
  • CLAUDE.md symlink guard: PASS

Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
@prk-Jr
prk-Jr requested a review from aram356 September 21, 2026 05:23

@aram356 aram356 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.

Summary

Second review pass, against head 7a82a944a (base main). The previous pass
raised twelve findings; 14c274cba addresses all twelve, and I verified each
fix against the code at this head rather than taking the replies at face value.

Two are worth calling out as substantively verified rather than merely
annotated. The new section 9.3 allowlist table is genuinely exhaustive: diffing
it mechanically against GptDiagnosticsRequestCycle gives 30 real members, 28
allowlisted, and exactly adManager and previousCreativeId excluded, with no
listed name that does not exist on the real type; the coverage keys, counters,
metadata, binding, and durations rows all match their interfaces exactly.
And the container-nesting cap moved 8 to 10, which restores two levels of
headroom over the deepest legitimate path (gpt_diagnostics.slots[].requests[].requestedSizes[][w], level 8).

One new blocking finding, introduced by the body-handling rewrite itself: the
replacement mechanism cannot produce the 413 the same bullet mandates, cites
a precedent that uses a different API, and misreads an empty body on the one
adapter that streams it. Details inline.

1 of the inline comments below carries a one-click GitHub suggestion.
The other two are prose: one names a trigger condition, one corrects an
explanation.

Blocking

🔧 wrench

  • Body-emptiness mechanism cannot return 413 and misreads streamed bodies
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:516

Non-blocking

📝 note / ⛏ nitpick

  • Blob revoke trigger is undefined — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1432
  • Favicon suppression is attributed to CSP rather than the <link> element
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1428

Cross-cutting / body-level findings

  • 📝 Prior-round findings verified as resolved. Recorded so the next
    pass does not re-litigate them: the unimplementable two-second body deadline
    and one-byte read are gone; configuration validation now specifies a
    raw-config hook modelled on validate_js_asset_proxy_config
    (crates/trusted-server-core/src/config.rs:280-299) and correctly explains
    why a schema validator never fires for a disabled integration; HEAD now
    requires explicit registration on all four adapters, citing
    dispatch_head_on_named_get_route_falls_through_to_publisher_fallback; the
    405 contract now requires the trace responder to supply Allow and the
    section 12.3 hardening itself rather than inheriting a router error; the CSP
    gained img-src data: and a class-toggle-only styling rule; the auth section
    now states first-match-wins and that the fail-closed backstop covers only
    /_ts/admin; the deprecated /__ts/page-bids alias is covered, and the TSJS
    retry it refers to is real (crates/trusted-server-js/lib/src/integrations/gpt/index.ts:1675-1692);
    and the slot-token, cookie-cap, AuctionSlot.ext, and source-enum
    paragraphs now distinguish new design from existing code. I re-verified the
    underlying code claims at this head.

  • 📝 One claim in the rewrite is accurate and load-bearing enough to
    keep.
    The statement that Spin buffers the body while Axum buffers only JSON
    checks out against the pinned dependency: Spin reads the full body into
    Body::Once unconditionally (edgezero-adapter-spin/src/request.rs:74-80),
    and Axum branches on content type
    (edgezero-adapter-axum/src/request.rs:21-35). That asymmetry is what drives
    the blocking finding above, so it is worth keeping the sentence even after
    the mechanism changes.

CI Status

No failing checks. Several are still running against the merge commit pushed
shortly before this review; they are recorded as pending rather than treated as
findings.

  • cargo fmt: PASS
  • cargo test: PASS
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native): PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • vitest: PASS
  • format-typescript: PASS
  • format-docs: PASS
  • CLAUDE.md symlink guard: PASS
  • Analyze (actions): PASS
  • Analyze (rust): PENDING
  • Analyze (javascript-typescript): PENDING
  • integration tests: PENDING
  • browser integration tests: PENDING
  • CodeQL: SKIPPED

Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
@prk-Jr
prk-Jr requested a review from aram356 September 24, 2026 05:15
aram356 added a commit that referenced this pull request Sep 24, 2026

@aram356 aram356 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.

Summary

Third review pass, against head c4d664aab (base main). Commit 155d3b09f
resolves all three findings from the previous round, and I verified each fix
against the pinned edgezero v0.0.8 source rather than against the replies.

The body-validation rewrite is the substantive one. It now matches both Body
variants explicitly, requires a clean EOF to prove a streamed body empty, and
names both traps from the last round — telling implementers not to copy
into_bytes().unwrap_or_default() and not to propagate
into_bytes_bounded errors as the response. I checked that this is actually
implementable: Body is a public, non-#[non_exhaustive] enum
(edgezero-core/src/body.rs:14-17), core already matches both variants in the
exact prescribed shape (crates/trusted-server-core/src/publisher.rs:201-211),
and async handlers are available on all four adapters, with Fastly driving them
under block_on. The favicon causality and the blob-revoke timing are both
correct now.

Two findings remain. Neither is a defect in the new text; both are places where
the spec is not yet self-contained. Since this document is the contract four
implementation PRs will be built from, closing them here is cheaper than
discovering them during implementation.

Both inline comments carry a one-click GitHub suggestion.

Blocking

🔧 wrench

  • Section 13 omits every body-validation status code — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1516

Non-blocking

📌 out of scope

  • Deferred-cleanup rule diverges from the console export that ships today
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:253

Cross-cutting / body-level findings

  • 📝 Prior-round findings verified as resolved, recorded so a fourth
    pass does not re-litigate them. The body-validation mechanism no longer
    depends on an API that cannot produce the mandated 413, and it no longer
    inherits the into_bytes().unwrap_or_default() behavior that would read a
    non-empty streamed body as empty — which matters, because a bodiless
    fetch() POST carries no Content-Type and Axum streams exactly that case
    (edgezero-adapter-axum/src/request.rs:24-35, pinned by its own tests at
    :97-118 and :167-181). Favicon suppression is now attributed to
    <link rel="icon"> with img-src data: only permitting the load. Blob
    cleanup is now a 1000 ms setTimeout with per-download scheduling, and the
    accompanying test lines are implementable: vi.useFakeTimers is already used
    across nine JS test files, and createObjectURL/revokeObjectURL are
    already mocked at api.test.ts:540-551.

  • 📝 One concern investigated and dismissed, noted so it does not
    resurface as a finding later. The 1000 ms revoke timer raises the question of
    what happens if the document is torn down before it fires. No specified flow
    navigates during a pending download: the section 6.2 storage-failure download
    happens on the publisher page, which that section says "remains in place",
    and the section 6.3 download happens on /_ts/trace, whose own
    Copy/Share/Download and clear actions do not navigate. Line 1729's "same-tab
    navigation occurs only after a successful write" governs the earlier handoff,
    before any download exists. If a document were torn down anyway, the object
    URL is reclaimed with it. No change needed.

CI Status

All 20 checks passing on c4d664aab.

  • browser integration tests: PASS
  • integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • prepare integration artifacts: PASS
  • CodeQL: PASS
  • Analyze (rust): PASS
  • Analyze (javascript-typescript): PASS
  • Analyze (actions): PASS
  • cargo fmt: PASS
  • cargo test: PASS
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native): PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • vitest: PASS
  • format-typescript: PASS
  • format-docs: PASS
  • CLAUDE.md symlink guard: PASS

@aram356 aram356 modified the milestones: 202609, 202610 Sep 28, 2026
@prk-Jr
prk-Jr requested a review from aram356 October 1, 2026 04:19

@jevansnyc jevansnyc 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.

👍

@aram356 aram356 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.

Summary

Fourth review pass, against head 162b3a473 (base main). Commit 4811d98ed
resolves both round-3 findings, with the suggested bytes applied verbatim: every
status code the spec defines now has a §13 entry (full §8 to §13
parity, with 408 appearing only in its intentional disclaimer), and §5.5
documents the deliberate divergence from TS Console's synchronous revoke.

This round went deeper into §9.3, §9.4, and §9.4.1, which earlier
passes had covered less thoroughly, and found two contradictions in how
correlation-layer failures feed auction_coverage.capture_status. They are the
same underlying bug reached by two paths: an issue that belongs to the
correlation layer is specified to change a server-capture status that §9.3
line 846 says it must not change. One of them puts a required §14.3 test
(line 1732) in direct conflict with §13's rule (line 1548), so the spec
currently mandates a test that its own failure-handling section would fail.

The remaining four findings are smaller: one ambiguity whose two readings
produce different observable behavior, one untestable test requirement, and two
places where the spec describes net-new work as if it already exists.

4 of the 6 inline comments carry a one-click suggestion. The other two
describe the change in prose because the fix is a naming decision rather than
a byte-level edit.

Blocking

🔧 wrench

  • Slot-token join failure downgrades a complete server capture — see
    inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1032
  • Correlation-sidecar eviction drives server-auction capture status —
    see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1151

Non-blocking

🤔 thinking / 📝 note

  • Truncation per-slot floor scope is ambiguous — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1263
  • “Prove published v1 bytes never change” is not testable — see
    inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1809
  • “The configured bid timeout” is ambiguous between three keys
    — see inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1130
  • Prebid onTimeout / onBidderError described as already pinned — see
    inline at
    docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md:1128

Cross-cutting / body-level findings

  • 📝 Surfaces checked this round that are clean, recorded so a fifth
    pass does not re-litigate them. Truncation counter coverage: every removal
    path in the §9.5 algorithm maps to one of the six counters, including
    sidecars removed alongside a removed auction (line 1259). Outer and nested
    truncation objects cannot double-count, because core bounds the inner model
    and the browser rejects rather than re-truncates it (lines 1244-1246).
    provider_to_slot_no_bid is consistently unavailable at all three
    references. The four transport shapes agree with their later prose
    descriptions. The 16 / 128 retention limits match §9.5's table with no
    third value anywhere. Acceptance criteria 1, 5, 10, 12, 13, 14 and 15 are all
    supported by the body. Every cited file, symbol, test name and issue
    reference resolves.

  • 📝 One suspected contradiction that resolves clean. §6.1 shows
    network and cookie health on a first visit, while §9.1 line 623 gates
    TraceRequestContextV1 behind a valid diagnostics cookie. These are two
    different computations: §9.1 governs injection into the publisher
    document
    , and §8 step 3 gives the trace route its own “bounded
    request-context inspection” for its own response, which needs no cookie.
    §6.1 line 288 and §6.3 line 317 both guard against conflating them.
    Worth one sentence naming the data contract for the setup-request projection,
    since no section does — an implementer currently has to infer that it
    reuses the §9.1 network block and §9.2 CookieHealth without the
    report envelope.

CI Status

All 20 checks passing on 162b3a473.

  • browser integration tests: PASS
  • integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • prepare integration artifacts: PASS
  • CodeQL: PASS
  • Analyze (rust): PASS
  • Analyze (javascript-typescript): PASS
  • Analyze (actions): PASS
  • cargo fmt: PASS
  • cargo test: PASS
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native): PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • vitest: PASS
  • format-typescript: PASS
  • format-docs: PASS
  • CLAUDE.md symlink guard: PASS

Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
Comment thread docs/superpowers/specs/2026-09-01-mobile-ad-render-trace-endpoint-design.md Outdated
@prk-Jr
prk-Jr requested a review from aram356 October 2, 2026 05:16

@aram356 aram356 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.

👍 Looks good. @prk-Jr Please get started on this. Thanks

This branch has not been deployed

No deployments
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.

SPEC Specify mobile ad-rendering trace endpoint

3 participants