colour -> color, behaviour -> behavior, centre -> center, favourite ->
favorite, and about twenty other pairs, applied consistently across
comments, docs, error/UI copy, and a handful of QML identifiers that
used the British spelling as their actual name: SystemSettings'
serialiseValue/serialiseTable/normaliseGradient, Displays'
normaliseModes, Wallpaper's normalisePolicy, SettingsBackup's
serialiseHomeState, DateTime's ntpSynchronised property, Clipboard's
_normalise helper, and ShortcutCapture's cancelled signal (with its
onCancelled handler in ShortcutsPage.qml). Every call site and the two
tests that assert on the literal source text (settings-ownership and
settings-backup-live contracts) were updated in lockstep.
Left untouched: config/dot/espanso/match/packages/misspell-en/ is a
vendored third-party autocorrect dictionary -- its entries are typo
corrections, not our prose, and rewriting them would fight the
package's own purpose (and any future re-sync from upstream).
The already-American `favorites` property (Home page pinned
accessories) was never actually misspelled -- only nearby comments and
error strings said "favourites" -- so no data migration was needed
there.
Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
The schema is the single source of truth for what a setting IS. It
cannot express what a setting USED to be -- and renaming a key, changing
its units, or splitting one setting into two all leave a stored value
the new schema does not recognise. Unrecognised keys are deliberately
carried through untouched so that rolling back to an older Panama does
not discard a newer version's settings, which means the user's choice
silently stops taking effect with nothing to explain it.
settings.json now carries a schemaVersion, and load() runs every pending
migration before anything reads a value. The list is empty: the point is
that the first breaking schema change becomes a routine edit rather than
an emergency, and Omarchy carries eighty of these.
The behaviours that make it safe to run against a real user's file:
A file with no schemaVersion predates this and is STAMPED, not
migrated -- running the list against it would apply upgrades designed
for schemas it never had.
A file from a NEWER Panama is left completely alone. Downgrading keys
is not something this can do correctly, and unknown keys already
survive, so an older build simply ignores what it does not understand.
A step that throws stops at the last good version. Skipping past it
would lose that conversion forever; failing the whole load would cost
the user every setting.
The list being empty is exactly why this is tested now: the first time
it runs for real will be against somebody's actual settings during an
upgrade, which is a poor moment to find out how it behaves. The harness
supplies fixture steps including one that throws, and the contract pins
all four behaviours above plus the promise that unknown keys survive.
One thing the contract earned its place on: stamping a pre-versioning
file changes it without running any step, so writing only on "migrated"
left the stamp in memory to be redone on every launch. It now writes
whenever the version moves, and explicitly does not write a file from
the future.
Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L