close
Skip to content

Add "abd" to BOUND_GIVEN_NAMES, and let a word in two vocabularies satisfy the join reserve - #400

Merged
derek73 merged 1 commit into
masterfrom
fix/abd-bound-given-name
Aug 19, 2026
Merged

Add "abd" to BOUND_GIVEN_NAMES, and let a word in two vocabularies satisfy the join reserve#400
derek73 merged 1 commit into
masterfrom
fix/abd-bound-given-name

Conversation

@derek73

@derek73 derek73 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

abd Allah Smith read given abd, middle Allah, where abdul Rahman Smith reads given abdul Rahman. The spellings that write the article as its own word — Abd Allah, Abd al-Rahman — match none of abdul/abdel/abdal, and the Arabic-script عبد has covered the same word since #269, so only the Latin side was short.

abd Allah Smith          ->  given='abd Allah'   family='Smith'      (was given='abd', middle='Allah')
Smith, abd Allah         ->  given='abd Allah'   family='Smith'
abd Rahman Ahmed Salem   ->  given='abd Rahman'  middle='Ahmed'      (pairwise, like abdul)

Why the wordlist alone doesn't do it

abd is also the postnominal ABD ("All But Dissertation") in SUFFIX_ACRONYMS. The join's reserve counted every piece except titles and suffixes — so the bound word's own piece didn't count toward the three it needed, and the rule declined silently on the common three-word shape. Adding the word and stopping there changes nothing:

                                  abd Allah Smith        Jane Smith, ABD
wordlist only                     unchanged (broken)     suffix='ABD'
+ move to acronyms-ambiguous      given='abd Allah'      given='ABD'  <- credential lost
+ drop from SUFFIX_ACRONYMS       given='abd Allah'      family='ABD' <- credential lost
+ fix the reserve count           given='abd Allah'      suffix='ABD'

The last row is this PR. The claimed piece now counts, which is what the reserve means: it asks whether enough other words are left to spare, and the piece the rule has already claimed as a name is not one of them to spare. Both readings survive — position tells them apart, so Jane Smith ABD, Jane Smith, ABD and Jane Smith A.B.D. all still read the credential as a suffix.

Same shape as #397

Dual set membership shrinking a count that gates a rule is exactly the Catalan i finding — there it shrinks the rootname count P3's single-letter carve-out tests. Second instance in two days. The general question (should membership in one set suppress a word from a count gating a rule keyed on another?) stays open on #397; this PR fixes only the instance in front of it, where the count was wrong on its own terms.

Verification

abd is the only shipped word in both sets — measured, not assumed — so nothing else can move. All 751 differential corpus names are byte-identical and the harness reports 0 unexplained at the 1.4.0 baseline. The corpus contains no abd name, so that is a blast-radius check, not evidence for the fix; the evidence is the tests.

Mutation-verified: reverting the count line alone puts abd Allah Smith back to given abd. The stage-level test in test_group.py uses a synthetic word in both vocabularies, so it pins the mechanism rather than the wordlist, and asserts the reserve still declines at two name words.

3522 tests pass, mypy clean. Per-word evidence comments added on both sides of the collision, in the #: style, so a future editor of either set sees the other.

Review round

Four reviewers ran against this branch. The code review could not break the change and proved the blast-radius claim rather than sampling it: the join's own guard requires a one-token piece, and a one-token piece can never carry a suffix ptag, so dual membership collapses to exactly the set intersection — {abd}. Spellings cannot sneak in either, since A.B.D. normalizes to a.b.d for the acronym test and never matches the bound word. Empirically: 0 diffs over the shipped corpora, and 0 over 124,535 constructed abd-free inputs across all three name orders.

