parse("Smith, PSM I") reads "PSM" as a given name — a suffix run breaks on a trailing I or V #430
Description
A comma suffix run terminates early when its last word is I or V, the two roman numerals that are also initial-shaped. Only on the one-word-family path:
parse("John Smith, PSM I") # -> given=John, family=Smith, suffix='PSM I' correct
parse("Smith, PSM I") # -> given='PSM', family=Smith, suffix='I'
parse("Smith, PSM I.") # -> given='PSM', family=Smith, suffix='I.'
parse("Smith, PSM II") # -> family=Smith, suffix='PSM, II' (roles right; render is #429)Two distinct wrong outcomes, depending on whether the run's first word is also in TITLES:
| input | today | wanted |
|---|---|---|
Smith, PSM I |
given=PSM, suffix=I | family=Smith, suffix=PSM I |
Smith, PhD I |
given=PhD, suffix=I | family=Smith, suffix=PhD I |
Smith, CBE I |
given=CBE, suffix=I | family=Smith, suffix=CBE I |
Smith, MD I |
title=MD, given=I | family=Smith, suffix=MD I |
Smith, Jr. I |
title=Jr., given=I | family=Smith, suffix=Jr. I |
The MD / Jr. rows reach the wrong answer through the leading-title peel instead (md is in TITLES by the deliberate #296 deviation; Jr. via _is_leading_title's period-abbreviation inference). A fix verified only on PSM would leave those shapes broken and still look green.
The rule this should follow
I and V are treated cautiously because they are the only suffix words that could equally be initials. But after a comma and after a suffix word, they are describing that suffix — PSM I is Professional Scrum Master level I — not serving as a generational marker and not standing in for a name.
An initial in that position is not a supported name shape, so the period should be ignored there too: Smith, PSM I. reads as suffix PSM I., not as an initial.
This is already what the full-name path does — parse("John Smith, PSM I.") gives suffix 'PSM I.' — so the fix is to bring the one-word-family path into line with an existing correct reading, not to invent a new one.
Out of scope
The no-comma shapes are unchanged by this issue, where I / V genuinely can be name material:
parse("John Smith V") # -> suffix='V'
parse("John Smith V.") # -> middle=Smith, family='V.'
parse("John Smith MA V.") # -> middle='Smith MA', family='V.'Where a trailing dotted word lands on the no-comma path is the separate trailing-word question tracked by #316; this issue takes no position on it.
Activity
derek73 commentedon Aug 24, 2026
Measured on the 1.4.0 wheel — this is not a #428 regression, the shape has read this way since 1.x:
So the two paths disagreed in 1.4.0 exactly as they do now, and fixing it is a deliberate deviation from v1 rather than a repair of one — it needs a release-log classification and a differential ledger rule.
derek73 commentedon Aug 24, 2026
Complement filed as #432: inside a comma segment a dotted
I/Vcontinues a suffix run (this issue —Smith, PSM I.→ suffixPSM I.) but must not attach to a name (#432 —Smith, John V.→ middleV.). What the previous word is decides it, so the two should be fixed together or at least reviewed against each other.docs(agents): a tenth review axis, and three conventions #291 earned
fix(pieces,assign): the review round -- strict restored, the rule re-…
test(pieces): a unit-test home, and the branch no parse can reach
Merge pull request #443 from derek73/fix/430-432-comma-numeral-fork
fix(pieces,assign): a comma-segment numeral is read by what precedes it
docs(design): suffix entries follow the written commas
docs(concepts,usage,group): three stale behavior claims, measured
Split rules/C1 and decisions/C1 into one rule per piece of evidence (#…
Address the second C-section review round (#761, #774)
Migrate the C rules to the skeleton format; add C14 (#761, part 3) (#772
Give decisions/C3 through C12 a Standing block (#762) (#817)