ReadonlychangesOptional ReadonlyhandlerReadonlyversionThis entry's version — must equal its index (so version 0 is the initial
schema and currentVersion === entries.length - 1). Redundant with position,
but makes a long history scannable; the guard test verifies it.
One entry in an ordered version history.
entries[i]IS versioni: applying itschangesover the previous version's schema yields versioni, soentries[0]builds version 0 (the initial schema) from the empty base andcurrentVersion === entries.length - 1. Folding every entry'schangesfrom{}reconstructs the current schema.Components and resources are patched separately so their namespaces stay distinct (a
Schemacan't say which it is) and so a component↔resource move is expressible as a removal in one plus an add in the other.handleris present iff the change is not automatically convertible (a major change — a type change, split, cross-component move, …). It runs against the store staged to the schema of versioni - 1— the input this entry transforms — and transforms the data in place. Additive / minor / removal changes carry no handler — load-time conversion handles them.SINGLE-QUADRANT CONTRACT. A handler touches exactly ONE persisted quadrant —
document(shared+persistent) orsettings(nonShared+persistent): the one its schema change is in, which the guard enforces. Only THAT quadrant is staged to the versioni - 1shape before the handler runs; the other quadrant is deliberately left unconformed, because per-quadrant versioning lets the two drift to different versions and staging the other one could down-convert it. So a handler must read and write ONLY its own quadrant's components/resources. Reading another quadrant is a silent bug: under a scoped/split load it may be absent or at a different version, so the read returns stale/default data and the migration decides wrong. This is not statically enforced — keep each handler within its own quadrant.