What the reviews changed here:

  • An assertion in the stage test was inertdual Allah never reaches the reserve, an outer >= 3 gate short-circuiting first, so it passed even with the reserve broken. Replaced with dual Allah jr, which the tempting simpler repair (count every non-title piece) fails by joining and leaving no family name.
  • The changed line is a suffix count and nothing combined a firing join with a suffix. Six such shapes reverted silently under mutation; they are now pinned, along with abd Allah Smith ABD — both readings in one string, which is the collision's whole thesis.
  • Two comment claims were false: "Abd Allah" and "Abd al-Rahman" are two-word and do not change at all, and the stated rationale ("spellings that write the article as its own word") names the one spelling still not joined — abd al rahman smith, where al chains forward. That half of the original exclusion survives and is now recorded as a known limit.
  • "Position tells them apart" was too strong: in the given slot of a family-comma name the credential still wins (Smith, Abdsuffix='Abd', no given name, no ambiguity emitted), where Smith, Abdul gives the given name.
  • decisions.md still listed abd under Excluded seven lines below the entry adding it; the constant's own docstring stated the reserve rule this PR falsifies; عبد shipped in 2.0, not 2.1; and the suffixes.py comment named عبد as the dual member when it is abd.
  • This is not a C-ii collision. C-ii settles a precedence by frequency where neither reading is a name. Here one reading is a name and both survive, decided by position — which is C-i's positional qualifier, the de row of that table rather than the vd row. Relabelled, because C-ii is cited elsewhere for a real precedence and the two must stay distinguishable.
  • rules.md#P5 now states its reserve and its S2 precedence, the way P6 already does for the identical situation. P5 previously had no interacts: line at all.
  • The release-log claim is reframed: 0 of 751 corpus names carry a dual-membership word, so byte-identity there tests the corpus. The real argument is arithmetic — for a non-suffix first piece the new expression reduces to the old one.

A pre-existing bug found in passing is filed as #401 (abdul Smith V loses the family name; the reserve counts an initial-shaped Roman numeral as a name word to spare). Not addressed here — it predates this PR and reproduces on master with abdul.

mechanisms.md gains one field note from the review method itself: re-exec'ing a module in-process rebinds its enums to new classes, so is comparisons against the original module's members answer wrong silently — that produced 3,150 phantom movers in one sweep before it was caught.

3531 tests pass, mypy clean, differential 0 unexplained.

🤖 Generated with Claude Code

@derek73 derek73 self-assigned this Aug 18, 2026
@derek73
derek73 force-pushed the fix/abd-bound-given-name branch from fce7dd3 to e862284 Compare August 18, 2026 10:18
@derek73 derek73 added this to the v2.2 milestone Aug 18, 2026
@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.53%. Comparing base (55a7822) to head (268b47e).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #400   +/-   ##
=======================================
  Coverage   98.53%   98.53%           
=======================================
  Files          44       44           
  Lines        2942     2942           
=======================================
  Hits         2899     2899           
  Misses         43       43           

☔ 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.

"abd Allah Smith" read given 'abd', middle 'Allah' where "abdul Rahman
Smith" reads given 'abdul Rahman'. The spellings that write the
article as its own word -- Abd Allah, Abd al-Rahman -- match none of
abdul/abdel/abdal, and the Arabic-script عبد has covered the same word
since #269, so only the Latin side was short.

