**Note** from Bead: Firewatch Camera Grid · [canonical source](https://redfish.acequia.io/guerin/.agents/65783732-7907-4a36-983a-3b015e75e80b/2026-06-13/notes/06-service-worker-cache-acequia-cdn.md) · session 2026-06-13 · discussion: Talk: Firewatch Camera Grid
## Problem simtable serves the archived frames with `Cache-Control: private, no-cache` (verified 2026-06-13), no `max-age`/`Expires`, no CDN. So the browser must **revalidate on every reuse** — a conditional-GET round-trip per tile per frame, even though it returns 304 (bytes are cached, latency isn't). The frames are **immutable** (fixed `Last-Modified`), so this is a mislabel, not intent. Kills "cache as you scrub."
## Fix: a cache-first service worker (don't rewrite the header — supersede it) A SW registered by the app intercepts the frame requests and serves from **Cache Storage, which ignores `Cache-Control` entirely** (it's an explicit developer cache). Cache-first ⇒ **zero revalidation**, persistent across reloads + tabs (disk-backed). Mechanics that make it work in our setup: - **Cross-origin is fine**: app on `redfish.acequia.io`, frames on `simtable.acequia.io`; the `fetch` event fires for cross-origin subresource requests within the SW scope, and cross-origin responses are cacheable. - **CORS `*`** on simtable ⇒ **non-opaque** responses: inspectable, no opaque-storage padding. - **Immutable ⇒ cache-first-forever** is safe; cap with an **LRU by count/MB** (816 × 10 × ~250 KB ≈ ~2 GB if fully cached — so bound it; cache scrubbed + prefetched frames only). - HTTPS both sides ⇒ SW allowed. (It *can* synthesize a `Response` with rewritten `Cache-Control` if a downstream consumer needs it, but the SW-as-cache pattern doesn't need that.) - Does NOT help the **first** fetch; removes cost on **reuse** (re-scrub, reload, other tabs). Pair with a small in-memory decoded-bitmap hot set + neighbor prefetch for the absolute hot path.
## Why it generalizes (Acequia-CDN / browser-as-CDN) A shared SW makes **any** acequia app cache **any** `no-cache` origin — the consumer-side complement to RTE (pixels remote; the edge holds a working set). This is the "Acequia-CDN" step the incident-viewer bead proposed; it belongs at the substrate, not per-app. So: build it for the wall first, then lift it to a shared `acequia-cdn` SW.
## Origin-side alternative (separate, offered — not ours to change unilaterally) simtable could serve `ops-alertcalifornia/**` with `Cache-Control: public, max-age=31536000, immutable` (nephele header config). Then browser HTTP cache + any future CDN serve free, no SW needed for caching. Touches simtable — offer to Stephen; the SW is the in-our-control path meanwhile, and still wins for cross-tab persistence + offline.
## Status **Queued (not built this session).** Scrubber-caching task: cache-first SW for the simtable frames + LRU cap + neighbor prefetch + in-memory hot set. Slots into Epic 2 (S4 scrub polish) / as the "Acequia-CDN" substrate step. See WORK-QUEUE.