Skip to content

Should a title written after the name still be a title? ("John Smith Prof." → family Prof.) #316

Description

@derek73

A title word appearing after the name is read as part of the name, so the family name lands on the honorific:

parse("John Smith Prof.")   # given='John', middle='Smith', family='Prof.'
parse("John Smith Mr.")     # given='John', middle='Smith', family='Mr.'
parse("John Smith Rev.")    # given='John', middle='Smith', family='Rev.'

The comma path disagrees with itself about this — it routes the same word to title:

parse("Smith, Prof.")       # title='Prof.', family='Smith'

The rule this questions

AGENTS.md recorded the doctrine as:

Title vs suffix is purely positional — a word matching TITLES at the front becomes title; the same word matching the suffix sets at the end becomes suffix (never both, regardless of the word's real-world meaning).

That is not quite what the code does, and the gap is the point. Leading position runs a structural inference — any multi-letter word ending in a period is a title — and that inference outranks vocabulary:

parse("Esq. Smith")         # title='Esq.'   — 'esq' is SUFFIX-only vocabulary
parse("Esq Smith")          # given='Esq'    — no period, no inference

Trailing position has no counterpart. So the real asymmetry is: an abbreviation is interpreted in pre-nominal position and not in post-nominal position, and where it is interpreted it overrides the vocabulary that disagrees.

Why the doctrine exists, and why it can't simply be inverted

TITLES carries 692 words that are in no suffix set, and many are ordinary English surnames:

abbot, bailiff, baron, bishop, chancellor, chaplain, deacon, friar, judge, king, master, mayor, pope, prince, provost, ranger, sergeant, sheriff, warden

A blanket "vocabulary outranks position" rule would be severe:

parse("Mary Jane King")     # would become title='King', family='Jane'
parse("Robert Prince")      # would become title='Prince', no family at all

In leading position a title shadows the given name, which the docs already warn about. In trailing position it would shadow the family name — strictly worse, since that is the field callers most depend on.

Proposal

Two parts, because the hazard above is entirely about bare words.

(a) Period-marked words: vocabulary decides the field, position does not. A trailing period marks an abbreviation, and the only name parts that get abbreviated are the ones standing outside the name — titles and post-nominals. So consult the vocabulary and route accordingly, in either position:

parse("John Smith Prof.")   # title='Prof.'  — title vocabulary
parse("John Smith Esq.")    # suffix='Esq.'  — suffix vocabulary   (unchanged)
parse("Mary Jane King")     # family='King'  — no period, untouched (unchanged)

This is safe precisely because King is a surname and King. is not. It also removes the Esq. Smith oddity, where a credential is reported as a title.

(b) A curated bare-safe subset for the words that are never surnames. Dr, Mr, Mrs, Prof are not English surnames, so they can be recognized without the period:

parse("Smith Dr")           # title='Dr', family='Smith'

This is the same shape as GLUED_HONORIFICS ⊆ SUFFIX_NOT_ACRONYMS (#308) — a riskier position gets a narrower, harsher subset of the base vocabulary, with the subset relation enforced. Entries qualify only if they can never end a name, which is exactly the test #308 already applies.

Both rest on the premise that the caller is handing the parser a name and not prose, so a trailing period means abbreviation rather than sentence punctuation. That premise is worth stating in the docs alongside this, if it is adopted.

What it would not change

Unrecognized abbreviations. parse("John Smith Xyz.") gives family='Xyz.' today, and under (a) still would — nothing in the vocabulary has an opinion. Whether the trailing slot should get a structural fallback the way the leading slot does is a separate question, and deliberately not bundled here: (a) and (b) move known words only, which is measurable; a fallback moves unknown ones, which the differential corpora cannot evidence (they hold only names someone wrote down).

Open questions

  1. Does the doctrine amendment need to be stated as "vocabulary decides for period-marked words, position decides for bare ones"? That is the honest summary, and it is more subtle than what the docs said before.
  2. Should (a) also apply to a leading suffix-only word, i.e. should Esq. Smith give suffix='Esq.'? It is the same principle, but it means the leading inference stops being unconditional, and Consider names followed by a period as titles or suffixes #109 shipped it that way on purpose.
  3. Scale: (a) touches 692 title-only words in a position they have never been recognized in. Differential coverage will be thin — the corpora hold few trailing honorifics — so this likely wants a dedicated probe set rather than reliance on a green run.
  4. Should the fork be reported as an Ambiguity? Probably not for (a) and (b): under the input-is-a-name premise a period-marked title is not a fork a reader would hesitate over. Revisit if a shape turns up where it is.

Related: is esq really an acronym?

Adjacent cleanup for the same milestone, since it is the same kind of question — whether a vocabulary entry describes the word or merely the machinery.

esq is the only member of SUFFIX_ACRONYMS ∩ SUFFIX_NOT_ACRONYMS. It entered SUFFIX_ACRONYMS in af5bdab ("add post-nominal list from wikipedia", #93) as part of a bulk import rather than a judgement, and Esquire is a contraction, not an initialism. The acronym membership uniquely covers exactly one spelling:

parse("John Smith Esq")      # suffix='Esq'      — word set
parse("John Smith Esq.")     # suffix='Esq.'     — word set
parse("John Smith Esquire")  # suffix='Esquire'  — word set
parse("John Smith E.S.Q.")   # suffix='E.S.Q.'   — ONLY the acronym set

d4dd8a1 restored it after a bad "deduplication" and justified it on 1.4-parity grounds, which is correct as far as it goes — but the spelling it protects is one nobody writes. Dropping it would make SUFFIX_ACRONYMS ∩ SUFFIX_NOT_ACRONYMS == ∅ assertable and retire a gotcha, a non-assert comment and a case row. It is a classified behavior change, since 2.x has shipped with it.

Relationship to #291 / #296

The comma-suffix bundle (#296) removes dr and sra from the suffix vocabulary, which drops them into the behavior described at the top — "John Smith Dr." moves from suffix='Dr.' to family='Dr.'. That is not a new defect: it makes dr consistent with prof, mr and rev, which have always parsed that way, and the v1-residue suffix entry was the only thing that had been hiding it. This issue is the general fix, and grouping the two into the same release avoids shipping the gap and its repair a version apart.

Activity

  1. added this to the v2.2 milestone on Aug 1, 2026
  2. modified the milestones: v2.2, v2.3 on Aug 30, 2026
  3. added a commit that references this issue on Sep 10, 2026
  4. derek73 commented on Sep 10, 2026

    @derek73
    OwnerAuthor

    Part (a) shipped in #520 for 2.3.0, as new rule H5. Part (b) stays open, below.

    The doctrine, answering open question 1. rules.md's H Background now carries it: a period-marked word is claimed by SHAPE at the front of a name and by VOCABULARY at the back. The leading slot infers unlisted abbreviations (H2, unchanged); the trailing slot has no shape rule and reads the title vocabulary only, so an unlisted abbreviation there stays a name word and a BARE title word there is a name word, because TITLES holds ordinary surnames.

    parse("John Smith Prof.")        # title='Prof.', given='John', family='Smith'
    parse("John Smith Prof. Dr.")    # title='Prof. Dr.'            (a run, mirroring H3)
    parse("Dr. John Smith Prof.")    # title='Dr. Prof.'            (input order)
    parse("Smith, John Prof.")       # title='Prof.'                (the comma segment gets the same walk)
    parse("John Smith Xyz.")         # family='Xyz.'                (unlisted: unchanged)
    parse("Mary Jane King")          # family='King'                (bare: unchanged)
    parse("John Smith Esq.")         # suffix='Esq.'                (the suffix peel runs first)

    The title is transparent to the suffix peel: X Prof. Y reads as X Y reads, plus the title, so John Smith Jr. Prof. keeps suffix Jr. and John Prof. MA keeps S2's bare-acronym reserve. Where the chain leaves one name word, H1 decides its field, and H1 now reaches a run behind the word too (Smith Sir. → given Smith).

    Open question 2, declined. Esq. Smith still reads title Esq.. #109 shipped the leading inference unconditional on purpose, the family comma already carries the credential case (Smith, Esq. → suffix), and a credential written before the name is malformed input either way. Making the leading slot consult suffix vocabulary would reverse S2's "a suffix never opens the string" for one word.

    Open question 3, by measurement. The differential was as thin as predicted: five corpus names moved at the fix, the four planted here plus one the drafting did not expect, Andrew Perkins (Mgr.), whose parenthetical arrives as a plain piece and mgr is title vocabulary. Fourteen names carry the rule once its rules.md examples entered the corpus. The case rows carry the rest of the coverage, each classified against the 1.4.0 wheel.

    Open question 4. No ambiguity is reported: under the input-is-a-name premise a period-marked title word is not a fork a reader would hesitate over. The one cost of that premise is recorded as accepted in rules.md#H5: a period-marked surname-collision word at the back reads as a title (Mary Jane King. → title King.), and every plain ASCII title is reachable that way.

    The adjacent esq cleanup, done. esq left SUFFIX_ACRONYMS; John Smith E.S.Q. no longer reads a suffix, Esq/Esq./Esquire still do through the word set, and SUFFIX_ACRONYMS ∩ SUFFIX_WORDS == ∅ is asserted at import.

    Part (b), the bare-safe subset, stays open. It needs #348's census of title-vs-given collisions, and the corpora show the bare trailing dr swallowed by P2's particle chain (dr Vincent van Gogh dr → family van Gogh dr), a different mechanism from the one this fixed. Leaving this issue closed on (a); (b) can be refiled when #348 lands.

  5. self-assigned this
    on Sep 11, 2026
  6. added 2 commits that reference this issue on Oct 9, 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