Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
cf16418
Add request phase timing design spec and implementation plan (#1069)
jevansnyc Aug 25, 2026
052eada
Add RequestTimings phase collection and Server-Timing rendering
jevansnyc Aug 25, 2026
7505fb8
Add observability settings and decouple tinybird access and auction e…
jevansnyc Aug 25, 2026
4ce413f
Add test coverage for the access_enabled without tinybird.enabled rej…
jevansnyc Aug 25, 2026
f83092a
Emit Server-Timing at the send freeze point on conclusively private r…
jevansnyc Aug 25, 2026
4b19c44
Record filter and geo spans and dedupe the per-request geo lookup
jevansnyc Aug 25, 2026
ce295f1
Record origin, template cache, and KV phase spans in core
jevansnyc Aug 25, 2026
c222ae2
Capture stream duration, auction wait placement, and response bytes
jevansnyc Aug 25, 2026
8b028bb
Add access telemetry snapshot, route classes, and coarse route templates
jevansnyc Aug 25, 2026
48acd81
Emit confirmed access telemetry rows after pull-sync post-send
jevansnyc Aug 25, 2026
72d5755
Extend access_logs_raw with phase columns and a non-null sorting key
jevansnyc Aug 25, 2026
c50be03
Widen time_elapsed_ms to nullable so dropped snapshots cannot quarant…
jevansnyc Aug 25, 2026
0aead79
Emit Server-Timing from the Axum terminal layer with adapter-specific…
jevansnyc Aug 25, 2026
e9cf5b9
Document the observability and access telemetry configuration surface
jevansnyc Aug 25, 2026
7942c74
Normalize telemetry method, guard zero sample rate, and mirror geo wr…
jevansnyc Aug 26, 2026
d8fcb5e
Add a local dev config envelope generator example
jevansnyc Aug 26, 2026
7cf7d86
Add JSONPaths and expression sorting key to the access datasource
jevansnyc Aug 26, 2026
600746f
Use web_time Instant on request timing paths
jevansnyc Aug 26, 2026
3d7e697
Reject opaque identifier segments in publisher route templates
jevansnyc Aug 26, 2026
38043d7
Address access telemetry review feedback
jevansnyc Aug 26, 2026
274241b
Add auction timeline offsets spec amendment
jevansnyc Aug 26, 2026
29d45e8
Add auction timeline offsets implementation plan
jevansnyc Aug 26, 2026
46911a6
Record T0-anchored auction timeline offsets in the access row
jevansnyc Aug 26, 2026
1fa9f8c
Remove generated integration wrangler config from tracking
jevansnyc Aug 26, 2026
2ef7635
Reject single-segment publisher paths in route templates
jevansnyc Aug 28, 2026
082461d
Sample access rows with real randomness at the snapshot rate
jevansnyc Aug 28, 2026
f3ee473
Drop the origin span before error-path auction telemetry
jevansnyc Aug 28, 2026
46b3c7f
Address remaining review feedback on timing surfaces and docs
jevansnyc Aug 28, 2026
a0a3af5
Merge remote-tracking branch 'origin/main' into feat/request-phase-ti…
ChristianPavilonis Aug 31, 2026
c6235b9
Enforce access telemetry body limit
ChristianPavilonis Aug 31, 2026
576ef33
Merge remote-tracking branch 'origin/feat/request-phase-timing' into …
ChristianPavilonis Sep 4, 2026
ca46e4f
Format auction timeline implementation plan
ChristianPavilonis Sep 4, 2026
6f133cc
Merge origin/main into feat/request-phase-timing
jevansnyc Sep 8, 2026
bcc1475
Bound route templates by allowlist and harden the telemetry config su…
jevansnyc Sep 8, 2026
a152367
Address round-3 telemetry robustness findings
jevansnyc Sep 8, 2026
bdb68dd
Merge feat/request-phase-timing and resolve auction timeline review f…
jevansnyc Sep 17, 2026
58f8a35
Correct the section 18 status line and give the wrangler ignore its o…
jevansnyc Sep 17, 2026
589d6cc
Merge main into feat/request-phase-timing
jevansnyc Sep 17, 2026
dae88a0
Improve GPT auction diagnostics observability
ChristianPavilonis Sep 4, 2026
30ccab8
Fix GPT auction diagnostics timing accuracy
ChristianPavilonis Sep 4, 2026
563670d
Address GPT diagnostics review feedback
ChristianPavilonis Sep 14, 2026
628ce28
Clarify GPT auction diagnostics evidence
ChristianPavilonis Sep 8, 2026
b316aee
Address GPT diagnostics review feedback
ChristianPavilonis Sep 14, 2026
9b5bb41
Align GPT diagnostics tests with current metadata
ChristianPavilonis Sep 17, 2026
54d33ad
Hide placeholder dimensions from diagnostics overlay
ChristianPavilonis Sep 17, 2026
3e8cde2
Update crates/trusted-server-js/lib/src/integrations/prebid/index.ts
ChristianPavilonis Sep 20, 2026
a7b19ca
Address remaining GPT diagnostics review feedback
ChristianPavilonis Sep 21, 2026
f951955
Fix cross-adapter GPT diagnostic timing origins
ChristianPavilonis Sep 21, 2026
0fa7dfb
Clarify Prebid diagnostics export boundaries
ChristianPavilonis Sep 25, 2026
2791ceb
Use shared EdgeZero request timing across adapters
ChristianPavilonis Sep 28, 2026
2abb8e8
Merge console timing updates into clarity
ChristianPavilonis Oct 1, 2026
3a8b8ba
Use neutral labels for unobserved server clocks
ChristianPavilonis Oct 2, 2026
74a8f44
Merge origin/main into feat/request-phase-timing
jevansnyc Oct 5, 2026
ee66fbf
Combine request timing and GPT diagnostics stack
ChristianPavilonis Oct 8, 2026
e6d51e3
Integrate main and address timing and diagnostics review
ChristianPavilonis Oct 9, 2026
06e1336
Fix request timing and access telemetry review blockers
ChristianPavilonis Oct 12, 2026
3d39b1e
Fix diagnostics isolation and timing privacy
ChristianPavilonis Oct 13, 2026
51aff43
Keep auction-wait metrics unset without provider launches
ChristianPavilonis Oct 13, 2026
686826e
Merge main into request timing branch
ChristianPavilonis Oct 13, 2026
ab58ced
Test zero-provider page-bids diagnostics omission
ChristianPavilonis Oct 27, 2026
39568b1
Keep immediate test outcomes unlaunched
ChristianPavilonis Oct 27, 2026
ba18e09
Reject legacy access datasets when emission is on
ChristianPavilonis Oct 27, 2026
b8ccff4
Retry failed Prebid diagnostics registration
ChristianPavilonis Oct 27, 2026
0305f9f
Suppress referrers on diagnostics dictionary links
ChristianPavilonis Oct 27, 2026
2e0722f
Honor readiness in the Axum dev-server bridge
ChristianPavilonis Oct 27, 2026
5cf32ab
Borrow settings when building access targets
ChristianPavilonis Oct 27, 2026
c4cec08
Correct timing review documentation and fixtures
ChristianPavilonis Oct 27, 2026
7214c60
Define access telemetry v2 outcome fields
ChristianPavilonis Oct 27, 2026
d964741
Measure auction collection from launch evidence
ChristianPavilonis Oct 27, 2026
e8ff076
Dispatch access telemetry without ingest waits
ChristianPavilonis Oct 27, 2026
3e4b73c
Load Prebid diagnostics only with its recorder
ChristianPavilonis Oct 27, 2026
b7d0d0b
Keep diagnostics controls outside creative bounds
ChristianPavilonis Oct 27, 2026
02f020a
Document request timing and delivery contracts
ChristianPavilonis Oct 27, 2026
9654deb
Finish request timing and diagnostics review cleanups
ChristianPavilonis Oct 27, 2026
13b5338
Merge main into feat/request-timing-console-combined
ChristianPavilonis Nov 2, 2026
443339b
Preserve validated HTTP ingress through Axum timing conversion and up…
ChristianPavilonis Nov 3, 2026
ee249d3
Refresh the coordinated EdgeZero request timing candidate
ChristianPavilonis Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ src/*.html

# Documentation proposal workflow scratch space
/.docs-proposal/
# Wrangler config rendered by the Cloudflare integration-test harness from
# wrangler.ci.toml for CI or test-specific configuration overrides.
wrangler.integration.generated.toml
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Fastly abandons unfinished requests; Axum, Cloudflare, and Spin cancel owned work.
- Explicit TS Console activation with `?ts_console=1` now sets a 30-minute diagnostics cookie instead of a browser-session cookie, independently of the mobile trace flag. Ordinary requests do not refresh it; end and explicitly enable diagnostics again to adopt the lifetime for an existing session.
- Publisher documents with diagnostics active now use private, no-store responses and strip conditional and range request headers before fetching the origin. An unexpected origin `304` becomes a private `502` because it cannot supply an instrumented document, including when mobile tracing is disabled.
- Access telemetry v2 now uses `auction_collected_ms` for collection return, sets `ts_version` to the TS build identifier matching `x-ts-version`, and adds `delivery_result` for local complete/partial/error transport handoff. It does not establish client receipt. Coordinate any deployed preview v2 schema before updating the producer.
- Access ingestion now dispatches without waiting for Tinybird's reply. Start failures are reported; later transport errors, non-2xx responses and remote ingestion acceptance are unobserved, with no retry.
- `/auction`, page-bids and HTML collectors share measured collection waits and outcome mapping. Real mediator-only work can have collection/wait/commit timing without a provider dispatch offset; routing and admission still decide whether any request is sent.
- Prebid diagnostics listener, targeting and correlation code now lives in the optional diagnostics bundle. Badge evidence passes clicks through, its small control sits outside observed creative bounds, and selecting the latest request no longer opens history.

- Auction telemetry failure batches for `/auction` and page-bids now include provider launch-failure rows alongside the summary, so a failed dispatch can emit more than one row. `/auction` summary `elapsed_ms` now uses the orchestrator's elapsed time.
- GPT diagnostics JSON exports now include bounded server winner and Prebid candidate/win bidder codes and bucketed `hb_pb` values. These observations do not establish which creative GAM ultimately served; raw CPM and creative markup remain excluded.
- The Axum dev server now runs its own serve loop to apply terminal request-timing handling.
- The default `tinybird.access_dataset` is now `access_logs_v2`. Since this field is serialized, an upgrade from TOML that omits it may produce a one-time config-envelope diff; review and push once to settle it. Explicit legacy dataset values must be changed before enabling access telemetry.
- **Breaking:** `x-ts-version` now reports the deployed git version — the release tag, else the branch, else the first 6 characters of the commit — compiled in from the build-time `TRUSTED_SERVER__GIT_VERSION` (set by the deploy pipeline) or local git, and is sent by every adapter, including on the Fastly `GET /health` probe. The Fastly service version it previously carried is now `x-ts-fastly-version`; update dashboards, monitors, and scripts that read `x-ts-version` as the Fastly version number. Builds with neither the override nor git omit the header.
- **Breaking:** `ts audit ad-templates generate` now previews the managed-field diff on stderr and asks before writing a changed config. Runs whose stdin or stderr is not a terminal fail without writing unless `--yes` is passed, so add `--yes` to scripts and CI jobs that apply generated slots. A declined prompt exits non-zero, `--yes` cannot be combined with `--dry-run`, and a candidate whose managed fields are unchanged is no longer rewritten.
- **Breaking:** `ts prebid bundle` is now `ts prebid client`, alongside the new `ts prebid server` namespace. Update scripts and runbooks to use `ts prebid client` with the same arguments. The old `bundle` spelling is no longer accepted and has no compatibility alias.
Expand Down Expand Up @@ -71,6 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `[rewrite] include_domains` limits creative asset rewriting to listed hosts. When non-empty, only asset URLs on matching hosts are proxied through `/first-party/proxy`, so only those hosts receive the EC ID on newly rewritten or signed asset URLs. The list is not enforced when a proxy URL is fetched, so previously issued proxy URLs can still forward the EC ID to hosts later removed from it. Other assets keep their original URL, and `/first-party/sign` returns `502` for them so the creative runtime loads them directly. Click-through links are not affected, and `exclude_domains` still wins. Entries must be host names, optionally prefixed with `*.`, dotted-quad IPv4 addresses, or bracketed IPv6 addresses; entries with a scheme, port, path, spaces or non-ASCII characters are rejected at load. Upgrading: deploy the binary first, then push a config that sets `include_domains`. Rolling back: remove `include_domains`, push the resulting config, then roll back the binary; older binaries reject the key because `[rewrite]` denies unknown fields.
- Added `[auction].rewrite_clicks` to control creative click-through wrapping (`<a href>`/`<area href>` → signed `/first-party/click`) independently of asset rewriting. Unset (the default) follows `rewrite_creatives` for `POST /auction` and SSAT/page-bids and keeps wrapping links in HTML fetched through `/first-party/proxy`, so existing configs keep their asset and link behavior; an explicit value applies to every path. `rewrite_creatives` now governs asset URLs only; bidder `<base>` handling and, on `POST /auction`, creative TSJS injection run when either setting is on. Click wrapping is what forwards the visitor's EC ID (`ts-ec`) to landing pages, so `rewrite_clicks = false` stops that on every path and `rewrite_clicks = true` starts it for configs with `rewrite_creatives = false`. Also changed for every config with rewriting on, including the default, and for HTML fetched through `/first-party/proxy` under every config: a bidder `<base target>` is now kept with its `href` dropped, instead of removing the whole element, so raw links keep opening where the bidder intended. Upgrading: deploy the binary first, then push a config that sets `rewrite_clicks`. Rolling back: remove any explicit `rewrite_clicks` (and its environment override), push the resulting config, then roll back the binary. Older binaries tie click wrapping to `rewrite_creatives` in both directions, so rolling back turns clicks back on for `rewrite_creatives = true` with `rewrite_clicks = false`, and off for `rewrite_creatives = false` with `rewrite_clicks = true`; rolling back from any `rewrite_clicks = false` also turns click wrapping back on in HTML fetched through `/first-party/proxy`.
- Added the `[auction].rewrite_creatives` (default `true`) and `[auction].sanitize_creatives` (default `false`) options. `rewrite_creatives` rewrites winning-bid adm to first-party endpoints across `POST /auction` and publisher SSAT/page-bids delivery (asset URL conversion to `/first-party/proxy`; bidder `<base>` handling, which drops the `href` and keeps a `target`, and creative TSJS injection on `POST /auction` only, both of which also run when `rewrite_clicks` is on). Click-through wrapping is controlled by `[auction].rewrite_clicks`, which follows `rewrite_creatives` when unset. Enabling `sanitize_creatives` strips executable markup from winning-bid adm before delivery.
- Added opt-in request-phase `Server-Timing` on private Fastly/Axum responses and sampled post-delivery Fastly access telemetry. Deploy the new `access_logs_v2` datasource and its scoped APPEND token before enabling access emission; the legacy `access_logs_raw` schema and data remain unchanged. Access rows retain bounded route templates and coarse operational dimensions for 30 days, with random UUID joins for active auction observations and null UUIDs for disabled auctions. Each row stores its sampling rate. Access ingestion starts after delivery without waiting for a reply. Before rolling back to an older binary, disable access emission, remove non-default `[observability]` config, and re-push; access-only deployments must also disable the Tinybird master switch. See the telemetry guide and Tinybird cutover runbook.
- `creative_opportunities.slot.gam_unit_path` is now a template supporting `{network_id}`, `{slot_id}`, and `{section}`, so a publisher whose ad unit varies by site section expresses it in one slot rule instead of one per (slot × section). `{section}` derives from the request path: `[creative_opportunities].section_segment` selects which path segment names the section (0-based, default `0`; set `1` for locale-prefixed URLs), and `section_root` supplies the value for paths with no such segment. `section_root` is required when a template uses `{section}`. Existing static and absent `gam_unit_path` configs are unchanged. Startup rejects a blank `gam_network_id` only when an absent/default path or `{network_id}` template consumes it. Trusted Server conservatively caps whole rendered dynamic paths at 100 UTF-8 bytes, informed by Google's 100-character per-ad-unit-code limit; an over-limit request-specific path omits that slot without failing the response. During typed/startup finalization, every placeholder-bearing template that omits `section_segment` materializes `section_segment = 0`, so an older binary rejects the blob loudly. Static and absent paths remain legacy-schema compatible only when both `section_root` and `section_segment` are omitted. Before rolling back below this feature, replace or remove dynamic paths, remove both keys, re-push and finalize the config, then roll back the binary.
- Added opt-in APS HTTP debug metadata for controlled test sites, exposing the direct request and response under `/auction` provider metadata using the Prebid Server `debug.httpcalls` shape.
- Added typed APS renderer transport for direct auctions and GAM/Prebid Universal Creative, using a minimized one-bid envelope, a fragment-bound nonce, and an opaque sandboxed renderer endpoint.
Expand Down
17 changes: 9 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ cssparser = "0.36"
derive_more = { version = "2.0", features = ["display", "error"] }
directories = "5"
ed25519-dalek = { version = "2.2", features = ["rand_core"] }
edgezero-adapter-axum = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11", default-features = false }
edgezero-adapter-cloudflare = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11", default-features = false }
edgezero-adapter-fastly = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11", default-features = false }
edgezero-adapter-spin = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11", default-features = false }
edgezero-cli = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11" }
edgezero-core = { git = "https://github.com/IABTechLab/edgezero", tag = "v0.0.11", default-features = false }
# Temporary integration pin for EdgeZero #389, including main's lifecycle and ingress APIs.
# Replace all six revisions with an approved release tag before merging into main.
edgezero-adapter-axum = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3", default-features = false }
edgezero-adapter-cloudflare = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3", default-features = false }
edgezero-adapter-fastly = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3", default-features = false }
edgezero-adapter-spin = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3", default-features = false }
edgezero-cli = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3" }
edgezero-core = { git = "https://github.com/IABTechLab/edgezero", rev = "31b66d4b1c48dd0bf4a600837268d7eb7e3fb5b3", default-features = false }
env_logger = "0.11"
error-stack = "0.6"
esi = "0.7.2"
Expand Down
5 changes: 3 additions & 2 deletions crates/trusted-server-adapter-axum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ path = "src/main.rs"

[dependencies]
async-trait = { workspace = true }
axum = { workspace = true }
edgezero-adapter-axum = { workspace = true, features = ["axum"] }
edgezero-core = { workspace = true }
error-stack = { workspace = true }
futures = { workspace = true }
log = { workspace = true }
reqwest = { workspace = true }
simple_logger = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "time"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "net", "signal", "sync", "time"] }
tower = { workspace = true, features = ["util"] }
trusted-server-core = { workspace = true }
web-time = { workspace = true }

Expand All @@ -37,4 +39,3 @@ axum = { workspace = true }
base64 = { workspace = true }
temp-env = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tower = { workspace = true, features = ["util"] }
Loading
Loading