Cache coherence — server-of-record [Flow]
Source path: knowledge-base/diagrams/flows/cache-coherence.md
# Cache coherence — server-of-record `[Flow]`
The intricate invariant: **`serverVersion ≥ cacheVersion`, always** → the browser is a disposable cache the server can always rebuild, even after the user clears everything (the browser DEK included).
```mermaid
flowchart TB
Boot["boot / open a domain"] --> Cmp{per record:<br/>cache vs server `updatedAt`}
Cmp -->|"cache absent<br/>(cleared / new browser)"| Hyd["**HYDRATE** — server → cache<br/>'restoring your data…'"]
Cmp -->|"server absent / cache ahead<br/>(migration / crash)"| Ado["**ADOPT** — renderer decrypts,<br/>POSTs plaintext · 'preparing…'"]
Cmp -->|"server AHEAD of a held doc<br/>(headless commit while closed)"| Sweep["**SWEEP** — version-gated pull<br/>(planStaleSweep vs the record-synced ledger;<br/>unprovable → deferred to warm-ledger re-run)"]
Cmp -->|"server = cache"| Live["**LIVE** (steady state)"]
Hyd --> Live
Ado --> Live
Sweep --> Live
Live -->|edit| Opt["optimistic apply → /mutate →<br/>SSE echo reconciles (rollback on fail)"]
Live -.->|guarantee| Inv["serverVersion ≥ cacheVersion →<br/>the browser is always safe to discard<br/>(daemon re-protects with its OWN key)"]
```
This is the persistence half of the [engine pipeline](engine-pipeline.md) drawn from the coherence angle — same `/mutate` + SSE echo, focused on the clock comparison that makes "clear everything" safe. The SWEEP branch is the eager half: a doc the cache *holds* but the record has moved past (a scheduler run or MCP commit made while no window was open) is re-pulled on the next connect, proved stale against the `record-synced` version ledger — never re-fetched on ignorance (the storm guard defers unprovable docs until hydration warms the ledger). Protocol detail: [sync-protocol](sync-protocol.md).
Open on GitHubRaw Markdown source