perf: bandwidth/browser measurement harness + 74 MB cold-load findings (#313, #345) - #346
Open
rdhyee wants to merge 1 commit into
Open
perf: bandwidth/browser measurement harness + 74 MB cold-load findings (#313, #345)#346rdhyee wants to merge 1 commit into
rdhyee wants to merge 1 commit into
Conversation
… MB cold load Answers isamplesorg#313 (open since 2026-06-26, never done: what browser/OS/bandwidth combinations does the Explorer work in?) and root-causes the 'falling back to full HTTP read' finding from the 2026-08-05 coherence audit. HEADLINE: a cold load of the default world view transfers ~74 MB. The site's own docs claim 'typically less than 1 MB for initial exploration'. Wrong by ~2 orders of magnitude. ROOT CAUSE: DuckDB-WASM probes range support with a HEAD carrying a Range header. data.isamples.org answers 200 instead of 206, so DuckDB concludes the server cannot do partial reads and downloads every file whole — including samples_map_lite_v3.parquet (62.9 MB) when it needs ~1.5 MB of it. PROVEN, not inferred. A transparent reverse proxy forwarded everything unchanged except HEAD+Range -> 206. Same build, same cold cache, one variable: unthrottled 74,202,598 B -> 3,341,812 B; 8 full-read fallbacks -> 0 3g-fast facet panel 440.6s -> 94.2s (4.7x), 74.2 MB -> 3.0 MB Fix is server-side in the Cloudflare Worker; no application code changes. WHY IT WAS MISSED: the server was cleared three times by curl tests that used GET. GET+Range correctly returns 206; HEAD+Range returns 200. Only the verb DuckDB actually sends was wrong. Documented so the next person checks HEAD. isamplesorg#313 RESULTS (production, cold cache, desktop): unthrottled globe 2.2s facets 10.8s 4g globe 15.4s facets 168.7s 3g-fast globe 38.7s facets 423.1s 3g-slow globe 156.6s facets NEVER (>600s budget) Cross-browser: works in Chromium, Firefox AND WebKit, desktop and mobile, zero uncaught page errors, comparable timings — that had been an open unknown. The 74 MB is identical in all three, so it is not a browser quirk. Adds two committed, reproducible instruments: tests/playwright/bandwidth_matrix.py — the measurement harness tests/playwright/range_fix_proxy.py — the A/B proxy that isolates the cause INSTRUMENTATION TRAPS documented in the report, both of which produced confidently wrong results before being caught: - page-level CDP does NOT see Web Worker traffic. DuckDB runs in a worker, so the page session reported 568 KB / 3 requests — a textbook 'only the bytes you need' result, off by 130x. Real accounting uses context-level events. - the instrument changed the measurement twice: waitForDebuggerOnStart paused workers that were never resumed (globe never rendered), and route interception inflated time-to-globe from 2.5s to 7.3s. Final harness is passive. No application code changed. No fix applied yet — the Worker change is not in this repo and wants RY's call. Refs isamplesorg#313 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCCDurpcLzMe7L72y2HDAa
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to #345 and #313.
🤖 rbotyee (Claude, operated by @rdhyee) — Raymond's intent: overnight work on making isamples.org more robust at scale. What I did: measured the Explorer across connection speeds and browsers, root-caused a large cold-load cost, and proved the cause with a controlled A/B. Filing because the fix lives in the Cloudflare Worker, not this repo.
Summary
A cold load of the Interactive Explorer transfers ~74 MB before the facet panel appears. Our own docs claim "typically less than 1 MB for initial exploration" (index.qmd) and "only the bytes you need are transferred" (explorer.qmd). Both are wrong by roughly two orders of magnitude.
The whole thing comes down to one status code.
DuckDB-WASM decides whether a server supports partial downloads by sending a
HEADrequest with aRangeheader.data.isamples.organswers200instead of206, so DuckDB concludes the server can't do partial reads and downloads every file whole — includingsamples_map_lite_v3.parquet(62.9 MB) when it actually needs about 1.5 MB of it.Proposed fix
In the Cloudflare Worker fronting
data.isamples.org: when aHEADcarries aRangeheader and the object supports ranges, respond206withContent-Range(no body, perHEADsemantics) rather than200.Content-Rangeis already inAccess-Control-Expose-Headers, so nothing else needs to change.Evidence — controlled A/B, not inference
A transparent reverse proxy forwarded every request to the real host unchanged, altering exactly one thing:
HEAD+Range→206. Same build, same cold cache, one variable.Unthrottled
| | Control (
200) | Treatment (206) ||
See #345 for the full write-up and the proposed Worker fix. This PR only adds the measurement instruments and the findings document — no application code changes, and the Worker fix is not applied here (it lives outside this repo).
🤖 Generated with Claude Code
https://claude.ai/code/session_01QCCDurpcLzMe7L72y2HDAa