Adding the word alone does not fix it, which is why this is not a
one-line change. `abd` is also the postnominal ABD ("All But
Dissertation") in SUFFIX_ACRONYMS, and the join's reserve counted
every piece except titles and suffixes -- so the bound word's own
piece did not count toward the three it needed, and the rule declined
silently on the common three-word shape. The claimed piece now counts,
which is what the reserve means: it asks whether enough OTHER words
are left to spare, and this piece is not one of them to spare.

Measured, the vocabulary-only alternatives each cost something this
does not: moving `abd` to SUFFIX_ACRONYMS_AMBIGUOUS loses
"Jane Smith, ABD", and dropping it from SUFFIX_ACRONYMS loses the
postnominal outright. Keeping both readings costs nothing here --
position tells them apart, and all three credential spellings still
parse.

`abd` is the only shipped word in both sets (asserted by measurement,
not assumption), so nothing else moves; all 751 differential corpus
names are byte-identical and the harness reports 0 unexplained.

Same shape as #397, where dual membership shrinks the rootname count
P3's carve-out tests -- recorded at decisions.md#P5, with the general
question left open on that issue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73
derek73 force-pushed the fix/abd-bound-given-name branch from 0b11278 to 268b47e Compare August 19, 2026 02:15
@derek73
derek73 merged commit 5b1d8b6 into master Aug 19, 2026
11 checks passed
@derek73
derek73 deleted the fix/abd-bound-given-name branch August 19, 2026 02:20
derek73 added a commit that referenced this pull request Aug 19, 2026
Price every candidate fix before choosing one, by simulating each
in-process rather than implementing it. Recorded because the practice
paid twice and its absence cost once, all in one session.

#397 and #400 both turned on it: the obvious fix in #400 -- add the
word to the list -- provably changed nothing on the common shape, and
the two vocabulary alternatives each lost a credential spelling. The
winner was a fifth option the wordlist framing had hidden, and none of
that was visible until the candidates ran side by side.

The counterexample is #403's ledger `fields`, widened on one
reviewer's finding without pricing what else the widening claimed. It
took {family, suffix} from a neighbouring rule and two more shapes
from UNEXPLAINED -- diffs in which the rule's own subject does not
move -- and had to be reverted.

Filed here rather than in AGENTS.md because AGENTS.md's own rule sends
a new reusable pattern to mechanisms.md, and it already points at this
section twice.

Refs #400, #403

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
derek73 added a commit that referenced this pull request Aug 19, 2026
From this session's practice, kept terse because AGENTS.md is loaded
every session:

- review the fix commit too -- second-round passes on #398, #400 and
  #403 each found defects in the first round's fixes
- check the PR description before merging; a review that moves
  behavior leaves it stale, and a stale body reads as authoritative
- a scripted multi-edit that asserts as it goes discards everything
  when a late pattern misses, silently, since prose edits fail no test

mechanisms.md's "check the receiver" field note gains the other half:
ask what the old behavior was CONCEALING. #379's attachment removed
the input a test used to build an all-particle middle name (#402), and
#400's reserve fix exposed the count shape #397 names.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
derek73 added a commit that referenced this pull request Aug 22, 2026
Review found the reserve fix necessary but not sufficient, and two
prose claims measurably false.

Excluding the departing words is not enough on its own. Where a suffix
sits INSIDE the name the marker walk stops early, so the excluded span
is short, enough words survive it to clear the reserve, and the join
fires and takes the MARKER -- after which nothing leaves at all and the
count that authorised the join was reasoning about a name that never
came to be. `abd née Jones Jr Smith Berg` read given 'abd née'.

The join now declines outright when the piece it would absorb is a
marker, which is what P5 meant all along: it joins the bound word to a
name word, and a marker is not one. Tested against the marker directly
rather than through the span, because the two differ exactly where it
matters -- a marker with nothing but a suffix after it has no span at
all, yet the join would still have absorbed it (`Berg, abdul née PhD`
read given 'abdul née'). That closes the P5 half of #412 for real; the
first cut only narrowed it while claiming it closed.

The docstring's "the count and the removal cannot disagree" was the
same overstatement this session already shipped once. Sharing the span
helper settles what a maiden span IS; it does not settle what leaves,
because the two calls run at different times on different piece lists
and the join between them can invalidate the span. Forbidding the join
to absorb a marker is what closes that -- the sharing only rules out
disagreeing about the span itself.

The pre-existence claim was backwards. `abd Berg née Jones` reads
CORRECTLY at 2.1.0; `abd` acquired the defect only when #400 made it a
bound given-name word this cycle, so for that spelling this fixes a
regression introduced earlier in the same release. The pre-existing
witness is `abdul`/`abdel`/`abdal`, which read the defect at 2.0.0 and
2.1.0 alike. The issue body carries the same error and needs it too.

Six more rows, each closing a measured gap:

- `Abd Berg née Mary Jones`. Capping the excluded span at two pieces
  reproduced #411 exactly with the whole suite green -- every existing
  row had a one-word maiden name, so none could tell the span from the
  marker plus one. A particle-led maiden name does not serve; P2 makes
  it a single piece.
- The two shapes the new guard fixes, and `Berg, abd née Jones`, where
  a declining join after a family comma leaves S2's suffix reading and
  the name has no given name at all -- as `Berg, abd` alone always
  parsed. It reads alarmingly and was in no bullet and no row.
- The marker immediately after the bound word, and the Arabic script.

Plus a piece-level pin that the join never merges a marker, and the
bound-given shapes added to the #409 chain invariant's inputs -- that
invariant is keyed on the particle chain, and the distinction is now
exercised rather than assumed.

`Berg, abd née Jones` arrived UNEXPLAINED at 1.4.0 on four fields, the
subset test correctly rejecting both nearby rules, and is read once
here.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant