A space-split Ph. D. followed by another suffix lands in the given name:
HumanName("Smith, Ph. D. Jr.")
# 1.4.0: last='Smith' suffix='Ph. D.' title='Jr.'
# 2.0.0: last='Smith' first='Ph. D.' suffix='Jr.' <- credential in first
# HEAD: same as 2.0.0
Boundary
Measured. Regresses only when all three hold — one word before the comma, the space-split Ph. D. pair, and at least one more suffix after it:
| input |
1.4.0 first |
2.x first |
|
Smith, Ph. D. Jr. |
'' |
'Ph. D.' |
regresses |
Smith, Ph. D. MD |
'' |
'Ph. D.' |
regresses |
Smith, Ph. D. III |
'III' |
'Ph. D.' |
regresses |
Smith, Ph. D. Jr. MD |
'MD' |
'Ph. D.' |
regresses |
Smith, Ph. D. |
'Smith' |
'' |
fine — 2.x better |
Smith, Ph.D. Jr. |
'Ph.D.' |
'Ph.D.' |
parity (one token, no merge) |
Smith, PhD Jr. |
'Jr.' |
'' |
fine — 2.x better |
Smith Jones, Ph. D. Jr. |
'Smith' |
'Smith' |
parity (two words → SUFFIX_COMMA) |
Neighbouring shapes go the other way — 1.4.0 puts a credential in first and 2.x correctly routes it to suffix, the known fix(comma-family) improvement. This is the one row going backwards.
Why
Same root cause as #319, hitting a different victim.
segment() picks SUFFIX_COMMA only when suffixy(groups[1]) and len(groups[0]) > 1. With one word before the comma it falls through to FAMILY_COMMA even though the post-comma run is entirely suffix-shaped — so _assign reads that run as name text.
Why only the space-split pair: suffixy merges adjacent Ph./D. into one unit, and _group has a matching merge. For Smith, Ph. D. the merged piece is the lone post-comma piece, so the "lone post-comma piece routes to suffix/title" rule fires and it lands correctly. Add another suffix and it is no longer lone, that rule stops applying, and the merged piece falls through to the name-text reading.
#319 is this defect reaching the honorific peel. This is it reaching _assign. #319's fix does not address this — that one changes the peel's scope; _assign's reading of segments[1] is untouched.
Why the differential did not catch it
unexplained: 0 is a true statement about a corpus that cannot express the shape. corpus.jsonl has John Smith, Ph. D. — two words before the comma, which makes it SUFFIX_COMMA and works. There is no one-word-before-comma variant with a multi-token suffix run anywhere in the three corpora. Worth adding regardless of when this is fixed.
Milestone
Filed v2.2 rather than v2.1 on two grounds: it shipped in 2.0.0, so this is not a "stop it reaching users" situation; and the honest fix is at segment()'s len(groups[0]) > 1 rule, which is v1-parity machinery whose change needs its own differential pass and would not be a small addition to the 2.1 queue. Move it if you would rather take it sooner — the reproduction is tight and the boundary is known.
Found while investigating the Ph./D. merge duplication noted in #319's spec.
A space-split
Ph. D.followed by another suffix lands in the given name:Boundary
Measured. Regresses only when all three hold — one word before the comma, the space-split
Ph. D.pair, and at least one more suffix after it:firstfirstSmith, Ph. D. Jr.'''Ph. D.'Smith, Ph. D. MD'''Ph. D.'Smith, Ph. D. III'III''Ph. D.'Smith, Ph. D. Jr. MD'MD''Ph. D.'Smith, Ph. D.'Smith'''Smith, Ph.D. Jr.'Ph.D.''Ph.D.'Smith, PhD Jr.'Jr.'''Smith Jones, Ph. D. Jr.'Smith''Smith'SUFFIX_COMMA)Neighbouring shapes go the other way — 1.4.0 puts a credential in
firstand 2.x correctly routes it tosuffix, the knownfix(comma-family)improvement. This is the one row going backwards.Why
Same root cause as #319, hitting a different victim.
segment()picksSUFFIX_COMMAonly whensuffixy(groups[1]) and len(groups[0]) > 1. With one word before the comma it falls through toFAMILY_COMMAeven though the post-comma run is entirely suffix-shaped — so_assignreads that run as name text.Why only the space-split pair:
suffixymerges adjacentPh./D.into one unit, and_grouphas a matching merge. ForSmith, Ph. D.the merged piece is the lone post-comma piece, so the "lone post-comma piece routes to suffix/title" rule fires and it lands correctly. Add another suffix and it is no longer lone, that rule stops applying, and the merged piece falls through to the name-text reading.#319 is this defect reaching the honorific peel. This is it reaching
_assign. #319's fix does not address this — that one changes the peel's scope;_assign's reading ofsegments[1]is untouched.Why the differential did not catch it
unexplained: 0is a true statement about a corpus that cannot express the shape.corpus.jsonlhasJohn Smith, Ph. D.— two words before the comma, which makes itSUFFIX_COMMAand works. There is no one-word-before-comma variant with a multi-token suffix run anywhere in the three corpora. Worth adding regardless of when this is fixed.Milestone
Filed v2.2 rather than v2.1 on two grounds: it shipped in 2.0.0, so this is not a "stop it reaching users" situation; and the honest fix is at
segment()'slen(groups[0]) > 1rule, which is v1-parity machinery whose change needs its own differential pass and would not be a small addition to the 2.1 queue. Move it if you would rather take it sooner — the reproduction is tight and the boundary is known.Found while investigating the
Ph./D.merge duplication noted in #319's spec.