Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions AGENTS.md

Large diffs are not rendered by default.

64 changes: 51 additions & 13 deletions docs/customize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,17 @@ Removing works the same way, and drops the word from recognition:
A few fields mark a subset of another — ``given_name_titles`` and
``after_given_titles`` over ``titles``, ``particles_ambiguous`` over ``particles``,
``suffix_acronyms_ambiguous`` over ``suffix_acronyms``,
``conjunctions_ambiguous`` over ``conjunctions``, and
``honorific_tails`` over ``suffix_words``. Entries belong in the base
field too, so add to both and remove from the marker first. Three of
them enforce that — ``particles_ambiguous``, ``suffix_acronyms_ambiguous``
and ``honorific_tails`` raise ``ValueError`` naming the orphans, because
an orphan in each of those does real harm rather than nothing. The
other three are deliberately unchecked because an orphan there is inert:
``conjunctions_ambiguous`` over ``conjunctions``,
``honorific_tails`` and ``suffix_words_ambiguous`` over
``suffix_words``, and ``agnomens`` over ``suffix_words_ambiguous``.
Entries belong in the base field too, so add to both and remove from
the marker first. Four of them enforce that — ``particles_ambiguous``,
``suffix_acronyms_ambiguous``, ``honorific_tails`` and
``suffix_words_ambiguous`` raise ``ValueError`` naming the orphans,
because an orphan in each of those does real harm rather than nothing.
The other four are deliberately unchecked because an orphan there is
inert, an ``agnomens`` entry being read only for a word
``suffix_words_ambiguous`` marks:
``given_name_titles`` matches a title run as one space-joined string, or
by that run's last word, so a legitimate entry like ``"sir and dame"``
is no single word in ``titles``; and a ``conjunctions_ambiguous`` or
Expand Down Expand Up @@ -303,12 +307,13 @@ Words that are also ordinary names

Some vocabulary words are also ordinary name words: an acronym suffix
that is also borne as a surname, a particle that doubles as a given
name, a connective letter that doubles as an initial. Three fields mark
them — ``suffix_acronyms_ambiguous``, ``particles_ambiguous`` and
``conjunctions_ambiguous``, one each for ``suffix_acronyms``,
``particles`` and ``conjunctions``. They add no vocabulary by
themselves; they narrow how an existing entry is read when it appears
alone, and the parse reports the fork as an ambiguity.
name, a connective letter that doubles as an initial. Four fields mark
them — ``suffix_acronyms_ambiguous``, ``suffix_words_ambiguous``,
``particles_ambiguous`` and ``conjunctions_ambiguous``, one each for
``suffix_acronyms``, ``suffix_words``, ``particles`` and
``conjunctions``. They add no vocabulary by themselves; they narrow how
an existing entry is read when it appears alone, and the parse reports
the fork as an ambiguity.

Credentials that are also surnames
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -348,6 +353,39 @@ The full reading of a bare marked acronym, in order:
- **In brackets**, ``"John Smith (BA)"`` falls through to nickname
parsing.

Generation words that are also surnames
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``suffix_words_ambiguous`` does the same for a suffix word: French
``fils`` and the Brazilian agnomens ``Filho``, ``Neto`` and
``Sobrinho`` mark a generation, and each is a surname too. An agnomen,
written in the case of the name around it and listed in ``agnomens``,
is a suffix only where the name keeps a word for its family. The
writing of ``fils`` speaks as well: in a mixed-case name a Title-case
``Fils`` is the family name even with a word to spare:

.. doctest::

>>> parse("Pedro Alves Neto").suffix
'Neto'
>>> parse("Ana Neto").family
'Neto'
>>> parse("Marie Fils").family
'Fils'

A caller whose data writes an agnomen as part of the surname takes it
out by removing the word from ``suffix_words`` and from the two
markers over it, together: an orphan in ``suffix_words_ambiguous``
raises ``ValueError``, and one left in ``agnomens`` is simply never read:

.. doctest::

>>> agnomen = {"neto"}
>>> kept = Lexicon.default().remove(
... agnomens=agnomen, suffix_words_ambiguous=agnomen, suffix_words=agnomen)
>>> Parser(lexicon=kept).parse("Pedro Alves Neto").family
'Neto'

