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
14 changes: 12 additions & 2 deletions docs/customize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -996,8 +996,18 @@ family name, are mostly that shape. Portuguese and Brazilian names
carry two family names too, the mother's first, but the people who
write them often give the last one alone as their family name: among
the UK company register's 5,333 Portuguese filers the switch breaks
1,481 names and mends 1,221 (measured 2026-10-24). The parser reports nothing for the names the switch
moves: the shape it reads is the same either way.
1,481 names and mends 1,221 (measured 2026-10-24), while among ORCID's
researchers working or living in Portugal, who split their own names
into its boxes, it mends 4,295 and breaks 2,034 of 20,000 (measured
2026-10-27): the two populations disagree, so measure the data you have
before switching it on. Filipino names often carry a middle name
between the given name and the family name, traditionally the mother's
maiden surname, and their bearers count it with their given names:
``"Maria Santos Reyes"`` has family ``Reyes``, which the switch reads
as ``Santos Reyes``. Among ORCID's researchers in the Philippines it
breaks 8,234 names of 20,000 and mends 265. The parser
reports nothing for the names the switch moves: the shape it reads is
the same either way.

.. _east-asian-defaults:

Expand Down
19 changes: 19 additions & 0 deletions docs/design/decisions/O6-two-family-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@

Among Spanish filers it fixes names of four name words 1,480 to 162 and of three 2,325 to 732, counted by the default reading's given, middle and family words. Of the records it breaks, 889 of 902 Spanish and 1,331 of 1,481 Portuguese filed a one-word surname. In the GND and Wikidata fielded corpora, the given-first renderings of the Spanish and Latin American double-surname strata (GND `compound-iberia` and `compound-latam`, Wikidata `surname2-es`, `-mx` and `-co`) disagree with the source on 315 of 390 by default, the RFC's count, and on 17 with the switch: 298 fixed, none broken; their index-form renderings disagree on none either way. The same switch over every other given-first rendering breaks 43 of GND's 408 and 141 of Wikidata's 250, and in the native-script Wikidata corpus moves 31 three- and four-word Arabic, Cyrillic, Bengali and Devanagari names, 11 to agreeing and 20 away. Recompute: for PSC, `local_agreement.read` per record under `Parser()` and under `Parser(policy=Policy(two_family_names=True))`, grouped by `group_of`, skipping records set aside on either side; for the fielded corpora, `cldr_agreement.disagreements` over the renderings with `shape` None, once with `_PARSERS[None]` as shipped and once set to the switched parser (clearing `_parser`'s cache), split by `label` and `order`. The comparator is the default parser on the same tree.
- 2026-10-27 #752 (Derek) — THE SWITCH SURFACES NO ALTERNATIVE: the reading it did not take is not reported, as the 2026-10-24 #754 entry's No report bullet left for #752 to answer. Phase 2m surfaces the reading not taken as `Ambiguity.alternative`, which rides on a report, so a switch that reports nothing carries none. The caller turned the convention on, which is the declaration that settles the fork, as a declared order settles field order without a report; a report on most names of three words or more would still teach the caller to ignore the field.
- 2026-10-27 #754 — MEASURED ON NAMES THE BEARERS SPLIT: ORCID's researchers (`local_agreement.py orcid-researchers`, the local corpus #927 added) typed their own given-names and family-name boxes, so a reading of the switch there is scored against the person, at a scale PSC holds only for Spain (20,000 records a country where PSC held 116 Peruvian filers). The switch is the convention most Spanish-speaking countries write: in the six below other than Argentina, agreement rises under it to between 85.6% and 93.7%, each fixing at least eight records for every one it breaks (a ratio of these six, not of every Spanish-speaking country: Uruguay's is 7 to 1). Where the convention is not written it breaks names, most of them filed with a one-word family box, and nearly all outside Brazil (1,922 of Brazil's 2,267). Argentina repeats PSC's finding. The Philippines is a population PSC barely held: Filipino names often carry a middle name between the given name and the family name, traditionally the mother's maiden surname, and the holders file it with their given names (8,024 of the 8,234 records the switch breaks hold a one-word family box; `Maria Santos Reyes` reads family `Reyes` by default, `Santos Reyes` with the switch). Portugal reads the other way from PSC's Portuguese filers, the switch mending more than it breaks among researchers working or living there; the populations differ in more than who wrote the names (nationality against country of work, company owners against researchers), so this is consistent with the docs' point that the result depends on who wrote the name down rather than a measure of it. All boxes agreeing before → after, records fixed and broken, and the broken records whose family box holds one word; a country is where the holder works or lives:

| Country | Records | Before → after | Fixed | Broken | Broken, one-word family |
|---|---:|---|---:|---:|---:|
| PE | 20,000 | 13.4% → 93.7% | 16,385 | 324 | 321 |
| CO | 20,000 | 23.6% → 91.7% | 14,413 | 789 | 780 |
| MX | 20,000 | 31.3% → 91.9% | 12,655 | 539 | 528 |
| VE | 20,000 | 37.4% → 85.6% | 10,871 | 1,230 | 1,215 |
| CL | 20,000 | 45.8% → 92.2% | 9,976 | 700 | 685 |
| ES | 20,000 | 48.0% → 91.5% | 9,353 | 649 | 626 |
| BR | 20,000 | 47.3% → 71.0% | 6,999 | 2,267 | 1,922 |
| PT | 20,000 | 70.0% → 81.3% | 4,295 | 2,034 | 1,975 |
| AR | 20,000 | 80.3% → 59.7% | 3,069 | 7,204 | 7,056 |
| IN | 20,000 | 73.0% → 64.5% | 582 | 2,268 | 2,265 |
| US | 20,000 | 90.8% → 88.3% | 620 | 1,109 | 1,102 |
| GB | 20,000 | 95.2% → 90.7% | 592 | 1,494 | 1,477 |
| PH | 20,000 | 94.7% → 54.9% | 265 | 8,234 | 8,024 |

Measured on master at 598167f4 over the 2025 Public Data File's extract fetched 2026-10-27. Recompute: `local_agreement.read` per record of `local_corpora.load("orcid-researchers")` with `FIELDED["orcid-researchers"]`, under `Parser()` and under `Parser(policy=Policy(two_family_names=True))` with `_title_words` of the default lexicon, grouped by the record's `country`; a record is fixed where it agrees only with the switch, broken where it agrees only without it, and the last column counts the broken records whose `family` box holds one word. A corpus capped at 20,000 records a country shows each country's convention, not how many people write it.
4 changes: 2 additions & 2 deletions docs/design/mechanisms.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,9 @@ print(len(MAIDEN_MARKERS), 'members ->', len(cls), 'structural classes')"

**Contract statement.** A name source does one or more of five jobs — WATCH, SCORE, COUNT, DERIVE and SURVEY — and the job decides where its data lives. Only WATCH and SCORE in CI need the names in the repository, so a source whose names cannot be committed still does COUNT and SURVEY, WATCH and SCORE outside CI, and DERIVE where its terms let a derived list ship.

**How it works.** WATCH asks whether a change moved a name: a committed corpus, `snapshot.jsonl` and a test that fails, or a local corpus read with `snapshot.py --local`, which no CI run sees. SCORE asks whether the parser agrees with someone who knows the fields: a committed fields file and agreement record, read by `cldr_agreement.py` from the repository alone, or a local corpus whose records carry the fields their filers typed, with its record kept in the cache beside it (`local_agreement.py`). The local score tells a change's author what moved among real filed names, by field, and gives agreement by group and how often each disagreement shape occurs. It cannot guard anything: no CI run and no reviewer sees it, and no test fails when it moves (the tool itself exits 1). Its truth is the filer's, so a box filled wrongly (a job typed as a title) reads as a miss unless the scorer sets it aside, and the scorer has to say what it sets aside. COUNT asks how one word is used: a cached source behind a row of `tools/name_usage.py`, with only the counts cited. DERIVE asks what a shipped list should hold: a cached source and a script writing the vocabulary (`tools/zh_surnames.py`). SURVEY asks how people write whole names, and how OFTEN they write each shape: a cached local corpus (`tools/differential/local_corpora.py`).
**How it works.** WATCH asks whether a change moved a name: a committed corpus, `snapshot.jsonl` and a test that fails, or a local corpus read with `snapshot.py --local`, which no CI run sees. SCORE asks whether the parser agrees with someone who knows the fields: a committed fields file and agreement record, read by `cldr_agreement.py` from the repository alone, or a local corpus whose records carry the fields their filers, or the bearers themselves, typed, with its record kept in the cache beside it (`local_agreement.py`). The local score tells a change's author what moved among real filed names, by field, and gives agreement by group and how often each disagreement shape occurs. It cannot guard anything: no CI run and no reviewer sees it, and no test fails when it moves (the tool itself exits 1). Its truth is the filer's, so a box filled wrongly (a job typed as a title) reads as a miss unless the scorer sets it aside, and the scorer has to say what it sets aside; where the bearer typed the boxes, a miss is a disagreement with the person, though one who typed a family-first name into the given box reads as a miss too. COUNT asks how one word is used: a cached source behind a row of `tools/name_usage.py`, with only the counts cited. DERIVE asks what a shipped list should hold: a cached source and a script writing the vocabulary (`tools/zh_surnames.py`). SURVEY asks how people write whole names, and how OFTEN they write each shape: a cached local corpus (`tools/differential/local_corpora.py`).

A second axis cuts across the jobs: whether the names are real or invented, labelled with fields or bare text, chosen or unselected. Every committed corpus is CHOSEN: invented to fill fields (CLDR, the conventions table, the rules examples), cataloged (GND), filtered to names whose every word aligns with a stated part (both Wikidata corpora, a filter that drops credentials and typos), or picked by someone testing or reporting a case (v1's test names in `corpus.jsonl`, the case-table rows in `corpus_cjk.jsonl` and `corpus_shapes.jsonl`, and the strings reporters typed into `corpus_issues.jsonl`). The last group does hold hand-typed shapes — a job title in the name (`Bob Jones, author`), a credential before the comma (`Washington Jr. MD, Franklin`) — but one instance of each, as chosen. What SURVEY adds is the unselected population and its frequencies: ClinicalTrials.gov's study officials (local corpus `ctgov-officials`, measured 2026-10-21) are typed into a free-text field by sponsors' staff, so they show how often each shape occurs, and hold some no committed corpus does, such as `MBBS,FCPS` with no space. The FEC's individual contributors (local corpus `fec-individuals`, measured 2026-10-22) are unselected too, but mostly a filer's software writing a form's fields in a fixed order, so nearly all of its 1.89 million names share one shape (capitals, family, comma, given) and the hand-typed part is what goes inside the fields (a credential run or a suffix after a second comma): the population for that shape's variants, and blind to case. The UK Electoral Commission's individual donors (local corpus `ukec-individuals`, measured 2026-10-22) are the opposite shape: names as a donee's return gave them, mixed case and in spoken order, `parse()` reading a title in 8,219 of 15,214 (`Mr`, `Lord`, `Sir`) and only 2 holding a comma. Brazil's individual donors to candidates (local corpus `tse-donors`, measured 2026-10-22) are the FEC's comma-less counterpart: 848,351 filed names, nearly all in capitals and in spoken order, full of particles and agnomens (`DE`, `DA`, `DOS`; `FILHO`, `NETO`, `JUNIOR`), each beside the tax registry's name for the same donor, so a typed form can be read against its reference form (205,925 of 854,531 pairs differ). A source that pairs two spellings of one person scores without fields: the parse of each spelling should find the same surname, so where the spellings differ only in what cannot move a surname (accents, case), a disagreement is the parser reading one name two ways, found with no one labelling either (`local_corpora.py pairs --agreement`; on `tse-donors` on 2026-10-22, 1,304 of 43,552 accents-only pairs, 1,121 of them from `JÚNIOR`/`JUNIOR` and `SÁ`/`SA`). Read it per shape: a pair that leaves a word out can change the surname for real. JRC-Names (local corpus `jrc-names`, measured 2026-10-24) widens the pair to a group: one person's spellings harvested from news text across scripts, 218,822 persons with two or more. Words in two scripts cannot be compared, so `local_corpora.py groups` compares the readings' structure instead (title, suffix, given, family, the family's length and where it stands), counting persons. Read it per pair of scripts, since a structure can differ by convention: a script read family first stands its family elsewhere, and a writing variant moves the reading for real (the Arabic comma, katakana with and without `・`). Companies House's people with significant control (local corpus `psc-individuals`, measured 2026-10-22) are unselected and labelled at once: each filer types the name into four boxes (title, forename, middle name, surname) and states a nationality, so the corpus is the one real population a local SCORE reads by nationality. It is filed through a form's boxes, so it holds almost no comma (838 of 1,040,708 sampled records) or credential. One source may do several jobs, each through its own code: Wikidata does COUNT live and WATCH and SCORE through its builders. A live source has no fixed file to pin, so its cached copy is the pin, carrying the source's own data date and a sha256 checked on every load (a truncated file otherwise reads as a run of false zeros, #775).
A second axis cuts across the jobs: whether the names are real or invented, labelled with fields or bare text, chosen or unselected. Every committed corpus is CHOSEN: invented to fill fields (CLDR, the conventions table, the rules examples), cataloged (GND), filtered to names whose every word aligns with a stated part (both Wikidata corpora, a filter that drops credentials and typos), or picked by someone testing or reporting a case (v1's test names in `corpus.jsonl`, the case-table rows in `corpus_cjk.jsonl` and `corpus_shapes.jsonl`, and the strings reporters typed into `corpus_issues.jsonl`). The last group does hold hand-typed shapes — a job title in the name (`Bob Jones, author`), a credential before the comma (`Washington Jr. MD, Franklin`) — but one instance of each, as chosen. What SURVEY adds is the unselected population and its frequencies: ClinicalTrials.gov's study officials (local corpus `ctgov-officials`, measured 2026-10-21) are typed into a free-text field by sponsors' staff, so they show how often each shape occurs, and hold some no committed corpus does, such as `MBBS,FCPS` with no space. The FEC's individual contributors (local corpus `fec-individuals`, measured 2026-10-22) are unselected too, but mostly a filer's software writing a form's fields in a fixed order, so nearly all of its 1.89 million names share one shape (capitals, family, comma, given) and the hand-typed part is what goes inside the fields (a credential run or a suffix after a second comma): the population for that shape's variants, and blind to case. The UK Electoral Commission's individual donors (local corpus `ukec-individuals`, measured 2026-10-22) are the opposite shape: names as a donee's return gave them, mixed case and in spoken order, `parse()` reading a title in 8,219 of 15,214 (`Mr`, `Lord`, `Sir`) and only 2 holding a comma. Brazil's individual donors to candidates (local corpus `tse-donors`, measured 2026-10-22) are the FEC's comma-less counterpart: 848,351 filed names, nearly all in capitals and in spoken order, full of particles and agnomens (`DE`, `DA`, `DOS`; `FILHO`, `NETO`, `JUNIOR`), each beside the tax registry's name for the same donor, so a typed form can be read against its reference form (205,925 of 854,531 pairs differ). A source that pairs two spellings of one person scores without fields: the parse of each spelling should find the same surname, so where the spellings differ only in what cannot move a surname (accents, case), a disagreement is the parser reading one name two ways, found with no one labelling either (`local_corpora.py pairs --agreement`; on `tse-donors` on 2026-10-22, 1,304 of 43,552 accents-only pairs, 1,121 of them from `JÚNIOR`/`JUNIOR` and `SÁ`/`SA`). Read it per shape: a pair that leaves a word out can change the surname for real. JRC-Names (local corpus `jrc-names`, measured 2026-10-24) widens the pair to a group: one person's spellings harvested from news text across scripts, 218,822 persons with two or more. Words in two scripts cannot be compared, so `local_corpora.py groups` compares the readings' structure instead (title, suffix, given, family, the family's length and where it stands), counting persons. Read it per pair of scripts, since a structure can differ by convention: a script read family first stands its family elsewhere, and a writing variant moves the reading for real (the Arabic comma, katakana with and without `・`). Companies House's people with significant control (local corpus `psc-individuals`, measured 2026-10-22) are unselected and labelled at once: each filer types the name into four boxes (title, forename, middle name, surname) and states a nationality, so the corpus is the one real population a local SCORE reads by nationality. It is filed through a form's boxes, so it holds almost no comma (838 of 1,040,708 sampled records) or credential. ORCID's researchers (local corpus `orcid-researchers`, measured 2026-10-27) are labelled by the bearer rather than a filer: each holder typed their own name into two boxes (given names, family name), from 250 countries. Two things keep it from being a SURVEY. It keeps at most 20,000 records a country, so it shows which shapes each country holds and how the parser reads them, never how often a shape occurs across countries. And its country is where a holder works or lives, most often taken from an employment, so a country's row is its institutions' researchers, not its nationals. It is the SCORE to read for a language pack: 80.5% of its 1,831,533 records agreed on every field, as few as 13.4% in Peru, and the other 17 countries of at least 1,000 records under half were Brazil and 16 Spanish-speaking ones (Argentina read 80.3%); in the two commonest disagreement shapes, 249,526 of the 357,517 records that disagreed, a two-word family box was read as one word (measured on master at 598167f4). One source may do several jobs, each through its own code: Wikidata does COUNT live and WATCH and SCORE through its builders. A live source has no fixed file to pin, so its cached copy is the pin, carrying the source's own data date and a sha256 checked on every load (a truncated file otherwise reads as a run of false zeros, #775).

**Reach for it when.** A source is proposed, before choosing between a builder and a tool column; and when a corpus would hold real people's names nobody vetted for publication, which is the case for a local corpus rather than a committed one.

Expand Down
Loading