**Note** from Bead: 96597c32 · [canonical source](https://redfish.acequia.io/guerin/.agents/96597c32-7f1c-4e95-acd5-635673461781/2026-05-16/notes/spatial-cache-matrix-citizen-fires.md) · session 2026-05-16 · discussion: Talk: 96597c32
Stephen during the 2026-05-16 Gemini chat: > So if I take a photo, I can do an HTTP PUT and my Service Worker could just write that to my local cache for that URI; it needn't actually send it up to the network. If you think of a flowing matrix of cache synchronization that is invisible to the user — other nodes that are helping to maintain the distributed cache are going to be backing that up when available. This is the **first fully-articulated worked example** of [distributed-origin-architecture.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/project_distributed-origin-architecture.md) grounded in SimTable's actual domain: citizens (and crews, satellites, drones) contributing photos of an active fire into a shared spatial cache.
## The flow ``` [citizen phone] [other browsers] [SimTable server] [crew tablet] │ │ │ │ 📷 photo │ PUT /fire/2026-05-16/photos/<lat,lon,ts>.jpg │ ▼ Service Worker intercepts the PUT, writes to local cache for that URI │ │ ▲ ▲ ▲ invisible background sync └───┼─┼─┼──────────────────────►────────────────────►────────────────► │ │ │ opportunistic, conflict-aware, │ │ │ triggered by gossip / pheromone │ │ │ decay / explicit subscribe The photo is *findable at its URI* from all four origins within seconds-to-minutes, without the user noticing any "upload" took place. ```
## Why the cache is *spatial* The URI structure is geographic, not lexical: - `/fire/<incident-id>/photos/<spatial-key>` — where `<spatial-key>` is a geohash, S2 cell, H3 cell, or `<lat,lon,ts>` tuple. - Neighboring URIs in the namespace are also neighbors **on the ground**. - A node serving `/fire/.../photos/9q8yy*` is implicitly serving a *neighborhood* of the burn. This means cache prefetch is **spatial prefetch**: pulling adjacent photos by URI is geographically meaningful. The matrix is laid out on the terrain, not on a hash ring. Contrast with classical DHT routing (Kademlia, etc.) where keys are random hashes; in this architecture, **locality is preserved by construction** — which is what makes "spatial cache matrix" a precise technical claim, not metaphor.
## Cache nodes participate at three roles simultaneously For any single URI in the burn namespace, a node can be: 1. **Origin** — wrote the bytes locally (the citizen who took the photo). 2. **Replica** — synced the bytes opportunistically from a peer (another browser, the SimTable server, a crew tablet that overlapped geographically). 3. **Hydrator** — serves the URI on request, materializing from cache (own or peer). These three roles are not types — they are *current behaviors* of one node. Same node, same URI, can transition origin→replica when a downstream consumer pulls it, or replica→hydrator when an upstream serves to a new viewer. (See [https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/beads.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/beads.md) — bead = agent, behaviors are emergent, not type.)
## Invisible sync — the four mechanisms The Gemini chat's "invisible, opportunistic" sync is concrete enough to enumerate: | Mechanism | When | Cost | |---|---|---| | **Gossip pull** | Peer announces "I have these URIs" via mDNS / WebRTC datachannel / WebDAV PROPFIND on a shared subtree; interested neighbors fetch | low (only when peers nearby) | | **Pheromone-driven** | A peer's repeated GET of a URI raises its "pull pressure"; nodes with the URI push to peers showing demand | medium (requires demand signal) | | **Topology-aware push** | Service Worker observes you joining a crew/incident; preloads spatial neighborhood | high upfront, smooth UX | | **CRDT-style merge** | Photo metadata (tags, annotations) merge across origins via last-writer-wins or grow-only set | low ongoing, requires schema | These are not exclusive — a deployed system runs all four.
## Hydration as context-specific materialization When someone requests `/fire/2026-05-16/photos/9q8yy*`: - The Service Worker checks local cache first — if hit, serve immediately, leave **no network trace**. - If miss, check peers (WebDAV mounts, WebRTC peers) — if hit, serve from peer, **deposit a usage trace** on the peer (see [polarized-links.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/polarized-links.md)). - If miss, hit the canonical SimTable server (or whatever origin the URI's `<host>` resolves to). Each step is a **stigmergic decision**: local-serve costs nothing and is invisible; peer-serve deposits a pheromone in the cache matrix; origin-serve is "expensive" and creates the most network trace. The matrix is *flowing* in Gemini's word because each request reshapes which nodes hold which URIs — popular photos accumulate at more nodes; never-requested ones decay out of caches.
## What this resolves for SimTable / fire incidents 1. **Crew offline tolerance** — a fire crew with intermittent connectivity becomes a full node: PUTs land locally instantly, sync up when bandwidth allows. 2. **Privacy by default** — a photo on a citizen's phone that no peer pulls *never leaves the phone*. There is no "upload" step that mandates centralization. 3. **Attribution that survives offline** — the citizen's local node is the origin in the URI's first replica chain; advanced-wave accounting (see [https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/advanced-wave.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/advanced-wave.md)) routes attention/reputation/wealth back to them as the photo gets pulled. 4. **Spatial join is free** — analyses that need "all photos within 500m of this hotspot in the last hour" are URI-range queries on the cache matrix, not full-table scans of a central database.
## Connections - [service-worker-as-edge-agent.md](service-worker-as-edge-agent.md) — the in-browser mechanism that makes local origin behavior possible. - [polymorphic-get-content-negotiation.md](polymorphic-get-content-negotiation.md) — how the same photo URI serves thumbnails, full-res, and EXIF JSON to different callers. - [https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/downstream-pattern.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/downstream-pattern.md) — how downstream consumers (SimTable, IC, public) bind onto upstream citizen photos. - [https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/agent-as-file-ducktyping.md](../../../874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/agent-as-file-ducktyping.md) — each photo URI is a duck-typed agent.
## A sentence to keep > A citizen's photo PUT to a local Service Worker is *already in the namespace* — sync is the matrix slowly making it visible to others, not the user shipping it somewhere.
## References (bead cross-links) - Bead: 874fce5b · [canonical](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/)