Skip to content

fix: keep the curly apostrophe when folding a lookalike word - #22

Open
cycanic wants to merge 1 commit into
moderation-api:mainfrom
cycanic:fix/curly-apostrophe
Open

cycanic wants to merge 1 commit into
moderation-api:mainfrom
cycanic:fix/curly-apostrophe

Conversation

@cycanic

@cycanic cycanic commented Nov 14, 2026

Copy link
Copy Markdown

What & why

When a word with a lookalike letter gets folded, its typographic apostrophe was
folded too:

analyze('Ivа’s').normalized // Cyrillic а
// before: "Iva's"   (U+2019 replaced by ASCII ')
// after:  "Iva’s"

The fold ran every character of the token through the confusables map, and U+2019's
prototype is '. The apostrophe is punctuation the token is allowed to have, not a
lookalike, so now it stays as typed. Detection is unchanged: Ivа’s is still
mixed_script and spoofed.

Small follow-up to the curly-apostrophe handling in #16.

Tests: a case in test/cases.data.ts and a test in analyze.test.ts
(Ivа’s, Ivа's, and the boss’ НОТ’ deal → the boss’ HOT’ deal).

Checklist

  • Tests added/updated (including false-positive cases for multilingual text)
  • pnpm lint && pnpm check-types && pnpm test && pnpm build pass locally
  • Added a changeset (pnpm changeset) if this is a user-facing change (patch)

Found while maintaining an extended version at https://github.com/cycanics/unicode-spoofing.

🤖 Generated with Claude Code

The fold ran every character of an affected token through the confusables
map, including U+2019, whose prototype is ASCII "'". So "Ivа’s" (Cyrillic
а) normalized to "Iva's" instead of "Iva’s". The apostrophe is punctuation
the token admits, not a lookalike; leave it as typed. Detection is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cycanic
cycanic requested a review from chrisdengso as a code owner November 14, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant