Skip to content

Add surname1, surname1_particles and surname1_base, the first of two family names (#1022) - #1047

Merged
derek73 merged 3 commits into
masterfrom
feat/1022-surname1
Nov 4, 2026
Merged

derek73 merged 3 commits into
masterfrom
feat/1022-surname1

Conversation

@derek73

@derek73 derek73 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Closes #1022.

Where rules/O6 (two_family_names) reads the family as two surnames, the new views read the first one:

input (two_family_names) family_base (unchanged) surname1 surname1_particles surname1_base surname2
Juan Pérez de la Vega Pérez Vega Pérez '' Pérez de la Vega
Juan de la Vega del Valle Vega Valle de la Vega de la Vega del Valle
Gabriel García Márquez García Márquez García '' García Márquez

A family read as one unit is its own first surname, so for the default parse the views equal family, family_particles and family_base. CLDR patterns fill surname-prefix / surname-core / surname2 from surname1_particles / surname1_base / surname2.

Decided (four questions plus one follow-up, recorded in decisions/R11)

  1. Shape. Three new views, named to pair with surname2. family_particles and family_base keep reading the whole family, so rules/R2 is unchanged. Rejected alternatives: the name surname, which sits next to the unrelated surnames, and narrowing the family views.
  2. What the first unit is. It is the first unit O6 read. A middle name O3 (middle_as_family) folds in is in neither unit, whether O6 read one unit or two. A particle P6 attached is in the first unit.
    • Measured on Wikidata's second-surname strata (330 names): the first surname is right in 264 with middle_as_family on, against 227 for "family minus surname2".
    • On CLDR 48, surname-core is right in 9 against 0.
    • Every source that fields two surnames puts middle names outside the first one.
  3. initials() is unchanged. It still initials the whole family's base; a monogram is a render pattern's job.
  4. Where the views appear: as render() keys and in rule examples. Like surname2, they stay out of as_dict(), --json, comparison_key() and the repr. Unlike surname2, they stay out of the snapshot too, since under the default policy they always equal the family views.

Mechanism

  • O6 now marks the first unit's words as it already marks the second's.
  • Where O6 marks nothing, O3 marks the family before folding middles into it.
  • The marks reach the published token as Reading.first_surname (ADDED_IN 3.0.0, not compared, so 2.8 pickles load).
  • The views needed this because a finished parse cannot tell O3's fold from P6's attachment: both carry FOLDED_TAG, and P6's own tag is dropped at assemble.

Docs and tools

  • New rules/R11 and decisions/R11, plus edits to rules/O6, decisions/R10, the RFC's render-pattern table and API table, and mechanisms.md.
  • User docs: usage.rst and customize.rst. Release-log bullet added.
  • cldr_agreement.py scores CLDR's prefix and core against the first unit's views as roles of their own, only where a surname2 is stated. The merged base keeps the second surname in, so the default parse, which reads one unit, isn't counted twice.

Accepted costs (rules/R11)

  • A first unit that is a lone particle has an empty base. This happens where O6 itself splits a family-first van Gogh Vincent; reading the particle as the base was tried and backed out, because it broke the partition.
  • A fold into an empty family: for , John Paul, nothing is marked.

Review

Three passes: code and design docs on the first commit, then one on the fix commit. Fixed:

  • untested patronymic paths;
  • the one-unit O3 case (decided as a follow-up);
  • missing summary lines;
  • stale RFC prose;
  • a recipe that first reproduced 262 instead of 264;
  • the lone-particle base, backed out.

Checks:

  • uv run pytest: 36,092 passed. Ruff and mypy clean. Sphinx doctests pass.
  • The clock-timed scaling rows failed on unrelated shapes at load average ~40; the frame guards pass.

🤖 Generated with Claude Code

@derek73 derek73 added this to the 3.0 milestone Nov 4, 2026
@derek73 derek73 self-assigned this Nov 4, 2026
derek73 and others added 3 commits November 3, 2026 19:22
…family names (#1022)

Where rules/O6 (two family names) reads the family as two units, the
new views read the first: `Juan Pérez de la Vega` under
`two_family_names` gives surname1 'Pérez' and surname1_base 'Pérez',
where family_base, unchanged, is 'Pérez Vega'; `Juan de la Vega del
Valle` gives 'de la Vega' / 'de la' / 'Vega'. A family read as one unit
is its own first surname. Decided in four questions (decisions/R11):
the surname1 trio beside unchanged family views; the first unit O6
read, so a middle O3 folds in is in neither unit and a particle P6
attached is in the first; initials() unchanged; render keys, out of
as_dict/--json/comparison_key/repr and the snapshot.

O6 marks the first unit's words as it marks the second's, carried out
on Reading.first_surname (ADDED_IN 3.0.0, not compared). New rule
rules/R11 and decisions/R11; cldr_agreement scores CLDR's
surname-prefix and surname-core against the first unit's views where a
surname2 is stated, as roles of their own beside the merged base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A fold's middles are left out of surname1 where O6 read one unit too
  (decided in chat as a follow-up to question 2): where O6 marked no
  units, O3 marks the family it folds into before folding, so
  `Ana María García López` under middle_as_family gives surname1 'López'.
- A first unit of nothing but particles is its own base, as R2 reads
  an all-particle part (`van Gogh Vincent` family-first gives
  surname1_base 'van').
- Tests for both patronymic re-readings in assemble, the fold without
  two units, and the all-particle unit; a duplicate row removed.
- cldr_agreement prints the surname1 roles in its summary and says
  what they score; records re-recorded.
- The RFC's output-model, API-changes table and render-pattern prose
  name the new views; decisions/R11's recipe is re-run on the shipped
  views (Wikidata 264 against 227, CLDR core 9 against 0, as stated).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Back out reading a lone-particle first unit as its own base: it
  broke the units' partition of the family's particles and base, and
  lowered CLDR's surname1_particles agreement under ES from 165 to 134
  of 369. rules/R11's Accepted records the empty base instead, and an
  empty-family fold (`, John Paul`), where nothing is marked.
- Test rows for middle_as_family with nothing to fold, a family comma,
  and replace() on a folded parse.
- rules/R11's When, Because and Signal, the tag comments, post_rules'
  Produces line, the RFC and usage.rst name O3 as the other rule that
  marks the first unit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@derek73
derek73 force-pushed the feat/1022-surname1 branch from 0035f66 to f956639 Compare November 4, 2026 03:23
@derek73
derek73 merged commit dd89e9c into master Nov 4, 2026
13 checks passed
@derek73
derek73 deleted the feat/1022-surname1 branch November 4, 2026 20:39
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.

Should a family read as two surnames split into particles and base per surname? Juan Pérez de la Vega reads family_base 'Pérez Vega'

1 participant