Currently, all CodeMirror preferences (except colorblind mode) are saved under a single user option, codemirror-preferences. It is a JSON blob with the keys as the feature names (i.e. codeFolding, lint) and the values being either 1 or 0.
T419337: Allow CodeMirror preferences to differ between wikitext and non-wikitext takes it a step further and introduces "mode IDs" so the preferences can be applied to specific environments (though that's likely to remain only wikitext and non-wikitext). The storage for the values is still an integer, meaning we have a small footprint with still plenty of room left for more features to be added. It does however mean we can't then also use the value to store anything other than whether the feature is off, or where it is enabled.
We need to expand the CodeMirrorPreferences logic and storage schema to support something more than off/on values. For example, we'll need at least integers great than 1 to for theming (T163533) and linter options (T408729).
Preventing user_properties bloat (T286270, T54777) as I understand it is more about row count, but at scale we want to keep the storage footprint reasonable as well. In production it is a MariaDB BLOB, which gives us 64KB… so I think we can easily squeeze in whatever we need into the existing codemirror-preferences, and have it be backwards-compatible.
Keeping on with T419337, we'll want the same content model (aka mode) granularity too. Something like:
Old schema
Boolean-only, applies to all editing environments.
{ "featureA": 0, "featureB": 1, "featureC": 0 }
After T419337
Same as before, but now with a separate user option codemirror-preferences-code that applies to non-wikitext.
New schema
Same as before, but in addition to 0 / 1 (disabled or enabled), a string value can be provided which implies enabled but with the given value. This value can take any form, such as serialized JSON.
{ "featureA": 0, "featureB": "custom data", "featureC": "{\"foo\":1,\"bar\":2}" }
In the future, we might have things like custom lint rules, custom highlighting of characters (T383285), so I'm trying to think ahead. So long as it's JSON-serializable, and we don't store any key where the value matches the same as the default, I think this will suffice.