A fold result could itself be foldable: ǿ folded to ø and ǽ to æ, while
the canonically equivalent ø+U+0301 and æ+U+0301 reached o and ae.
Normalize writes a result without folding it again, so the generator now
folds every result letter by letter until it settles (and fails if it does
not), making the committed table fully reduced. TestLetterFoldsFullyReduced
pins that, and the canonical-equivalence tests now cover ǿ and ǽ through
Normalize, Similar and Deduper.IsDuplicate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the hand-written accent map with letterFolds, a table generated
offline by gen_folds.py from Python's unicodedata: every code point whose
canonical decomposition contains combining marks maps to its base letters,
plus stroked Latin letters and ligatures. Combining marks are still dropped,
so composed and decomposed spellings ("Phở" and "Phở") now
normalize equal. No new dependency.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add harness.Normalize (lowercase, fold accents, strip punctuation, drop
filler words, collapse whitespace), harness.Similar (token-set Jaccard
similarity, threshold 0.85) and a Deduper built from the Regulars, Quest
log, pending suggestions and passed names that answers IsDuplicate.
Maestro task: f046ec6c-dbe2-4b12-bc95-3081c07714eb
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>