Skip to content

fix(#535, #538): a trailing title ends the maiden clause; a delimiter core is stepped over beside a link - #550

Merged
derek73 merged 14 commits into
masterfrom
claude/535-maiden-clause-trailing-title
Sep 27, 2026
Merged

derek73 merged 14 commits into
masterfrom
claude/535-maiden-clause-trailing-title

Conversation

@derek73

@derek73 derek73 commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Closes #535. Closes #538.

What changes

A trailing title after a maiden clause is a title (#535). The maiden walk (rules.md#M2) now reads the end of a name the way assign does — the S2 peel and the H5 title chain to their fixed point — wherever a trailing rule reads the clause (no comma, the part before a suffix comma, the given part after a family comma).

2.3.0 now
Jane Doe nee Smith Prof. maiden Smith Prof. title Prof., maiden Smith
Jane Doe nee Smith MA Prof. maiden Smith MA Prof. title Prof., suffix MA, maiden Smith
Jane Doe nee Smith Prof. MA maiden Smith Prof. MA the same as the line above
Jane Doe nee Smith V Prof. maiden Smith V Prof. title Prof., suffix V, maiden Smith
Mary Smith née Jones Prof. maiden Jones Prof. title Prof., maiden Jones
  • One release check for every stop. The numeral, credential and title stops each give up a run only where the name the take leaves reads the WHOLE run as titles or post-nominals, and no join below the take absorbs it. That is M2's invariant, "a word the clause gives up reads as a post-nominal or the clause keeps it". A first draft that checked only the stop's own word broke that invariant on 513 of 5,198 sweep parses.
  • The first word after the marker stays, for the title stop as for the credential stop. Jane Doe nee King. keeps its maiden name, and Jane Doe nee Prof. Dr. keeps Prof. and gives up Dr..
  • Numeral stop fixes found on the way:
  • After a family comma, the given part is read as assign reads it (two passes). A title word stuck behind a class member stays in the clause (Doe, Jane nee Smith Rev. MA Prof. reads maiden Smith Rev., not middle Rev.), and a lenient numeral counts as a suffix where only chained titles stand behind it (Doe, Jane nee Smith MA V gives up MA V, as bare Doe, Jane MA V reads it).
  • A link word the title chain newly refuses asks the release question. Jane Doe nee Smith i DO Prof. keeps maiden Smith i DO instead of putting Doe i in the middle name. Links refused either way stop as before (Doe, Jane nee Smith i V gives up suffix i V).
  • A released title that is also a particle stays in the clause after a family comma, since P6 would attach it to the family (Doe, Jane nee Smith St. keeps maiden Smith St.).

A delimiter core is stepped over beside a link (#538). Under Policy(extra_suffix_delimiters=(" - ",)), Smith, John, PhD née Puig Mr. - i Soler keeps maiden Puig Mr., as the text written without the delimiter does. This is recorded in rules.md#P3 (a separator sentence), #M2 and #R1. The defect existed only within this cycle, so the release log folds it into the Catalan-link bullet.

Recorded boundaries (M2 Accepted rows, rather than code)

  • Two spellings still split where something can take the title. … Smith <run> Prof. and … Smith Prof. <run> split where something in or ahead of the clause could take the title: a particle chain, a bound-given join, a name left with no name word, or, after a family comma, the given part's own title chain stopping short of a title word.
  • Where the clause keeps the credential, the spellings split too: Doe nee Smith ba Prof. against … Prof. ba.
  • Bracket content ending in a period reads as the bare clause (S1/M3), so Jane Doe (nee Smith Prof.) gives title Prof..
  • Jane Doe nee Smith King. gives title King.. That is H5's accepted Mary Jane King. cost, now reaching into the birth name.

Follow-ups filed

Verification

  • Full suite: 10208 passed. mypy and ruff are clean; _group.py and _pieces.py are at 100% line coverage.

  • Differential gate: exit 0 at all five baselines, and the radar-unclassified counts are unchanged (0/5/6/7/7). Each new corpus name is attributed to the change that moves it, checked against the baseline wheel, the parent tree and HEAD, with joint labels where more than one change moves it.

  • M2 invariant against the parent d9d80492 (every word after the marker ends maiden, title or suffix), over three generated grids whose recipes are in decisions.md:

    Grid Texts New violations Fixed Remaining
    A 327,936 0 2,012 17,854
    B (bound-given) 173,057 0 1,222 11,149
    C (four-word) 146,410 0 1,368 15,534

    The remaining violations are the Should a maiden clause keep a credential it would hand to a name part? Dr. nee Smith PhD Prof. reads family PhD #548 class. Two more populations came from the toolkit review: a 411,936-parse link grid (links i, y, e, and and their runs × 3 name orders) shows 0 new violations against the tree before the link check, and every clean reading that moved now matches the same run read without a clause; a 107,352-parse fuzz with titles, links and St. shows 12 new violations against master, all Dr. nee Smith i MA|V <title> twins of master's own Dr. nee Smith i MA (Should a maiden clause keep a credential it would hand to a name part? Dr. nee Smith PhD Prof. reads family PhD #548's class).

  • Frames per parse (py3.11): unchanged for names without a clause, +2 for a plain clause, +11 for Jane Doe nee Smith MA, and more for a clause that now releases a title.

  • Review: spec and quality review per commit, a design-docs review, a whole-branch review, and a /pr-review-toolkit round (code, tests, comments). Each fix commit was reviewed again. The second passes found the given-part regression 82148faa fixes; the toolkit round found the link and particle-title regressions 45257708 fixes, and its re-review found that fix over-reaching, which d585c01d narrows.

Commits

  1. d9d80492 fix(Should a suffix delimiter inside a maiden clause count as a name word beside a link? Smith, John, PhD née Puig Mr. - i Soler keeps i Soler in the maiden name #538)
  2. 7564a0ab fix(Should Jane Doe nee Smith Prof. read Prof. as a title? The maiden name keeps it, where Jane Doe Prof. gives the title #535)
  3. b1c98995, d54fcb1d, 88c9682e: decision records, release notes, and claims scoped to what holds
  4. 82148faa fix(Should Jane Doe nee Smith Prof. read Prof. as a title? The maiden name keeps it, where Jane Doe Prof. gives the title #535): the given part's title chain stops at a class member with a title behind it
  5. 78a8d749, 8ebcaf22: claims bounded to measured populations
  6. ff29a18a test: lint (a loop variable shadowed an import)
  7. 45257708 fix(Should Jane Doe nee Smith Prof. read Prof. as a title? The maiden name keeps it, where Jane Doe Prof. gives the title #535): a refused link and a released particle title ask the release question
  8. 222a7f5d, 188569ca refactor: exhaustive reader dispatch (one site per function), stale comments
  9. d585c01d fix(Should Jane Doe nee Smith Prof. read Prof. as a title? The maiden name keeps it, where Jane Doe Prof. gives the title #535): the link check only where the title chain made the refusal; the given part's lenient numeral in both passes
  10. 55bc9215 docs: grid counts re-measured on the final tree

🤖 Generated with Claude Code

derek73 and others added 8 commits September 26, 2026 14:32
The link exception inside a maiden clause asks for a name word on
each side of the link. A delimiter core past the clause's first word
was an ordinary index to the neighbour walk and passed for that word,
so 'Smith, John, PhD née Puig Mr. - i Soler' under a ' - ' delimiter
kept 'i Soler' in the maiden name. The walk now steps over a core as
it steps over a connective, so the clause reads as the same text
written without the core. rules.md#M2's deviation becomes a statement
and two examples; decisions.md records the boundary reading declined.

The same stepping also applies to the `frozen` loop's own
`_run_neighbours` call, which reaches every credential tail and not
just a maiden clause: a connective of generational vocabulary beside
a declared delimiter core looks past it, and where a credential or
nothing stands beyond, it stays a lone suffix word and the core -- a
lone piece with nothing joined to it -- is dropped as #206 drops any
lone core, so 'Smith, John, PhD - i Soler' reads suffix
'PhD - i Soler' -> 'PhD, i Soler'. Where a name word stands beyond
the core instead, the link joins across it and the core survives in
the suffix text ('Smith, John, Puig - i Soler' stays
'Puig - i Soler'); an ordinary connective's join still takes the
core as its neighbour regardless ('Smith, John, PhD - and MD' keeps
'PhD - and MD'). rules.md#P3 states the general separator-stepping
sentence this rests on; rules.md#R1 gains an example; both
cross-reference each other and M2. decisions.md's #538 entry records
the measured population and the unrepaired cases.

Two new corpus names land in the ledgers. 'Smith, John, PhD née
Puig - i Soler' landed in _CORPUS_CLAIMS, in _NOT_A_VOCABULARY_COPY
in tests/v2/test_ledger_guards.py, and in the #397 rule's alternation
in all five tools/differential/expected_since_*.toml ledgers, since
it reaches the DEFAULT facade there with no delimiter configured.
'Smith, John, PhD - i Soler' diffs at no baseline (the tree's own
default reading is unchanged from every baseline's), so it needed no
ledger alternation, only the corpus-wide growth in two 1.4.0
_CORPUS_CLAIMS comma rules (372 -> 373).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maiden walk read the trailing suffix run and never the trailing
title chain, so 'Jane Doe nee Smith Prof.' kept the title in the
maiden name and a title behind a credential or numeral hid it from the
#533 and #424 stops: 'Smith MA Prof.' and 'Smith Prof. MA' disagreed.
Where a trailing rule reads the words, the walk now reads the end of
the name as assign does (tail_reading), so a title is a stop and the
two spellings agree.

The credential and title stops each ask one question of the whole
span they give up: does the name left standing read it as titles or
suffixes, with no join below absorbing it (rules.md#M2's invariant),
and each spares the first word after the marker. The numeral stop
does not: it reads FROM the marker by design, so a numeral standing
straight after it declines the clause outright rather than sparing
the word -- 'Jane Smith née V' stays a marker with nothing behind it,
and 'Jane Doe nee V Prof.' declines through the title the same way,
title 'Prof.' landing on the declined name exactly as it would on
'Jane Doe nee V' bare. The numeral stop never asked the join half
either, so 'Berg, abdul nee Smith V' read given 'abdul nee', suffix
'V' at 2.0/2.1 and given 'abdul V' at 2.2/2.3 (#411's own reserve
differs between those pairs before #535 ever runs); it keeps maiden
'Smith V' now at every baseline.

The first-word floor lives in the H5 chain itself (`trailing_titles`
and `tail_reading` take a `floor`, defaulting to 1; the maiden walk
passes the position just past the marker's first word), not in a
clamp read after the fact -- a chain that took the first word had
already spliced it out of the count the re-peel reads, which is why
'Jane Doe nee King. ba' lost the suffix 'Jane Doe nee Smith ba'
keeps. The join half of the release check is scoped to the GIVEN_SLOT
reader alone: P5's bound-given join is `BoundJoin.LENIENT` only after
a family comma, and before one the reserve is `BoundJoin.STRICT` and
already declines a join that would change a suffix reading, so asking
there over-declined 'abdul nee Smith V'. And after a family comma the
given slot reads a lone numeral as a suffix only where the given part
is the LAST comma part (#144), asked of the maiden clause too now: a
credential tail behind the numeral withdraws the release, so
'Doe, Jane nee Smith V, PhD' keeps 'V' where the comma-less
'Doe, Jane nee Smith V' gives it up -- and the withdrawal reaches
through a title behind the numeral too, so 'Doe, Jane nee Smith Prof.
V, PhD' never gets to H5 at all and keeps maiden 'Smith Prof. V',
unlike its numeral-first twin 'Doe, Jane nee Smith V Prof., PhD'
(title 'Prof.', maiden 'Smith V') -- the same asymmetry the bare given
slot already has with no marker in it ('Doe, Jane Prof. V, PhD' vs
'Doe, Jane V Prof., PhD').

The differential ledgers classify a diff by every change that causes
it, not #535 alone: a name whose reading already differed from a
baseline before this change (checked against the parent tree
d9d8049) keeps that earlier rule, or gets a joint label when #535
moves it further. This landed seven such attributions across the five
ledgers: fix(#274) for 'Dr. nee Jones Smith Prof.' at 1.4.0 (only a
title precedes the marker there, so #535 moves nothing -- v1's
missing maiden reading is the whole diff); fix(#274/#535) for the
rest of 1.4.0's title-stop names; fix(#274/#296/#535) for 'Jane Doe
nee Prof. Dr.' at 1.4.0 alone, where v1's missing maiden reading and
'dr' still being suffix vocabulary both predate #535; fix(#411/#535)
for the numeral-join name, shared by 1.4.0 and 2.0.0/2.1.0 (they read
it identically, so #274 moves nothing there either -- the
bound-given reserve decides given/maiden before #535 runs); a new
fix(#399) sibling for 'Jane van der Berg nee Smith Prof.' at
2.0.0/2.1.0 (the general rule's one-trailing-word anchor can't reach
it, and #535 moves nothing there either); fix(#296/#535) for 'Jane
Doe nee Prof. Dr.' at 2.0.0/2.1.0 alone, where 'dr' is still suffix
vocabulary at those two baselines but not at 1.4.0; and
fix(#533/#535) for 'Jane Doe nee Smith Prof. MA' at every 2.x
baseline (#533 already gives the credential up to `suffix` and
reports the fork; #535 then reads the title standing in front of it
through the credential). 'Jane Doe nee King. ba' is NOT an eighth:
the parent tree already reads it exactly as HEAD does at every
baseline (no chain ever ran on it, since nothing but its own first
word and a trailing credential stand after the marker), so its whole
diff is #533's and it joins the existing declining-half/movers rules
there; #535 moves nothing. 'Doe, Jane nee Smith V, PhD' gets its own
fix(#535) rule at 2.2.0/2.3.0, the only baselines where it moves
anything.

Mutation-checked: `_release_reads_off`'s particle-ahead `return False`
replaced with `pass` fails test_a_released_title_behind_a_particle_is_withdrawn.
Mutation-checked: the title-stop's `if _release_reads_off(...)` replaced
with `if True` fails test_the_title_stop_needs_a_name_word_left_standing.
Mutation-checked: `trailing_titles`' `while k > floor:` replaced with
`while k > 1:` fails test_the_floor_keeps_the_first_word_in_the_chains_count.
Mutation-checked: the given-slot numeral's `tail_follows` clause dropped from
`kept = (...)` fails test_a_given_slot_numeral_with_a_credential_tail_stays.
Mutation-checked: `_join_takes_the_member`'s `reader is TailReader.GIVEN_SLOT`
guard dropped fails test_the_bound_given_half_of_the_join_model_is_the_given_slots_alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
decisions.md (M2): the 2026-09-26 #535 entry, after the #538 one. It
resolves the NOT TRANSPARENT HERE clause of the #533 entry and records:
both halves taken together (a trailing title ends the clause, and the
credential or numeral in front of it gets its stop); reader scope
unchanged; the first-word floor moved into the H5 chain as a `floor`
parameter, and why a clamp was measurably wrong ('Jane Doe nee King.
ba'); the one span-level release check for all three stops, with the
first draft's 513-of-5,198 evidence; the join rules (a title with a
particle ahead declines; the P5 half is the given slot's alone, and
'abdul nee Smith Dr.' reading as 'abdul Dr.' does); the three
numeral-stop readings that move with it ('Berg, abdul nee Smith V',
'Doe, Jane nee Smith V, PhD', 'Jane Doe nee V Prof.'); the bracketed
'(nee Smith Prof.)' accepted; the plain suffix-word stop deferred as
D5, Open: follow-up to be filed; the two generated grids as dated
snapshots with the recipe in words (0 new M2 violations against
d9d8049; 2,012 and 1,222 fixed; 17,854 and 11,149 remaining, every
one ending the clause before a suffix-vocabulary word); and the frame
costs on CPython 3.11.16 with the recompute.

release_log.rst (2.4.0 Unreleased):
- new bullet: a trailing title after a maiden marker (closes #535);
- new bullet: a roman numeral ending a maiden clause landing in the
  first or middle name (#535);
- #538 is folded into the Catalan link bullet rather than given one
  of its own: measured on the 2.3.0 wheel, both of its names already
  read there as the tree reads them now, the defect having existed
  only inside this cycle, after the link landed. That bullet now
  closes #397 and #538.

Prose fixes, each a statement the change had made false:
- release_log.rst, the #533 bullet: it said a trailing title is not
  transparent in a clause and the MA Prof. / Prof. MA spellings
  disagree; it now points at the trailing-title bullet.
- _group.py, TailReader docstring: the reader was described as the
  acronym fork's alone; it is what every stop's release check asks,
  and it decides whether the walk reads the title chain at all.
  TRAILING's member comment names the H5 chain beside the S2 peel.
- _group.py, the rules.md#S2 citation comment: the maiden walk no
  longer ends at trailing_start's answer wherever a trailing rule
  reads the clause; it ends at tail_reading's.
- _group.py, the rules.md#M2 citation comment: the walk's stops were
  listed as a suffix word or the trailing numeral; they now include
  the trailing credential and, where a trailing rule reads the
  clause, a trailing title.
- mechanisms.md#ONE-PREDICATE-PER-QUESTION: trailing_start is what
  M2's walk stops at only where no trailing rule reads the clause;
  tail_reading gains the maiden walk as a caller; the walk asks the
  bare peel only for that same reader.

Read and left alone: AGENTS.md's Architecture, Extension Patterns and
Gotchas (nothing there describes the maiden walk's stops); _group.py's
module docstring (its Reads: line still matches the Policy/Lexicon
fields the module consults); _pieces.py's module docstring; rules.md
M2, H5, P3, P5 and M4, which the two fix commits already brought in
line ('J. nee Jones Smith Prof.' reads family 'J.' by H1, which M4
assigns to H1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each claim below was checked by a parse run for this commit, on this tree
and, where a release is named, on that release's wheel.

rules.md
- M2: "No stop takes the first word after the marker" now names the
  credential and title stops, and adds that a numeral there declines the
  clause as it does written alone ('Jane Smith née V', 'Jane Doe nee V
  Prof.').
- M2: "Those stops are each asked TWICE" now names the trailing numeral,
  credential and title stops.
- M2: the title-release sentence is scoped to the three trailing stops
  and to the whole run each gives up. The quoted invariant is left
  word for word. A new Accepted row covers the plain first-suffix-word
  stop, which asks no release question: 'Doe nee Smith Jr. Prof., Jane'
  gives family 'Doe Prof.'. Open: #548.
- M2: the delimiter sentence gains the period-final exception. S1's
  statement does not say that a trailing period makes content
  suffix-shaped. M3's Accepted note says so, and _extract's
  `_suffix_shaped` does it, so the sentence cites M3 for the shape and
  S1 for the dropped brackets. The bracket Accepted row's "(S1)" becomes
  "(M3) … (S1)" the same way, and S1 gains `interacts: M2`.
- M2: new Accepted row for the transparency boundary. Where the clause
  keeps the credential, the two spellings differ: 'Doe nee Smith ba
  Prof.' gives maiden 'Smith ba' and 'Doe nee Smith Prof. ba' gives
  maiden 'Smith Prof. ba'. 2.3.0 read maiden 'Smith ba Prof.' and
  'Smith Prof. ba'.
- M2: new Accepted row for H5's reach. 'Jane Doe nee Smith King.' gives
  title 'King.' with maiden 'Smith'; 2.3.0 gave maiden 'Smith King.'.
- H5: the "not such a join" sentence gains "where the name the take
  leaves reads it as a title (M2)".

decisions.md
- #535 entry: "the two spellings give one answer" is scoped to where the
  clause gives the credential up. It now records the transparency
  boundary, measured: 'Doe nee Smith ba/Prof.' and 'abdul nee Smith
  MA/Prof.' pairs, with the report difference ('Doe, Dr. nee Smith MA
  Prof.' reports nothing, '… Prof. MA' reports). It also records H5's
  King. reach.
- #535 entry: the "D5" label is dropped in favour of "the plain
  suffix-word stop"; its Open line is now #548.
- #535 entry: grid B's fourteen hand-written texts are listed. The count
  of 11,149 remaining violations is recorded as including one detector
  artifact, the quoted nickname in 'Doe, Jane nee Smith V "Bo"'. Every
  other violation stops at an unambiguous suffix word written the way
  the plain stop takes it; this was re-measured by stop word.
- #538 entry: the three heads of the 191-of-8,097 sweep are named, with
  the comparison stated ('_run_neighbours' handed its cores vs none).
  Re-measured here: 191 texts, all moving `suffix` alone. The follow-up
  phrase is now "Open: #549".
- New pointer entries dated 2026-09-26 at #P3 (the separator sentence,
  pointing to #538) and #H5 (the Accepted row's maiden half, pointing to
  #535).

release_log.rst
- #533 bullet: the title sentence is scoped to where the clause gives
  the credential up.
- #535 bullet: the MA Prof. / Prof. MA agreement is scoped the same way.
  It adds the 'Doe nee Smith ba Prof.' pair and the 'Jane Doe nee Smith
  King.' reach, and scopes "the clause keeps the title" to where the
  title itself ends the clause.

Comments and docstrings
- _group.py: the #538 comment's "stops at the title" becomes "ends at
  the link after the title … the title is the word on the link's left
  and refuses".
- test_group.py: "ran on past a title it otherwise stops at" becomes
  "ran on past the link it otherwise ends at".
- test_properties.py: the transparency invariant's docstring is scoped
  to heads and runs where the credential is given up. All 72 of its
  parses were checked to release it. The test logic is unchanged.

Differential
- corpus_rules.jsonl is rebuilt with four new example names.
- 'Doe nee Smith Jr. Prof., Jane' diffs at no baseline, so it needs no
  rule; only reach grows.
- 'Jane Doe nee Smith King.' joins the title-stop rule at every
  baseline: fix(#535) at 2.x, fix(#274/#535) at 1.4.0.
- 'Doe nee Smith ba Prof.' joins fix(#535) at 2.3.0. At the earlier
  baselines its diff also has #342's cause ('ba' was a plain suffix
  word there) and, at 2.0/2.1/1.4.0, #445's (plus #274's at 1.4.0), so
  each of those gets a joint-labelled rule. This was checked against
  the parent tree d9d8049, which reads maiden 'Smith ba Prof.'.
- 'Doe nee Smith Prof. ba': the parent tree reads it as HEAD does, so
  #535 moves nothing. It joins "fix(#533) the maiden clause reports the
  credential it keeps" at 2.3.0 and gets joint #342/#533-labelled rules
  (with #445, and #274 at 1.4.0) elsewhere.
- Ledger-guard values are recorded as printed. The #535 roster sets
  gain King.; 2.3.0 splits from 2.2.0 for 'Doe nee Smith ba Prof.'.
  The #533 report set gains 'Doe nee Smith Prof. ba'.
- _CORPUS_CLAIMS changes:
  - 1.4.0 fix(#274) reach: 91 -> 95.
  - 1.4.0 comma-family and comma-precomma-family rules: 377 -> 378,
    from corpus growth.
  - Title-stop rules: 8 -> 9 (1.4.0), 7 -> 8 (2.0.0 and 2.1.0),
    8 -> 9 (2.2.0), 8 -> 10 (2.3.0).
  - 2.3.0 #533 report rule: 14 -> 15.
  - Eight new one-name rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every reading below was checked with a parse run for this commit on
the tree, and where a baseline is named, on the 2.3.0 wheel or on the
parent tree d9d8049.

Transparency (the #535 entry, the release bullets, rules.md#M2, and
the transparency test's docstring). Two spellings can give the
credential up in both and still differ. That happens where something
ahead of the clause would take the title: the first-suffix-word stop
ends the clause before the title check runs, and the title check then
declines on its own. The measured pairs:
- 'Jane van der Berg nee Smith PhD Prof.' gives title 'Prof.';
  '... Prof. PhD' gives maiden 'Smith Prof.'.
- 'Berg, abdul nee Smith ... ' and 'Doe, Dr. nee Smith ...' split the
  same way.
- The bare 'Jane van der Berg Smith PhD Prof.' / '... Prof. PhD' also
  split, which is H5's accepted particle-chain boundary.
- The parent and 2.3.0 read all of these as the tree does.

A released particle with a title behind it is withdrawn:
- 'Jane Doe nee Smith DO Prof.' gives maiden 'Smith DO'.
- '... Prof. DO' gives suffix 'DO'.

The claims are narrowed to "and nothing ahead stands to take the
title", and M2 gains an Accepted pair for each shape.

Numeral straight after the marker. It declines the clause only where
the name left standing reads it as a suffix; otherwise the clause
keeps it:
- 'Dr. nee V' keeps maiden 'V' (a new M2 boundary example).
- 'Doe, Dr. nee V' and 'Doe, Jane nee V, PhD' keep maiden 'V' as well.
This is fixed in rules.md#M2, the #535 entry, the numeral release
bullet, the _maiden_take docstring, and one case note.

Unrecorded movement, now recorded. 'Doe, Jane nee V, PhD' read given
'Jane', middle 'nee V' at 2.3.0 and at the parent; it now reads maiden
'V', suffix 'PhD'. 'Doe, Jane nee V, Jr.' moves the same way. The
change is recorded as a new case row (fix(#535), no shape tag), a
sentence in the #535 entry, and a sentence in the numeral release
bullet.

#533 release bullet: "does not change that" now reads "does not change
how the credential is read", and is scoped to where nothing ahead of
the clause would take a title.

Ledgers: the joint-cause comments on the 'Doe nee Smith ba Prof.'
rules now say Three (2.0.0, 2.1.0) and Four (1.4.0) causes together.

Differential. Five new rules.md example names entered
corpus_rules.jsonl. Each is classified with a one-name rule,
attributed against the parent tree:
- 'Jane Doe nee Smith DO Prof.':
  - 2.x: fix(#535).
  - 1.4.0: fix(#274/#535).
- 'Jane Doe nee Smith Prof. DO' (the parent already gave DO up and
  reported it):
  - 2.x: fix(#533/#535).
  - 1.4.0: fix(#274/#535), as 'Prof. MA' is labelled there.
- 'Jane van der Berg nee Smith PhD Prof.':
  - 2.2.0: fix(#316).
  - 2.0.0/2.1.0: fix(#316/#399).
  - 1.4.0: fix(#274/#316).
- 'Jane van der Berg nee Smith Prof. PhD':
  - 2.0.0/2.1.0: fix(#399).
  - 1.4.0: explained by the fix(#274) marker rule.
  - 2.2.0/2.3.0: no diff.
- 'Dr. nee V':
  - 1.4.0: fix(#274).
  - 2.x: no diff.

_CORPUS_CLAIMS is recorded as printed:
- 1.4.0 fix(#274) reach: 95 -> 100.
- 1.4.0 initials-per-word reach: 113 -> 115.
- Seventeen new one-name claims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a title behind it

After a family comma, the maiden walk's release check accepted a
title word anywhere in the run it gave up. Assign reads that run
differently: the given part's title chain runs from the END, over
what its FIRST suffix pass leaves. That pass takes a class member as
the credential only where every piece behind it is taken too, so a
member with a title behind it is still a name word there, and the
chain stops at it. The bare 'Doe, Jane Dr. MA Prof.' reads middle
'Dr.', title 'Prof.'.

A clause that gave up 'Rev. MA Prof.' therefore put 'Rev.' in the
current middle name. 'Doe, Jane nee Smith Rev. MA Prof.' read title
'Prof.', middle 'Rev.', suffix 'MA', maiden 'Smith', which breaks
rules.md#M2's invariant. The spellings with 'King.' and 'Dr.' in
place of 'Rev.' did the same.

The GIVEN_SLOT branch of `_release_reads_off` now models the two
passes. `chain_ok[q]` says whether the chain, walking from the end,
is still running at `q`, and a title word counts as covered only
there. That name now reads title 'Prof.', suffix 'MA', maiden
'Smith Rev.'. 2.3.0 and d9d8049 read maiden 'Smith Rev. MA Prof.'.

The one suffix that first pass reads and `is_suffix_piece` does not
is the lenient trailing numeral (#144). It counts only as the LAST
piece, and only where a later numeral stop has already asked it.
'Doe, Jane nee Smith Prof. V' reads title 'Prof.', suffix 'V', maiden
'Smith', as 'Doe, Jane Prof. V' reads title 'Prof.', suffix 'V'.
2.3.0 read maiden 'Smith Prof.', suffix 'V'.

Two new case rows pin both names, as does the new unit test
tests/v2/pipeline/test_group.py::
test_the_given_title_chain_stops_at_a_member_with_a_title_behind.

Mutation-checked in a copy of the tree, running test_group.py,
test_cases.py and test_properties.py:
- The `chain_ok[q]` requirement was dropped, so any title word
  counted as covered. 2 tests failed: the new unit test, and the
  case row the_given_title_chain_stops_at_a_member_with_a_title_behind.
- The lenient-numeral clause was dropped. 3 tests failed: the new
  unit test, the case row a_lenient_numeral_leaves_with_the_title_in_front,
  and test_a_trailing_title_is_transparent_to_the_maiden_clause.

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

Each claim below is stated over a measured population or as a list
of examples; none is universal. Every reading was checked for this
commit on the tree and on the 2.0.0, 2.1.0, 2.2.0 and 2.3.0 wheels,
or on the parent tree d9d8049 where noted.

Transparency (decisions.md #535 entry, release_log #535 and #533
bullets, rules.md#M2, the transparency property's docstring):
- The two spellings agree over the forms the property test
  exercises.
- They split where something in or ahead of the clause stands to
  take the title: a particle chain ahead of the clause or inside it,
  a bound-given join, or a name left with no name word.
- The recorded Accepted pairs are examples, not a complete list.
- M2's particle block gains the inside-the-clause pair: 'Jane Doe
  nee Smith do MA Prof.' gives maiden 'Smith do MA'; '... do Prof.
  MA' gives maiden 'Smith do', suffix 'MA'. Both have title 'Prof.';
  2.3.0 kept every word of both in the maiden name.

Numeral straight after the marker (rules.md#M2, decisions.md, the
release bullet, _maiden_take's docstring, two case notes):
- The sentence is replaced with a non-universal one: the numeral stop
  is not held to the first-word floor and may decline the clause.
- The examples are 'Jane Smith née V' and 'Dr. nee V'.
- decisions.md adds 'Doe, J. nee V', which keeps maiden 'V' though
  'Doe, J. V' reads suffix 'V'.
- It also adds 'Doe nee V, Jane' and 'Smith, John, PhD nee V', which
  read no clause at all, as at 2.3.0.

'Doe, Jane nee V, PhD' now reads maiden 'V', which is what 2.0.0 and
2.1.0 read. 2.2.0, 2.3.0 and the parent read middle 'nee V'. The
case row, decisions.md and the release bullet all say so.

rules.md#M2's release sentence is scoped to where a trailing rule
reads the words.

The #548 Accepted row gains 'Doe nee Smith V, Jane', which gives
family 'Doe V'. Before a family comma the trailing numeral's stop is
made over the peel alone, with no release question. 2.2.0, 2.3.0 and
the parent read the same; 2.0.0 and 2.1.0 read maiden 'Smith V'.
decisions.md's #548 paragraph records it too.

The #535 entry's MEASURED recipe adds grid C: five heads, ' nee ',
every four-word sequence over eleven words, and '' or ', PhD'. That
is 146,410 texts. Its counts are 0 new, 1,368 fixed and 15,534
remaining against d9d8049. I re-ran grids A and B on this tree:
0 / 2,012 / 17,854 and 0 / 1,222 / 11,149, unchanged. The counts are
now labelled per grid, and the stop-word classification is scoped to
grids A and B, which is where it was measured.

Differential. Three new rules.md example names entered
corpus_rules.jsonl. Each gets a one-name rule, attributed against the
parent tree:
- 'Jane Doe nee Smith do MA Prof.': fix(#535) at 2.x, fix(#274/#535)
  at 1.4.0.
- 'Jane Doe nee Smith do Prof. MA': the parent already gave MA up and
  reported it. It gets fix(#533/#535) at 2.x and fix(#274/#535) at
  1.4.0.
- 'Doe nee Smith V, Jane': "fix(#424) accepted: ..." at 2.0.0 and
  2.1.0. It has no diff at 1.4.0, 2.2.0 or 2.3.0.

_CORPUS_CLAIMS changes, recorded as printed:
- 1.4.0 fix(#274) reach: 100 -> 103.
- 1.4.0 comma-family and comma-precomma-family rules: 378 -> 379.
- Twelve new one-name claims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… check does not ask

decisions.md's #535 entry listed the causes of a split between the
'<run> Prof.' and 'Prof. <run>' spellings as if the list were
complete; after a family comma the given part's own title chain adds
one (`Doe, Jane nee Smith Rev. MA Prof.` against `... Rev. Prof. MA`,
as bare `Doe, Jane Rev. MA Prof.` reads middle 'Rev.'). The list now
says "for example" and names it.

`_release_reads_off`'s docstring said the given slot's lenient numeral
is a reading the check does not model; the given-slot title chain now
counts it as the first pass's suffix. The sentence says what the span
check does and does not ask.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73 derek73 added the bug label Sep 27, 2026
@derek73 derek73 self-assigned this Sep 27, 2026
Two property tests looped over `runs` with `run`, shadowing the
`run` the module imports (ruff F402). Renamed the loop variable to
`tail`; the tests are otherwise unchanged.

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

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.81%. Comparing base (e0f1a2f) to head (55bc921).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #550      +/-   ##
==========================================
+ Coverage   98.78%   98.81%   +0.02%     
==========================================
  Files          45       45              
  Lines        3703     3796      +93     
==========================================
+ Hits         3658     3751      +93     
  Misses         45       45              

☔ 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 5 commits September 26, 2026 22:19
…sk the release question

Reading the end of the clause through the title chain lets the link
exception refuse a link it used to join. In 'Jane Doe nee Smith i DO
Prof.', the DO is the trailing peel's once 'Prof.' is chained. A stop
at a link gives up every word behind it, and nothing asked what those
words would become. 'Jane Doe nee Smith i DO Prof.' read middle
'Doe i', family 'DO Prof.'. 'Berg, abdul nee Smith i V Prof., MD'
read middle 'V'. 'Doe, Jane nee Smith i DO Prof., MD' read middle
'DO Prof.'.

The walk now handles a link the exception refuses like this:
- It asks `_release_reads_off` of the run it would give up.
- It asks only where a trailing rule reads the clause, and only when
  the link is not the first word after the marker. A stop there
  declines the clause and gives nothing up.
- Where the check fails, the clause keeps the link and walks on.

Readings now:
- 'Jane Doe nee Smith i DO Prof.': title 'Prof.', maiden 'Smith i
  DO', with a report on the kept DO. 2.3.0 read middle 'Doe i',
  family 'DO Prof.'.
- 'Berg, abdul nee Smith i V Prof., MD': maiden 'Smith i V Prof.',
  suffix 'MD'.

After a family comma, P6 attaches a particle trailing the given part
to the family. A released title that is also particle vocabulary is
exactly that, so 'Doe, Jane nee Smith St.' read family 'St. Doe'.
`_join_takes_the_member` now declines a released title with the
particle tag under GIVEN_SLOT. It applies to titles only: the
credential DO is the given slot's own lean, which the credential stop
has already asked (#533). 'Doe, Jane nee Smith St.' and 'Doe, Jane
nee Smith MA St.' read maiden 'Smith St.' and 'Smith MA St.', as
2.3.0 did.

rules.md#M2 gains one implementation-free sentence for each of these,
with examples 'Jane Doe nee Smith i DO Prof.' and 'Doe, Jane nee Smith
St.'. The decisions.md #535 entry records both and re-measures the
grids against d9d8049 (2026-09-26):
- Grid A: 0 new, 3,772 fixed, 16,094 both. It was 0 / 2,012 / 17,854
  before this commit.
- Grid C: 0 / 1,368 / 15,534.
- Grid B: 0 / 1,222 / 11,149.

A fuzz of 107,352 parses against e0f1a2f fixes 2,228 texts and
newly violates 12. All 12 are 'Dr. nee Smith i MA|V' followed by
'Prof.', 'King.' or 'St.', with or without ', MD'. Each is the
title-carrying twin of 'Dr. nee Smith i MA' / 'Dr. nee Smith i V',
which read family 'i' at e0f1a2f already. That is #548's class, and
the entry records it.

Tests:
- Case rows for the four names above, plus 'Jane Doe nee Smith MA Ph.
  D.' and 'Doe, Jane nee Smith MA Ph. D.' (maiden 'Smith', suffix
  'MA Ph. D.'; 2.3.0 read maiden 'Smith MA'). These two pin the
  TRAILING reader's `"suffix" in view_tags[q]` clause, which nothing
  covered.
- Two unit tests in tests/v2/pipeline/test_group.py, each with a
  contrasting control: 'i MA Prof.' gives the link up; 'Prof.', the
  credential 'DO' and the comma-less 'St.' still leave.
- test_a_title_the_clause_gives_up_lands_in_title gains five bodies
  (240 texts, about 0.03s). Its recorded control, re-measured
  2026-09-26 on a copy of this tree with the title stop's check
  replaced by `if True:`: 83 tokens across 78 of 240 texts.

Mutation checks, run on a copy of this tree with
--import-mode=append, over test_group.py, test_cases.py and
test_properties.py:
- New link release check dropped: 4 failed. They are the new unit
  test, both link case rows, and the title-landing property.
- `j > m + run` dropped: 1 failed,
  test_the_marker_is_not_the_name_word_on_the_links_left.
  'Doe, Jane nee i PhD Smith' already reads middle 'nee Smith' on
  this tree and at 2.3.0.
- Particle-title clause dropped: 4 failed. They are the new unit
  test, both St. case rows, and the title-landing property.
- `or "suffix" in view_tags[q]` dropped: 1 failed, the 'Jane Doe nee
  Smith MA Ph. D.' case row.

Differential: 'Doe, Jane nee Smith St.' diffs at no baseline. 'Jane
Doe nee Smith i DO Prof.' gets a one-name rule at every baseline. The
parent read maiden 'Smith i DO Prof.', so the label is fix(#397/#535)
at 2.x and fix(#274/#397/#535) at 1.4.0. _CORPUS_CLAIMS changes,
recorded as printed:
- 1.4.0 fix(#274): 103 -> 105.
- 1.4.0 comma-family and comma-precomma-family: 379 -> 380.
- Five new one-name claims.

No release-log bullet. 'Doe, Jane nee Smith St.' reads as 2.3.0 did.
'Jane Doe nee Smith i DO Prof.' moves from 2.3.0 in the way the
Catalan-link and trailing-title bullets already describe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew found stale

No parse changes. The full suite passes, all five differential gates
are unchanged, and frames per parse are identical to 4525770 on
CPython 3.11.16 for all ten reference names.

Reader dispatch:
- `_release_reads_off` takes
  `reader: Literal[TailReader.TRAILING, TailReader.GIVEN_SLOT]` and
  dispatches `if GIVEN_SLOT / elif TRAILING / else assert_never`.
- `_maiden_take` has three reader branches: the walk's first reading,
  the numeral view check, and the link release check. Each names
  TRAILING and GIVEN_SLOT explicitly and ends in `assert_never`.
- The title stop is gated `reader is not NONE`. `chained` is empty for
  NONE anyway, and the gate narrows the type.
- TailReader's promise, "a fourth member is a type error at every
  reader", now holds at every reader. mypy is clean, and
  test_an_unmapped_reader_is_a_loud_failure_rather_than_a_default
  passes.

`stop < trailing` is restored in the acronym fork. The floor is an
index, and the title chain's splice can leave the numeral stop in
front of it: in 'Jane Doe nee V Prof.' the fork sees stop 4 against
trailing 3 (instrumented in a copy of the tree). The paragraph that
said the condition guarded nothing is rewritten.

`tail_follows` is keyword-only and required on `_maiden_take`, and the
duplicated `reader is GIVEN_SLOT` test beside it is gone: group()
computes the flag from that reader. `_group_segment` keeps its
default, because its test callers do not pass it.

`_join_takes_the_member`:
- The docstring now names all three joins, each with its condition:
  - P2's chain, including a particle with a title behind it.
  - P6's attachment, for a released particle title after a family
    comma.
  - P5's bound-given join.
- The duplicated P5 rationale is gone.
- The `rules.md#P5:` citation now sits on one line, and
  test_doc_citations collects it.
- A note about a never-shipped intermediate reading is dropped.

Other code comments and docstrings:
- `_maiden_take`: all three stops, and a link the walk stops at, ask
  the release check; only the credential and title stops spare the
  first word.
- `_maiden_take`: the numeral view check reads only `Peel.numeral` for
  the NONE reader.
- `_maiden_take`: `peel_start` is the title-aware start for the other
  readers, and a `peel_start` past `trailing` is harmless because the
  walk never reaches `trailing`.
- `_maiden_take`: a frame comparison against a baseline that was never
  committed is dropped.
- The lone-core "keep in step" comments now say the #206 drop's copy
  adds `len(pieces) > 1`.
- `_run_neighbours` and the core-invariant test: "the #206 drop takes
  a LONE core out".
- `GIVEN_SLOT`'s comment names the H5 chain.
- `_pieces.py`: `trailing_start` names who stops at it. `trailing_titles`
  documents `floor`. `credential_at_the_given_slot` and `tail_reading`
  name their callers instead of counting them.

Tests and cases:
- Case a_title_behind_a_tail_bound_numeral_keeps_both: the title stop
  IS asked, and declines because 'V' stays a name word and the given
  part's chain stops at it.
- The clamp-era names are renamed and rewritten:
  - The case is now the_first_word_floor_holds_for_titles_too.
  - The unit test is now
    test_the_first_word_floor_holds_a_title_out_of_the_chain.
- Case notes name "the #538 commit d9d8049". A note describing a
  never-shipped state is dropped. test_group says "at 2.2.0 and 2.3.0".
- test_a_title_the_clause_gives_up_lands_in_title: the reader list is
  corrected. 'Jane Doe, PhD' is a tail segment and reaches NONE, and
  no head puts the clause before a family comma. The property holds at
  e0f1a2f over all 240 texts (checked).
- test_a_title_first_word_counts_as_a_word also asserts that both sides
  take a clause whose first word is the head. Its recorded control was
  re-measured 2026-09-26 with the floor removed entirely (`tail_reading`
  handed 1): all 30 pairs fail, on the head check alone, and 0 disagree
  on the suffix. The earlier "14 of 30" for a clamp variant is replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`_maiden_take` asked `assert_never` at four sites, and only the first
was reachable: a reader outside the enum raises there, so the other
three were dead lines (codecov/patch flagged them). The walk now
dispatches ONCE, exhaustively, and binds `reads` -- the reader where a
trailing rule reads the clause, None where none does -- which every
later site branches on, narrowed. A fourth `TailReader` member is still
a type error at that dispatch, and `_release_reads_off` keeps its own
two-reader dispatch, now reached by a test with a value outside the
enum as `_maiden_take`'s is. No reading changes: full suite passes and
`_group.py` / `_pieces.py` are at 100% line coverage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ade the refusal

The walk's release check at a refused link fired on every refused link,
so it kept links the name left standing reads off: `Doe, Jane nee Smith
i V` kept maiden 'Smith i' where every release gives up suffix 'i V',
`Berg, abdul nee Smith i PhD` kept 'Smith i', and `Doe, J. nee Smith i
Prof. V` swallowed the title -- 23,472 of a 411,936-parse link grid
(links i, y, e, and and their runs, 8 heads, 3 cases, 3 name orders)
moved clean readings. The check is now asked only where the link
exception, bounded by the peel over the words as WRITTEN, would have
joined the link: the refusal is the title chain's, which is the case
the check exists for ('Jane Doe nee Smith i DO Prof.' still keeps maiden
'Smith i DO'). The as-written peel is read only on a refused link.

The given-part model inside `_release_reads_off` now reads the lenient
numeral (#144) in both of assign's passes -- the literal last piece in
the first, the last one standing once the chain has taken the titles
behind it in the second -- and only where no comma part follows the
given one (`tail_follows`, now a required keyword): `Doe, Jane nee
Smith i V Prof.` gives up 'i V' and the title, as bare `Doe, Jane i V
Prof.` reads them, and `... i V Prof., PhD` keeps maiden 'Smith i V'.

Measured 2026-09-26 against the tree before the link check (ff29a18):
link grid 0 new M2 violations, 6,195 fixed; the clean readings that
still move now match how the given part reads the same run without a
clause (`DOE, JANE NEE SMITH MA I` gives up 'MA I', as `DOE, JANE MA I`
reads suffix 'MA I'). Against d9d8049: grid A (327,936) 0 new / 2,012
fixed, grid C (146,410) 0 / 1,368; the 107,352-parse fuzz keeps only
its 12 bare-title-head twins of #548's class. Full suite passes; all
five differential gates exit 0 with radar counts unchanged; rules.md#M2
and decisions.md's #535 entry say the narrower rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the narrowed tree

decisions.md's #535 entry quoted grid A and the fuzz as an intermediate
tree measured them, before the link check was narrowed; re-stated at
0 / 2,012 / 17,854 and 588 fixed / 12 new, with the intermediate
figures labelled as that tree's. One clause records that the lenient-
numeral model moves the credential stop too ('Doe, Jane nee Smith MA
V' gives up 'MA V', as 'Doe, Jane MA V' reads it). The 'stop <
trailing' note is marked defensive: its example never reaches the
class-member test, and dropping the guard moves no reading on the
maiden grids.

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