From 7d9eeb69ca063cd96aafa8dc78f523411185ce52 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 24 Oct 2026 19:16:38 -0700 Subject: [PATCH 1/3] Read a bare Wm as the given name it abbreviates, not a title (#789) `wm` was listed as a title for #68, which asked that `Wm. Scott Magargee III` not read given name `Wm.`. Wm is William written short, so the request was mistaken; on 08d130ed bare WM opened the given part of 69 FEC donor names, every one read as a title. The title reading is refused in en.toml with that reason. The dotted Wm. opening the given part is still rules/H2's title; a given reading that outranks H2 is phase 2's (#752). Where vocabulary read it (a trailing Wm., H5; a Wm. before a family comma, H6) it is a name word again, as in 1.4.0. Co-Authored-By: Claude Opus 5.5 --- .../design/decisions/vocabulary-exclusions.md | 2 +- docs/design/decisions/vocabulary-model.md | 9 ++++++-- docs/design/mechanisms.md | 2 +- docs/release_log.rst | 1 + nameparser/config/_compiled.py | 1 - nameparser/vocab/README.md | 2 +- nameparser/vocab/en.toml | 2 +- tests/v2/cases.py | 22 +++++++++++++++++++ 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs/design/decisions/vocabulary-exclusions.md b/docs/design/decisions/vocabulary-exclusions.md index da51f852e..e4d7b89a3 100644 --- a/docs/design/decisions/vocabulary-exclusions.md +++ b/docs/design/decisions/vocabulary-exclusions.md @@ -59,7 +59,7 @@ Excluded (Lexicon.honorific_tails — a glued tail peels only if it could never Excluded (TITLES): -- The per-word refusals are data since #750 (2026-10-19): each word refused a title reading — the Indic ঠাকুর/ठाकुर, कुमारी/কুমারী, बेगम/বেগম, शेख/শেখ, आचार्य and राजा/रानी (#343, #344), and #606's ông/bà, thiru, puan, pan, rodina, gróf, cik, paron, tikin, Latin janab, marshal and justice, #662's malam (Derek's decline) and bay, and #660's shehu — is an `excluded` entry in its language's file with its reason, and with its counts as name readings where they were taken. `uv run python tools/vocab/query.py --excluded title` lists them. A contributor who adds one back meets the reason as a build error. +- The per-word refusals are data since #750 (2026-10-19): each word refused a title reading — the Indic ঠাকুর/ठाकुर, कुमारी/কুমারী, बेगम/বেগম, शेख/শেখ, आचार्य and राजा/रानी (#343, #344), and #606's ông/bà, thiru, puan, pan, rodina, gróf, cik, paron, tikin, Latin janab, marshal and justice, #662's malam (Derek's decline) and bay, #660's shehu, and #789's wm (2026-10-22) — is an `excluded` entry in its language's file with its reason, and with its counts as name readings where they were taken. `uv run python tools/vocab/query.py --excluded title` lists them. A contributor who adds one back meets the reason as a build error. - shehu's counts do not settle a graf-class weighing, and must not be read as if they did: its one leading-position figure, the Wikidata given-name count on its entry, is a lower bound (Shagari's own entry has no given-name statement), and its other counts are family-name bearers, a position C-i does not ask about. The evidence that Shehu leads a name is not a count. It is Shagari himself, and CLDR's Hausa sample data, whose six renderings carrying the word all file it as the given name (`grep '"given": "Shehu"' tools/differential/cldr_fields.jsonl`). It arrived with an early bulk import (1a51555f) and was never put to C-i before #660. Whoever re-argues it counts Hausa given-name use first; the accepted cost is the honorific use, `Shehu Abubakar` reading given Shehu as any untitled name does, and the reading belongs in an opt-in pack if anyone asks for it. malam is the opposite case: CLDR's Hausa data files Malam as the title (`grep '"title": "Malam"' tools/differential/cldr_fields.jsonl`), so its refusal is a decline on the counts, not a shehu-style removal. - The class-level half of the Indic refusals stays here: the divergence on शेख/শেখ is deliberate and is the sri/shri case run backwards — the Latin sheikh cluster SHIPS as given-name titles for the Arabic addressing form, while the Indic spellings name the family. shehu's removal moved three CLDR corpus names (`Shehu Muhammed`, `Muhammed, Shehu`, `Modibbo, Shehu Bello`), all three now agreeing with CLDR on every role (moves: `uv run python tools/differential/snapshot.py --since v2.4.1`). - The trailing-position rule that must NOT be adopted, and 2026-09-08 says what the line is: TITLES holds hundreds of words in no suffix set, at least nineteen of them ordinary English surnames (king, judge, bishop, baron, sheriff, ...), so a blanket "vocabulary outranks position in the trailing slot" reading would turn "Mary Jane King" into title="King" with the family name gone. The leading half of this argument is AGENTS.md's "Dean is deliberately absent" gotcha; this is the trailing half, and it shadows the family name rather than the given (#316). What #316 settled is that the prohibition is on BARE words: "Mary Jane King" still reads family King, while "John Smith Prof." reads title Prof. **The second half of that argument is RETRACTED 2026-09-09**, in review of the docs commit: "a period-marked trailing word being one nobody writes as a surname" claimed the period keeps the collision out of the trailing slot, and it does not. Measured on the branch tree — "Mary Jane King." reads title "King.", given Mary, family Jane, the family name shadowed exactly as the bare reading would have shadowed it, and "John Smith Judge." reads title "Judge." The reach is the vocabulary rather than a handful: of the 746 titles in no suffix set, 627 read as a trailing title once a period is written behind them, and every one of the 119 that do not is kept out by the abbreviation SHAPE — a digit, a hyphen, an apostrophe, or a script whose letters carry combining marks (rules/H2 records that half) — no plain ASCII-letter title missing at all. So king, judge, bishop, baron and sheriff ARE reachable in the trailing slot; what the prohibition above buys is the bare spelling and nothing more. The period is a WRITING convention the rule can read, not evidence about the word, and reading it is an ACCEPTED COST under the premise that the input is a name (rules.md H Background): someone who ends a name with a period-marked word has written an abbreviation. rules/H5 carries it as an Accepted clause with "Mary Jane King." as the executable example. Recompute the reach with `L = Parser().lexicon; ws = [w for w in L.titles - L.suffix_acronyms - L.suffix_words if " " not in w]; len([w for w in ws if parse("Mary Jane %s." % w).title])` against `len(ws)` — 627 of 746 on 2026-09-09 — the digits move as the vocabulary grows and neither argument does. See #H5. diff --git a/docs/design/decisions/vocabulary-model.md b/docs/design/decisions/vocabulary-model.md index cc4cca14b..7808f5b7d 100644 --- a/docs/design/decisions/vocabulary-model.md +++ b/docs/design/decisions/vocabulary-model.md @@ -25,7 +25,8 @@ The vocabulary was a set of base sets plus marker subsets (`particles` and `part - The names later phases will use (`default`, `prefer`, `strict`, the position and attachment keys) are build errors naming their phase, not inert data; locale-pack vocabulary and the Korean surname list stay in Python — 2026-10-18 #737. - Every language file is in build-checked order (kind, then the `same_as` path from its root head, then the codepoints of the text), the check naming the entry to move, running last, and refusing a `same_as` loop of any length; `und.toml` is exempt — 2026-10-19 #747; 2026-10-21 #762. - The particles take eight kinds beside the generic one, `expands` carrying a particle's gloss and `note` its vetting, and the particle keep-outs are exclusions — 2026-10-19 #749. -- The titles take ten kinds beside the generic one, `academic` and `occupation` divided by function rather than subject, and the title keep-outs are exclusions; `wm` alone keeps the generic kind — 2026-10-19 #750, title kinds; 2026-10-19 #750, the rest of the titles. +- The titles take ten kinds beside the generic one, `academic` and `occupation` divided by function rather than subject, and the title keep-outs are exclusions — 2026-10-19 #750, title kinds; 2026-10-19 #750, the rest of the titles. +- `wm` is no title: William's abbreviation reads as the given name it is (`Wm Smith` → given 'Wm'), and its title reading is refused in en.toml. The dotted `Wm.` opening the given part is still rules/H2's title; a given reading that outranks H2 belongs to phase 2 (#752) — 2026-10-22 #789. - Abbreviations and full words spelled alike across European languages (`dr`, `prof`, `doctor`, `professor`, `docent`) are in `mul.toml`; a credential goes to a file only on evidence that names in that language carry it, so none is in `mul.toml` — 2026-10-19 #750, the rest of the titles; 2026-10-20 #751, the credentials. - `und.toml` holds only `bon` and `dí`, particles of unrecorded origin; every other word, the credentials, conjunctions, bound given names and birth markers included, is in a language file or in `mul.toml` — 2026-10-19 #749; 2026-10-20 #751, the conjunctions. @@ -100,7 +101,7 @@ Open: #752 (phase 2, derived ambiguity), #753 (phase 3, language packs), #754 (p - **The title keep-outs became exclusions**, in the file of the language whose reading they refuse, with their counts as name readings where counts were taken (malam, bay, shehu): `uv run python tools/vocab/query.py --excluded title`. The per-word counts in decisions/salutation-titles moved onto the `note` of each word's title reading, and the prose points at the query. The reasons the given-addressing comments gave for leaving `lord`, `lady`, `venerable`, `rabbi` and `imam` out of GIVEN_NAME_TITLES are notes on those words in und.toml until their kinds are assigned (they moved with them in part 2, the same day). - **Recompute** rather than quoting: `uv run python tools/vocab/query.py --kind salutation --count`, `--kind title --file und --count` (the titles still in `und.toml`, all of them generic until part 2 emptied it the same day, leaving one generic title, `wm`, in en.toml; `--kind title` names the whole category, so no query counts the generic kind alone), `--excluded title`. -- **2026-10-19 #750 — the rest of the titles classified (part 2 of #750).** No compiled set moves: `tools/vocab/build.py --check` reports the committed module current, and `tools/differential/snapshot.py` matches. The 644 titles still generic in `und.toml` on e943665e took their kinds, all but `wm` (below), and left for the files of the languages whose names they occur in, so `und.toml` holds no title. Part 1's hard cases are applied as decided there: `lord`, `lady`, `knight` and `chief` are `nobility`, `deputy` an `office`, and `dr` and `prof` are in mul.toml. +- **2026-10-19 #750 — the rest of the titles classified (part 2 of #750)** (its `wm` bullet superseded by 2026-10-22 #789). No compiled set moves: `tools/vocab/build.py --check` reports the committed module current, and `tools/differential/snapshot.py` matches. The 644 titles still generic in `und.toml` on e943665e took their kinds, all but `wm` (below), and left for the files of the languages whose names they occur in, so `und.toml` holds no title. Part 1's hard cases are applied as decided there: `lord`, `lady`, `knight` and `chief` are `nobility`, `deputy` an `office`, and `dr` and `prof` are in mul.toml. - **English holds most of them**: the bulk import's occupations, the US military ranks and their abbreviations, the offices, and the modifiers. `modifier` takes what is a title only inside a phrase: the qualifiers of ranks and offices (`vice`, `rear`, `petty`, `field`), the domain words of the descriptive titles (`baseball`, `software`, `tax`), the ordinals, and the court words of #9's list of judges' titles (`designated`, `docket`, `pro`, `edmi`). - **Address, not subject, decides `academic`.** Besides the doctors and professors of every script, it takes the English words used to address a professional (`advocate`, `attorney`, `engineer`, `nurse`, and `md` as the medical degree written before a name), the German abbreviations written before a name (`ra`, Rechtsanwalt; `wp`, Wirtschaftsprüfer; `pd` and `priv.-doz`; `dipl.-ing`), and the Devanagari `पंडित` and `पं`, a scholar's title, as part 1's refusal of the Latin `pandit` already keyed it. - **`wm` keeps the generic kind**, in en.toml: it is William's abbreviation, made a title for #68 so that `Wm. Scott Magargee III` would not read given `Wm.`, and no title kind describes it. Removing it moves a parse, though only of the bare spelling: `Wm Smith` reads title `Wm` with the word listed and given `Wm` without it, while the period-abbreviation shape rule takes `Wm.` either way (measured 2026-10-19 with `Lexicon.default().remove(titles={'wm'})`). So it is left to its own change. @@ -122,3 +123,7 @@ Open: #752 (phase 2, derived ambiguity), #753 (phase 3, language packs), #754 (p - **Comments became fields.** The block over the single-letter connectives (#383, #479, #397) was class-level, held by decisions/P8 and rules/P3, and is gone; its per-word facts are notes on `e` and `i`, and its keep-outs, `y` and the Cyrillic `и`, `і` and `й`, are `excluded = { may_be_initial = … }` (decisions/vocabulary-exclusions' conjunctions_ambiguous block keeps the class-level part). The #269 blocks over the Cyrillic, Greek and Arabic connectives and the Arabic-script bound given names became an `issue` on each and notes on `і`, `و` and `عبد`; `abd`'s comment became its note in ar.toml, beside the credential note part 1 left in en.toml. Spellings carry `same_as` where one word has several (`abdel` and `abdal` of `abdul`, `abou` of `abu`, `й` of `і`, `nee` of `née`, the е spellings of the ё ones), and gender is recorded where the form marks it (`née` and `né`, `geborene`, `rozená`, the Russian participles). - **Two keep-outs became data that had been prose.** The Scandinavian abbreviation `f.`, which collides with the initial F., is an exclusion in da.toml. `roz`, removed from the birth markers on 2026-08-26, is an exclusion in cs.toml with its reason, measured again: with it listed, `Rosalind Roz Smith` reads maiden 'Smith' and takes Rosalind for the family, where the 2026-08-26 record says it left no family name at all. - **Recompute** rather than quoting: `uv run python tools/vocab/query.py --file und`, `--kind conjunction`, `--kind bound_given --file ar --count`, `--kind birth_marker`, `--excluded may_be_initial`, `--excluded birth_marker`. + +- **2026-10-22 #789 (Derek) — `wm` LEAVES THE TITLES.** SUPERSEDES: the `wm` bullet of 2026-10-19 #750, the rest of the titles. #68 asked that `Wm. Scott Magargee III` not read given name `Wm.`, and `wm` was listed as a title for it in 0.5.5. The request was mistaken: `Wm` is William written short, and a name it opens is a man named William, which a reader of the name would not hesitate over. The case came back from the FEC donor list (`tools/differential/local_corpora.py`, fec-individuals), where bare `WM` opened the given part of 69 names on 08d130ed, every one read as a title with the given name taken from the next word or left empty. The title reading is refused in en.toml with that reason, so a contributor who adds it back meets it as a build error. + - **The dotted spelling is split by position, not by spelling.** rules/H2's shape reads an unlisted period-marked abbreviation opening the given part as a title, so `Wm. Smith` keeps title 'Wm.' and `Smith, Wm.` too; making `Wm.`, `Chas.`, `Geo.`, `Ma.` or `Jo.` a given name there is a reading that outranks a shape rule, phase 2's question (#752, D14(b) of its spec), and tests/v2/cases.py pins today's `Wm. Smith` so that change shows. Where VOCABULARY reads the word, the dotted spelling moves with the bare one: a trailing `Wm.` was rules/H5's title (`John Smith Wm.` → family 'Wm.', `Smith, John Wm.` → middle 'Wm.', the readings of 1.4.0 through 2.2.0), and a `Wm.` opening the part before a family comma was rules/H6's (`Wm. Smith, John` → family 'Wm. Smith', the reading of 1.4.0 through 2.4.0). The 2026-10-19 bullet said removal moves only the bare spelling; it took the off-switch parse at the head of the name only. + - **Measured** against 08d130ed (`snapshot.py --local` with the base recorded by `--tree`): the committed corpora and the CLDR, GND and Wikidata agreement views do not move, nor do psc-individuals' field agreements. fec-individuals moves 77 of 1,893,964 names: 69 with bare `WM` opening the given part, 3 with bare `WM` behind another title in it, 3 with a trailing `WM.` and 2 with `WM.` before the family comma. ctgov-officials moves 1 of 352,104, `Wm` behind a title before a family comma. diff --git a/docs/design/mechanisms.md b/docs/design/mechanisms.md index c26dab6cf..ea727f942 100644 --- a/docs/design/mechanisms.md +++ b/docs/design/mechanisms.md @@ -430,7 +430,7 @@ A second axis cuts across the jobs: whether the names are real or invented, labe - Release notes describe intent; TAGS are ground truth. Before trusting a changelog cross-reference about what shipped where, run `git diff -- ` — the "1.2.1 pickle shim" claim recurred twice from a changelog line describing a thing that never shipped. - Never pipe a check's output when its exit code matters. Under zsh, `snapshot.py | tail` makes `$?` tail's status. Redirect to a file and read the file. - Mutation-test a new guard before believing it, and mutate the thing the guard watches — a survivor usually means the fixture satisfies the invariant for free. A guard over a HAND COPY of a pipeline set has two such holes, and #744's review found both in one test of tools/vocab/build.py's check 2, which copies the tokenizer's sets because the tool cannot import the package it writes. Pinning a copy to its source sees only the classes someone copied: the first test pinned `DIVIDERS` alone, and emoji, which the tokenizer strips under `Policy.strip_emoji`, had no copy and no check, so `dr★` compiled and the test passed. Its replacement swept every codepoint `_tokenize._ignorable` drops but accepted any refusal short of a TOML error, so the space in `dr x` passed because the phrase-title check refused it, and a class check 2 never learned would pass too wherever a later check happened to refuse its test text. Drive the sweep from the pipeline's own predicate, match the refusal by the checked rule's own messages, and record the control (hiding the emoji check behind its pinned constant fails the sweep: `test_every_character_the_tokenizer_ignores_is_refused` in tests/v2/test_vocab.py, which now leaves the space out, a phrase's word separator). The predicate reaches only what it decides, though: the interpunct between East Asian characters (rules/T3) is divided by context in `_tokenize_region`, never by `_ignorable`, so hiding that check passes the sweep (measured in #746's review, 2026-10-19). What holds it is its `MUTATIONS` row (`text-with-an-east-asian-interpunct`, input `先·生`); the `EAST_ASIAN_RANGES` and `INTERPUNCT` pins hold only the copies, and stay green with the check gone. Name such a class where the guard stands, and the test that holds it, rather than let the sweep imply it. -- A claim about what a vocabulary entry DOES is a claim about the parse WITHOUT it, so take that parse (`Parser(lexicon=Lexicon.default().remove(titles={...}))`) and compare: the parse with the entry present shows only that the output is consistent with it. #773's first note on `wm` said that removing it would move `Wm. Smith`, read off the parse with the word listed; with the word removed, `Wm. Smith` reads exactly as before, rules/H2's leading-abbreviation title claiming `Wm.` either way, and only the bare `Wm Smith` moves (title `Wm` listed, given `Wm` removed). A shape rule can shadow an entry in one spelling and leave it load-bearing in another, so take the off-switch parse for each spelling, bare and period-marked. +- A claim about what a vocabulary entry DOES is a claim about the parse WITHOUT it, so take that parse (`Parser(lexicon=Lexicon.default().remove(titles={...}))`) and compare: the parse with the entry present shows only that the output is consistent with it. #773's first note on `wm` said that removing it would move `Wm. Smith`, read off the parse with the word listed; with the word removed, `Wm. Smith` reads exactly as before, rules/H2's leading-abbreviation title claiming `Wm.` either way, and only the bare `Wm Smith` moves (title `Wm` listed, given `Wm` removed). A shape rule can shadow an entry in one spelling and leave it load-bearing in another, so take the off-switch parse for each spelling, bare and period-marked, and in each position: the shape rule shadows only the slot it reads, and #789's removal of `wm` moved a trailing `Wm.` (rules/H5) and a `Wm.` before a family comma (rules/H6), which read vocabulary, where the first note had measured only the head of the name. - Verify the restore, not just the mutation: diff against the pre-mutation copy; do not trust the harness's own restore report. - Run all the gates, not the ones you remember: ruff runs before mypy and pytest in CI, and each has caught what the others passed. - Purge __pycache__ between same-length source mutations; stale bytecode makes a changed file measure as unchanged. diff --git a/docs/release_log.rst b/docs/release_log.rst index e14118d4a..3055f5b3f 100644 --- a/docs/release_log.rst +++ b/docs/release_log.rst @@ -19,6 +19,7 @@ Release Log - **Add Júnior as a suffix.** ``José Silva Júnior`` gives last ``Silva``, suffix ``Júnior``, as ``José Silva Junior`` does, where 1.4.0 through 2.5.0 gave middle ``Silva``, last ``Júnior``. ``Filho``, ``Neto`` and ``Sobrinho`` still read as the last name. :issue:`843` - **Read a semicolon between post-nominals as a comma.** ``John Smith, MD; PhD`` gives first ``John``, last ``Smith``, suffix ``MD; PhD``, where 1.4.0 through 2.5.0 gave first ``MD;``, last ``John Smith``. A delimiter set in ``extra_suffix_delimiters`` counts the same way when glued to a suffix word or written between two (``MD/PhD``), and a semicolon before the first comma (``John Smith MD; PhD``) is still read as part of a word. :issue:`871` - **Read a leading Md as the given name it abbreviates, Muhammad, rather than a title.** ``Mr Md Karim Uddin`` gives title ``Mr``, first ``Md``, middle ``Karim``, where 1.4.0 through 2.5.0 gave title ``Mr Md``, first ``Karim``; ``John Smith, MD Jones`` gives last ``Smith``, suffix ``MD Jones`` where it gave title ``MD``, last ``John Smith``. ``MD`` after a name is still the degree, and ``Md.`` with a full stop is still a title. One limit: ``Md`` opening the part after a family comma reads as a credential, so ``Uddin, Md Karim`` gives suffix ``Md Karim`` where it gave title ``Md``, first ``Karim``. :issue:`853` + - **Read Wm as the given name it abbreviates, William, rather than a title.** ``Wm Smith`` gives first ``Wm``, last ``Smith``, where 1.4.0 through 2.5.0 gave title ``Wm`` with no first name. ``Wm.`` with a full stop opening the name is still a title. :issue:`789` - **Fix a surname written as two dotted initials reading as a credential.** ``Ram Bahadur B.K.`` gives middle ``Bahadur``, last ``B.K.``, where 2.4.0 through 2.5.0 gave last ``Bahadur``, suffix ``B.K.``, restoring 2.3.0's reading, and ``Hari G.C.`` gives last ``G.C.``, where 2.0.0 through 2.5.0 gave suffix ``G.C.`` with no last name. Three or more dotted letters after a full name are still a credential (``John Smith X.Y.Z.``), and so is a listed one (``John Smith M.A.``). :issue:`864` * 2.5.0 - October 19, 2026 diff --git a/nameparser/config/_compiled.py b/nameparser/config/_compiled.py index b9937ab1d..35adb1501 100644 --- a/nameparser/config/_compiled.py +++ b/nameparser/config/_compiled.py @@ -773,7 +773,6 @@ 'warden', 'warrant', 'wing', - 'wm', 'wo-1', 'wo1', 'wo2', diff --git a/nameparser/vocab/README.md b/nameparser/vocab/README.md index 494f964d8..dd9703719 100644 --- a/nameparser/vocab/README.md +++ b/nameparser/vocab/README.md @@ -95,7 +95,7 @@ The build checks the order and never rewrites a file, because a comment above an ## Kinds -A reading's key is its **kind**. The table lists the kinds in their canonical order, which is the [word order](#word-order)'s first key and `CATEGORY`'s order in `tools/vocab/build.py`. Each kind belongs to one **category**, and the category decides which compiled set the reading feeds. For title, suffix, particle and conjunction the category's own name is also a kind (`title = {}`: a title not yet classified), so classifying a word later is a data edit that moves no compiled set. The one exception: a generic `suffix = {}` classified as `credential` moves from `SUFFIX_WORDS` to `SUFFIX_ACRONYMS`, because a credential's `acronym` is true unwritten; write `acronym = false` to keep it where it was. The suffix and particle categories are classified (two particles of unrecorded origin, `bon` and `dí`, keep the generic kind in `und.toml`); so are the titles (#750), but for `wm`, William's abbreviation, which keeps the generic kind in `en.toml`; the others carry their generic kind. +A reading's key is its **kind**. The table lists the kinds in their canonical order, which is the [word order](#word-order)'s first key and `CATEGORY`'s order in `tools/vocab/build.py`. Each kind belongs to one **category**, and the category decides which compiled set the reading feeds. For title, suffix, particle and conjunction the category's own name is also a kind (`title = {}`: a title not yet classified), so classifying a word later is a data edit that moves no compiled set. The one exception: a generic `suffix = {}` classified as `credential` moves from `SUFFIX_WORDS` to `SUFFIX_ACRONYMS`, because a credential's `acronym` is true unwritten; write `acronym = false` to keep it where it was. The suffix and particle categories are classified (two particles of unrecorded origin, `bon` and `dí`, keep the generic kind in `und.toml`); so are the titles (#750); the others carry their generic kind. | Kind | Category | Compiled into | |---|---|---| diff --git a/nameparser/vocab/en.toml b/nameparser/vocab/en.toml index fd6d17e82..afd6a7dcc 100644 --- a/nameparser/vocab/en.toml +++ b/nameparser/vocab/en.toml @@ -2,7 +2,7 @@ schema = 1 [[word]] text = "wm" -title = { issue = 68, note = "William, abbreviated, and no title of any kind: added for #68, where 'Wm. Scott Magargee III' read first name 'Wm.'; a bare 'Wm Smith' reads title Wm and no given name, while the dotted 'Wm.' is taken by the leading period-abbreviation shape rule whether listed or not" } +excluded = { title = { reason = "William, abbreviated, and no title of any kind: #68 asked that 'Wm. Scott Magargee III' not read given name 'Wm.', a request judged mistaken, since Wm is the given name; a bare 'WM' opened the given part 69 times in the FEC donor list on master, every one read as a title. The dotted 'Wm.' is still taken by the leading period-abbreviation shape rule whether listed or not", issue = 68, decided = 2026-10-22 } } [[word]] text = "goodman" diff --git a/tests/v2/cases.py b/tests/v2/cases.py index 5a2bd314f..1c1f64177 100644 --- a/tests/v2/cases.py +++ b/tests/v2/cases.py @@ -10807,6 +10807,28 @@ def _check_cjk_shape_purity(self) -> None: {"title": "Mr.", "given": "John", "family": "Smith"}, classification="fix(#316)"), + # -- #789: `wm` (William) is no title. Bare, it is the given name in + # every position; dotted, H2's shape still takes it at the head of + # the given part, and vocabulary no longer does anywhere else. + Case("wm_bare_is_the_given_name", "Wm Smith", + {"given": "Wm", "family": "Smith"}, + classification="fix(#789)", + notes="1.4.0 through 2.5.0 read title 'Wm' and no given name"), + Case("wm_bare_behind_a_title_is_the_given_name", "Dr. Wm Smith", + {"title": "Dr.", "given": "Wm", "family": "Smith"}, + classification="fix(#789)"), + Case("wm_dotted_opening_the_name_is_h2s_title", "Wm. Smith", + {"title": "Wm.", "family": "Smith"}, + notes="rules/H2's shape reads an unlisted abbreviation here, " + "listed or not; a given reading that outranks it is " + "phase 2's (#752), and this row should move with it"), + Case("wm_dotted_trailing_is_a_name_word", "John Smith Wm.", + {"given": "John", "middle": "Smith", "family": "Wm."}, + notes="H5 read a listed `wm` as a title here from 2.3.0 " + "through 2.5.0; unlisted, it is a name word again"), + Case("wm_dotted_trailing_after_a_family_comma", "Smith, John Wm.", + {"given": "John", "middle": "Wm.", "family": "Smith"}), + # -- #316(a): the trailing title RUN. The leading slot has a SHAPE # rule that outranks vocabulary (H2); the trailing slot has no # shape rule and reads vocabulary only. #316(b), the bare-safe From f9a9b6a9a348624835506c2e3f13ff586a31ab0b Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 24 Oct 2026 19:21:02 -0700 Subject: [PATCH 2/3] Correct the wm measurement in place, key the refusal to #789, and leave the dotted half open (#789 review) Co-Authored-By: Claude Opus 5.5 --- docs/design/decisions/vocabulary-model.md | 10 +++++----- docs/design/mechanisms.md | 2 +- nameparser/vocab/en.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/design/decisions/vocabulary-model.md b/docs/design/decisions/vocabulary-model.md index 7808f5b7d..b4e6781ae 100644 --- a/docs/design/decisions/vocabulary-model.md +++ b/docs/design/decisions/vocabulary-model.md @@ -32,7 +32,7 @@ The vocabulary was a set of base sets plus marker subsets (`particles` and `part Not standing: the plans the classifications carried out, phase 1's mechanical conversion of the unclassified categories into `und.toml` (2026-10-18 #737) and the shared readings left in place until their categories were classified (2026-10-19 #749), both done by 2026-10-20 #751, the conjunctions; and #747's reason for exempting `und.toml`, its entries keeping the Python lists' order for its vetting comments to point along (2026-10-19 #747), overtaken once it held two entries and no such comment. -Open: #752 (phase 2, derived ambiguity), #753 (phase 3, language packs), #754 (phase 4, order, shapes and the output model), #766 (whether `bon`, `dí` and three other words stay in the vocabulary). +Open: #752 (phase 2, derived ambiguity), #789 (whether the dotted `Wm.`, `Chas.`, `Geo.`, `Ma.` and `Jo.` opening the given part read given, outranking rules/H2's shape; phase 2's), #753 (phase 3, language packs), #754 (phase 4, order, shapes and the output model), #766 (whether `bon`, `dí` and three other words stay in the vocabulary). ## Log @@ -101,10 +101,10 @@ Open: #752 (phase 2, derived ambiguity), #753 (phase 3, language packs), #754 (p - **The title keep-outs became exclusions**, in the file of the language whose reading they refuse, with their counts as name readings where counts were taken (malam, bay, shehu): `uv run python tools/vocab/query.py --excluded title`. The per-word counts in decisions/salutation-titles moved onto the `note` of each word's title reading, and the prose points at the query. The reasons the given-addressing comments gave for leaving `lord`, `lady`, `venerable`, `rabbi` and `imam` out of GIVEN_NAME_TITLES are notes on those words in und.toml until their kinds are assigned (they moved with them in part 2, the same day). - **Recompute** rather than quoting: `uv run python tools/vocab/query.py --kind salutation --count`, `--kind title --file und --count` (the titles still in `und.toml`, all of them generic until part 2 emptied it the same day, leaving one generic title, `wm`, in en.toml; `--kind title` names the whole category, so no query counts the generic kind alone), `--excluded title`. -- **2026-10-19 #750 — the rest of the titles classified (part 2 of #750)** (its `wm` bullet superseded by 2026-10-22 #789). No compiled set moves: `tools/vocab/build.py --check` reports the committed module current, and `tools/differential/snapshot.py` matches. The 644 titles still generic in `und.toml` on e943665e took their kinds, all but `wm` (below), and left for the files of the languages whose names they occur in, so `und.toml` holds no title. Part 1's hard cases are applied as decided there: `lord`, `lady`, `knight` and `chief` are `nobility`, `deputy` an `office`, and `dr` and `prof` are in mul.toml. +- **2026-10-19 #750 — the rest of the titles classified (part 2 of #750)** (its `wm` decision superseded by 2026-10-22 #789, and its measurement corrected in place). No compiled set moves: `tools/vocab/build.py --check` reports the committed module current, and `tools/differential/snapshot.py` matches. The 644 titles still generic in `und.toml` on e943665e took their kinds, all but `wm` (below), and left for the files of the languages whose names they occur in, so `und.toml` holds no title. Part 1's hard cases are applied as decided there: `lord`, `lady`, `knight` and `chief` are `nobility`, `deputy` an `office`, and `dr` and `prof` are in mul.toml. - **English holds most of them**: the bulk import's occupations, the US military ranks and their abbreviations, the offices, and the modifiers. `modifier` takes what is a title only inside a phrase: the qualifiers of ranks and offices (`vice`, `rear`, `petty`, `field`), the domain words of the descriptive titles (`baseball`, `software`, `tax`), the ordinals, and the court words of #9's list of judges' titles (`designated`, `docket`, `pro`, `edmi`). - **Address, not subject, decides `academic`.** Besides the doctors and professors of every script, it takes the English words used to address a professional (`advocate`, `attorney`, `engineer`, `nurse`, and `md` as the medical degree written before a name), the German abbreviations written before a name (`ra`, Rechtsanwalt; `wp`, Wirtschaftsprüfer; `pd` and `priv.-doz`; `dipl.-ing`), and the Devanagari `पंडित` and `पं`, a scholar's title, as part 1's refusal of the Latin `pandit` already keyed it. - - **`wm` keeps the generic kind**, in en.toml: it is William's abbreviation, made a title for #68 so that `Wm. Scott Magargee III` would not read given `Wm.`, and no title kind describes it. Removing it moves a parse, though only of the bare spelling: `Wm Smith` reads title `Wm` with the word listed and given `Wm` without it, while the period-abbreviation shape rule takes `Wm.` either way (measured 2026-10-19 with `Lexicon.default().remove(titles={'wm'})`). So it is left to its own change. + - **`wm` keeps the generic kind**, in en.toml: it is William's abbreviation, made a title for #68 so that `Wm. Scott Magargee III` would not read given `Wm.`, and no title kind describes it. Removing it moves a parse, though only of the bare spelling: `Wm Smith` reads title `Wm` with the word listed and given `Wm` without it, while the period-abbreviation shape rule takes `Wm.` either way (measured 2026-10-19 with `Lexicon.default().remove(titles={'wm'})`). So it is left to its own change. (Corrected 2026-10-24, #789: the measurement was wrong on its date. It took the off-switch parse at the head of the name only; a trailing `Wm.`, rules/H5's since 2.3.0, and a `Wm.` before a family comma, rules/H6's since 2.5.0, read vocabulary and move with the bare spelling.) - **mul.toml** takes `docent`, `doctor` and `professor` beside `dr` and `prof`: full words spelled alike in several European languages, listed once rather than in a file per language. - **A transliteration goes to its source language**, as in part 1: the Islamic titles to ar.toml (`imam`, `mufti`, `mahdi`, `murshid`, `hajji`, `vizier`), or to fa.toml where the Latin spelling is the Persian form (`ayatollah`, `akhoond`, `mullah`, `pir`); `rabbi` to he.toml and `rebbe` to yi.toml; `maharajah`, `maharani` and `subedar` to hi.toml; `giani` and `gyani` to pa.toml; `tsar` and `tsarina` to ru.toml; `effendi` to tr.toml; `vardapet` to hy.toml. The Buddhist, Jain and Zoroastrian titles (`arhat`, `bodhisattva`, `buddha`, `siddha`, `tirthankar`, `saoshyant`) are in en.toml: no source-language name is written with these Latin spellings, which are English loanwords. Four files are new: bin (Edo, `edohen` and `ekegbian`), ff (Fula, `lamido`), mi (Māori, `rangatira`) and yi. - **Gender** follows part 1's rule. The man's title of a noble pair is marked (`count`, `baron`, `graf`) as `king` is, and so is a `-man` word whose `-woman` pair the list holds (`businessman`); a descriptive noun beside its `-ess` form marks only the feminine (`actress`, `heiress`). `sultan` records none, Ottoman usage having given it to imperial women too (its note in tr.toml). @@ -125,5 +125,5 @@ Open: #752 (phase 2, derived ambiguity), #753 (phase 3, language packs), #754 (p - **Recompute** rather than quoting: `uv run python tools/vocab/query.py --file und`, `--kind conjunction`, `--kind bound_given --file ar --count`, `--kind birth_marker`, `--excluded may_be_initial`, `--excluded birth_marker`. - **2026-10-22 #789 (Derek) — `wm` LEAVES THE TITLES.** SUPERSEDES: the `wm` bullet of 2026-10-19 #750, the rest of the titles. #68 asked that `Wm. Scott Magargee III` not read given name `Wm.`, and `wm` was listed as a title for it in 0.5.5. The request was mistaken: `Wm` is William written short, and a name it opens is a man named William, which a reader of the name would not hesitate over. The case came back from the FEC donor list (`tools/differential/local_corpora.py`, fec-individuals), where bare `WM` opened the given part of 69 names on 08d130ed, every one read as a title with the given name taken from the next word or left empty. The title reading is refused in en.toml with that reason, so a contributor who adds it back meets it as a build error. - - **The dotted spelling is split by position, not by spelling.** rules/H2's shape reads an unlisted period-marked abbreviation opening the given part as a title, so `Wm. Smith` keeps title 'Wm.' and `Smith, Wm.` too; making `Wm.`, `Chas.`, `Geo.`, `Ma.` or `Jo.` a given name there is a reading that outranks a shape rule, phase 2's question (#752, D14(b) of its spec), and tests/v2/cases.py pins today's `Wm. Smith` so that change shows. Where VOCABULARY reads the word, the dotted spelling moves with the bare one: a trailing `Wm.` was rules/H5's title (`John Smith Wm.` → family 'Wm.', `Smith, John Wm.` → middle 'Wm.', the readings of 1.4.0 through 2.2.0), and a `Wm.` opening the part before a family comma was rules/H6's (`Wm. Smith, John` → family 'Wm. Smith', the reading of 1.4.0 through 2.4.0). The 2026-10-19 bullet said removal moves only the bare spelling; it took the off-switch parse at the head of the name only. - - **Measured** against 08d130ed (`snapshot.py --local` with the base recorded by `--tree`): the committed corpora and the CLDR, GND and Wikidata agreement views do not move, nor do psc-individuals' field agreements. fec-individuals moves 77 of 1,893,964 names: 69 with bare `WM` opening the given part, 3 with bare `WM` behind another title in it, 3 with a trailing `WM.` and 2 with `WM.` before the family comma. ctgov-officials moves 1 of 352,104, `Wm` behind a title before a family comma. + - **The dotted spelling is split by position, not by spelling.** rules/H2's shape reads an unlisted period-marked abbreviation opening the given part as a title, so `Wm. Smith` keeps title 'Wm.' and `Smith, Wm.` too; making `Wm.`, `Chas.`, `Geo.`, `Ma.` or `Jo.` a given name there is a reading that outranks a shape rule, phase 2's question (#752, D14(b) of its spec), and tests/v2/cases.py pins today's `Wm. Smith` so that change shows. Where VOCABULARY reads the word, the dotted spelling moves with the bare one: a trailing `Wm.` was rules/H5's title (`John Smith Wm.` → family 'Wm.', `Smith, John Wm.` → middle 'Wm.', the readings of 1.4.0 through 2.2.0), and a `Wm.` opening the part before a family comma was rules/H6's (`Wm. Smith, John` → family 'Wm. Smith', the reading of 1.4.0 through 2.4.0). The 2026-10-19 bullet said removal moves only the bare spelling, and is corrected in place. + - **Measured** against 08d130ed (`snapshot.py --local` with the base recorded by `--tree`): no committed corpus holds the token `wm`, so the snapshot and the CLDR, GND and Wikidata agreement views could not move and did not; psc-individuals' field agreements do not move either. fec-individuals moves 77 of 1,893,964 names: 69 with bare `WM` opening the given part, 3 with bare `WM` behind another title in it, 3 with a trailing `WM.` and 2 with `WM.` before the family comma. ctgov-officials moves 1 of 352,104, `Wm` behind a title before a family comma. diff --git a/docs/design/mechanisms.md b/docs/design/mechanisms.md index ea727f942..7ec0e8741 100644 --- a/docs/design/mechanisms.md +++ b/docs/design/mechanisms.md @@ -430,7 +430,7 @@ A second axis cuts across the jobs: whether the names are real or invented, labe - Release notes describe intent; TAGS are ground truth. Before trusting a changelog cross-reference about what shipped where, run `git diff -- ` — the "1.2.1 pickle shim" claim recurred twice from a changelog line describing a thing that never shipped. - Never pipe a check's output when its exit code matters. Under zsh, `snapshot.py | tail` makes `$?` tail's status. Redirect to a file and read the file. - Mutation-test a new guard before believing it, and mutate the thing the guard watches — a survivor usually means the fixture satisfies the invariant for free. A guard over a HAND COPY of a pipeline set has two such holes, and #744's review found both in one test of tools/vocab/build.py's check 2, which copies the tokenizer's sets because the tool cannot import the package it writes. Pinning a copy to its source sees only the classes someone copied: the first test pinned `DIVIDERS` alone, and emoji, which the tokenizer strips under `Policy.strip_emoji`, had no copy and no check, so `dr★` compiled and the test passed. Its replacement swept every codepoint `_tokenize._ignorable` drops but accepted any refusal short of a TOML error, so the space in `dr x` passed because the phrase-title check refused it, and a class check 2 never learned would pass too wherever a later check happened to refuse its test text. Drive the sweep from the pipeline's own predicate, match the refusal by the checked rule's own messages, and record the control (hiding the emoji check behind its pinned constant fails the sweep: `test_every_character_the_tokenizer_ignores_is_refused` in tests/v2/test_vocab.py, which now leaves the space out, a phrase's word separator). The predicate reaches only what it decides, though: the interpunct between East Asian characters (rules/T3) is divided by context in `_tokenize_region`, never by `_ignorable`, so hiding that check passes the sweep (measured in #746's review, 2026-10-19). What holds it is its `MUTATIONS` row (`text-with-an-east-asian-interpunct`, input `先·生`); the `EAST_ASIAN_RANGES` and `INTERPUNCT` pins hold only the copies, and stay green with the check gone. Name such a class where the guard stands, and the test that holds it, rather than let the sweep imply it. -- A claim about what a vocabulary entry DOES is a claim about the parse WITHOUT it, so take that parse (`Parser(lexicon=Lexicon.default().remove(titles={...}))`) and compare: the parse with the entry present shows only that the output is consistent with it. #773's first note on `wm` said that removing it would move `Wm. Smith`, read off the parse with the word listed; with the word removed, `Wm. Smith` reads exactly as before, rules/H2's leading-abbreviation title claiming `Wm.` either way, and only the bare `Wm Smith` moves (title `Wm` listed, given `Wm` removed). A shape rule can shadow an entry in one spelling and leave it load-bearing in another, so take the off-switch parse for each spelling, bare and period-marked, and in each position: the shape rule shadows only the slot it reads, and #789's removal of `wm` moved a trailing `Wm.` (rules/H5) and a `Wm.` before a family comma (rules/H6), which read vocabulary, where the first note had measured only the head of the name. +- A claim about what a vocabulary entry DOES is a claim about the parse WITHOUT it, so take that parse (`Parser(lexicon=Lexicon.default().remove(titles={...}))`) and compare: the parse with the entry present shows only that the output is consistent with it. #773's first note on `wm` said that removing it would move `Wm. Smith`, read off the parse with the word listed; with the word removed, `Wm. Smith` reads exactly as before, rules/H2's leading-abbreviation title claiming `Wm.` either way. The corrected note then said only the bare `Wm Smith` moves, and that was wrong too (#789, 2026-10-24): it took the off-switch parse at the head of the name only, and a trailing `Wm.` (rules/H5) and a `Wm.` before a family comma (rules/H6), which read vocabulary rather than shape, moved as well. A shape rule shadows an entry only in the spelling and the slot it reads, so take the off-switch parse for each spelling, bare and period-marked, in each position a rule reads the word in. - Verify the restore, not just the mutation: diff against the pre-mutation copy; do not trust the harness's own restore report. - Run all the gates, not the ones you remember: ruff runs before mypy and pytest in CI, and each has caught what the others passed. - Purge __pycache__ between same-length source mutations; stale bytecode makes a changed file measure as unchanged. diff --git a/nameparser/vocab/en.toml b/nameparser/vocab/en.toml index afd6a7dcc..14b72d9cb 100644 --- a/nameparser/vocab/en.toml +++ b/nameparser/vocab/en.toml @@ -2,7 +2,7 @@ schema = 1 [[word]] text = "wm" -excluded = { title = { reason = "William, abbreviated, and no title of any kind: #68 asked that 'Wm. Scott Magargee III' not read given name 'Wm.', a request judged mistaken, since Wm is the given name; a bare 'WM' opened the given part 69 times in the FEC donor list on master, every one read as a title. The dotted 'Wm.' is still taken by the leading period-abbreviation shape rule whether listed or not", issue = 68, decided = 2026-10-22 } } +excluded = { title = { reason = "William, abbreviated, and no title of any kind: #68 asked that 'Wm. Scott Magargee III' not read given name 'Wm.', a request judged mistaken, since Wm is the given name; a bare 'WM' opened the given part 69 times in the FEC donor list on 08d130ed, every one read as a title. The dotted 'Wm.' opening the given part is still taken by the leading period-abbreviation shape rule whether listed or not", issue = [68, 789], decided = 2026-10-22 } } [[word]] text = "goodman" From 01c45e802b5cc42b9e3c4212f0cdfddb5a15b740 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 24 Oct 2026 19:22:02 -0700 Subject: [PATCH 3/3] Date the wm count as re-measured after the decision (#789 review) Co-Authored-By: Claude Opus 5.5 --- docs/design/decisions/vocabulary-model.md | 2 +- nameparser/vocab/en.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/design/decisions/vocabulary-model.md b/docs/design/decisions/vocabulary-model.md index b4e6781ae..cb78c0f33 100644 --- a/docs/design/decisions/vocabulary-model.md +++ b/docs/design/decisions/vocabulary-model.md @@ -124,6 +124,6 @@ Open: #752 (phase 2, derived ambiguity), #789 (whether the dotted `Wm.`, `Chas.` - **Two keep-outs became data that had been prose.** The Scandinavian abbreviation `f.`, which collides with the initial F., is an exclusion in da.toml. `roz`, removed from the birth markers on 2026-08-26, is an exclusion in cs.toml with its reason, measured again: with it listed, `Rosalind Roz Smith` reads maiden 'Smith' and takes Rosalind for the family, where the 2026-08-26 record says it left no family name at all. - **Recompute** rather than quoting: `uv run python tools/vocab/query.py --file und`, `--kind conjunction`, `--kind bound_given --file ar --count`, `--kind birth_marker`, `--excluded may_be_initial`, `--excluded birth_marker`. -- **2026-10-22 #789 (Derek) — `wm` LEAVES THE TITLES.** SUPERSEDES: the `wm` bullet of 2026-10-19 #750, the rest of the titles. #68 asked that `Wm. Scott Magargee III` not read given name `Wm.`, and `wm` was listed as a title for it in 0.5.5. The request was mistaken: `Wm` is William written short, and a name it opens is a man named William, which a reader of the name would not hesitate over. The case came back from the FEC donor list (`tools/differential/local_corpora.py`, fec-individuals), where bare `WM` opened the given part of 69 names on 08d130ed, every one read as a title with the given name taken from the next word or left empty. The title reading is refused in en.toml with that reason, so a contributor who adds it back meets it as a build error. +- **2026-10-22 #789 (Derek) — `wm` LEAVES THE TITLES.** SUPERSEDES: the `wm` bullet of 2026-10-19 #750, the rest of the titles. #68 asked that `Wm. Scott Magargee III` not read given name `Wm.`, and `wm` was listed as a title for it in 0.5.5. The request was mistaken: `Wm` is William written short, and a name it opens is a man named William, which a reader of the name would not hesitate over. The case came back from the FEC donor list (`tools/differential/local_corpora.py`, fec-individuals), where bare `WM` opened the given part of 69 names (re-measured 2026-10-24 on 08d130ed), every one read as a title with the given name taken from the next word or left empty. The title reading is refused in en.toml with that reason, so a contributor who adds it back meets it as a build error. - **The dotted spelling is split by position, not by spelling.** rules/H2's shape reads an unlisted period-marked abbreviation opening the given part as a title, so `Wm. Smith` keeps title 'Wm.' and `Smith, Wm.` too; making `Wm.`, `Chas.`, `Geo.`, `Ma.` or `Jo.` a given name there is a reading that outranks a shape rule, phase 2's question (#752, D14(b) of its spec), and tests/v2/cases.py pins today's `Wm. Smith` so that change shows. Where VOCABULARY reads the word, the dotted spelling moves with the bare one: a trailing `Wm.` was rules/H5's title (`John Smith Wm.` → family 'Wm.', `Smith, John Wm.` → middle 'Wm.', the readings of 1.4.0 through 2.2.0), and a `Wm.` opening the part before a family comma was rules/H6's (`Wm. Smith, John` → family 'Wm. Smith', the reading of 1.4.0 through 2.4.0). The 2026-10-19 bullet said removal moves only the bare spelling, and is corrected in place. - **Measured** against 08d130ed (`snapshot.py --local` with the base recorded by `--tree`): no committed corpus holds the token `wm`, so the snapshot and the CLDR, GND and Wikidata agreement views could not move and did not; psc-individuals' field agreements do not move either. fec-individuals moves 77 of 1,893,964 names: 69 with bare `WM` opening the given part, 3 with bare `WM` behind another title in it, 3 with a trailing `WM.` and 2 with `WM.` before the family comma. ctgov-officials moves 1 of 352,104, `Wm` behind a title before a family comma. diff --git a/nameparser/vocab/en.toml b/nameparser/vocab/en.toml index 14b72d9cb..d98298563 100644 --- a/nameparser/vocab/en.toml +++ b/nameparser/vocab/en.toml @@ -2,7 +2,7 @@ schema = 1 [[word]] text = "wm" -excluded = { title = { reason = "William, abbreviated, and no title of any kind: #68 asked that 'Wm. Scott Magargee III' not read given name 'Wm.', a request judged mistaken, since Wm is the given name; a bare 'WM' opened the given part 69 times in the FEC donor list on 08d130ed, every one read as a title. The dotted 'Wm.' opening the given part is still taken by the leading period-abbreviation shape rule whether listed or not", issue = [68, 789], decided = 2026-10-22 } } +excluded = { title = { reason = "William, abbreviated, and no title of any kind: #68 asked that 'Wm. Scott Magargee III' not read given name 'Wm.', a request judged mistaken, since Wm is the given name; a bare 'WM' opened the given part 69 times in the FEC donor list (re-measured 2026-10-24 on 08d130ed), every one read as a title. The dotted 'Wm.' opening the given part is still taken by the leading period-abbreviation shape rule whether listed or not", issue = [68, 789], decided = 2026-10-22 } } [[word]] text = "goodman"