Repository navigation
fix: reliability batch 1 — language identity, atomic model switch, structured outcomes, NFC dictionary - #80
Conversation
Use unicode-normalization because Rust's standard library does not provide NFC normalization. Reconcile persisted v3 dictionary identity deterministically while preserving display strings and recording discarded replacement rules for review.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dcbc2072f9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if is_manual_trust_entry(&group[index]) && !is_manual_trust_entry(&group[winner_index]) | ||
| { | ||
| winner_index = index; |
There was a problem hiding this comment.
Preserve active dictionary entries during NFC merge
When a user has NFC-equivalent duplicates where the active entry is auto-learned and a later manual/imported duplicate has been quarantined or disabled, this winner selection chooses the inactive manual-tier entry solely because of its source. The migration then drops the active entry and rebuilds custom_words from the retained inactive entry, so that phrase stops being used for prompts/replacements after upgrade even though the user still had an active dictionary entry for it.
Useful? React with 👍 / 👎.
Batch 1 changed set_active_model to return ModelSwitchOutcome { reason }.
The Playwright mock still returned the pre-batch unit (null) shape, so
modelStore.selectModel's result.data.reason access threw during first-run
onboarding, stalling the model->shortcut step. Update the mock to the real
shape and null-guard the frontend read defensively.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Before Submitting This PR
Human Written Description
This is the semantic-foundations layer for the language and dictionary reliability work — plumbing and data migrations that the pipeline fixes build on, with no new end-user behavior beyond correcting wrong outputs. The bilingual bugs mattered most to me: language tags getting case-mangled (
zh-Hans→zh-hans, breaking Chinese conversion), a locked language silently reverting to Auto after a failed model switch, and Arabic dictionary entries not matching when composed vs decomposed Unicode forms differed.What's in the batch
normalize_bcp47helper: primary subtag lowercased, script subtag Title-case (zh-Hans), region UPPER (en-US), used everywhere a code is stored. Legacy stores with a concrete language but missing mode now resolve to Single, and the frontend treats the backend mode as authoritative.selected_model+selected_language+dictation_language_mode+adaptive_language_shortlist; a failed load restores all four (previously only the model). When a lock is genuinely incompatible with the new model, lock+mode+shortlist clear together and a translated reason is surfaced instead of a silent revert to Auto.LanguageOutcome { requested, effective, supported: Supported|Unsupported|Unknown, detected, detection_confidence, translation_requested, translation_performed }, populated truthfully — empty capability list ⇒Unknown(not "accept any"), and engines that ignore the language param leavetranslation_performed=false. The guard/history are not rewired to consume it yet (that's the next batch).unicode-normalization; one canonical key (NFC + case-fold + whitespace + smart-punct) used by learning, exact/fuzzy match, suppression, and the mirror. Display strings are never normalized. A v3 migration collapses canonically-equal entries (manual-tier wins, else first), preserving order and recording any discardedreplacement_ofas a review candidate rather than dropping it. Forced-save + rollback like v2.Testing
dictionary_suffix_punctuationhelper).tsc, ESLint, Prettier, translations (870 keys × 19 locales), generated bindings, frontend language-mode suite (8 tests), settings-lock coverage, andcargo-deny(advisories/bans/licenses/sources) all pass.unicode-normalization 0.1.25is the only new dep.Needs device/runtime verification (follow-up, not blocking desktop review):
detected/detection_confidenceare honestly leftNone.AI Assistance
If AI was used:
🤖 Generated with Claude Code