Skip to content

Divide a bracketed clause's words at a glued comma (#1268) - #1339

Draft
derek73 wants to merge 11 commits into
masterfrom
fix/issue-1268-glued-comma-in-clause
Draft

derek73 wants to merge 11 commits into
masterfrom
fix/issue-1268-glued-comma-in-clause

Conversation

@derek73

@derek73 derek73 commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

A bracketed clause of credentials glued at a comma reads as credentials:

parse("John Smith (MD,PhD)")      suffix 'MD,PhD'   (every release a nickname: 'MD PhD' in 2.0.0–2.4.0, 'MD,PhD' otherwise)
parse("John Smith (Jr.,MD)")      suffix 'Jr.,MD'   unchanged (3.0.0 on)
parse("Jane (Janey,Jo) Smith")    nickname 'Janey,Jo'   unchanged
parse("John Smith (Dr.,PhD)")    nickname          unchanged: a title glued to a credential
parse("John Smith (Ma,PhD)")      nickname          unchanged: a word that may be a name
parse("John Smith (MD,,PhD)")     nickname          unchanged: a doubled comma

Re-scoped in the fourth round. The first design ended a clause's word at a glued comma in tokenize, in every clause, nicknames included. Three review rounds then compensated for it without converging (a rejoin in Parser.revise, guards for degenerate shapes). That design is gone:

  • tokenize, extract, _vocab and _parser.py (revise) are master's;
  • the change is in post_rules' _set_apart_clauses alone, where rules/S1 is decided for good.

