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.
A space-separated run of post-nominals renders with a comma the writer never typed, when the name has no comma in it:
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:
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:
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 followassign's content read, but only where the structure isFAMILY_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: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.