Skip to content

fix(#531): a credential ending the given part after a family comma reads as one, and reports - #532

Merged
derek73 merged 5 commits into
masterfrom
claude/531-given-part-trailing-slot
Sep 19, 2026
Merged

derek73 merged 5 commits into
masterfrom
claude/531-given-part-trailing-slot

Conversation

@derek73

@derek73 derek73 commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Closes #531.

What changes

After a family comma, a member of the ambiguous credential class that ends the given part is now read by the same rule the comma-less spelling uses, and reports suffix-or-name whichever way it reads. Words to spare are there by construction at this slot (the comma named the family, the first word is the given name), so the writing is the only evidence left.

Input Before After
Doe, John MA / DOE, JOHN MA / doe, john ma middle, silent suffix MA, reports (1.4.0's reading)
Doe, John Q. MA middle Q. MA middle Q., suffix MA, reports
Doe, John MA PhD / Doe, John MA, PhD middle MA, suffix PhD suffix MA PhD / MA, PhD, reports
Doe, John Ma / Doe, Mary Jo Ma / Doe, John Ed middle, silent middle, reports
Doe, John X.Y.Z. middle, silent suffix, reports (dotted switch off: middle, reports)
Doe, John DO family DO Doe suffix DO, reports
Doe, John do / Do / DOE, JOHN DO particle rule (P6) unchanged
Doe, John MA Smith, Doe, John V, PhD, Doe, MA unchanged

do — capitals decide, otherwise the particle rule keeps it. do is the one class member that is also a particle. One-case NASCIMENTO, EDSON ARANTES DO and SMITH, JOHN DO are the same shape and read alike (family DO …, particle-or-given): right about the first, wrong about the second, which is the accepted cost. In mixed case the writing can tell them apart, and does: Nascimento, Edson Arantes do keeps family do Nascimento, Doe, John DO gives suffix DO. P6 gained a stand-down condition for exactly that piece; vd / mc are untouched. A particle in front (Doe, John van DO) is one particle run before this slot exists and attaches whole — pre-existing, recorded.

Design calls made with Derek

  • Approach "one rule for both spellings" over report-only and over capitals-only. Agreement sweep (78 comma / comma-less pairs): 48 disagreed before, 3 after — all three the lower-case do rows P6 owns.
  • Accepted: Doe, John van MA → family van Doe, suffix MA (P6 now sees van trailing the given part, as in Berg, Jan van Jr.); Doe, John Prof. MA gains title Prof. (H5 transparency); Smith, LEED AP under unlisted_caps_suffixes → suffix AP; declined members report.
  • Out of scope, follow-up drafted for approval: the maiden walk (Doe, Jane nee Smith MA stays maiden Smith MA, silent).

Four silences remain and are named in AmbiguityKind.SUFFIX_OR_NAME's docstring: a name word behind the member, the maiden walk's take, no name word in front (Doe, Dr. MA), and a member a particle run absorbed or left behind (Doe, John van Ma, Doe, John MA do).

Commits

  1. fix(#531) — the branch inside reads_as_a_suffix (one predicate for both of the walk's readers), the fifth SUFFIX_OR_NAME emitter, P6's condition, 42 case rows, unit tests, the agreement property test, rules.md example lines, corpora and claims. Review found the first draft exponential in the length of a trailing member run (24 members: 5.8 s); fixed with a member memo and one hoisted floor walk, readings byte-identical over 68,056 generated rows, and guarded by a frame-ratio test (168× unfixed, 2.08× fixed, bound 10×).
  2. test(#531) — ledgers at all five baselines. The 1.4.0 rule fix(given-part-trailing-slot) is re-pointed to the declined members (_ambiguities cannot diff below 2.0).
  3. docs(#531) — rules.md S2/C1/P6, decisions.md (### S2 bullets closing the open follow-up, cross-amendments under P6 and ma-do), mechanisms.md field note (a frame budget cannot see algorithmic blowup; a ratio can), release log (new bullet, and the existing 2.4.0 bullet's now-false "stays silent" sentence corrected in place), customize.rst.

Verification

  • Suite: 8905 passed, 309 skipped, 4 xfailed; mypy and ruff clean; sphinx doctest 253 / 0 failures; README doctest clean.
  • Frames: parse 412.00 / facade 449.00; non-trigger comma names +0 (Smith, John, Doe, John Q., Smith, John V, Smith, MA, Berg, Jan vd); triggers Doe, John MA +6, Doe, John MA PhD +25.
  • Differential gates, all 0 unexplained: 1.4.0 1255 names / 465 intentional; 2.0.0 1262 / 419; 2.1.0 1262 / 331; 2.2.0 1262 / 188; 2.3.0 1262 / 74 (radar unclassified 0 / 5 / 6 / 7 / 7, all pre-existing).
  • Blast radius on the corpus as it stood before this branch, default policy: two names (Doe, John MA, Doe, John X.Y.Z., both added by Case and shape decide a bare ambiguous credential acronym (#289, #516) #530). The rest of the ledger growth is this change's own case rows.
  • Independent reviews: code review of commit 1 (126,684 generated inputs × 6 policies, no token reported twice) and a design-docs review of commit 3; findings from both are folded into the commits.

🤖 Generated with Claude Code

derek73 and others added 3 commits September 18, 2026 23:14
After a family comma, a member of the ambiguous credential class
standing at the END of the given part read as a middle name and
reported nothing, while the comma-less spelling of the same name did
the opposite on both counts. Over a generated sweep of 78 pairs, 48
disagreed about whether the word was a credential or a name, every one
of them in the same direction. After this change 3 disagree, and all
three are the lower-case `do` rows rules.md#P6 owns.

The comma has already named the family and the first word after it is
the given name, so the words to spare S2's count asks about are there
by construction and the count says nothing at this slot. What decides
is the writing, which is the same evidence the comma-less spelling
reads: a member written in a cased form that is neither capitals nor
wholly lower, in a name written in more than one case, stays a name.
`Doe, John MA` reads suffix `MA` again, as 1.4.0 read it; `Doe, John
Ma` keeps middle `Ma`. Either reading is now reported.

The branch is INLINE in `reads_as_a_suffix`, the one predicate both
readers of this walk already ask, with the membership test first on
tags already in hand: measured, a comma name carrying no class member
pays +0 frames, and a helper on that path cost +1 on every one of
them.

`do` is the one class member that is also particle vocabulary. P6's
attachment keeps every spelling but the capitals: `Doe, John DO` reads
suffix `DO` while `Doe, John do`, `Doe, John Do`, `DOE, JOHN DO` and
`doe, john do` attach to the family exactly as they do today, each
reporting P6's own kind and no second report. P6's run walk declines a
one-token suffix-roled piece carrying `vocab:suffix-ambiguous`, which
is narrow enough to leave `vd` and `mc` inside the run.

The three generated corpora move with the case rows and the rules.md
example lines: 26 distinct names join, 1230 to 1256, and twelve
`_CORPUS_CLAIMS` digests follow the corpus text rather than any rule
-- seven at 1.4.0, three at 2.0.0, two at 2.1.0, no roles joined.

Review round: that trailing walk re-entered the predicate that owns
it, so a run of k class members cost 2**k -- 'Doe, John ' + 'MA '*24
took 5.8s where cc78c96 took 0.24ms. The member verdict is now
memoized per (piece, titled), which is sound because nothing the
verdict rests on reads `.role`, and the report's own walk runs ONCE
for the loop rather than per member, that emitter having been cubic
over the same run. Readings are byte-identical over 17,015 names x
four policies; a frame-ratio guard in test_benchmark.py fails at
168x on the unfixed code and reads 2.1x now. Also: the cost comment
no longer claims a member is asked once, SUFFIX_OR_NAME's docstring
names the THIRD silent boundary and stops claiming both directions
where P6 reports instead, and the 'Doe, John Ma' note no longer
calls itself the only report-without-a-move. Two control rows join,
'Doe, John van DO' (grouping merges the member into a particle
piece, so the capitals lean never reaches it) and 'Doe, Dr. MA'
(the third boundary), which takes the counts above to 28 names,
1230 to 1258, and seventeen digests -- ten at 1.4.0, four at 2.0.0,
three at 2.1.0, still no roles joined.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Twenty-one rules, written from the gate's own output rather than
predicted beside the change -- the plan's "six rules, two corpus
names" was written before commit 1 admitted twenty-eight names to the
corpora, and every count in it is superseded by the numbers below.

TWENTY corpus names move under #531, measured name by name against the
tree at cc78c96: eighteen on the contract tier and the two caseless
comma forms on the radar tier. Thirteen take the credential reading,
four keep their name reading because the WRITING declines and gain the
report alone, one is the `do` spelling the capitals take from P6, and
two are the CJK forms where the lean is inert and the positional
reading is not.

At 1.4.0 the existing given-part-trailing-slot rule neither retired as
its own comment predicted nor narrowed to `_ambiguities`: it CHANGED
NAMES. 'Doe, John MA' now matches the 1.4.0 wheel on every role and
leaves the ledger -- the report it gains is a v2 surface that cannot
enter a diff below baseline 2.0 -- and the four names that replace it
carry the same reading the rule describes, declined by the writing
rather than by the slot's silence. Its dotted sibling gets a rule of
its own: 'Doe, John X.Y.Z.' is a middle name at 1.4.0 too, so reading
it as a suffix is a new divergence rather than a restoration, and it
is recorded as the accepted cost it is.

Six more 1.4.0 divergences are NOT this change's and are attributed
where they belong. 'Doe, John MA Smith' is a 2.0-era family-comma
routing difference and files under fix(comma-family), the
classification its case row already carries. The five trailing
particle-and-credential names -- 'Berg, Jan mc' and the four `do`
rows -- are P6's, and carry fix(#380)'s decision read over the other
two collision words; 'Doe, John DO' is the spelling #531 takes OUT of
that set, and is a _MUST_NOT_MATCH probe there because of it. Three
lone post-comma credentials ('Doe, MA', 'Doe, MA PhD', 'Doe, Dr. MA')
join the existing fix(#289) rule at the four 2.x ledgers only; at
1.4.0 an earlier comma rule already owns their diff.

Every rule is literal-anchored for the reason its siblings give: the
class is a SLOT, and a regex for the slot would claim every
family-comma name whose given part ends in an ambiguous acronym,
including the ones that do not move. _MUST_NOT_MATCH gains a key per
new rule, and fix(#380)'s key is rekeyed to its full issue text, the
same repair fix(#360)'s pair already records.

All five gates exit 0 with `unexplained: 0`:

  1.4.0  1255 names; intentional 465; unexplained 0; radar 0
  2.0.0  1262 names; intentional 419; unexplained 0; radar 5
  2.1.0  1262 names; intentional 331; unexplained 0; radar 6
  2.2.0  1262 names; intentional 188; unexplained 0; radar 7
  2.3.0  1262 names; intentional  74; unexplained 0; radar 7

Radar-unclassified drops by exactly the two CJK movers at every 2.x
baseline (7/8/9/9 to 5/6/7/7); the seven that remain are older and
were verified byte-identical across this change. No cross-rule contest
appeared: _CROSS_RULE_WINNERS and _RECORDED_DIFFS need no new row,
because the comma rules that reach 'Doe, John X.Y.Z.' narrow by roles
its diff does not move.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
rules.md#S2 states the rule the given part's trailing slot now
follows -- the comma settled the count, so the writing is the only
evidence there is -- and says what "ending the given part" reaches
past, what ends its reach, and how many times a run of members
reports. Its "evidence is SECOND" clause is split between the two
comma slots, since it was only ever true of the first one. #C1 names
the second place the comma's own decision is reported, and #P6 gains
the capitals exception with three example lines. #S2 gains P6 to its
`interacts:` and three example lines of its own: the two-report run
('Doe, John MA JD'), and 'Doe, John MA Ma' twice, where the LAST
member declines and the run stays middle text on ONE report. S2's
slot sentence and S3's exclusion went in commit 1 and are not
touched again.

decisions.md gets two dated bullets under S2. The first records
Derek's `do` decision and the two carve-outs it takes, one of them in
the report rather than the reading, plus the spelling the pairing
cannot reach ('Doe, John van DO', where grouping merges the member
into a particle piece before this slot exists). The second CLOSES the
2026-09-18 comma-reach bullet -- which is left exactly as it landed,
and is referred to by its heading rather than by position -- and
records the measurement that settled the noise question: 48 of 78
generated pairs disagreed about this word before the change and 3 do
after. It also records Derek's choice of restoring the ROLE over a
report-only or capitals-only change, the parity split, the seven
accepted costs, and the blast radius as the gate can see it: twenty
corpus names move and TWO of them predate this branch. One-line
cross-amendments go to #P6 (the stand-down condition, narrowed to the
ambiguous tag so `vd` and `mc` stay inside the run) and to #ma-do.

mechanisms.md gains a field note for the trap this arc hit: a frame
BUDGET pinned on one reference name cannot see algorithmic blowup and
a frame RATIO over two sizes can -- 412/449 never moved while a run
of 24 credentials went from 0.24ms to 5.8s.

The release log gains a bullet and loses a sentence: the existing
comma-report bullet named this slot as one that stays silent, and
2.4.0 being unreleased, that sentence is corrected in place rather
than supplemented. customize.rst's two 2.4 switch entries name the
family-comma form the slot brings into their reach.

corpus_rules.jsonl takes the three new example texts. All three were
already in corpus_shapes.jsonl, so the gate's deduped name set does
not grow, no _CORPUS_CLAIMS digest moves, and all five gates still
exit 0 with `unexplained: 0`.

Design-docs review round: the capitals exception and this slot's
silences were both stated universally, and a particle falsifies both.
#P6 and #S2 now carry the carve-out -- a particle in front of the caps
`do` makes one particle run the attachment takes whole, and
'Doe, John van DO' is P6's example line for it -- #S2's reach clause
names the particle BEHIND the member and the `vd`/`mc` exception to
that, and SUFFIX_OR_NAME's silences go from THREE to FOUR, the new one
covering both directions with the caps spellings that are NOT in it.
The `do` bullet's "one spelling" was a SHAPE; its sweep composition
multiplied to 108 rather than 78 and now reads as the test builds it;
and mechanisms.md stops quoting one wall-clock figure where the two
recorded runs read 5.8s and 5.9s. corpus_rules.jsonl takes one further
example text, already a corpus_shapes.jsonl name, so the gate set is
again unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@derek73 derek73 added this to the 2.4 milestone Sep 19, 2026
@derek73 derek73 added bug enhancement docs Documentation fixes and updates labels Sep 19, 2026
@derek73 derek73 self-assigned this Sep 19, 2026
@codecov

codecov Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.74%. Comparing base (cc78c96) to head (03625a2).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #532      +/-   ##
==========================================
+ Coverage   98.73%   98.74%   +0.01%     
==========================================
  Files          45       45              
  Lines        3475     3509      +34     
==========================================
+ Hits         3431     3465      +34     
  Misses         44       44              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

derek73 and others added 2 commits September 19, 2026 03:37
… and the silences the docstring left out

A. The trailing slot is ONE monotone descent per `titled` value, shared
by the predicate and by the report, so both are linear: `'Doe, John ' +
'MA '*k` measures 2.1/4.1/8.3/17.1ms at k=200/400/800/1600 against the
memo's 8.6/31.4/120/463 and cc78c96's 1.5/3.2/7.2/17.3. The report's
own walk is gone -- it was cubic on `'Doe, ' + 'John '*r + 'MA '*r`
(5.8/28/175/1229ms at r=100..800), now 1.8/3.7/8.0. Readings
byte-identical over 64,322 names x 6 policies; call_count 412.00/449.00;
frames +0 on all five controls, -2 on 'Doe, John MA PhD', -1 on
'Doe, John MA JD'. test_benchmark gains a second frame pair (16 vs 64):
8-vs-16 cannot separate quadratic from linear -- the memo reads 2.08x
there against this tree's 1.73x -- while 16-vs-64 reads 7.42x against
3.53x. Bounds 6.0 and 5.0, asserted in that order.

B. Eleven case rows. 'Doe, John MA y' and 'Doe, John DO Ed' kill the two
`len(piece) == 1` guards, which both SURVIVED at e7fbb4c (each deleted
in a scratch copy to prove it). The rest pin the documented silences and
boundaries, measured, plus the stale-floor catcher 'Doe, John MA Ma MA'.
corpus_shapes/corpus_rules regenerated (+7/+2 names), five _CORPUS_CLAIMS
digests re-recorded, two new 1.4.0 rules and two 2.x literal sets
widened; all five differential gates exit 0 with 0 unexplained.

C. "a kind is worth adding only if a reader would hesitate too" is
AGENTS.md's, not rules.md#A1's, at both sites; the exponential's timings
are quoted once with the profiled/unprofiled split named;
SUFFIX_OR_NAME's silences now cover the member HEADING a particle chain
and say the first-piece emitter reads that piece and no further, with
rules.md#S2 and four ledger sentences corrected to match; one
release-log clause for the report belonging to the spelling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… descent left uncovered

'Doe, John MA Prof. Jr' puts the titled piece between the member and a
suffix, so the descent steps over it; every existing row put the title
at an end of the run. Found by the patch-coverage gate (97.14% of the
diff against a 98.73% target); _assign.py is back to 100%.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@derek73
derek73 merged commit 2f57ff2 into master Sep 19, 2026
11 checks passed
@derek73
derek73 deleted the claude/531-given-part-trailing-slot branch September 19, 2026 19:56
derek73 added a commit to IMGillusion/python-nameparser that referenced this pull request Sep 22, 2026
…nd the ph removal is on the record

Maintainer fix-up on PR derek73#521 after the merge from master, the eight
items of the 2026-09-16 review comment:

- decisions.md R4: the reach is remeasured on the merged tree with
  the recipe's comparator named (master's `_cap_word` at 23e52dc),
  and the two earlier snapshots are explained rather than replaced --
  the `ph` removal took 13 forced movers back to `Ph. D.`, and the
  rows PRs derek73#530/derek73#532/derek73#534 added account for the rest of the drift.
  The exceptions map's job is stated as the spellings
  `str.capitalize()` gets wrong, not "non-all-caps" (II/III/IV are
  all-caps); the precedence over Mac/Mc and the role-not-tag reach
  of the gate are recorded.
- decisions.md: an `Excluded (SUFFIX_ACRONYMS — ph)` block beside
  esq's, so a wordlist sweep does not put the fragment back.
- rules.md R4: the non-acronym clause is qualified by the exceptions
  map (`john smith ii` -> `II`), the acronym repair's precedence over
  the Mac/Mc convention is stated and pinned by a `john smith mcse`
  row (`McSe` without it), and the Accepted paragraph names which
  clause it is about and states the acronym repair's contrast on a
  spliced suffix.
- release_log.rst: the bullet moves from the shipped 2.3.0 section
  to 2.4.0 with the current digits, and `ph` leaving the set gets
  its own bullet in the rai/cha shape.
- corpus_rules.jsonl regenerated (three new R4 rows).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug docs Documentation fixes and updates enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Should Doe, John MA read MA as a credential, as 1.4.0 did, or at least report the fork?

1 participant