Mirror / foldkit-mirror

Key-value restore semantics

A store restore is intentionally conservative. Prefs.reduce(model, message) only restores fields that are still at their initial value.

That protects an edit made before the asynchronous restore finished:

initial draft = ''
store draft   = 'remembered'

user types 'new text' before restore returns

MirrorRestored arrives
      |
      v
current draft is no longer initial
      |
      v
keep 'new text'

The write Subscription starts with the initial Model, before the store has answered. Until the Model has taken in what the store holds, writing it would replace the stored document with the initial slice, so a key-value mirror holds each write until its slice is one the restore leaves unchanged:

cold load: Model at defaults, store holds { sidebar: 'closed' }

write (after the throttle)   held: a restore would still change the Model
restore answers              MirrorRestored -> reduce -> Model has sidebar 'closed'
write                        goes ahead: the Model holds what the store held

The check is against the latest restore's answer, or, before any answer, the store's own content at the first write, so a mirror nobody restores (a test harness, a Model kept across a hot reload) writes once its slice agrees with the store. An empty store holds back nothing. A read that fails answers as an empty store: MirrorRestored carries no keys, and later writes replace whatever the store held. A second restore holds writes again until its answer is taken in. The hold is per runtime (per built KeyValueStore), so two runtimes never wait on each other.

When URL and KV mirrors both represent one field, cold-load precedence is:

URL value, when present
      >
key-value restore
      >
initial value

because startup reduces the URL first and the later store restore only fills fields still at their defaults.