0009 the phonetic encoders follow jellyfish whole - CyrilB1531/lodestar GitHub Wiki
0009 — The phonetic encoders follow jellyfish whole
Status: accepted · Date: 2026-09-27
Context
0005 holds Soundex,
NYSIIS, Metaphone and the match rating to jellyfish 1.2.1, and draws the scope of that parity
short of jellyfish's whole behaviour: Metaphone is proven on real words, jellyfish's answers on
degenerate letter sequences being its C implementation's, of no value to reproduce.
0007 records a second boundary as a deliberate divergence:
jellyfish measures a match rating codex in UTF-8 bytes for the truncation, the length-gap check
and the minimum-rating lookup, and the C# measured characters.
The pre-1.0 review of 2026-09-26 found the boundary drawn in the wrong place
(#1194,
#1195,
#1198). The divergences were not confined to
non-words: 54 of 5,402 real ASCII words differed in Metaphone (Fletcher, Mitchell, Highness),
9 in NYSIIS (Reeves, Fischer), and an apostrophe — Keats's, O'Brien — changed the Soundex,
NYSIIS and match rating answers of every possessive in the dictionary, because the C# dropped what
jellyfish reads. The implementation behind jellyfish 1.2.1 is Rust, not C, and its rules are
visible in behaviour: a full uppercase mapping (ß is SS), a decomposition or a grapheme cluster
as each encoder takes one, and every other character standing where it is.
Decision
Soundex, NYSIIS, Metaphone and the match rating reproduce jellyfish 1.2.1 on every input, not
on real words only. The input is uppercased by the full case mapping; Soundex and Metaphone read
its NFKD decomposition, NYSIIS and the match rating its extended grapheme clusters; a character no
rule names is kept where it stands, and acts there as jellyfish's rules make it act. The match
rating measures its codex in UTF-8 bytes, as jellyfish does, and Compare answers null where
jellyfish answers None for a name the codex refuses.
This amends 0005's phonetics row: the Metaphone corpus is no longer the boundary of the claim,
and degenerate sequences are inside it. It withdraws 0007's match rating row: byte length is no
longer a divergence, so Codex("並丝七世") is jellyfish's 並丝七丝七世. The rules are
reproduced from what jellyfish answers, as 0002
allows, and each is proven by its oracle, not by the source.
Consequences
- Two Unicode facts .NET does not expose are tables in
Lodestar.Text: the scalars whose full uppercase differs fromchar.ToUpperInvariant, and the Other_Alphabetic markschar::is_alphabeticadmits. Both were measured over every scalar against jellyfish 1.2.1 and Python'sunicodedata15.0; a scalar Unicode assigned after that follows the runtime's tables, and a grapheme boundary follows the runtime's segmentation, which on .NET Framework predates extended clusters. - A differential test replaces the real-word boundary: 134,334 inputs — the dictionary and
30,000 random strings over apostrophes, spaces,
ß, combining marks, emoji and letter numbers — agree with jellyfish on all four encoders, and 33,003 pairs on the comparison. The corpora gain the names and the non-ASCII cases that used to sit outside the claim. - Metaphone's corpus,
metaphone.json, is no longer special: it stays because its names cover the rules, not because it bounds what is promised.