Repository navigation
Make one visible name one identity - #2694
Conversation
The identity key was trim().toLowerCase(), so two canonical spellings of one name, and a name carrying an invisible format character (U+200B and the other Cf characters), were different keys: the duplicate guard admitted a twin Bot or group chat, and a lookup could miss the record it named. normalize now NFC-normalizes, drops the Cf characters, trims, lowercases and NFC-normalizes again, so every existing call site inherits one key. nameProblem refuses a name of only invisible characters, and createBot, updateBot and cleanRoomName store the visible form. A name already in state.json is never rewritten. Written-by: Dev Fixes #2691 Owner: Dev Reviewer: Reviewer
|
Verdict: PASS at adf25f6 Ran at this tip: Review notes (tip
One non-blocking observation: dropping all Checks at this tip: |
Written-by: Dev
Fixes #2691
Owner: Dev
Reviewer: Reviewer
What changed
One identity key for a name.
normalizeincore/src/host/text.jsnow NFC-normalizes, drops the Unicode format characters (\p{Cf}: U+200B–U+200D, U+FEFF, U+00AD and the rest — bidi controls, word joiner, the other invisiblestrim()keeps), trims, lowercases, and NFC-normalizes again because a lower can compose a new sequence (U+0130). Every existing call site inherits it:findBot,findRooms,track_tasks, model refs.The guards and the queries use that same key:
createBotandupdateBotstill refuse throughfindBot,cleanRoomNamethroughfindRooms, so two records cannot share a key through any admission path.nameProblemincore/src/shared/mentions.jsnow refuses a name that is only invisible characters.createBot,updateBotandcleanRoomNamestore the visible form (the\p{Cf}characters stripped before the 40 /ROOM_NAME_MAXcut), so what is saved is what is shown. A name already instate.jsonis never rewritten: the key is computed from what is stored, so an old NFD name still resolves.core/src/shared/mentions.jsis imported by the client, socore/client.jswas rebuilt withnpm run build(never hand-edited).patches/ds-bot/was regenerated fromcore/(with the bundled git on this box) andcanonicalconfirms it is whatgeneratewrites.Red first
The three source files this change touches —
core/src/host/text.js,core/src/shared/mentions.js,core/src/host/roster.js— put back at the base blob6f086fa5, with the new test kept. All six cases fail:Narrower revert, for the split: with only the
normalizeexpression back atString(value ?? '').trim().toLowerCase()(sonameProblemand the stored-name cleanup stay fixed) cases 1, 3, 4 and 5 fail and 2 and 6 pass. With onlycore/src/host/text.jsat the base blob the test file does not load at all, because a changed module importsstripInvisiblefrom it.Ran at this tip:
adf25f6d75df0e591376760a602411e06a405638— all 12 changed files at that tip were compared byte-for-byte with the worktree these commands ran on.Not run: the full
npm run verify— the brief says not to run it. The core suite was run only for the affected files (store, roster, rooms, mentions, text, models, tasks and create/update Bot); the plugin suites were not run because no plugin file changed.Checkpoint
{ "pr": 2694, "claim": "Dev", "issue": 2691, "summary": "One identity key for names: canonical spellings and invisible format characters no longer make a second Bot or group chat. The duplicate guards and the lookups share that key, and an admitted name is stored in the visible form. A name already in state.json is not rewritten, so old records still resolve.", "files": ["core/src/host/text.js", "core/src/shared/mentions.js", "core/src/host/roster.js", "core/test/name-identity.test.js", "changelog.d/2691-name-identity.fixed.md"], "checks": { "ran": "affected core tests + ds-bot-patches check/canonical + build-client --check + lint-plugins + changelog + mojibake + arch-docs", "result": "green", "at": "adf25f6d75df0e591376760a602411e06a405638" }, "next": "none — ready for review" }