Skip to content

de Mesnil Jean reads Jean as part of the surname: the leading-particle fold takes the rest of the name #471

Description

@derek73

Under the default (given-first) order, a name opening with a never-given particle has its ENTIRE remainder read as the surname:

parse("de Mesnil Jean")            family 'de Mesnil Jean'    →  should be family 'de Mesnil',  given 'Jean'
parse("de la Cruz Juan Carlos")    family (whole string)      →  should be family 'de la Cruz', given 'Juan', middle 'Carlos'
parse("ibn Awf abdul Rahman")      family (whole string)      →  should be family 'ibn Awf',    given 'abdul Rahman'

Jean is not part of that surname. The fold is reaching past the thing it is entitled to.

The criterion

The fold takes the particle's own unit and ONE name word. Whether the name is surname-only is then decided by what is left over:

  • nothing left → surname-only is the only available reading, and the fold is right (de la Vega, Mc Donald, dos Santos, De Groot, Ste Marie, de los Santos)
  • something left → that something IS a name component, and the fold has no business taking it

The mechanism already exists: the family-first branch of rules.md#P1 has narrowed exactly this way since #395. Only the default order kept the wider reach, and nothing recorded a reason.

Measured

10 parses, 5 names, default order only, over the 1094-name corpus × 3 name_order values × middle_as_family off and on. Every surname-only name is untouched; the conjunction join (de la Vega y Santos Juan) and the bound-given pair (ibn Awf abdul Rahman) stay whole.

This is a v1 parity break, and that is why it is its own issue

Unlike the family-first work in #467 — where v1 has no name_order and so no answer to compare against — this changes the order every existing caller is on, and 1.4.0 has a definite answer that we currently match:

1.4.0   HumanName("de Mesnil Juan").last  ==  'de Mesnil Jean'

Prototyped, the differential gate goes red at the 1.4.0 baseline with 5 unexplained diffs (the five names above), and tests/test_particles.py::LastNamePrefixSplitTestCase::test_leading_non_first_name_prefix_with_middle_name_as_last fails outright. Landing it needs ledger rules at all three baselines, the v1 test repointed, and a release note saying default-order behaviour changed — none of which should be bundled into a family-first fix.

Scope note

The leftover must be laid out as the positions the declared order gives it, with the family slot already filled. The current code uses _name_positions(order, len(rest) + 1)[1:], which is correct only where the family comes first; under the default order the family is last, so the slice takes the wrong roles.

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions