Back to Worldmonitor

Bootstrap R2 timeout measurement

docs/solutions/2026-07-14-bootstrap-r2-timeout-measurement.md

2.10.08.2 KB
Original Source

Bootstrap R2 timeout measurement

Status: CONCLUDED — KTD7 NO-GO (2026-07-24). R2-origin serving abandoned; the bootstrap-egress objective is met instead by the KV storage-primitive path (see Verdict). Serving constants in api/_bootstrap-r2.js remain null and Redis remains authoritative — production was never affected.

This was the evidence record for issue #5300 U3a (Vercel Edge → R2 serving). It never reached a go: the calibration and validation gates below stayed blocked, and a 2026-07-24 review established that the blocker is a feasibility failure, not an incomplete measurement window. The pending/zero tables that follow are retained as the audit trail of why the gates never cleared.

Verdict: KTD7 no-go

The architecture cannot pass. R2 is single-region (bucket in ENAM), so every far-region read is a cross-planet round trip. Per the 2026-07-24 review analysis, using p95 as the conservative mobile-tail overhead:

  • Fast overhead 778 ms → C_happy(fast) = 1200 − 778 = 422 ms. Even the best regions exceed at the maximum allowable timeout: iad1 34/1,326 = 2.56%, cle1 36/1,302 = 2.76% — against a required ≤0.2%. Distant regions reach ~96%.
  • Since every valid T(fast) must be ≤422 ms, no smaller timeout can improve that result, and more samples cannot repair a feasibility failure. This is the exact zero-savings-plus-added-latency outcome KTD7 exists to prevent.

Independently verified 2026-07-24 (not from the review, checked against the tree/Axiom): BOOTSTRAP_R2_TIMEOUT_MS_FAST and _SLOW are still null; bootstrap_r2_shadow spans 19 Vercel execution regions; no regional cohort reached n ≥ 2,000; slow cohorts would take months at current rates. The DebugBear-specific overhead figures above are the review's analysis and were not independently re-derived here.

Does not reopen #5300. #5300 closed 2026-07-14 as complete — its accepted savings came from the demand-driven / compaction work, not this experiment. The R2 sub-exploration (under #5338) is abandoned, not a regression of #5300.

Surviving path — the objective is still met. The bootstrap-egress goal is pursued via the KV storage-primitive cutover: a Cloudflare Worker serving from globally-replicated Workers KV (evidence: docs/solutions/2026-07-16-bootstrap-kv-verify.md). KV reads are local-POP, avoiding the exact single-region hop that sank R2 — measured at 99.6–99.7% of global reads under the 1200 ms budget vs the incumbent's ~84%. KV serving remains flag-gated off; production still serves from Redis.

Follow-up applied: DEBUGBEAR_RUM_SAMPLE_RATE dropped 100 → 10 — full RUM sampling existed to feed this measurement and had overrun the DebugBear monthly quota (~529k/500k).


Historical record of the blocked gates (never cleared):

Instrumented contract

  • BOOTSTRAP_R2_SHADOW_MEASURE=1 is honored only when VERCEL_ENV=production.
  • Public fast and slow origin requests still assemble and return Redis data.
  • The R2 read runs only in ctx.waitUntil with the independent 5,000 ms probe ceiling.
  • Axiom receives one exact-allowlist bootstrap_r2_shadow event with the shared r2 | fallback outcome vocabulary.
  • The first shadow probe in an isolate is tagged cold; later probes are tagged warm.
  • The response temporarily exposes its Redis duration and cache classifier headers for client RUM.
  • Each shadow Redis pipeline appends one ignored marker read: bootstrap:r2-shadow-origin-marker:<tier>. MONITOR counts these markers instead of inferring origin traffic from the canonical tier pipeline, which the publisher now executes too.
  • Client RUM chooses one tier per page and queues only three numeric DebugBear custom metrics (total, Redis, derived non-R2 overhead) plus three closed tags (tier, success/abort, mobile/desktop). It rejects missing, cached, conflicting, malformed, or impossible timing samples.

Required setup before collection

  1. Restore Railway CLI write authentication and create publish-bootstrap-tiers in production.
  2. Install only the scoped publisher credentials in Railway and verify two successive advancing objects for both tiers. Set IRAN_EVENTS_ENABLED explicitly to the same value in Railway and Vercel so the publisher and serving registry cannot resolve different tier shapes.
  3. Merge and deploy the disabled instrumentation.
  4. In DebugBear RUM settings, map the currently unused custom slots: metric1=bootstrap total, metric2=bootstrap Redis, metric3=bootstrap non-R2 overhead, tag1=bootstrap tier, tag2=bootstrap outcome, and tag3=device class. Use a project with session tracking disabled (or disable it for this window) and record that setting below; the existing project currently reports sessions enabled, which would violate U3a's no-stable-ID evidence contract even though the six custom fields themselves contain no identifier.
  5. Confirm USAGE_TELEMETRY=1, AXIOM_API_TOKEN, the scoped R2 read credentials, and the shared bucket routing values are present in Vercel production. Do not install them in preview.
  6. Purge the two public bootstrap CDN objects, capture the first MISS and following HIT, and record the observed Age, X-Vercel-Cache, and CF-Cache-Status tuple below. The current classifier is a conservative candidate; no RUM sample is evidence until this production check passes.
  7. Enable BOOTSTRAP_R2_SHADOW_MEASURE=1 in Vercel production.

DebugBear documents five programmatic numeric metric slots and five string tag slots through its snippet API. The public WorldMonitor snippet inspected on 2026-07-14 reported no configured custom mappings. Adding the six bootstrap values does not add a request, user, or device ID to the page-level custom fields. That is not sufficient by itself: the collector's project-level session setting applies to the resulting page view. Record proof that sessions are disabled before treating any sample as U3a evidence; otherwise use a dedicated privacy-minimal project or collector.

DebugBear session tracking disabled for the measurement window: pending — blocked.

Controlled cache-classifier proof

CheckObserved UTCAgeX-Vercel-CacheCF-Cache-StatusResult
Purged origin MISSpendingpendingpendingpendingblocked
Following cache HITpendingpendingpendingpendingblocked

Calibration

Minimum 2,000 observations per (tier, execution region), spanning cold/warm execution and a full daily traffic cycle.

TierRegionStart/end UTCnCold nWarm nCandidate T (ms)C_happy (ms)
fastpendingpending000pendingpending
slowpendingpending000pendingpending

Independent validation

Freeze each candidate before this subsequent full-day window. Record the one-sided 95% binomial upper confidence bound for P(L > T); every cohort must be at most 0.2%.

TierRegionStart/end UTCnExceedances95% upper boundPass
fastpendingpending00pendingblocked
slowpendingpending00pendingblocked

Formula/tool: pending.

Denominator certification

Run Redis MONITOR over the exact Axiom window. Count the unique per-tier marker GETs and compare them with bootstrap_r2_shadow events. Each tier must differ by no more than 1%, and every region observed in production Vercel function logs must appear in Axiom.

TierStart/end UTCMONITOR markersAxiom eventsDifferencePass
fastpending00pendingblocked
slowpending00pendingblocked

Resulting serving constants

ConstantValueStatus
BOOTSTRAP_R2_TIMEOUT_MS_FASTnullblocked pending evidence
BOOTSTRAP_R2_TIMEOUT_MS_SLOWnullblocked pending evidence

Do not implement U4 while either value is null or any cohort, cache-classifier, or denominator gate is incomplete.

Disablement proof before U4

  • BOOTSTRAP_R2_SHADOW_MEASURE disabled: pending.
  • Both CDN objects purged after disablement: pending.
  • Production responses contain no Server-Timing: wm_bootstrap_redis: pending.
  • Temporary RUM no longer queues new samples: pending.