Reframed 2026-08-30. The original issue read this as initials() failing to honor rules.md#R3's "even then" clause. A fix on that reading was implemented and then backed out of #463 — it made initials() disagree with family_base about the same token, which is the defect the rest of that branch removes. The clause is the question, not the code.
R3 promises two things that do not agree
Initials take the first letter of each given, middle, and base family word; titles, suffixes, particles and nicknames contribute nothing — except the particles of a part whose every word is one, which are not acting as particles there (R2) and initial like any other name word. A CONJUNCTION never initials, so a base that is one contributes nothing even then.
The first sentence says initials follow the base. The last overrides it. Where they collide, the views split:
parse("Juan de y").family_base # 'y'
parse("Juan de y").initials() # 'J.' -- the base word contributes nothing
The parse has already decided de is a working particle and y is the base — family_particles is 'de'. Only initials() disagrees.
The carve-out is right where the conjunction is doing its job
parse("Juan Velasquez y Garcia").family_base # 'Velasquez y Garcia'
parse("Juan Velasquez y Garcia").initials() # 'J. V. G.' -- correct, y is joining
Here y links two surnames and must not initial. So the clause is not wrong in general; it is unqualified where it should be conditional.
The proposed rule
A conjunction with nothing to join is not acting as a conjunction, exactly as a particle with nothing to join is not acting as a particle. R2 already draws that line for particles and the machinery exists. Applied evenly:
|
today |
proposed |
Juan Velasquez y Garcia |
J. V. G. |
J. V. G. unchanged — the y joins |
Juan de y |
J. |
J. y. — the y joins nothing |
Juan y |
J. |
J. y. |
Every row then agrees with family_base, which is what R3's own first sentence promises.
The gap is wider than this, and the wider half is reachable by default
"A CONJUNCTION never initials" is unqualified, and a conjunction in the given group has always initialed. Measured over the 1094-name differential corpus, 25 names do it today:
'Duke of Edinburgh' -> 'D. o. E.'
'Dean of Chemistry' -> 'D. o. C.'
'John & Jane' -> 'J. &. J.'
Unlike the family-side shape, this needs no custom vocabulary — so it can carry a rules.md example line and a real deviates: marker, which the family-side shape cannot.
Scope notes for whoever takes it
rules.md#R4 cross-references this clause. It grounds case repair's ungated conjunction conjunct in "the carve-out R3 states for initials". Settling R3 settles that sentence too, and R4 currently carries no trace of the question.
- The all-particle shape cannot carry an example line. Every
rules.md example parses with the default vocabulary, where particles ∩ conjunctions is empty — in the defaults and in every locale pack — so no input string reaches a conjunction inside an all-particle part. It is pinned in tests/v2/test_render.py instead, asserting today's output so that settling this fails the suite until the pin moves.
rules.md's preamble says grep deviates: is the deviation backlog, with three named exceptions. This gap fits none of them and can carry no marker on the family side, so R3 currently reads as fully implemented.
- The readmission must not be widened by word count.
Jon Dough and has base Dough and; Juan y Garcia has base y Garcia. A criterion phrased as "the base has a word the initials view skipped" condemns those and Velasquez y Garcia too. The mark is the criterion — it speaks about a whole part — not the word count.
Original report follows.
rules.md#R3 states a carve-out that initials() does not honor once a part is marked all-particle. Reproduction needs a Lexicon where a word is in both particles and conjunctions:
from nameparser import Lexicon, Parser
lex = Lexicon.default().add(particles={"y"})
p = Parser(lexicon=lex)
p.parse("Juan de y").initials() # 'J. d. y.'
p.parse("Anh y Van").initials() # 'A. y. V.'
Under the reframing above these outputs are correct — the part is all-particle, so its words are name words — and it is R3's clause that needs the condition.
Reframed 2026-08-30. The original issue read this as
initials()failing to honorrules.md#R3's "even then" clause. A fix on that reading was implemented and then backed out of #463 — it madeinitials()disagree withfamily_baseabout the same token, which is the defect the rest of that branch removes. The clause is the question, not the code.R3 promises two things that do not agree
The first sentence says initials follow the base. The last overrides it. Where they collide, the views split:
The parse has already decided
deis a working particle andyis the base —family_particlesis'de'. Onlyinitials()disagrees.The carve-out is right where the conjunction is doing its job
Here
ylinks two surnames and must not initial. So the clause is not wrong in general; it is unqualified where it should be conditional.The proposed rule
A conjunction with nothing to join is not acting as a conjunction, exactly as a particle with nothing to join is not acting as a particle. R2 already draws that line for particles and the machinery exists. Applied evenly:
Juan Velasquez y GarciaJ. V. G.J. V. G.unchanged — theyjoinsJuan de yJ.J. y.— theyjoins nothingJuan yJ.J. y.Every row then agrees with
family_base, which is what R3's own first sentence promises.The gap is wider than this, and the wider half is reachable by default
"A CONJUNCTION never initials" is unqualified, and a conjunction in the given group has always initialed. Measured over the 1094-name differential corpus, 25 names do it today:
Unlike the family-side shape, this needs no custom vocabulary — so it can carry a
rules.mdexample line and a realdeviates:marker, which the family-side shape cannot.Scope notes for whoever takes it
rules.md#R4cross-references this clause. It grounds case repair's ungated conjunction conjunct in "the carve-out R3 states for initials". Settling R3 settles that sentence too, and R4 currently carries no trace of the question.rules.mdexample parses with the default vocabulary, whereparticles ∩ conjunctionsis empty — in the defaults and in every locale pack — so no input string reaches a conjunction inside an all-particle part. It is pinned intests/v2/test_render.pyinstead, asserting today's output so that settling this fails the suite until the pin moves.rules.md's preamble saysgrep deviates:is the deviation backlog, with three named exceptions. This gap fits none of them and can carry no marker on the family side, so R3 currently reads as fully implemented.Jon Dough andhas baseDough and;Juan y Garciahas basey Garcia. A criterion phrased as "the base has a word the initials view skipped" condemns those andVelasquez y Garciatoo. The mark is the criterion — it speaks about a whole part — not the word count.Original report follows.
rules.md#R3states a carve-out thatinitials()does not honor once a part is marked all-particle. Reproduction needs aLexiconwhere a word is in bothparticlesandconjunctions:Under the reframing above these outputs are correct — the part is all-particle, so its words are name words — and it is R3's clause that needs the condition.