{ "$comment": [ "Shared behavioural contract for the dictionary correction pass.", "", "The macOS app (Swift) and the Windows app (C#) implement this logic independently.", "Independent implementations drift. This file is the thing that stops them: both must", "run every case below and produce exactly the stated output. A change to correction", "semantics starts here, not in either implementation.", "", "Rules under test:", " 1. Whole matches only - a rule must never bite into a longer word.", " 2. Case-insensitive - the trigger matches in any case; output is verbatim.", " 3. Longest match first - a longer trigger wins over a shorter overlapping one.", " 4. Glued words match - parts may be separated by any number of spaces or hyphens,", " including none at all.", " 5. Disabled is inert - a disabled entry changes nothing." ], "version": 1, "cases": [ { "name": "basic phrase replacement", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "I use cloud code every day.", "expected": "I use Claude Code every day.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "glued together with no separator", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "I use CloudCode every day.", "expected": "I use Claude Code every day.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "joined by a hyphen", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "I use Cloud-Code every day.", "expected": "I use Claude Code every day.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "multiple spaces between parts", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "I use cloud code every day.", "expected": "I use Claude Code every day.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "trigger matches regardless of case", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "CLOUD CODE is great.", "expected": "Claude Code is great.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "must not corrupt a longer word that starts the same way", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "Cloudflare fronts the cloudcodex service.", "expected": "Cloudflare fronts the cloudcodex service.", "expectedCorrections": [] }, { "name": "must not touch the ordinary word alone", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "The cloud is fine and the code is fine.", "expected": "The cloud is fine and the code is fine.", "expectedCorrections": [] }, { "name": "longest trigger wins over a shorter overlapping one", "entries": [ { "kind": "correction", "hear": "cloud", "write": "Claude" }, { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "cloud code", "expected": "Claude Code", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "counts repeated hits", "entries": [ { "kind": "correction", "hear": "clawed code", "write": "Claude Code" } ], "input": "clawed code, then clawed code again, and clawed code.", "expected": "Claude Code, then Claude Code again, and Claude Code.", "expectedCorrections": [ { "to": "Claude Code", "count": 3 } ] }, { "name": "punctuation is a boundary", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "(cloud code), \"cloud code\"; cloud code!", "expected": "(Claude Code), \"Claude Code\"; Claude Code!", "expectedCorrections": [ { "to": "Claude Code", "count": 3 } ] }, { "name": "a possessive still matches - the apostrophe is not a letter", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "cloud code's output", "expected": "Claude Code's output", "expectedCorrections": [ { "to": "Claude Code", "count": 1 } ] }, { "name": "a disabled entry changes nothing", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code", "isEnabled": false } ], "input": "I use cloud code every day.", "expected": "I use cloud code every day.", "expectedCorrections": [] }, { "name": "a term entry never rewrites text", "entries": [ { "kind": "term", "write": "Anthropic" } ], "input": "anthropic makes models.", "expected": "anthropic makes models.", "expectedCorrections": [] }, { "name": "single word trigger is honoured when asked for", "entries": [ { "kind": "correction", "hear": "vercell", "write": "Vercel" } ], "input": "Deployed on Vercell today.", "expected": "Deployed on Vercel today.", "expectedCorrections": [ { "to": "Vercel", "count": 1 } ] }, { "name": "several independent rules in one pass", "entries": [ { "kind": "correction", "hear": "clawed code", "write": "Claude Code" }, { "kind": "correction", "hear": "whisper flow", "write": "Wispr Flow" } ], "input": "clawed code beat whisper flow.", "expected": "Claude Code beat Wispr Flow.", "expectedCorrections": [ { "to": "Claude Code", "count": 1 }, { "to": "Wispr Flow", "count": 1 } ] }, { "name": "empty input is left alone", "entries": [ { "kind": "correction", "hear": "cloud code", "write": "Claude Code" } ], "input": "", "expected": "", "expectedCorrections": [] }, { "name": "replacement containing regex metacharacters is literal", "entries": [ { "kind": "correction", "hear": "c plus plus", "write": "C++" } ], "input": "I write c plus plus.", "expected": "I write C++.", "expectedCorrections": [ { "to": "C++", "count": 1 } ] }, { "name": "trigger containing regex metacharacters is literal", "entries": [ { "kind": "correction", "hear": "dot net", "write": ".NET" } ], "input": "Built with dot net.", "expected": "Built with .NET.", "expectedCorrections": [ { "to": ".NET", "count": 1 } ] }, { "name": "accented trigger matches decomposed input (NFC normalization)", "$comment": "macOS hands back NFD strings from several APIs. Without normalizing both sides, an accented trigger silently never fires. Input here is deliberately NFD.", "entries": [ { "kind": "correction", "hear": "café racer", "write": "Café Racer" } ], "input": "a café racer bike", "expected": "a Café Racer bike", "expectedCorrections": [ { "to": "Café Racer", "count": 1 } ] } ] }