Mark a word, or leave it out
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions docs/design/decisions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Entry conventions:
- [S8 — the credential's trailing run](S8-credentials-trailing-run.md)
- [S9 — unlisted words that join the ambiguous class by shape](S9-unlisted-words-that-join-the-ambiguous-class-by-shape.md)
- [S10 — the trailing roman numeral](S10-trailing-roman-numeral.md)
- [S11 — a suffix word that is also a name](S11-suffix-word-that-is-also-a-name.md)

## Nicknames & quoted names (N)

Expand Down
23 changes: 23 additions & 0 deletions docs/design/decisions/S11-suffix-word-that-is-also-a-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# S11 — a suffix word that is also a name

## Standing

- A generation word with a `given` or `family` reading is gated as a bare ambiguous acronym is: the generation where the name has words to spare, the name otherwise, either reading reported (`Pedro Alves Neto` → suffix 'Neto', `Ana Neto` → family 'Neto') — 2026-10-25 #752.
- The Brazilian agnomens (`filho`, `filha`, `neto`, `neta`, `netto`, `sobrinho`, `sobrinha`) are generation readings of the `agnomen` kind, gated by the count alone, their writing never leaning; `fils` is a `generation` reading whose lower case in a mixed-case name is the generation and whose Title case leans to the name (`Marie Fils` → family 'Fils') — 2026-10-25 #752.
- A suffix word that is also a name makes no chunk claim inside a word with interior periods, which reads by its dotted shape as it did before the word was listed: `Pedro M.Filho` keeps family 'M.Filho', and `Pedro Alves M.Filho` reads suffix 'M.Filho' as on master — 2026-10-25 #752.

- Only name words in front of a generation word that is also a name count toward its words to spare, and a suffix word there is no company for it: `Pedro Junior Filho` and `Pedro VI Filho` keep family 'Filho' — 2026-10-25 (Derek), #890.

- The floor holds before a generation word's case: a lower-case `fils` in a mixed-case name is the generation only where the name keeps a family word, so `Dumas fils` and `Pedro Junior fils` read family 'fils' — 2026-10-25 (Derek), #890, THE FLOOR.

Open: none in this file; #843 keeps the agnomens' abbreviations (`FH`, `FO`, `NT`, `SB`).

## Log

- 2026-10-25 #752 (its ACCEPTED suffix word in front of an agnomen superseded by 2026-10-25 (Derek), #890) — A GENERATION WORD THAT IS ALSO A NAME IS GATED BY THE COUNT, AND ITS KIND SAYS WHAT ITS WRITING MEANS. Carries out the generation half of the 2026-10-23 #752 entry in decisions/vocabulary-model (phase 2h), replacing decisions/generational-words' 2026-10-23 #843 decision to keep the agnomens family names. An agnomen is no part of the surname a family shares: it marks its bearer against a relative of the same name, as Júnior does, so it ends the name the way a generation does. But each one is a borne name as well, `Neto` a surname (US Census 1,645, Wikidata 276+) and a given name (Wikidata 12+), `Neta` a given name (US SSA 3,226 female births, mostly the Hebrew Neta), `Filho` and `Netto` surnames, counts from `tools/name_usage.py` on 2026-10-25 recorded on the words in `pt.toml` and `pt-BR.toml`, and a plain generation reading leaves a two-word name with no family name. So the reading is gated as an ambiguous acronym is, by the words to spare (rules/S4's count), through the same sites. Case is a cue for a generation word and none for an agnomen: French writes `Alexandre Dumas fils` with the generation in lower case and `Marie Fils` with her surname in Title case, where an agnomen is written in the case of the name around it (`Pedro Alves Neto`, `PEDRO ALVES NETO`). Capitals say nothing for either, a surname being often written in them. The kind carries the difference: an `agnomen` reading and a `generation` reading each beside a name reading derive `SUFFIX_WORDS_AMBIGUOUS`, and the agnomen kind `AGNOMENS` inside it.
WHY THE COUNT ALONE FOR THE AGNOMENS, MEASURED. The only spike run before the design was agreed carried S6's Title-case lean, which kept 98 mixed-case ctgov agnomens as names and moved nothing in PSC. The count-only reading was measured on origin/master 225f3d6f against that tree (`--base`, counts and shapes only; Python 3.11): PSC 23 records fixed, 20 broken, 8 changed, every one of them a name of three words or more, so no two-word name moves. The 23 fixed: the filer typed both surnames, the second the agnomen, in the surname box; the 20 broken: the filer typed only the agnomen as the surname, the surname before it in the middle box. Filers split on where the agnomen's companion goes, and the reading follows the larger half. Shown these figures, Derek decided on 2026-10-25: "keep the count-only agnomen gate". The committed corpora move 4 names: `Pedro Alves Filho` gains the agnomen as the suffix, `Marie Fils` gains a report, and CLDR's French sample and its family-first twin gain `fils` as the suffix (cldr_agreement: 4 fields newly agreeing, 1 still wrong but changed). tse-donors: 21,059 of 848,351 filed names move, all of them in capitals, 12,811 where the agnomen had been the whole family name and the word before it now is, 8,198 where the family held more, and 45 a report only; FEC 12, reports only; ctgov 110 entries, 4 a report only, most of the rest the agnomen joining the credentials after a comma (`Neto, MD`, as `Júnior, MD` reads). The spelling pairs: of the 405 tse filed/registry pairs that differ only by a trailing agnomen, master gives both spellings the same last family word in 1, the gate in all 405; over all 205,925 differing pairs, compared given and family word by word with accents folded and an initial matching its word, 604 go from apart to alike and 258 from alike to apart, against the lean spike's 604 and 304. The 258 are mostly pairs master read alike only because the agnomen was the family name in both spellings, and the 46 fewer are the ones the lean's case cue moved.
ACCEPTED. A word standing straight before the agnomen counts as a name word, as before an ambiguous acronym: an initial there is left as the family name (`Pedro J. Neto` → family 'J.', 568 tse names, the initial most often abbreviating the surname), a particle as a family name of its own (`Pedro de Neto` → family 'de', one tse name), and a given name that is a generation word (`PEDRO JUNIOR FILHO`) or dotted initials (`PEDRO C.M. FILHO`) join the agnomen in a suffix run that leaves no family name (5 tse names). A three-word name whose surname is an agnomen spelling loses it to the suffix, reported (`Ruth Ann Neta`). The particle chain's report on a member it takes into the name reaches an agnomen inside a name, `PEDRO DE JESUS NETO DE SOUSA` reading as before with a report, as `PEDRO DE JESUS MA DE SOUSA` does.
NOT DONE. The filed abbreviations of the agnomens read as the family name, where the registry spelling of the same donor now reads the agnomen as the suffix, so those pairs stay apart: `FH` 229, `NT` 119, `FO` 99, `SOBR` 19, `FILH` 16, `F` 15, `NET` 12, `SB` 11 pairs and fewer of others. Listing them is #843's, short capitals meeting initials and credentials.
Recompute: `uv run python tools/differential/snapshot.py --local tse-donors --base <checkout of this commit's parent>` (and `ctgov-officials`, `fec-individuals`), `uv run python tools/differential/local_agreement.py psc-individuals --base <the same checkout>`; the pair counts read tse-donors' records through `tools/differential/local_corpora.py` (`require("tse-donors")`, `read_records(..., text_only=True)`), keep the 205,925 whose filed `name` and `registry` differ, and parse both spellings in each tree, run from that tree's checkout; a pair is alike when its given names and its family names match word by word, each word folded (NFD, combining marks dropped, upper case, edge periods stripped) and a one-letter word matching any word it begins. The 405 are the pairs whose longer spelling, split on spaces in upper case, is the shorter one plus one trailing agnomen, compared on the family's last word. `local_corpora.py pairs tse-donors --agreement` reports in whole percents, which do not move for these counts.
- 2026-10-25 (Derek), #890 (its accepted lower-case `fils` superseded by 2026-10-25 (Derek), #890, THE FLOOR) — A SUFFIX WORD IN FRONT OF AN AGNOMEN IS NO WORD TO SPARE. SUPERSEDES: the ACCEPTED sentence of 2026-10-25 #752 on a generation word or dotted initials in front of an agnomen. Derek approved the fix before merge, on the language-packs session's finding: the entry above accepted that a generation word or credential straight before an agnomen joined it in the suffix, leaving no family name, as a cost of 5 tse names, but that count was of capitals only, and the shape is ordinary in mixed case (`Pedro Junior Filho`, `Pedro Júnior Neto`, `Pedro Jr. Filho`, each read with no family name). One word was counted twice: the count took `Junior` as the agnomen's word to spare and the peel then took `Junior` as a suffix; and an unambiguous suffix word in front made the agnomen a credential by rules/S7's company. A generation word that is also a name now counts only the name words in front of it, skipping what the trailing run takes there (a suffix word, a numeral of two or more letters read as the generation, which the review of the fix found still counted in `Pedro VI Filho`, a member of the ambiguous class its writing makes a suffix, `Pedro MA Filho`, and a bare member any of those carries in front of it, `Pedro Junior Ma Filho` and `Pedro Junior do Filho`, the second review's), and keeps no company, so `Pedro Junior Filho` reads given 'Pedro', middle 'Junior', family 'Filho' as master did, while `Pedro Alves Junior Filho` still reads suffix 'Junior Filho'; dotted initials in front read as master did too (`PEDRO C.M. FILHO` → middle 'C.M.', family 'FILHO'), and so does a credential (`Pedro PhD Neto` → family 'Neto'). The count asks a scan that stops at the first word the walk keeps, not the walk itself: asking the walk over the words in front was tried and is exponential on a run of agnomens, quadratic when memoized, and the scaling guard (`agnomens`, `carried_agnomens` in tests/v2/test_benchmark.py) refuses both. The lower-case `fils` of a mixed-case name is settled by its case and not the count, so `Pedro Junior fils` still reads suffix 'Junior fils' (rules/S11's Accepted).
- 2026-10-25 (Derek), #890, THE FLOOR — A NAME KEEPS ITS FAMILY WORD BEFORE A GENERATION WORD'S CASE IS READ. SUPERSEDES: the lower-case `fils` sentence of 2026-10-25 (Derek), #890, and the 2026-10-25 #752 entry's reading of `Dumas fils`. Derek: "apply the floor to fils too". In the gate the agreed design orders (decisions/vocabulary-model, 2026-10-23 #752), the floor, a name keeping a word to address, is the first step and the form cue the second, so case may settle a generation word against the name only where the floor already holds. A lower-case `fils` in a mixed-case name had been taken with no word to spare, as an acronym's capitals are, so `Dumas fils` read given 'Dumas' with no family name and `Pedro Junior fils` suffix 'Junior fils'. Both now read family 'fils', as master did; `Alexandre Dumas fils` and `Pedro Alves Junior fils` keep the suffix, `Marie Fils` her family name, and after a comma, where a family is already named, lower case still settles it (`Dumas, Alexandre fils` → suffix 'fils'). The same holds after a comma with no name before it, the review of the fix found: `, Dr. fils` and `(Pe), Dr. fils` had read suffix 'fils' with no family, the comma decision taking the lower case where no family is named, and read family 'fils' now, as master did; and its second review found the head's name-word count too generous for this, a joined salutation (`Mr. and Mrs., fils`) and a lone name word behind a given-name title (`Sir Alexandre, fils`) counting one where no family remains, so at the first slot after a comma a generation word's lower case adds nothing to rules/C4's count, which reads two name words before the comma first: `Dumas, fils` reads given 'fils', family 'Dumas', as master did, and `Alexandre Dumas, fils` suffix 'fils'. An acronym keeps its capitals' lean with no word to spare (rules/S6, `Jack MA`); an agnomen has no case to weigh, so no other gated word changes. Measured with `--base` against master 225f3d6f: no corpus name moves against the commit before.
2 changes: 2 additions & 0 deletions docs/design/decisions/S6-case-signal-at-the-suffix-slot.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- `Freiherr von Berg MA` reads family 'von Berg', suffix 'MA', the lean ending P2's chain with no words to spare — 2026-09-15 (Derek).
- The whole-PR review's five readings stand: an acronym the particle chain absorbs reports `suffix-or-name` (`John van der Berg Ma`); the CJK stage asks the post-comma run with the one-case fact; a by-shape credential in a tail segment raises no `comma-structure`; a word a caller lists as a surname is never caps-shaped; and a dotted listed member takes the lean — 2026-09-18, WHOLE-PR REVIEW ROUND.

Elsewhere: the case a generation word that is also a name reads (rules/S6's bullet on it) is decisions/S11's 2026-10-25 #752 entry.

Open: none in this file.

## Log
Expand Down
2 changes: 2 additions & 0 deletions docs/design/decisions/T5-written-shape-of-an-initial.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- The written shape of an initial is its own rule, split from T4, which keeps the case contrast; the shape itself was decided in v1, narrowed to scripts that write initials by #320 (decisions/initials-repertoire) and asked of the composed spelling since #665 (decisions/nfd-shapes) — 2026-10-19.

Elsewhere: the one-letter generations recorded off by default (rules/T5's Accepted bullet on them) is decisions/vocabulary-model's 2026-10-25 #752, phase 2h entry.

Open: none in this file.

## Log
Expand Down
Loading
Loading