Problem
Team correction keywords introduced in #567 do not match canonically equivalent Unicode text. A French keyword written with a precomposed accented character matches, while the same visible prompt with a combining accent does not. This can undercount course corrections in dashboard/session metrics and affect correction-based contribution nudges.
Reproduction
Configure the team's teamai.yaml:
sharing:
intervention:
correctionKeywords: [réessaye]
Dispatch a prompt through the built CLI with either payload (use a valid project cwd or an initialized user-scope config):
{"session_id":"unicode-nfc","prompt":"r\u00e9essaye"}
{"session_id":"unicode-nfd","prompt":"re\u0301essaye"}
teamai hook-dispatch prompt-submit --tool claude < payload.json
Inspect ~/.teamai/dashboard/events.jsonl:
- NFC prompt:
correction: true.
- NFD prompt:
correction: false.
Expected: both prompts match the configured keyword. Both render as “réessaye”. To observe the aggregate count, submit the prompt within 60 seconds after a Stop event in the same session.
Cause and suggested fix
containsKeyword and isCorrectionPrompt in src/dashboard-collector.ts lowercase text but do not normalize Unicode. Normalize both the prompt and configured keywords to NFC before matching. Add regression coverage for both directions (NFC keyword/NFD prompt and NFD keyword/NFC prompt), including aggregate correction counts.
Local validation
Reproduced through the real built CLI across Claude, Codex, CodeBuddy and OpenCode, with local team configurations declaring each of the git, gitlab and github providers. This is a hook-dispatch/event-persistence test; it does not exercise live provider authentication or agent GUIs.
The 108-case matrix had 96 passes and 12 failures, all for the NFD version of this keyword. Existing Spanish false-positive examples, English and Chinese corrections, underscore boundaries, full-prompt matching past 200 characters, and the NFC French keyword passed. A focused regression test also reproduces the failure.
Scope
Follow-up accepted separately from #567. Normalize matching input without changing persisted prompt text or the existing correction time window.
Problem
Team correction keywords introduced in #567 do not match canonically equivalent Unicode text. A French keyword written with a precomposed accented character matches, while the same visible prompt with a combining accent does not. This can undercount course corrections in dashboard/session metrics and affect correction-based contribution nudges.
Reproduction
Configure the team's
teamai.yaml:Dispatch a prompt through the built CLI with either payload (use a valid project cwd or an initialized user-scope config):
{"session_id":"unicode-nfc","prompt":"r\u00e9essaye"}{"session_id":"unicode-nfd","prompt":"re\u0301essaye"}teamai hook-dispatch prompt-submit --tool claude < payload.jsonInspect
~/.teamai/dashboard/events.jsonl:correction: true.correction: false.Expected: both prompts match the configured keyword. Both render as “réessaye”. To observe the aggregate count, submit the prompt within 60 seconds after a Stop event in the same session.
Cause and suggested fix
containsKeywordandisCorrectionPromptinsrc/dashboard-collector.tslowercase text but do not normalize Unicode. Normalize both the prompt and configured keywords to NFC before matching. Add regression coverage for both directions (NFC keyword/NFD prompt and NFD keyword/NFC prompt), including aggregate correction counts.Local validation
Reproduced through the real built CLI across Claude, Codex, CodeBuddy and OpenCode, with local team configurations declaring each of the
git,gitlabandgithubproviders. This is a hook-dispatch/event-persistence test; it does not exercise live provider authentication or agent GUIs.The 108-case matrix had 96 passes and 12 failures, all for the NFD version of this keyword. Existing Spanish false-positive examples, English and Chinese corrections, underscore boundaries, full-prompt matching past 200 characters, and the NFC French keyword passed. A focused regression test also reproduces the failure.
Scope
Follow-up accepted separately from #567. Normalize matching input without changing persisted prompt text or the existing correction time window.