Skip to content

October release candidate (DO NOT MERGE) - #1228

Draft
ChristianPavilonis wants to merge 171 commits into
mainfrom
rc/202610
Draft

ChristianPavilonis wants to merge 171 commits into
mainfrom
rc/202610

Conversation

@ChristianPavilonis

@ChristianPavilonis ChristianPavilonis commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

October release candidate, replacing September RC #1112.

This PR is an integration branch for release-candidate validation. Do not merge it into main.

Contents

Fifteen pending PRs included in September's description or actual merge history are carried forward at the revisions listed below. #1154 and #1183 have newer branch tips that are not reflected in this table. #1121 uses its September-integrated revision because its newer dependency-pin commit is incompatible with this RC. #1076 is inherited through the stacked #1121 branch.

PR Review Included revision Status in RC
#1052 changes requested 285e0037 included
#1074 changes requested a1523675 included
#1076 changes requested 58f8a354 included through #1121
#1107 changes requested 162b3a47 included
#1121 changes requested f951955f September revision; newest commit excluded
#1137 changes requested d163be2a included
#1154 changes requested 0fa7dfb6 included
#1173 approved 4170c4cb included
#1175 changes requested a1710a05 included, carries the EdgeZero pin
#1176 approved 21eb7251 included
#1177 approved 7dc56385 included
#1180 approved 44144f0b included
#1181 approved 35ca3677 included
#1182 approved 4b03d6c3 included
#1183 approved b253a000 included

Each included revision was verified as an ancestor of the RC head. This rollover does not add other pending PRs. All fifteen listed PRs and this RC are assigned to milestone 202610: thirteen listed PRs moved from 202609, #1107 was already assigned to 202610, and #1183 and this RC previously had no milestone.

jevansnyc and others added 30 commits August 24, 2026 19:02
* Add request phase timing design spec (Server-Timing subtimings + access telemetry)

* Address review round 1: freeze point, template-cache naming, snapshot semantics, KV scope, geo carry, route template, sink confirmation, sampling and query model, config rollback

* Address review round 2: auction-wait placement modes, conservative private-only header emission, non-null sorting key with service identity, coarse publisher route template, telemetry snapshot and outage behavior, tinybird flag decoupling, adapter phase semantics

* Add request phase timing implementation plan

* Address engineer review: KV timing decorator, try_lock sampling, route metadata extension, adapter-derived env, typed template-cache state, adapter-owned emission context, per-mode delivery semantics, Axum outer wrapper
…ite-back in middleware

Three final-review fixes for access telemetry correctness:

- Normalize the HTTP method to an allowlist (GET/HEAD/POST/PUT/DELETE/
  PATCH/OPTIONS, else "other") inside access_event_row, so a client-
  controlled extension-method token can never inflate the LowCardinality
  method column, regardless of which adapter builds the row.
- Guard emit_access_telemetry_after_send against snapshots carrying a
  degraded sample_rate of 0.0 (captured on the app-state-build-failure
  fallback path), which could otherwise be sampled in by freshly reloaded
  settings and corrupt the sum(1.0/sample_rate) volume estimator.
- Mirror the geo lookup write-back from apply_entry_point_finalize_headers
  into FinalizeResponseMiddleware::handle, so a middleware-finalized
  response that resolved geo via fallback carries the resolved
  GeoLookupState for the access-telemetry snapshot instead of showing
  country "unknown".
std::time::Instant::now() panics on wasm32-unknown-unknown, so every
publisher request on the Cloudflare adapter trapped when the timing
collector was constructed, and the two auction-wait sites would trap
once an auction dispatched. web_time re-exports std's Instant on every
other target, so Fastly, Axum, and Spin behavior is unchanged.