How

  • A clause's token holding a single comma glued between two words is read as those words, for S1's tests (_post_rules._glued_kind).
  • Where every word takes one kind (all credentials or generations, or all titles, a title/suffix dual taking its neighbours'), the token is set apart whole and keeps its comma as written.
  • Any other token keeps the base's reading.
  • A clause S1 does not set apart yields the base's tokens, tags and text.

Why the token is not divided:

  • S1 is decided twice: provisionally in extract, before tokens exist, and for good in post_rules, two stages after tokenize.
  • Each declines clauses the other takes: post_rules declines Justin (JP,PhD) Stearns, John (MD,PhD.) Smith and (Dr.,Prof.), which extract approved, and sets apart (Ma, PhD), which extract refused.
  • So tokenize can't divide only the clauses S1 sets apart.
  • Dividing in post_rules would insert tokens after the pieces, the segments and the stages' reports already index them.

Decision for the maintainer

  • Chosen: the glued word is set apart whole and reads as written: suffix MD,PhD, not the spaced twin's MD, PhD.
  • What it costs:
    • A title glued to a credential ((Dr.,PhD), the issue's fullwidth example) stays a nickname, since one token can't take two roles.
    • A word that may be a name ((Ma,PhD), (MD/PhD,MBA)) stays a nickname too.
    • revise(suffix="MD,PhD") gives MD, PhD: a bare value has no clause, so the comma divides. This is recorded as a round-trip limit beside the glued-word one.
  • Alternative: divide the token, so the reading matches the spaced twin and the mixed word reads as title plus suffix. That needs a token split in post_rules with every token index remapped, or a division in tokenize that also reaches clauses S1 leaves as nicknames. That is the design that didn't converge.
  • Also possible: park the PR. The shape is in 3 ORCID names and in no real ClinicalTrials.gov name.
  • The issue's open questions: a nickname keeps its comma as written (the first reading). The semicolon is left alone: a spaced one in a clause already reads as a nickname.

Measurements (against 8437022, a git archive, __file__ asserted)

  • revise: 18 values × 3 spellings × 7 fields, compared on fields, initials() and capitalized(): 0 of 378 differ from the base.
  • Shapes the reviews found: all read as at the base: doubled commas, a comma before or behind a dropped separator, (,,MD), (,,Jr.) between and after the name, (MD,,PhD), and comma-free clauses holding a separator.
  • What moves:
    • John Smith (MD,PhD);
    • the same text under bracket maiden_delimiters (maiden → suffix, S1 taking a maiden pair's clause first);
    • two ORCID names: Dr. Thierry Ingabire, (MD,PhD) and Dr. Md Safiul Alam Bhuiyan (DVM.MS,PhD).
  • Committed snapshot: no existing name moves; the new rule and case examples are added.
  • snapshot.py --local ctgov-officials --base: matches the base. match_diff: 0 of 654,864 rows move.
  • Frames:
    • A plain name and a clause with no glued comma pay nothing: John Smith 126, John "Jack" Smith 198, John Smith (MD, PhD) 247, each as at the base.
    • A clause with a glued comma pays the word's reading: (MD,PhD) 196 → 214, (Janey,Jo) 198 → 199.

Docs

Checks

On 8ea9f50: uv run pytest (45,185 passed), uv run pytest -n0 -m serial (62 passed), uv run mypy, uv run ruff check, sphinx-build -b doctest, all clean.

Merge note

Merged with master f03856f (#1340, #1341). PR 1338 touches the same release-log place and the snapshot files; whichever lands second needs a master merge and snapshot.py --record.

Closes #1268

🤖 Generated with Claude Code

A comma glued between two words of a delimited clause now ends the
first word, kept on it, as a spaced comma's tokens are: 'John Smith
(MD,PhD)' reads suffix 'MD, PhD' and '(Dr.,PhD)' title 'Dr.', suffix
'PhD', where both read as a nickname. Tokenize divides the clause, and
extract's and post_rules' S1 tests read it through one splitter,
_vocab.clause_words, held to tokenize's division by a test. A
nickname keeps its text as written ('Jane (Janey,Jo) Smith' gives
nickname 'Janey,Jo').

Amends rules/S1 and rules/N1, with dated entries in decisions/S1 and
decisions/N1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73 derek73 added bug suffixes Generational suffixes and credentials (rules/S) nicknames Nicknames, brackets and quoted names (rules/N) labels Nov 11, 2026
@derek73 derek73 self-assigned this Nov 11, 2026
derek73 and others added 4 commits November 11, 2026 11:52
…weep

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parser.revise joins back a word a glued comma ended, since its harvest
drops the spans a parse's views join it by ('(Janey,Jo)' stays
'Janey,Jo'). Extract and post_rules read a clause through one string
splitter, _vocab.clause_words, and post_rules reads a clause only where
those words are its tokens, text for text, so a separator tokenize
divides at and whitespace is not keeps the clause its pair's reading,
as decisions/S13 (#810) decided ('(MD,・PhD)', '(MD​,PhD)' read as
at the base). A clause with no comma pays no new frame.

Rows for the period-final glued clauses, the configured maiden pair,
the two separator boundaries and revise; version ranges corrected from
the wheels; rules/N1 says a whitespace run collapses; rules/S1 accepts
a comma standing alone or opening a clause; decisions/S1 and N1 state
the recipe, the base SHA, the ORCID names and the frame cost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit compared the words' text with the tokens', which
moved ten comma-free clauses the base set apart ('John Smith (MD・
PhD)', '(PhD MBA​)'). post_rules now compares their count, as the
base did, the splitter's words being the base's split with a glued
comma ending a word: a clause with no comma reads exactly as at the
base, and one with a glued comma beside a separator reads as its
spaced twin read ('(MD,・PhD)' as '(MD, ・PhD)').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73 derek73 added this to the 3.1 milestone Nov 11, 2026
derek73 and others added 6 commits November 11, 2026 13:30
Splitting at every glued comma moved degenerate clauses the base set
apart: a doubled comma ('(MD,, PhD)'), a comma before a character
tokenize drops ('(Dr.,‏)', '(MD,😀)') and a comma behind one
('(JP​,PhD)', its words out of step with its tokens). Tokenize
and _vocab.clause_words now end a word at a comma only with a word
character on both sides, asking the same _ignorable, which now takes
the policy, so each of those clauses reads as at the base.

Parser.revise joins back, inside one delimited clause, words across no
gap or across the commas S1 took off, with no tags, so every field's
value reads as at the base (378 values x fields, initials and case
alike).

Rows for each shape; rules/S1's comma bullet true on its own; prose
fixed in nameparser/AGENTS.md, test_tokenize, cases.py and
decisions/N1's #653 entry; decisions/S1 rewritten to what shipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_vocab may import only _lexicon, _policy and _state, so the splitter
that asks tokenize's _ignorable lives beside it, private, read by
extract and post_rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eview)

Nine rows defaulted to parity; each is labelled from the wheels with
the release its reading arrived in (#653, #272, #851, #792).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in #1340 and #1341. The release log kept both bullets; the
snapshot and corpora were regenerated and match the merged files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first design ended a clause's word at a glued comma in tokenize,
in every clause, and Parser.revise, extract and the clause splitter
compensated for it without converging. They are restored to master:
tokenize, extract, _vocab and _parser are the base's, so a clause
rules/S1 does not set apart yields the base's tokens, tags and text,
and revise reads every value as at the base.

Post_rules' _set_apart_clauses, where S1 is decided for good, now
reads a token holding a single comma glued between two words as those
words (_glued_kind); where they share one kind the token is set apart
whole, its comma kept as written: 'John Smith (MD,PhD)' reads suffix
'MD,PhD'. A doubled comma, a word holding a member of the ambiguous
class, and a title glued to a credential keep the pair's reading.

rules/S1 and decisions/S1 rewritten to what ships, rules/N1 and
decisions/N1 back to master, nameparser/AGENTS.md's spacing sweep
records why the division cannot live in tokenize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter its pattern

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73
derek73 marked this pull request as draft November 11, 2026 22:43
@derek73

derek73 commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner Author

Parked, not merged. Four attempts across two designs did not converge on review.

  • Dividing the glued comma in tokenize (heads through e88094c) reached every bracketed clause, nicknames included, and needed a rejoin in Parser.revise to undo it; that rejoin dropped a comma in some values and invented one in others (5,138 of 34,664 revise cases differed from 8437022).
  • Keeping the word whole and reading its halves in post_rules' S1 decision (8ea9f50) makes one word stand for several credentials: John Smith (Jr,III) reads suffix Jr,III with an empty generation view, (MD,PhD,FACS) reads as one suffix word, and a comma-free clause moved (John (MD<U+200B>) Smith, suffix on master, nickname here).

Incidence, measured 2026-11-11: ClinicalTrials.gov holds 9 names with a comma glued in parentheses, none of them a person's credentials and none reading differently from its spaced form; ORCID holds 6, of which 3 read differently. A comma glued inside a clause with no full stop in it keeps reading as a nickname; #1342 records that limit in rules/S1 and decisions/S1. #1268 stays open for a decision on closing it.

🤖 Generated with Claude Code

derek73 added a commit that referenced this pull request Nov 11, 2026
…clined (#1268) (#1342)

* Record a comma glued inside a clause as word text, and the designs declined (#1268)

`John Smith (MD,PhD)` reads nickname 'MD,PhD' where `(MD, PhD)` reads
the credentials. rules/S1 gains an Accepted bullet with that pair;
decisions/S1 a dated entry declining both designs PR #1339 tried
(dividing in tokenize; reading the word's halves in post_rules), with
the evidence, the incidence recipe over the local corpora and an Open
line for #1268; cases.py pins both readings, labelled from the wheels;
nameparser/AGENTS.md's spacing sweep says what a change to a clause's
division reaches. Nothing a caller sees changes.

Refs #1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Scope #1268's limit to clauses with no full stop, and date its counts (review)

On master a full stop brings other rules in: a clause ending in one
takes the period escape ('(USN,Ret.)' divides), and a word with one
inside is read whole through its chunks ('(Jr.,MD)'). rules/S1's
bullet, the decisions headline and Standing line and the case note
say so, and the bullet names which spacings part ('(MD , PhD)' stays
a nickname). The AGENTS.md lesson puts each input with the design
that moved it, and the revise counts name e88094c and 8ea9f50, a
reviewer's grid not in the repository.

Refs #1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the (Jr.,MD) example from rules/S1's #1268 bullet (CI)

As a rule example it joined the committed corpus, where two property
tests read it: its suffix 'Jr.,MD' revises to 'Jr., MD' as a bare value,
and with the Mongolian comma U+1808 the same clause reads as a nickname.
Both are master's readings, outside this docs-only PR; the bullet's
prose keeps the full-stop case.

Refs #1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug nicknames Nicknames, brackets and quoted names (rules/N) suffixes Generational suffixes and credentials (rules/S)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Should John Smith (MD,PhD) read the credentials when the comma has no space beside it? It gives nickname MD,PhD today

1 participant