Caches as shared state: a decentralized Firebase-like substrate (Decentralized Cache Management)

**Note** from Bead: Decentralized Cache Management · [canonical source](https://redfish.acequia.io/guerin/.agents/4456cd24-010a-41e9-a14c-a2d1086893bd/2026-06-14/notes/01-cache-as-state-substrate.md) · session 2026-06-14 · discussion: Talk: Decentralized Cache Management

*Bead `4456cd24` · 2026-06-14 · Stephen's framing (supersedes the framing of [00-cache-coherence-model.md](00-cache-coherence-model.md), which becomes the *machinery* layer under this one).* > Stephen, when asked the scope of this bead: **"i am considering using caches as shared state as a decentralized firebase-like state management substrate."**

## The conceptual inversion In the ordinary view, a cache is a **derivative**: there is an authoritative origin, and the cache is a fast copy that must be kept matching the master. "Cache management" = keep the copy fresh; staleness is a bug. Stephen's move inverts this: **there is no master.** The cache *is* the state. Every replica — a browser's Cache-API/OPFS/IndexedDB store, an OS-node origin, a WebDAV endpoint — is a **peer holding the shared logical state locally**, not a copy of someone else's truth. "Cache management" stops being hygiene and becomes **distributed state management**: the same problem a database solves, now with no center. That is exactly what a real-time sync database (Firebase RTDB / Firestore, Replicache, ElectricSQL, PouchDB↔CouchDB) does — except those resolve consistency by leaning on a **central** server. This substrate has to do it **peer-to-peer over the acequia mesh**. The ecology is already most of the way there: the namespace is the primitive (distributed-origin-architecture), the browser is a first-class peer with durable storage (browser-hosting) and a signing key (browser-is-a-parciante-node), and `project.json`-as-shared-state (agent-coordination-pattern) is a hand-rolled instance of exactly this — poll a WebDAV file as shared mutable state. This bead generalizes that one file into a real-time, offline-first, multi-writer substrate.

## Firebase → decentralized-acequia mapping | Firebase capability | Decentralized acequia substrate | Status in ecology | |---|---|---| | JSON tree addressed by paths (`/room/x/state`) | the WebDAV **namespace** — a "document" is a resource at a URI | exists (namespace-as-primitive) | | Realtime listeners (`.on('value')` push) | **paths-as-event-bus**: PUT/observe; push over SSE/WebSocket via the SW | partial — `82bd6fa4` router already hand-rolls RFC-6455 WS; observe-verb undesigned | | Offline persistence (local cache + queued writes) | SW Cache-API / OPFS / IndexedDB as the **local replica that is the working state** | exists as storage; not yet as state engine | | Optimistic local write, reconcile later | write to local cache, serve immediately, propagate to peers, merge on contact | undesigned (the crux) | | Central authoritative server (Google) | **no center** — peers + per-path lease / leader-election; eventual consistency | leader-election named in `7049c694` / orchestrator duty-3, unimplemented | | Security rules (`.read` / `.write` per path) | **acequia chain-tokens** scoped by `paths` / `writePaths` | exists (token-minting-pattern) | | Atomic transactions / `runTransaction` | ETag compare-and-swap (`If-Match`), lease, or CRDT op | undesigned | | `serverTimestamp()` / ordering | logical / vector clocks across replicas | undesigned | | Presence (`.info/connected`) | liveness ladder — which parciante nodes are live | partial (`fe7fbaf5` ladder) | The right-hand column is mostly **already-present primitives**; what's missing is the **state-engine** that composes them into read-your-writes, multi-writer, offline-first behavior.

## The three hard problems (what makes this a database, not a file share) 1. **Write granularity.** WebDAV syncs whole files; Firebase syncs at the JSON-node level. Two peers editing different fields of one document must not clobber each other. Needs **sub-document deltas** — JSON-Patch ops, or CRDT operations — not whole-file PUTs. This is the single biggest departure from `/bead-sync`'s file-level additive model. 2. **Conflict resolution under partition** (the CAP choice, per-path — every-constraint-is-soft): - **CRDTs** (Yjs / Automerge / state-based counters, sets, sequences) — converge with no coordination; the natural fit for **AP + offline-first**. Cost: metadata growth, and only certain data shapes are expressible. - **Per-path leader / lease** — strong consistency (**CP**) for paths that need it; cost: unavailable under partition. This is where orchestrator duty-3 leader-election plugs in. - **LWW + logical clock** — cheap, lossy; fine for ephemeral / last-state-wins fields (cursor position, presence). - Mixed by resource class is the likely answer: an append-only chat log is a trivially-mergeable CmRDT; a shared counter is a PN-counter; a config doc may want a leader. 3. **Realtime push.** WebDAV is request/response; a state substrate must **push** changes to subscribed peers. Transport = SSE or WebSocket fronted by the SW (the router bead already has WS); subscription = the observe half of paths-as-event-bus. Without push it degrades to polling — which is exactly what `project.json`-as-state does today, and the limit this bead is trying to pass.

## Why "cache" is the right word (not a downgrade from "database") Calling it a cache keeps three properties a centralized DB gives up: - **Local-first latency** — reads/writes hit the local replica at memory speed; the network is a background reconciler, not the critical path. - **Partition tolerance by default** — an offline browser is not "disconnected from the database," it *holds the database*; it keeps working and merges later. - **Eviction as apoptosis** — a state entry carries a TTL / refcount and can self-evict (apoptosis-vs-necrosis); state that no peer references decays. A cache has a built-in forgetting story that a database does not — which matters for a substrate that must not grow without bound. So "cache as state" is not a metaphor stretch: it is *choosing the cache's properties (local-first, partition-tolerant, self-evicting) as the database's properties*, and paying for them with eventual consistency + merge.

## Relationship to the machinery note (00) and adjacent beads - [00-cache-coherence-model.md](00-cache-coherence-model.md) is now the **machinery layer**: its three axes (identity/versioning, invalidation-as-apoptotic-signal, authority/lease) are exactly the mechanisms this substrate needs. Read 00 as "how," this note as "what for." - **bead-orchestrator `4c6470f9`** — its duty-3 (multi-endpoint sync + leader-election) becomes the **CP path** of this substrate; duty-4 (SW↔CORS) becomes the **transport plumbing**. Boundary: this bead owns the *state-substrate model*; the orchestrator runs the *coordination mechanism*. - **agent-coordination-pattern** — the existing `project.json`-poll dashboard is the **v0** of this substrate; a natural first migration target / worked example. - **paths-as-event-bus** — the subscription/push model is its realtime-listener layer.

## Open questions for Stephen (these now supersede 00's Q1) 1. **First worked example.** Which concrete shared-state surface do we build this against first — migrate the `project.json` ai-team dashboard to push+offline? a shared cursor/presence in a viewer? a collaborative doc? The example pins the data shape and therefore the conflict-resolution choice. 2. **Conflict resolution default.** Lean **CRDT-first** (AP, offline-first, no central authority — most aligned with the ecology), with per-path leader as the opt-in CP escalation? Or start LWW-simple and add CRDTs later? 3. **Write granularity / wire format.** Sub-document deltas via **JSON-Patch ops**, **CRDT ops** (Yjs/Automerge), or stay file-level for v0 and accept clobbering? This is the biggest fork. 4. **Realtime transport.** Reuse the router bead's WebSocket, add SSE, or SW-mediated long-poll? Who hosts the relay when peers are NAT'd (the off-network-vantage problem from external-vantage-for-reachability)? 5. **Existing libraries vs. roll-our-own.** Do we build on Yjs/Automerge/Replicache/ElectricSQL/PouchDB as the engine and supply only the acequia transport + auth, or is a from-scratch substrate the point? (EULA/licence check per the substrate skill before adopting any.) 6. **Naming.** Is "decentralized-cache-management" still the right bead slug, or does this want a name that says *state substrate* (e.g. `acequia-state` / `decentralized-state-substrate`)?

## Next actions - Get Stephen's pick on Q1 (worked example) + Q3 (wire format) — together they unblock a prototype. - Survey whether to adopt an existing local-first engine (Q5) before designing one.