The publisher.rs sites are qualified locally because that module's
std Instant import still serves the pre-existing template-cache sites,
which are out of scope here.
The character allowlist alone does not bound identity: [a-z0-9_-] is
exactly the alphabet UUIDs, hex ids, reset tokens, and article slugs
are built from, and truncating to 32 characters still leaves a
globally unique prefix. A first segment now rejects whole to /other/*
when it exceeds 32 characters or carries more than 7 ASCII digits,
alongside the existing charset rejection. Year archives and
hyphenated section names still pass.

Extends the adversarial tests to the publisher-fallback path with
UUID, hex-id, token, and slug shapes, and fixes the stale event_date
reference in the row-builder doc.
- Gate building the access snapshot on tinybird.enabled and
  access_enabled, threaded through SendContext: a disabled deployment
  (the default) no longer pays env reads and String allocations on
  the pre-send path. DeliveryOutcome.snapshot becomes Option and the
  emitter treats None as nothing to send.
- Classify asset-fallback responses as route_class asset with the
  operator-configured route prefix as the template, instead of
  landing in the other/unknown bucket alongside 404s.
- Pin Phase::index() to PHASE_COUNT with a uniqueness-and-bounds
  test so a future variant fails the suite instead of panicking at
  runtime.
- Drop the tautological sampled-out emission test; the 0.0-rate
  behavior is covered by sampled_in_boundary_rates_are_unconditional.
- Clarify that the local dev config env var name genuinely triples
  trusted_server_config (prefix, store, key) rather than reading as
  a find/replace mistake.
Adds section 18 to the request phase timing spec: three first-call-wins
T0 offsets (auction dispatched, resolved, committed) on RequestTimings,
emitted as additive nullable columns on access_logs_raw with auction_id
as the join key to the per-bidder auction dataset. Answers the
overlap-proof questions the two existing clocks cannot: when the
auction started relative to request entry, when the final bid landed,
and when targeting was committed toward GAM.
Implements spec section 18: three first-call-wins marks on
RequestTimings (dispatched at the DispatchAuctionOutcome::Dispatched
arm, resolved after collect at both sites, committed after
write_bids_to_state at both sites), carried through TimingSnapshot into
four additive access_logs_raw columns: auction_dispatched_ms,
auction_resolved_ms, auction_committed_ms, and auction_id as the join
key to the per-bidder auction dataset. Null offsets mean no auction
ran; a failed dispatch records nothing. FORWARD_QUERY fills the new
columns with typed defaults for pre-existing rows.

No header emission, no config surface, no adapter changes: the values
ride the existing snapshot and the tinybird.access_enabled gate.
The Cloudflare integration harness writes
wrangler.integration.generated.toml at test time; it was swept into the
previous commit by accident. Ignore it so local CI=1 runs cannot commit
it again.
The first path segment is only a section name when the path has depth:
under a /%postname%/ permalink structure every article is a
single-segment path, so keeping those segments verbatim put full
article slugs into the 30-day dataset, against spec section 9. Depth
is now required for a named template; single-segment paths, root
landing pages included, bucket to /other/*. Route slicing keeps
route_class and multi-segment templates like /news/*.
The bucket-quantized sampler truncated rates below one in a million to
a zero threshold (silently emitting nothing) and quantized other low
rates downward while rows still carried the configured rate, biasing
the sum(1.0 / sample_rate) volume estimator. Its no-rand premise was
also wrong: rand::thread_rng() is WASI-backed on this target and the
EC generation path already relies on it. The sampler is now a direct
uniform-roll comparison, and the roll gates on the rate stored in the
snapshot itself, so emission probability and the row's sample_rate
column cannot diverge; the divergence guard and its tests are removed.

Also per review: the settings-reload fallback in the post-send path
could never emit (no snapshot exists when settings were absent) and is
removed; the dead_code allow on DeliveryOutcome narrows to the one
collected-but-unemitted field; and the post-send ordering test is
narrowed to the leg it actually proves, that request_elapsed is
stamped when send returns.
On origin failure with a dispatched auction, the origin span guard
stayed alive through the emit_abandoned_auction await, so ts-origin
and origin_ms absorbed Tinybird emission time. The span now closes
when the send resolves, before either branch, with an error-path
regression test.
- Pin HEADER_PHASES against Phase::header_name() in the phase-index
  test, closing the second hand-synced list.
- Add RouteClass::Asset to the snake_case rendering test; rename the
  lowercasing test to say what it does.
- Give the Axum adapter a named, fully configured construction path
  (TrustedServerApp::dev_server_service) so server_timing_enabled is
  never silently discarded; the tuple API is private now.
- Document that Server-Timing is client-visible when enabled, in the
  configuration guide's observability section.
- Replace stale event_date references in the spec, plan, and dashboard
  guidance with the toDate(event_ts) sorting-key expression, and state
  the single-segment rejection rule in spec section 9.
…ming

# Conflicts:
#	crates/trusted-server-adapter-fastly/src/app.rs
#	crates/trusted-server-adapter-fastly/src/main.rs
#	crates/trusted-server-adapter-fastly/src/middleware.rs
#	crates/trusted-server-core/src/publisher.rs
#	crates/trusted-server-core/src/settings.rs
#	docs/guide/configuration.md
#	trusted-server.example.toml
The access emitter carried the configured body limit without enforcing it, allowing oversized rows to bypass the intended transport safeguard.
dhruv8sh and others added 22 commits October 1, 2026 16:31
Preserve main’s resolved credentials, consent-store removal, route-specific EID persistence, and lazy pull-sync while adding request timings. Adapt timing wrappers to the current KV traits and carry September’s config-push expectation for the pinned EdgeZero revision.
Carry f951955, the revision included in September. The newer shared-timing migration pins a diverged EdgeZero revision missing PR #1175 store-selector changes.
return 'Delivery evidence: Not observed';
default:
return unhandledCase(cycle.delivery);
return unhandledCase(cycle.delivery) ?? 'Delivery evidence: Not observed';
CI timed out before the first browser fixture reached any page assertions. Set the shared browser startup budget to 60 seconds instead of chromiumoxide’s 20-second default. Navigation, CDP, settling, teardown bounds and all fixture assertions remain unchanged.

The existing GPT fixture fails with a 22-second Chrome startup delay before this change and passes afterward. Full CLI, adapter, lint, parity, JS and formatting gates pass locally.

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.

5 participants