354 lines
8.7 KiB
JSON
354 lines
8.7 KiB
JSON
{
|
|
"$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
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|