Skip to content

parse("John Smith MD PhD").suffix returns "MD, PhD" — a run without a comma renders with one #436

Description

@derek73

A space-separated run of post-nominals renders with a comma the writer never typed, when the name has no comma in it:

parse("John Smith MD PhD").suffix    # 'MD, PhD'   -- wanted 'MD PhD'
parse("John Smith CBE MC").suffix    # 'CBE, MC'
parse("John Smith MA V").suffix      # 'MA, V'

The comma forms are correct and have been since 1.4.0 for the full-name path, and since #429 for the family-comma path:

parse("John Smith, MD PhD").suffix   # 'MD PhD'
parse("Smith, MD PhD").suffix        # 'MD PhD'

So the same credential run renders two different ways depending on whether the name has a comma somewhere else in it.

Parity

Long-standing, not a regression. Measured on the wheels:

input 1.4.0 2.0.0 2.1.0 master
John Smith MD PhD 'MD, PhD' 'MD, PhD' 'MD, PhD' 'MD, PhD'

Fixing it is a deliberate deviation from 1.4.0 and needs a release-log classification and ledger rules.

Why #429 did not fix it

#429 made group's one-entry join follow assign's content read, but only where the structure is FAMILY_COMMA — the segment a family comma leaves behind. The no-comma path has no writer-drawn boundary at all, which is a different question, so it was deliberately left alone (docs/design/decisions.md, the 2026-08-23 #429 entry).

Consequence worth knowing

This is why round-tripping is not stable on the shapes #429 fixes. str() of a fixed parse is a no-comma string, so re-parsing it takes this path and re-inserts the comma:

parse(str(parse("Smith, MD PhD"))).suffix   # 'MD, PhD', not 'MD PhD'

An early draft of #429's release bullet claimed round-tripping was stable; it was corrected before merge, and this issue is the reason it could not be.

Note on approach

#437 proposes deriving the suffix separator from whether the writer actually typed a comma between the two words, which would fix this shape and the two comma paths with one rule rather than three. If that lands, this closes with it.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions