fix: stop Rust overwriting camelCase settings — root cause of app being unusable #4736
Cross-repo impact
See what breaks downstream if this PR merges.
⮌ Merged
This pull request was merged into main.
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts
Originally written by @ccantynz-alt on GitHub.
Imported from https://github.com/ccantynz-alt/voxlen/pull/65
Summary
This PR fixes the root cause of settings being lost on every restart, which made the app non-functional (every launch requires re-entering API keys, language, etc. before anything works).
Root cause: camelCase vs snake_case mismatch in persistence layer
The frontend (TypeScript/Zustand) saves settings as camelCase JSON to the Tauri store (
{ "sttEngine": "deepgram", "sttApiKey": "..." }). The Rust backend uses snake_case structs (stt_engine,stt_api_key). Every time Rust wrote to the store it silently corrupted the file with snake_case — which the frontend then couldn't read, causing an all-defaults reset.There were two places Rust was writing snake_case into the frontend-owned store:
update_settingscalledpersist_settings(fixed in a prior commit)load_settings_from_disktried to parse the camelCase JSON as snake_case, failed, then overwrote the store with snake_case defaults — destroying all saved settings on every launchChanges
src-tauri/src/commands/settings.rs—load_settings_from_diskupdate_settingssrc/App.tsxuseSettingsStore.subscribe(...)effect that was saving the entire Zustand state — includingsttApiKey,grammarApiKey,voxlenApiKey— to plain JSON on every settings change. This was a privacy violation for a product used by lawyers.schedulePersist()instores/settings.tsalready handles all persistence correctly (keychain for API keys, Tauri store for everything else).checkFirstLaunch(now readslegalAcceptedVersiondirectly from the raw store JSON to avoid racing withusePersistedSettings)src/hooks/useGlobalShortcuts.tsstart_dictationfails in Tauri context (no API key configured, mic permission denied, engine error), the UI was left permanently stuck showing "Listening" with no feedback. Now resets status to idle and shows an error toast.Test plan
settings.jsonshould not containsttApiKeyetc.)🤖 Generated with Claude Code
https://claude.ai/code/session_01Ggw2m7nwT2HDNaQJqSX6Sp
Generated by Claude Code