Repository navigation
A title displaces a particle out of leading position, so Dr. Van Johnson reads as one surname #367
Description
A leading particle deliberately does not chain — that is what makes Van Johnson read as given Van, family Johnson rather than as one surname. But the exception is keyed on piece index 0, so a title displaces the particle out of leading position and the chain fires. Identical name text then parses differently depending on whether a title precedes it:
Van Johnson given='Van' family='Johnson'
Dr. Van Johnson given='' family='Van Johnson'
Sir Van Johnson given='Van Johnson' family='' (no surname at all)
The last row compounds it: with a given-name title, post_rules rule 1's carve-out then hands the whole chain to given, so the name ends with no surname.
Decision: titles are transparent to the leading-particle exception
A title is not part of the name, so it should not change whether the name begins with a particle. Dr. Van Johnson and Sir Van Johnson should read as Van Johnson does.
The change is one line in nameparser/_pipeline/_group.py — the chain loop's if k == 0 becomes "the first piece that is not a title".
Measured: prototype vs current
Changes — every one is a titled name whose first name-piece is a particle:
current prototype
Dr. Van Johnson family='Van Johnson' given='Van' family='Johnson'
Dr. Van Johnson Smith family='Van Johnson Smith' given='Van' middle='Johnson' family='Smith'
Mr. Van Nguyen family='Van Nguyen' given='Van' family='Nguyen'
Sir Van Johnson given='Van Johnson' family='' given='Van' family='Johnson'
Sir Van Johnson Smith given='Van Johnson Smith' given='Van' middle='Johnson' family='Smith'
Sir de Mesnil given='de Mesnil' family='' given='' family='de Mesnil'
Sheik Abu Bakar given='Abu Bakar' family='' given='Abu' family='Bakar'
Unchanged, including the exact shapes v1 worried about:
Mr. Smith / Mrs. Smith / Mr. Nguyen / Mr. John Smith
Sir Ian / Sir Ian McKellen / King Henry
Van Johnson / de Mesnil / de Mesnil Garcia (no title)
Dr. de Mesnil
Sheik abdul salam
This fixes a v1-era xfail that says it cannot be fixed
tests/test_first_name.py:
@pytest.mark.xfail
def test_first_name_is_prefix_if_three_parts(self) -> None:
"""Not sure how to fix this without breaking Mr and Mrs"""
hn = HumanName("Mr. Van Nguyen")
self.m(hn.first, "Van", hn)
self.m(hn.last, "Nguyen", hn)The prototype makes it pass. And it does not break Mr and Mrs — every bare Mr./Mrs. Surname shape is byte-identical, because those have no particle to displace. v1's concern was about the fix it had in mind, not about this one.
And it reverses a case row that pins the opposite
tests/v2/cases.py:
Case("titled_ambiguous_particle_chains", "Dr. Van Johnson",
{"title": "Dr.", "family": "Van Johnson"},
ambiguities=("particle-or-given",),
notes="... a leading title shifts Van off the given position, the prefix
chain fires, and the fork is reported from group rather than
assign (v1 parity on the fields)")Mr. Van Nguyen and Dr. Van Johnson are the same shape. The repository currently pins one as broken-and-unfixable and the other as correct-by-v1-parity. This resolves the contradiction in favour of the xfail. The row must be rewritten to given='Van', family='Johnson'.
Note "v1 parity on the fields" is accurate — 1.4.0 does give last='Van Johnson' — but v1 also ships the xfail calling the same shape wrong, so parity is not the tiebreaker it appears to be.
The fork is still reported either way: under the change Dr. Van Johnson emits particle-or-given from _assign instead of from _group, i.e. from the same place the untitled Van Johnson reports it.
Blast radius
Nine test failures on the prototype, all coherent:
| test | why |
|---|---|
test_first_name_is_prefix_if_three_parts |
the xfail now passes — this is the fix |
titled_ambiguous_particle_chains + its facade twin |
the case row above; rewrite |
4 × test_chained_particle_detail_* |
_group's PARTICLE_OR_GIVEN emitter loses its only reachable case, since titles were what displaced the particle |
test_ambiguous_particle_reports_both_branches_of_its_fork |
same cause |
test_add_title |
fallout; investigate |
Whether _group's emitter becomes dead code needs checking — if a non-title piece can never precede a chaining particle, the emitter and its tests should go.
Scope and verification
Changes default-order output — the first change in this sequence to move the default-order corpus, byte-identical through #354, #358 and #361. Needs a tools/differential pass at all three baselines with ledger entries.
Related
- A particle chain lands in the given or middle name under the family-first orders #368 — a particle chain landing in
given/middleunder family-first orders. Independent mechanism (name_order, no title), family-first only. Sheik Abu Bakarregresses here fromgiven='Abu Bakar'togiven='Abu',family='Bakar'. That case works today only becauseabuhappens to be a particle as well as a bound given name —Sheik abdul salamshows bound-given alone does not chain. Tracked separately.- Should
de Mesnil Juanbe all surname, or familyde Mesnilplus givenJuan? #364,Mesnil Garcia destrands the particle under FAMILY_FIRST but folds it under FAMILY_FIRST_GIVEN_LAST #365 — unrelated; no chain is involved in either.
Activity
Stop documenting the Sir de Mesnil reading as intended (#359, #367)
derek73 commentedon Aug 10, 2026
Note on a conflict with #359's wording, surfaced while trimming #361.
#359's body says of
Juan de la VegaunderFAMILY_FIRST: "the chain does survive the order change and only the destination flips (family='de la Vega'→given='de la Vega') — that case works as intended."The principle in this issue says the opposite: a particle chain is a surname wherever it appears, so
given='de la Vega'is wrong and it should befamily='de la Vega'. This issue supersedes that sentence in #359. Flagging it explicitly because #361's code comments cite that row, and they now describe it as what the rule mechanically does rather than as a blessed output — so they stay true whichever way this lands.[-]A particle chain can land in the given name: `Sir de Mesnil` gives given='de Mesnil' and no surname[/-][+]A particle chain after a given-name title lands in the given name: `Sir de Mesnil` has no surname[/+][-]A particle chain after a given-name title lands in the given name: `Sir de Mesnil` has no surname[/-][+]A title displaces a particle out of leading position, so `Dr. Van Johnson` reads as one surname[/+]Make the chained emitter's vocabulary precondition executable (#367)
Say which fields the title fix actually moves (#367)
Correct the claims #367's own change falsified (#367)
Pin the shapes #367 moves, and stop its ledger rule claiming the cana…
Stop the respelled no-op row claiming 1.4 parity (#367)
Merge pull request #370 from derek73/claude/issue-367-title-transpare…
Merge master (#370) into the ledger-exclusions branch
6 remaining items
Sweep the prose that says a title changes the name behind it
feat(differential): a fourth corpus from the rules doc's own examples
fix(group): ask the peel over the pieces the chain and the walk leave
docs(design): record the review round of #424
fix(group): a given-name title licenses the bound-given join
fix(group): the chain and the maiden walk stop where assign's peel be…
fix(vocab,assign): give each title/suffix overlap word its true class…
fix(differential,guards): port the derek73#360 mc and derek73#367 de …
fix(differential,guards): narrow three 1.4.0 rules to the roles they …
fix(differential,guards): narrow five 2.0.0 rules to the roles they e…
fix(differential,guards): narrow six 2.1.0 rules to the roles they ex…
feat(differential): fail the gate on a rule wider than the diffs it e…
docs(decisions): three derek73#451 claims the derek73#452 review fals…
docs(release_log): cut the 2.2.0 entry to what a caller needs to decide
Correct AGENTS.md's particles.py bullet to P1's one-site fold