Skip to content

Gate the suggester's trailing-initial vote on the group's share; fix a title-only name's crash - #1345

Merged
derek73 merged 4 commits into
masterfrom
fix/suggest-trailing-initial-share
Nov 12, 2026
Merged

derek73 merged 4 commits into
masterfrom
fix/suggest-trailing-initial-share

Conversation

@derek73

@derek73 derek73 commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

Two fixes to Parser.suggest (unreleased, 3.1), the first of three PRs implementing the #1254 decision (its decision comment is on the issue).

A title-only name no longer raises

Parser().suggest(["Dr."]) raised IndexError. So did any group holding a name that is nothing but titles: Professor, Chief Physician, and Jr., which rules/H2's shape reads as a title at the head. The cause: once the leading titles are read past, _ends_in_post_nominal read words[-1] before asking whether any word was left. test_no_signal_raises and a new group-level test now sweep 32 inputs: empty and blank text, title-only, post-nominals only, a nickname clause only, punctuation only, one letter. 14 rows fail on the merge base.

trailing-initial votes only where initials end most of the group

One rule at every count: where any name casts a trailing-initial order vote, the votes are cast only where at least 3 names, and at least 60% of the group's names, end in initials no other signal in the same name contradicts. Otherwise every one is set aside, a contested one included, so the given-name vote that contested it then stands.

  • The group is the names holding a word with a letter or a digit once their titles and post-nominals are read past. A comma name, a blank, a mark, a zero-width character alone (\u200b) and a name of nothing but titles leave it.
  • Uncontested: a name whose listed given name contradicts the initial (Anna R S) is not counted. Anna R S, Maria J M and Mary A B under a family-first base read given-first with or without an uncontested Huntley R P beside them.

A byline list ends nearly every name in initials (Huntley R P, Smith J.). Elsewhere the letters are often the family (Lakshmi R S, Nepal's Durga B K) or a middle and a family initial (Brazil's truncated MARIA J M B). Today the vote moves those whole lists to a family-first order.

How a set-aside vote is handled:

  • It is not cast at all. It leaves the name's NameEvidence.votes, so the counts add up and disagreeing() names no one for a vote the group did not count.
  • The order evidence carries a note: "1 of the group's 4 names ends in initials no other signal contradicts, too few for the trailing-initial signal to vote: …".
  • The name still counts in the patronymic share's denominator. Without that, PatentsView's Russian family-first row under a family-first base fell to 69.7% at 10 names: Popov Ivan I. left the denominator, and five East Slavic names of seven decided the rule. test_a_set_aside_name_still_counts_in_the_patronymic_share fails without it. The patronymic evidence's note says how many names count there with no vote left.

Measurements

suggest_measure.py

Run with uv run python tools/differential/suggest_measure.py --base <checkout of 62bbdeb1>; outputs are in the 3.1 cycle's session notes.

  • Same-order rows: none moved below 98%. PatentsView's Russian family-first row under a family-first base reads 100 / 100 / 100 / 98 / 98 / 100 / 100 / 100%, unchanged. The one row below 95% is new with this PR and the same at the base: see orcid-byline below.
  • Rows written against the base: the family-first rows under a given-first base lose where the given name carries a middle initial (Smith John A.). The trailing-initial vote had read those right. At sizes 2 / 3 / 4 / 5 / 10 / 20 / 50 / 200:
row before after
US 41 / 68 / 83 / 95 / 100 / 100 / 100 / 100 3 / 20 / 43 / 66 / 81 / 95 / 100 / 100
Russian 30 / 52 / 74 / 86 / 98 / 100 / 100 / 100 2 / 10 / 27 / 40 / 55 / 79 / 97 / 100
Brazilian 16 / 32 / 44 / 57 / 87 / 97 / 100 / 100 11 / 17 / 32 / 40 / 75 / 91 / 99 / 100
  • Other rows: Dutch loses more than Brazilian at 2–4 names (38.7 / 64.3 / 84.3% → 18.0 / 39.7 / 60.3%); Spanish, French, German and Italian lose less. India's family-first row under a given-first base loses at 10–50 names (51.0 / 81.0 / 99.3% → 25.0 / 52.3 / 89.3%), while its given-first row under a family-first base gains (67.7% → 79.3% at 20).
  • orcid-byline, a population added to the tool here: ORCID credit names written as a byline, the holder's boxes confirming the word in front is the family and the first initial the given name's first letter (2,215 names on 2026-11-11). Written family-first under a given-first base: 47.7 / 78.3 / 92.0 / 98.0 / 100 / 100 / 100 / 100% → 0.0 / 34.7 / 68.3 / 84.3 / 84.0 / 91.3 / 98.0 / 100%, the gate's cost on real bylines. Its given-first writing (GH Yoon) keeps its order under a given-first base in 96 / 85 / 76 / 67 / 27 / 9 / 0 / 0% of groups and is read given-first under a family-first base in none, at the base and here alike: the capitals signal reads joined initials in front as a family name. That is pre-existing and left as found, noted in root AGENTS.md's anti-goal sentence.
  • Where the base moves at 95%: from 10 to 50 names for Russian, and from 20 to 50 for Brazilian. The rest are unchanged.
  • Parliaments: only in_sansad moved. It is still decided given-first, with 78 names against instead of 167. No TURKIC row moved.
  • --checks: byte-identical to the base.

