Skip to content

Fix vd/mc splitting by case before and after a family comma (#573) - #579

Merged
derek73 merged 7 commits into
masterfrom
fix/issue-573-particle-credential-uniform-case
Oct 2, 2026
Merged

derek73 merged 7 commits into
masterfrom
fix/issue-573-particle-credential-uniform-case

Conversation

@derek73

@derek73 derek73 commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Closes #573. The issue's fourth bullet (the silent mixed-case Doe, Jane PhD vd Ma) moved to #578.

What changes

A word in both the particle and the unambiguous suffix vocabulary (vd, mc) split in three shapes. Each split was one stage acting on a reading the next stage never took.

text before (master) after
SMITH VD MA, JOHN family SMITH MA, suffix VD family SMITH VD MA
DOE, JANE PHD VD MA family VD DOE, suffix PHD, MA suffix PHD VD MA
SMITH, VD MA family SMITH VD, suffix MA family SMITH VD MA
  • Before a family comma (P2). In the per-piece read of the family part, a particle that is suffix vocabulary too, with a name piece behind it, heads that name and is not peeled. With nothing or a suffix word behind it, it stays a suffix (SMITH VD, JOHN, SMITH VD JR, JOHN).
  • Between post-nominals after a family comma (P6, third exception). P6's attachment stands down when assign read the run whole around the word: a post-nominal in front (a credential or a generation; a title between them is transparent) and another behind. With nothing behind it the word still attaches (Doe, Jane PhD vd → vd Doe). Two such words side by side are one particle run, which P6 takes whole.
  • A never-given particle opening the given part (S2, P1). The member behind the particle run is the surname it heads, not a word to spare. Mixed-case capitals still make it a credential (Smith, de MA), and an ambiguous particle keeps the given name (SMITH, VAN MA). P1's fold and the slot share one predicate, _pieces.is_lone_never_given_particle.

Decided with the maintainer, including that a generation counts on either side: Berg, Jan PhD vd Jr. reads suffix PhD vd Jr., where 2.2 and 2.3 read family vd Berg.

Docs

  • rules.md: P2, P6 and S2 amended, with examples. P2's implemented: gains _assign.py.
  • decisions.md: the record is in the P6 section (2026-10-02). It includes what each reading declined and an exact recipe for the blast radius. P2 and S2 carry pointer entries.
  • Ledgers: fix(#573) rules at every baseline, plus guard-roster enrollments, all reach verified name by name.
  • release_log.rst: one bullet.

Blast radius

Measured against e56dd296:

  • Differential gate: exits 0 at all five baselines, with radar counts unchanged. No existing corpus name moves; only the new rules.md examples differ.
  • Generated grid (recipe in decisions.md): 5,676 of 409,498 parses move. Every one is either a family gaining the words behind its particle (3,534) or vd/mc leaving the family for the credential run (2,142). No list of ambiguity kinds changes, and 1,310 of the movers are mixed case.

Review history

Three review rounds. Each round's findings were reproduced before being fixed:

  • Round 1, code and design docs. The P2 fix had sat in group's chain stop and broke Berg de MA, Prof.; it moved to assign. P6 asked S2's company query and missed DOE, JANE MA VD PHD and the titled shape. S2 overrode mixed-case capitals and missed chained particle runs. The docs claimed mixed case was already right, which 2.2 and 2.3 disprove.
  • Round 2. The lead test was quadratic: 165,591 frames against 29,670 at k=256. It now walks the run once, and _REREAD_SHAPES["lead"] guards it; the guard fails on the old code. P6's scope was stated, and a dead title skip removed.
  • Round 3. No code defects. Equivalence was checked over 740,853 parses. One P2 sentence and some benchmark comments were corrected.

Commit 30e38ed5's message says Smith, de MA "moved in silence"; it moved but reported. The correction is in 43672bb9's message.

Verification

  • uv run pytest: 10,975 passed, 327 skipped, 3 xfailed. mypy and ruff are clean.
  • The clock-timed test_parse_cost_grows_no_worse_than_linearly[credential_run] failed on CI (3.11, 8.9x) and in full-suite runs, never alone. It was not load, as first assumed. On that input this branch and master run identical, exactly linear frame counts (96,100 → 384,100). The extra time was a full cyclic-GC pass over the heap earlier tests leave live, landing inside one parse. 44a8fa8c times the scaling guards with the collector off after one collection. In the failing sequence the ratio was 6.33x with GC on and 4.00–4.06x with it off. A planted O(n)-per-piece scan still fails the row 3/3 at 16x.

🤖 Generated with Claude Code

derek73 and others added 6 commits October 2, 2026 02:21
Three uniform-case shapes split a word of both the particle and the
unambiguous suffix vocabulary, each because one stage acted on a
reading the next never took:

- before a family comma, the particle chain stopped before a trailing
  run the family part never reads, and the per-piece read then peeled
  VD from between two family words ('SMITH VD MA, JOHN');
- between credentials after a family comma, P6's attachment pulled VD
  out of the middle of a run assign had read whole
  ('DOE, JANE PHD VD MA');
- behind a never-given particle opening the given part, S2's slot read
  the member as a credential with words to spare that P1's fold then
  removed ('SMITH, VD MA').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rules.md: P2's chain stop applies only where a trailing run is read;
P6 gains a third exception (a word inside a credential run); S2's
given slot names the never-given particle that leaves no word to
spare. decisions.md records the three readings and what each
declined, with the blast radius over a generated grid. The ledgers
classify the new rules.md examples at every baseline, and the guard
rosters record their reach and probes.

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

Code review and the docs review, plus a widened grid (adding MA and
Prof. to the pool), found the first round wrong in five places:

- P2's fix lived in group's chain stop for the whole family part, and
  a comma followed by no name word reads that part positionally, so
  'Berg de MA, Prof.' lost its trailing credential and its report.
  Moved to assign's per-piece family read, the site of the defect.
- P6's stand-down asked S2's company query, which counts only an
  unambiguous credential in front: 'DOE, JANE MA VD PHD' and the
  titled 'DOE, JANE PHD PROF. VD MA' still split. It now asks whether
  assign read the run whole, titles transparent; an empty run (a 'do'
  assign already read as the credential) declines.
- S2's never-given lead overrode mixed-case capitals ('Smith, de MA'
  moved in silence) and missed a chained particle run ('SMITH, VD DE
  LA MA'). Capitals now speak first; every token of a piece is asked.
- The lead test was a hand copy of P1's fold predicate; both now call
  `_pieces.is_lone_never_given_particle`.
- decisions.md, the ledgers and the release note claimed mixed case
  was already right; 2.2.0 and 2.3.0 split 'Smith vd Ma, John' too,
  and 1,310 of the grid's movers are mixed case. Rewritten, with a
  recipe that reproduces the grid exactly, and pointers from the P2
  and S2 sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The given-slot lead test rescanned the particle run once per member,
  quadratic on 'SMITH, VD ' + 'DE '*k + 'MA '*k (29,670 -> 165,591
  frames at k=256 against e56dd29). The run's end is kept once per
  title set, and _REREAD_SHAPES["lead"] guards it (3.38x kept, 7.53x
  rescanning, bound 6.0; checked failing on the rescanning code).
- P6's third exception counts any post-nominal, a generation included,
  which the code did and the statement did not say. Decided and
  recorded: 'Berg, Jan PhD vd Jr.' reads suffix 'PhD vd Jr.'.
- Its title skip BEHIND the word was dead (a title there leaves the
  word a name in assign) and is removed; the statement now says a
  title in front is transparent.
- decisions.md: the false linear-cost claim corrected with the
  measurement, the residual positional split ('Smith vd Ma, Prof.')
  named as not decided. P2 says a lone letter behind the particle is a
  name word. Stale "company exception" label and comment drift fixed.

Correction to 30e38ed's message: 'Smith, de MA' moved at ce4e1c5
but reported suffix-or-name; it did not move in silence.

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

P2 said a lone letter behind the particle is a name word; a lowercase
one is the numeral, as it is with no particle ('smith vd v, john' as
'smith v, john'). The _REREAD_SHAPES header and failure message now
record the lead row, its thin broken-side margin, and that counting
<genexpr> frames is not isolated from the rest of the parse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73 derek73 added this to the 2.4 milestone Oct 2, 2026
@derek73 derek73 added the bug label Oct 2, 2026
@derek73 derek73 self-assigned this Oct 2, 2026
@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.91%. Comparing base (e56dd29) to head (44a8fa8).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #579   +/-   ##
=======================================
  Coverage   98.90%   98.91%           
=======================================
  Files          45       45           
  Lines        4118     4151   +33     
=======================================
+ Hits         4073     4106   +33     
  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.

credential_run failed on CI (3.11, 8.9x) and in three local full-suite
runs, never alone. Frame counts on that input are identical to master
and exactly linear (96,100 -> 384,100); the extra time was a full
cyclic-GC pass over the heap earlier tests leave live (~339k objects),
landing inside group's snapshot comprehension (34ms self time at
x3200). Its cost is the heap's, not the parse's. Measured in the
failing sequence: 6.33x with the collector on, 4.00-4.06x off.

_best now collects once, then times with the collector disabled. A
planted O(n)-per-piece scan still fails the row 3/3 at 16x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73
derek73 merged commit 7a207b5 into master Oct 2, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Why does SMITH VD MA, JOHN read family SMITH MA with VD as a suffix?

1 participant