[v0.1/P1] Make config enum growth forward-compatible per field #314
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#314
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent: #12. Related: #4, #8, #140, #143.
Problem
The config reference calls the schema additive and says unknown keys are ignored so one file remains forward-compatible across versions. Closed enum growth does not have that property.
ConfigDocument::resolvedeserializes the merged document as oneEffectiveConfig. An unknown enum token in any ordinary field makes that deserialize fail and replaces the entire effective document withEffectiveConfig::default(). For example, an older client reading a futurecursor.blink = "future_mode"loses otherwise valid font, theme, window, and clipboard settings as well as the one unsupported value.The keymap already has the safer boundary: it retains raw TOML entries and drops one malformed or unknown binding with a warning. Ordinary config enums (
cursor.blink,shader.animate,shader.post.builtin,window.backdrop,clipboard.osc_52, and future equivalents) have no corresponding field-local recovery rule.Adding an enum value is a natural additive extension to a public config surface. Once v0.1 ships with whole-document failure, old binaries cannot be taught to tolerate a newer shared config file.
Decision required before v0.1.0
Define enum evolution as part of the additive config contract. The preferred rule is:
Current JSON Schema may keep enumerating the values known to that schema revision: editor validation describes the current vocabulary, while the runtime's lenient fallback provides old-reader/new-file compatibility.
If whole-document rejection is retained instead, the docs must withdraw the broad forward-compatibility claim and declare every enum-value addition a config-breaking change. That is not preferred because it makes routine growth of presentation options require a new config epoch or a flag day.
Acceptance criteria
shader.post.builtin, for example) falls back at the smallest typed boundary rather than resetting the document.felis config check, startup, and live reload report the same diagnostic; live reload keeps or applies state according to the documented invalid-value rule.[client.felis].Principle check
Direction agreed 2026-09-21 after three
soldesign-review rounds (final verdict PASS). Full plan and batch order: see the comment on #12.its documented default with a full-path warning. Implementation follows the
font.fallbackprecedent: a lenientdeserialize_withhelper that swallowsan unknown string token into the default (a table/int/bool stays a shape
error) on the six enum-typed fields, plus a
validate::closed_enumspassthat re-reads the merged TOML and warns
DiagnosticKind::ValuewithKeyOrigin::attributeso overlay paths readclient.<id>.…. Turning theerror into a warning fixes
config check, startup, and live reload at once.Syntax errors keep whole-document failure.