π€ 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 HEAD request with a Range header. data.isamples.org answers 200 instead of 206, so DuckDB concludes the server can't do partial reads and downloads every file whole β including samples_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 a HEAD carries a Range header and the object supports ranges, respond 206 with Content-Range (no body, per HEAD semantics) rather than 200.
Content-Range is already in Access-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) |
| Bytes from data host |
74,202,598 |
3,341,812 |
full HTTP read fallbacks |
8 |
0 |
samples_map_lite_v3.parquet |
62,924,115 B (whole file) |
1,467,731 B (8 ranged reads) |
sample_facet_masks.parquet |
10,138,648 B (whole file) |
767,000 B (48 ranged reads) |
3G fast (1.6 Mbps) β the user-visible result
|
Control |
Treatment |
| Globe drawn |
54.0 s |
54.1 s |
| Facet panel |
440.6 s |
94.2 s |
| Bytes |
74.2 MB |
3.0 MB |
4.7Γ faster to a usable filter panel, 24Γ less data. Globe and table are unchanged β they read the small H3 summary, not the big files.
Why this went unnoticed
I cleared the server three times before finding it, because I kept testing with GET:
| Probe |
Result |
GET + Range |
206 + Content-Range β
|
HEAD + Range |
200, no Content-Range β β what DuckDB actually sends |
OPTIONS preflight |
204, allows Range β
|
CORS exposure of Accept-Ranges |
correct β
|
Everything was right except the one verb that mattered. Please verify any fix with HEAD, not GET.
Worth noting this is not an RFC violation β raw.githubusercontent.com answers 200 to HEAD+Range too. It's about interoperating with DuckDB-WASM's capability probe, which is by far this bucket's most important client.
Also answers #313
The same harness answers @akthom's #313, open since June and never done.
Production, cold cache, desktop:
| Connection |
Globe |
Facet panel |
| Unthrottled |
2.2 s |
10.8 s |
| 4G |
15.4 s |
168.7 s |
| 3G fast |
38.7 s |
423.1 s |
| 3G slow |
156.6 s |
never (>600 s) |
On a slow connection the facet panel never appears at all.
Cross-browser (good news): works in Chromium, Firefox and WebKit/Safari, desktop and mobile viewports, zero uncaught page errors, comparable timings. The 74 MB is identical in all three, so this is not a browser quirk.
Reproducing
Both instruments are committed in perf/313-bandwidth-findings on the rdhyee fork:
tests/playwright/bandwidth_matrix.py β the measurement harness
tests/playwright/range_fix_proxy.py β the A/B proxy that isolates the cause
Full write-up with method notes and limitations: PERF_BANDWIDTH_FINDINGS_2026-08-06.md on that branch.
After the fix
index.qmd's "less than 1 MB" and explorer.qmd's "only the bytes you need" should be updated to the measured figure (~3.3 MB cold) β still a good story, and an honest one.
Caveat on the numbers: single runs on one machine and uplink, DevTools throttling rather than a real cellular link, cold-cache first visits only. Order-of-magnitude, not benchmarks. The A/B comparison is the reliable part, since both arms ran under identical conditions.
π€ 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
200)206)full HTTP readfallbackssamples_map_lite_v3.parquetsample_facet_masks.parquet3G fast (1.6 Mbps) β the user-visible result
4.7Γ faster to a usable filter panel, 24Γ less data. Globe and table are unchanged β they read the small H3 summary, not the big files.
Why this went unnoticed
I cleared the server three times before finding it, because I kept testing with
GET:GET+RangeContent-RangeβHEAD+RangeContent-Rangeβ β what DuckDB actually sendsOPTIONSpreflightRangeβAccept-RangesEverything was right except the one verb that mattered. Please verify any fix with
HEAD, notGET.Worth noting this is not an RFC violation β
raw.githubusercontent.comanswers200toHEAD+Rangetoo. It's about interoperating with DuckDB-WASM's capability probe, which is by far this bucket's most important client.Also answers #313
The same harness answers @akthom's #313, open since June and never done.
Production, cold cache, desktop:
On a slow connection the facet panel never appears at all.
Cross-browser (good news): works in Chromium, Firefox and WebKit/Safari, desktop and mobile viewports, zero uncaught page errors, comparable timings. The 74 MB is identical in all three, so this is not a browser quirk.
Reproducing
Both instruments are committed in
perf/313-bandwidth-findingson the rdhyee fork:tests/playwright/bandwidth_matrix.pyβ the measurement harnesstests/playwright/range_fix_proxy.pyβ the A/B proxy that isolates the causeFull write-up with method notes and limitations:
PERF_BANDWIDTH_FINDINGS_2026-08-06.mdon that branch.After the fix
index.qmd's "less than 1 MB" and explorer.qmd's "only the bytes you need" should be updated to the measured figure (~3.3 MB cold) β still a good story, and an honest one.Caveat on the numbers: single runs on one machine and uplink, DevTools throttling rather than a real cellular link, cold-cache first visits only. Order-of-magnitude, not benchmarks. The A/B comparison is the reliable part, since both arms ran under identical conditions.