fw-09 — Analysis

The premise

Server state is shared, stale by default, and asynchronously invalidated by actors you cannot see. Treating it as client state is one of the most expensive architectural mistakes in frontend work; a query cache is the machinery that admits the difference.

Required invariants

  1. Order by a monotonic counter you control, incremented at dispatch. Not wall clock, not arrival order, not server time.
  2. One in-flight request per key, shared by all subscribers.
  3. A cancelled or superseded response never writes to the cache.
  4. Cache keys compare structurally, with stable ordering.
  5. Rollback restores a defined state, and you have decided which.

Why timestamps fail

t=0   request A dispatched
t=10  request B dispatched
t=50  response B arrives   (server processed at t=20)
t=90  response A arrives   (server processed at t=15)

By arrival, A is newest. By server processing, B. By dispatch, B. Only dispatch order is under your control and monotonic on the client. Client clocks disagree across tabs; server timestamps have skew and insufficient resolution.

A sequence number is one integer and it is exactly correct. Same conclusion as fw-08's navigation ordering, which is why the two modules are adjacent.

Optimistic rollback when the base moved

StrategyCorrectnessCost
Snapshot and restoreloses concurrent updatestrivial
Invalidate and refetchcorrecta round trip, and a flicker
Optimistic layer over server statecorrect and composablesubstantial machinery

Most libraries do the first and document it. The rule worth stating in review: optimistic UI is a latency optimisation that trades correctness under concurrency. Right for low-contention data (your own profile), wrong for high-contention data (a seat booking). "Is this data contended?" is a product question.

Normalised vs document caches

Document caches stay simple and push consistency onto explicit invalidation; normalised caches give automatic cross-query consistency and demand a schema. Most libraries chose document caches — and the reason is that REST responses have no reliable identity. GraphQL clients normalise because the format hands them __typename and id.

The data format determined the client architecture. A good example for any argument that API design has consequences far beyond the wire.