Skip to content

parse("Smith, PSM I") reads "PSM" as a given name — a suffix run breaks on a trailing I or V #430

Description

@derek73

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

  1. added this to the v2.2 milestone on Aug 24, 2026
  2. self-assigned this
    on Aug 24, 2026
  3. derek73 commented on Aug 24, 2026

    @derek73
    OwnerAuthor

    Measured on the 1.4.0 wheel — this is not a #428 regression, the shape has read this way since 1.x:

    1.4.0:  HumanName("Smith, PSM I")       -> first='PSM', last='Smith', suffix='I'
    1.4.0:  HumanName("John Smith, PSM I")  -> first='John', last='Smith', suffix='PSM I'
    

    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.

  4. derek73 commented on Aug 24, 2026

    @derek73
    OwnerAuthor

    Complement filed as #432: inside a comma segment a dotted I/V continues a suffix run (this issue — Smith, PSM I. → suffix PSM I.) but must not attach to a name (#432 — Smith, John V. → middle V.). What the previous word is decides it, so the two should be fixed together or at least reviewed against each other.

  5. added a commit that references this issue on Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions