Skip to content

Read the spaced Ph. D. as a credential only where the lexicon lists phd (#1000) - #1004

Merged
derek73 merged 5 commits into
masterfrom
fix/issue-1000-phd-pair-by-lexicon
Nov 3, 2026
Merged

derek73 merged 5 commits into
masterfrom
fix/issue-1000-phd-pair-by-lexicon

Conversation

@derek73

@derek73 derek73 commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Closes #1000.

What changes

_vocab.split_pair merged Ph. + D. into a credential by a fixed pattern, with no vocabulary lookup. So removing phd from a Lexicon turned off the joined PhD but left the spaced pair a credential. Nothing could turn the pair off, and Lexicon.empty() and a strict choice whose files leave phd out read the two spellings differently.

The pair now follows the lexicon:

lexicon split_pair("Ph.", "D.") John Smith Ph. D.
lists phd as unambiguous suffix vocabulary, a credential (the default, every plain choice) or a suffix word "suffix", as before suffix 'Ph. D.' (unchanged)
no unambiguous phd: removed, marked ambiguous as a credential (add("phd", kind="family")) or as a suffix word, Lexicon.empty(), strict pt/es None, the two words middle 'Smith Ph.', family 'D.'

Where the lexicon holds no phd, the spaced pair and PhD agree that neither is a credential, and where it lists phd as unambiguous suffix vocabulary of either kind, that both are. Where phd is marked ambiguous, the pair is its two words while PhD is left to the count, so the two can still part (John Smith, Ph. D. reads title 'Ph.', given 'D.', where John Smith, PhD reads suffix 'PhD'). They cannot read identically otherwise, since unmerged the pair is two name words where PhD is one. The dotted Ph.D. stays a suffix by its shape (rules/S3) under every lexicon. Where the pair does not merge, an overlapping pair whose fold is listed merges instead: Jane Doe Dr. Ph. D. reads suffix 'Dr. Ph. D.', taking Dr. Ph. as drph.

Measured

The counts are in the #1000 comment, taken on master b2b75948.

  • 687 corpus entries (684 distinct names) write the pair spaced, 624 of them in ctgov-officials, which also holds 100,908 joined PhD / Ph.D..
  • Moves, master against this branch over those 687 entries (684 distinct names), comparing the seven role fields:
    • 491 entries (489 names) under strict pt, strict es and Lexicon.empty() (ctgov 441, fec 13, orcid 12, cz 1, committed 24);
    • 425 entries (423 names) with phd removed;
    • 0 under the default.
  • tools/differential/snapshot.py: matches the snapshot, so no default parse moved.

Review

The independent review found that the first version answered "split" for an ambiguous phd, unlike every other ambiguous fold, and lost the pair's precedence over Dr. Ph.; ecc8e5a leaves such a phd to the other pairs' path and fixes the prose it flagged. The second review of that fix found the gate asked suffix_acronyms alone, so phd listed as a suffix word parted the spellings again, and four prose claims wrong when run; e5c0cab widens the gate to unambiguous suffix vocabulary of either kind and fixes them. The third review found that a phd marked ambiguous as a suffix word still fell through to the split-credential path, which admits it as a counted member; 00e28b2 has the pair answer directly, "suffix" or None, and its rows fail against e5c0cab.

Docs

  • rules/S12: the Except bullet for the Ph./D. pair now says it is a credential only where the lexicon lists phd as unambiguous suffix vocabulary, and states the shape reading of Ph.D. and the overlap. The rule grew 674 → 777 words, and rules_budget.json is re-recorded. The new clause reads the vocabulary the rule already reads, so it adds no new signal.
  • decisions/phd-merge: a Standing bullet and a dated Log entry, which records the declined option (b).
  • Stale "whatever the vocabulary" passages amended:
    • decisions/S12's Standing;
    • decisions/vocabulary-exclusions' ph bullet;
    • vocabulary-model's 4i-d item (3), which opened this issue;
    • classify's pre-check comment.
  • Release log: a Behavior Changes bullet.

Tests

  • test_phd_pair_is_no_credential_where_the_lexicon_lists_no_phd: seven shapes under five lexicons without an unambiguous phd, one of them a family-first strict choice: neither word of the pair is a suffix.
  • test_phd_pair_reads_its_two_words_where_it_does_not_merge: the two-word reading and Ph.D.'s shape reading, with phd removed or marked ambiguous.
  • test_phd_pair_outranks_an_overlapping_pair_only_where_it_merges.
  • test_phd_listed_as_a_suffix_word_reads_both_spellings_alike: phd listed as a suffix word reads the pair as PhD reads.
  • test_an_empty_lexicon_names_no_file: restores coverage of the empty-lexicon branch of the reading-files lookup, which only the old Ph. D. reading under Lexicon.empty() reached.
  • Negative controls: every new _vocab.py row fails against master's (test_an_empty_lexicon_names_no_file excepted, which tests _lexicon.py); 6 ambiguous rows fail against the first-round fix (1bf9f0b), while the ambiguous rows for John Ph. D., John Ph. D. Smith and the overlap read the same in both versions; the 3 suffix-word rows fail against ecc8e5a's suffix_acronyms-only gate.
  • Updated tests that pinned the old behavior:
    • test_the_ph_d_pair_merges_whatever_the_vocabulary_says, renamed test_the_ph_d_pair_reads_by_the_vocabulary;
    • the strict half of test_reading_languages_under_a_strict_choice_name_the_chosen_files.
  • test_layering's recorded count of unguarded _sets reads is 112 → 117, the gate's four new reads and one sets = binding.

Not in scope: whether phd and other credentials used across languages belong in mul.toml, and whether a strict choice should read mul.toml. That gets its own issue.

🤖 Generated with Claude Code

…hd (#1000)

The Ph./D. answer of split_pair asked no vocabulary, so removing `phd`
from a Lexicon turned off the joined PhD and left the spaced pair a
credential, with no way to turn it off; Lexicon.empty() and a strict
choice whose files leave `phd` out read the two spellings apart too.
The pair now answers by the lexicon: "suffix" where `phd` is an
unambiguous credential (the default, unchanged), "split" where it is
marked ambiguous, and otherwise it is asked as any other pair.

rules/S12's Except bullet and decisions/phd-merge record it, with the
corpus counts from #1000; the stale "whatever the vocabulary" passages
in decisions/S12, vocabulary-exclusions and vocabulary-model's 4i-d
item, and classify's pre-check comment, are amended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
derek73 and others added 4 commits November 2, 2026 17:43
No parse under Lexicon.empty() takes a vocabulary reading since the
Ph./D. pair reads by the lexicon, so the empty branch of
_ReadingFiles.languages lost its only covering input.

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

The first version answered "split" for a `phd` marked ambiguous, which
no other pair whose fold is ambiguous gets (`pharmd` never merges), and
which lost the pair's precedence over an overlapping `Dr. Ph.`. The pair
is now the unambiguous credential only where `phd` is one, and is asked
as any other pair otherwise, so ambiguous and unlisted read alike.

Review fixes besides: rules/S12 and decisions/phd-merge say removing
`phd` turns off `PhD` and the spaced pair while the dotted `Ph.D.` stays
a suffix by its shape, scope the overlap precedence to where the pair
merges, and replace the 504 disagreements with the measured move count
(491 under strict pt/es and Lexicon.empty(), 425 with phd removed, 0
under the default); the release bullet no longer says the two
spellings read alike; stale "whatever the vocabulary" prose in
pipeline/test_vocab.py and the split tags' docstrings in _types.py and
_classify.py is scoped. Tests pin the two-word reading, the shape
reading of Ph.D., the overlap under both lexicons and a family-first
strict choice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r kind (#1000 second review)

A caller listing `phd` as a suffix word read `PhD` as an unambiguous
suffix while the spaced pair fell to the other pairs' path and read as
two words (`John Ph. D.` middle 'Ph.', family 'D.' against `John PhD`
suffix 'PhD'); the gate now takes `phd` in either suffix set and in
neither ambiguous one, as the joined spelling reads it.

Prose the second review found wrong when run: decisions/phd-merge said
all 16 default-lexicon disagreements open the string (6 do), stated the
`Dr. Ph.` overlap reading where `drph` is unlisted too, gave the declined
"split" answer's cost as the overlap (it was the counted suffix), and
counted per-file entries as names (687 entries, 684 names; 491 moves,
489 names). rules/S12's bullet no longer says one thing twice. Stale
comments in _comma.py, _group.py and pipeline/test_vocab.py, and a
vacuous empty-lexicon assertion, are fixed.

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

The pair fell through to the split-credential path wherever the gate
refused it, and that path admits an ambiguous suffix word as a counted
member: a `phd` marked ambiguous as a suffix word read `John Smith
Ph. D.` suffix 'Ph. D.' where the docs promise the two words. The fold
of the pair is `phd` itself, so the fall-through could only ever reach
that case; the pair now answers directly, "suffix" or None.

Also: decisions/phd-merge counts the 504 and 16 disagreements as entries
and names, and names both ways of marking `phd` ambiguous; the comma and
group comments say "unambiguous"; test_layering's count is 117, the gate
adding one `sets =` binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73
derek73 merged commit 2c77d14 into master Nov 3, 2026
20 of 21 checks passed
@derek73
derek73 deleted the fix/issue-1000-phd-pair-by-lexicon branch November 4, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vocabulary Per-word vocabulary model and language packs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Should John Smith Ph. D. read suffix 'Ph. D.' under a lexicon that lists no phd, such as parser_for(locales.PT, strict=True) or Lexicon.empty()?

1 participant