The study's populations

These come from the throwaway prototype in the session notes (vote.py, measure_letters.py). The readings are modelled from each name's shape; the suggestion is the real one from this tree. Mean share of known names read right over sizes 2–200, before → after:

population before after
ORCID India (whole list) 88% 96%
Nepal, half-initialed 26% 87%
TSE, all-initialed 12% 39%
pure byline groups 92% 73%
byline groups, three-quarters initialed 67% 38%

Whole real lists (ORCID, Lok Sabha, Turkey's parliament, ClinicalTrials.gov) are made worse in 0–2% of groups.

Threshold choice

Chosen with the prototype (vote.py --trailing-share) on half of each population and read on the other half, then checked with suggest_measure.py --set _MIN_TRAILING_SHARE=<v>. At a share of 0.3 or 0.4, groups of ten or more half-initialed Nepali or South Indian names are made worse in 70–100% of draws; at 0.6, in 0–4%. A list 75% or more initialed that is not a byline list is still read family-first at every share: no share tells it from a byline list.

Decisions for the maintainer

  • A set-aside vote leaves NameEvidence.votes, a public type, rather than being kept and flagged. The docstring now says so.
  • The share is "at least" 60%, where the order and patronymic shares are "strictly more than". Three of five initialed names vote; three of six do not.
  • The byline cost. Byline groups lose (92% → 73%) to protect South Asian and Brazilian lists. So do family-first lists whose given names carry a middle initial (the US, Russian and Brazilian rows above). name_order=FAMILY_FIRST stays the lever for a known bibliography.

Docs

  • docs/suggest.rst: the trailing-initial evidence, with its threshold and one clause of why.
  • Parser.suggest's docstring: the threshold, and the re-taken "95% from N names" figures.
  • decisions/group-suggestion: a new 2026-11-11 TRAILING INITIAL entry with the re-taken table, a Standing line, and forward pointers from SIGNALS and THRESHOLDS.
  • Root AGENTS.md: the suggester paragraph's pointer to the table.
  • tools/differential/suggest_measure.py: --set accepts the two new thresholds; a name the base tree lacks is left to its own rule there, with a note, rather than raising; the orcid-byline population.
  • The release-log bullet for Parser.suggest() is unchanged; its claims still hold.

Review round 1 (fix commit e9dfab2 on top of 4823493)

  • A group whose every trailing initial was contested kept those votes while one uncontested name set them aside: one rule now applies at every count.
  • The patronymic evidence's note now says what its share counted.
  • A comma name, a blank, a mark or \u200b alone no longer counts as a group name; the comma check that guarded nothing is gone, with the reason in the docstring.
  • The note counts the names it names; docs/suggest.rst and the docstring say "uncontested" and "the group's names".
  • --set with a name the base lacks no longer raises AttributeError.
  • decisions/group-suggestion: the Dutch and India costs, which tool gave the 70–100% figures, the orcid-byline row, a pointer from THRESHOLDS, and Open: now names Should an ALL-CAPS word in a mixed-case name mark the family name? DUPONT Jean gives given DUPONT #659 (Can nameparser suggest settings for a list of names? (Smith Mary, Kim Minjun, Wang Xiaoming should read family-first) #1308 is closed).
  • Measured and not adopted: counting a short-capitals name (Zhi LI, Hoy AM) toward the share without its voting. It recovers orcid-byline's family-first row (0 / 68.7 / 90.3 / 98 / 100 …) and pure byline groups (73% → 84% of names read right), but makes Nepal's 75%-initialed groups of 200 worse in 98% of draws instead of 82%.
  • Each gate arm has a test that fails when it is mutated (the isalnum skip, the contested test, the set-aside count, the early return).

Review round 2 (fix commit 4587f3c)

  • The declined short-capitals variant is now recorded in the decisions entry, with its measurement and date.
  • The group-word test's rows each hold three fillers that only the letter-or-digit test excludes: zero-width characters, marks, combining marks and punctuation. All four rows fail with that test dropped.
  • The patronymic note counts only names a set-aside vote left with none. It prints only where a patronymic vote exists. Both rules are pinned by mutation.
  • test_suggest_measure.py: the byline test says it guards the filter alone, and an ORCID file holding no byline gives a note.
  • The 98% / 95% claims: Parser.suggest's docstring, docs/suggest.rst and tools/differential/README.md now name the exception. Bylines written with the initials first (GH Yoon) keep their order less often, because the capitals signal reads joined initials as a family name. This predates this PR, and the gap is on the Open: line.
  • The byline curve for the maintainer's decision is measured on Gate the suggester's trailing-initial vote on the group's share; fix a title-only name's crash #1345 and Add Policy.initials_as_family, reading letters ending a name as its family (#1254) #1347 stacked, and reported to the coordinator. The thresholds are unchanged.

The share, decided

The share stays at 60% and the minimum at 3 names. The decisions entry records the curve behind that, measured stacked with #1347 and then on this PR alone. A lower share recovers bylines: ORCID's at 10 / 20 names go from 84 / 91% to 95 / 99% at 0.5. But it moves groups to the wrong order:

  • half-initialed South Indian groups, made worse at 10 names in 4% of draws at 0.6, 61% at 0.5 and 90% at 0.4;
  • three-quarters-initialed Brazilian groups;
  • on this PR alone, half-initialed Nepali groups.

0.5, 0.4 and a minimum of 2 names are each declined there. docs/suggest.rst tells a caller with a short byline list to set name_order=FAMILY_FIRST.

Conflicts with the PRs that follow

PR 2 (#1347, the letters-are-the-family setting and its suggestion) touches nameparser/_suggest.py, tests/v2/test_suggest.py, tools/differential/suggest_measure.py, Parser.suggest's docstring, docs/suggest.rst, decisions/group-suggestion and the release log. PR 3 (the ambiguity report) shares only the release log with this one.

Checks

  • uv run pytest: 45,439 passed.
  • uv run pytest -n0 -m serial: left to CI; the frame band (test_parse_cost_stays_within_its_band) passes locally.
  • uv run mypy, uv run ruff check, uv run sphinx-build -b doctest docs, uv run sphinx-build -W -b html docs and uv run python tools/vocab/build.py --check: clean.

Refs #1254

🤖 Generated with Claude Code

…a title-only name's crash

Parser.suggest raised IndexError on a group holding a name that is
nothing but titles (`Dr.`, `Professor`, and `Jr.`, which rules/H2's
shape reads as a title at the head): _ends_in_post_nominal read the
last word before asking whether any was left.

The trailing-initial signal now votes only where at least three names,
and at least 60% of the group's names, end in initials it reads
uncontested. A byline list ends nearly every name that way; in a South
Asian list the letters are often the family (`Lakshmi R S`, `Durga B K`)
and in a truncated Brazilian one a middle and a family initial, and
there the vote moved whole lists to a family-first order. A set-aside
vote leaves the name's NameEvidence, and the order evidence's note says
why; the name still counts in the patronymic share's denominator.

Measured with tools/differential/suggest_measure.py against 62bbdeb:
no same-order row below 98%; the family-first rows under a given-first
base lose where a given name carries a middle initial (Russian and
Brazilian now reach 95% from 50 names). decisions/group-suggestion's
2026-11-11 #1254 entry holds the re-taken table.

Refs #1254

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73 derek73 added this to the 3.1 milestone Nov 12, 2026
@derek73 derek73 added bug name-order Name order, family-first and two family names (rules/O) initials Reading initials and the initials() view (rules/T) labels Nov 12, 2026
@derek73 derek73 self-assigned this Nov 12, 2026
derek73 and others added 3 commits November 11, 2026 18:28
One rule at every count: where any name casts a trailing-initial vote
and the gate fails, every one is set aside, a contested one included.
The group is the names holding a word with a letter or a digit, so a
mark or a zero-width character alone no longer counts; the note counts
the names it names; the patronymic evidence says how many names whose
only vote was set aside count in its share. suggest_measure.py leaves a
threshold the base lacks to its own rule and draws an ORCID byline
population. The decisions entry's costs, sources and Open line are
corrected, with the re-taken table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The group-word test's rows now each fail without it; the patronymic
note counts only the names a set-aside vote left with none, and prints
only where a patronymic vote exists; the byline population test says
what it guards and an empty population is a note. The docs no longer
claim every same-order row holds 98%: bylines written with the
initials first are the exception, on the Open line. The declined
short-capitals variant is recorded with its measurement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The share stays at 60% and the minimum at 3 names. The decisions entry
holds the curve behind that (lower shares recover bylines but move
half-initialed South Indian, three-quarters-initialed Brazilian and,
without the letters setting, Nepali groups to the wrong order) and
declines 0.5, 0.4 and a minimum of 2 names. docs/suggest.rst tells a
caller with a short byline list to set the order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73
derek73 merged commit bc229fe into master Nov 12, 2026
14 checks passed
@derek73
derek73 deleted the fix/suggest-trailing-initial-share branch November 12, 2026 04:16
derek73 added a commit that referenced this pull request Nov 12, 2026
Resolved: _suggest.py keeps #1345's gate and #1347's letter runs, a
group whose letters are its family setting its trailing-initial votes
aside through the gate's path; test_suggest.py's recorded controls and
suggest_measure.py's SETTABLE keep both PRs' rows; AGENTS.md and
decisions/group-suggestion keep both PRs' text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug initials Reading initials and the initials() view (rules/T) name-order Name order, family-first and two family names (rules/O)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant