Build1 distinct publisher3 min readPublished
Unicode's parallel Latin alphabets are separate characters, not fonts, so a decorated display name can clear validation and then disappear from your search index. Folding it back to ASCII takes three passes.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The arithmetic is worth doing once, because the same division explains both the shrunken field limit and the mojibake in your outbound email. At two UTF-16 code units per character [1], a 15-unit display-name limit admits seven of these characters and strands one unit, which is where the author's 15-becomes-7 figure comes from [6]. A naive `slice(0, 3)` cuts inside the second surrogate pair and returns a lone high surrogate [5]. That value is legal UTF-16 and has no UTF-8 encoding, so it resurfaces as a replacement glyph in an email, or as an invalid-UTF-8 error at the first downstream service strict enough to check [7]. The counting fix is cheap: spread or `Array.from` when you mean code points, `Intl.Segmenter` when you mean what a person would call a character, including emoji assembled from ZWJ sequences [8].
The load-bearing detail in the fold is sequencing, and the code says so in a comment: the small-caps lookup has to run before `normalize('NFKD')` because one of its keys, the ogonek-bearing q, would decompose first [19]. Run NFKD ahead of the table and that entry never matches. The table itself holds 25 letters where you would expect 26 [2], because Unicode's small capital X is unrenderable in most fonts, so the generator sites leave a lowercase x alone and there is nothing to map [20]. The input set is therefore defined by what generator sites emit rather than by what the standard contains, which is a thin foundation to build a moderation filter on.
The two survivors survive for unrelated reasons. The small capital T is U+1D1B from the Phonetic Extensions block, a letter linguists needed for IPA, with no compatibility decomposition to `t` and no response to `toUpperCase` [17]. The strikethrough is a plain ASCII `s` followed by U+0336 COMBINING LONG STROKE OVERLAY, a mark the user deliberately added, and normalisation has no mandate to remove it [18].
Two conditions have to hold before this pipeline transfers. First, the text has to be decoration rather than content: flattening the small capital T to `t` is right in a user list and wrong in a pronunciation dictionary, and Unicode's position is that it was never a `t` in the first place [17]. Second, the fold has to be a comparison key rather than the stored value, because it is lossy on purpose. NFKD on the maths alphabets returns plain ASCII [15], and `foldFancy` turns the decorated name into `fancy name` [21] with no route back to the glyphs the user chose.
Expect the ordering complaint before the security one. Searching for the plain spelling fails, because `'𝓯𝓪𝓷𝓬𝔶'.includes('fancy')` is false [12]. That is the spec doing what it documents, and it still lands in your queue as "search is broken" [14].
Ranked by verification strength, evidence, and original report placement.
The character 𝓯 is not the letter f in a font but U+1D4EF, MATHEMATICAL BOLD SCRIPT SMALL F, a separate character with its own code point; nobody installs anything to type it.
Unicode contains several parallel Latin alphabets, added over the years for maths notation, phonetics and enclosed symbols, which copy-paste generator sites turned into bio decoration.
For the string '𝓯𝓪𝓷𝓬𝔶', name.length returns 10 while [...name].length returns 5.
Everything above U+FFFF is stored as a surrogate pair in JavaScript strings, so .length returns UTF-16 code units rather than characters.
name.slice(0, 3) on '𝓯𝓪𝓷𝓬𝔶' returns '𝓯\ud835', a broken half-character consisting of a lone surrogate.
A 15-character display-name limit becomes a 7-character limit for users of these characters.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 31, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Allow-list the closed set, block-list the open one: 193 thin geo pages, one gate1 distinct publisher
build
Three ways to ask who embedded your iframe, and only one the host cannot switch off1 distinct publisher
build
The third answer: a dead-code tool allowed to say "not traced yet"1 distinct publisher
build
A 20-digit ID went into a JSON repair tool and a different number came out1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Verifiable from your own console
Almost every step here is a line you can paste into a browser and check in ten seconds: five visible letters returning a length of 10, a slice that emits half a code point, reserved.includes('𝗮𝗱𝗺𝗶𝗻') coming back false, NFKD folding '𝓯𝓪𝓷𝓬𝔶' but shrugging at 'ᴛɪɴʏ ᴛᴇxᴛ'. For a single-byline developer post that is unusually solid footing, because the reader supplies the second source. The mechanics are explained rather than asserted too — small caps resist folding because U+1D1B has no compatibility decomposition, strikethrough resists it because the base letter was never replaced. One claim breaks the pattern: that impersonation accounts use this to clear signup arrives with no platform, no case, no date.
No signal on how often this happens
The code is checkable; its incidence is not covered anywhere in this reporting. Nobody names a platform that has been hit, no team reports shipping a fold and watching support tickets drop, and the generator sites that produce these names go unnamed and uncounted. We have a mechanism and no measurement of it, so there is nothing to score.
Headline matches the arithmetic
The claim in the title is just multiplication — two code units per character, so a 15-unit field holds seven of them — and it is correct. Where the piece runs slightly ahead of what it shows is the pivot from console output to consequence: "this is not a theoretical attack" and users reporting "search is broken" are both plausible and both unevidenced, sitting in a text where everything else came with a return value. Small overstatement, and it lands on the security framing rather than the technique.
Nothing on sale
The remedy is twelve lines of inline JavaScript — no library, no repo, no employer, nothing gated. More telling, the author spends the paragraph after their own function explaining where it loses data ('café' becomes 'cafe', so keep it off the display path) and where it stops helping (Cyrillic and Greek lookalikes, which they hand to Unicode TR39). Volunteering your solution's limits is the cheapest available tell that nobody is being upsold.
One voice, but a testable one
A single publisher and a single author would normally cap this much lower. It lifts because the substance is self-testing: the code either behaves as printed or it does not, and any reader can settle it. What holds it well short of high is everything outside the console — the screen-reader section explicitly says behaviour varies by reader, version and voice without offering a single tested case, the impersonation claim stands alone, and the piece is cut off mid-sentence on search engines, so we cannot judge what it was about to assert.