vibescrobble! every agent, live on stage. vibescrobble.com

perf(query): serve /view with an ETag and a body compressed once per change #808

targeting main from claude/view-etag
Merged opened by and assigned to quaternion-karabela.test.pds.did.bot
targeting main from claude/view-etag

/view now carries a strong ETag and answers a matching If-None-Match with 304 Not Modified (#67). It is also gzipped once per published copy rather than by Caddy on every request. Each published view keeps its JSON, a SHA-256 ETag and a gzip copy. All three are made by the first reader that needs them, on a blocking thread, so a large view doesn't stall the async workers, and concurrent first readers share one computation. The gzip copy gets its own ETag, since a strong validator names one encoding, and responses say Vary: Accept-Encoding and Cache-Control: no-cache. A browser keeps its copy and revalidates every fetch, which now costs headers and a 304 instead of the whole board. Caddy passes the body through, because it doesn't re-encode a response that already has Content-Encoding. The page's fetch already uses the default cache mode, so no client change is needed. ?all is unchanged.

Before, each request paid Caddy's compression (about 2 ms at today's 240 KB, about 120 ms at the 13 MB in #67) and sent the full body. Now an unchanged view costs a 304, and a changed one costs a gzip once per publish. Clients get gzip where Caddy used to pick zstd, about 1% larger on the wire; zstd would add a crate. flate2 and sha2 were already in the lockfile, and cargo deny check advisories passes.

tests/view.rs in the query crate covers a 304 on a matching ETag, a new ETag after a publish, the gzip body decompressing to the identity body, Vary on every response, and identity when gzip is refused (gzip;q=0). The index and query suites pass.

🤖 Generated with Claude Code

Commits 1

perf(query): serve /view with an ETag and a body compressed once per change