Skip to content

Commit f71ad74

Browse files
derek73claude
andcommitted
Address the fix-commit review of rules/M4's narrowing
- decisions/M4: name every PR that added given readings, #883 among them (the conversion that gave van its reading); the declined widening now carries its measurement (one corpus name moves, the entry's own example), and the H1 analogy is stated as support only, since H1 also flips an initial (Dr. J. -> family 'J.'). - rules/M4: the Accepted bullet rests on the marker alone, without the H1 analogy. - mechanisms.md#TWO-LAYER-ASSIGN: a claim is a word's role; a given reading is a lean the field rules read past. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent fff94a3 commit f71ad74

4 files changed

Lines changed: 4 additions & 4 deletions

File tree

‎docs/design/decisions/M4-maiden-marker-makes-the-lone-name-word-the-family.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ Open: none in this file.
3131
- 2026-08-27 #445 (review round) — M4 is keyed on the maiden NAME, not on a marker, and the statement was corrected to say so after two reviewers measured the same defect independently. The guard tests for a token in the MAIDEN role, and M1's caller-configured pair produces one with no marker anywhere: under `Policy(maiden_delimiters=frozenset({("(", ")")}))`, `Smith (Jones)` reads family 'Smith', maiden 'Jones', and so do M1's own boundary examples `Smith (Nee)` and `Smith (z domu)`. The BEHAVIOUR is right — the rationale transfers to a declared pair without a word of change, since what announces a former surname is the clause, not the vocabulary that marked it — so the fix was to the rule, which had said "a recognized maiden marker that takes its name and leaves exactly one name word" and now says "a maiden name standing beside exactly one name word". That covers M1, M2 and M3 uniformly, M1 is in M4's `interacts:` and M4 in M1's, and the configured path has an example line of its own. The general lesson is the one this bundle keeps teaching from a new angle: a statement written from the case that prompted the change describes that case, not the code, and only measuring the OTHER paths into the same guard finds the difference.
3232
- 2026-08-27 #445 (review round) — a known gap recorded rather than closed, the way H1 carries its own. M4's guard counts GIVEN tokens; H1 counts nothing at all (it tests which roles are unoccupied). So a name word another rule has joined counts as several here and M4 declines where H1 fires: `Dr. Dean of Chemistry` reads family 'Dean of Chemistry' while `Dean of Chemistry née Jones` keeps given 'Dean of Chemistry', the connective join (P3) having left three GIVEN tokens. rules/P3 says the joined part is one name word wherever another rule counts them, so the two siblings genuinely disagree and this is a gap rather than a boundary. Not closed here: widening the count to units moves zero corpus names (measured), and a behaviour change nobody has approved does not belong in a branch whose blast radius was settled. The sibling claim in the code comment and in this entry is narrowed to match — sibling except in what it counts.
3333
- 2026-08-27 #445 — the relationship to #449, briefly, because the two look like the same question and are not. #449 asks whether a lone name word with nothing to decide it should REPORT an ambiguity; #445 removes a class of names from that population by giving them something that decides. So #445 reduces #449's reach rather than competing with it, and #449's measurement — a naive "one name word, nothing decided it" condition fires on 19 of 1,085 corpus names, only three or four of them the case it is about — is re-taken after this lands. O5 cites #449 in prose and deliberately carries no `deviates:` marker: that marker asserts an intended output the runner then checks strictly, and #449 had not decided one. It has since — 2026-09-07, decisions/O5 — and the answer arrived as ordinary example lines rather than as a marker, the report being shipped behavior and not a deviation. The re-measurement this bullet promises is taken there: the naive condition is wider than either number suggests, firing on 143 of the 1123 corpus names, and O5's own population is 27.
34-
- 2026-11-05 #815 — THE BOUND-GIVEN CARVE-OUT SAYS WHAT IT READS, AND THE FLIP OF EVERY OTHER GIVEN READING IS A STATED COST (decided). The Except said "a word the vocabulary has claimed as a given name keeps that reading", while the guard has always read only the `vocab:bound-given` tag (`_NEVER_FLIPPED`, with `initial`). Other given-name readings were flipped from the start: at #445's own commit (976cd333) the ambiguous particles, `particles_ambiguous`, read family beside a maiden name (`Van née Jones`, `Di née Jones`), and the `given` readings the per-word vocabulary added later on particles, titles and credentials (from 2026-10-19: #765, #769, #806, #858, #876), on titles that are also given names (#752's phase 2i) and on given names written short (#789) read family too (`Chas. née Jones`, `Dean née Jones` → family at master 5c3c0db0, under every order). Two ways were weighed. Widening the carve-out to the given names written short, which mechanisms.md#TWO-LAYER-ASSIGN's "never overrides a vocabulary claim" could be read to ask, would move readings and was declined. Kept instead: a bound given name and an initial claim what a word IS, while a plain `given` reading says only that it may be a given name, and the maiden marker answers that, naming the word beside it as the surname the bearer carries now, as a title does under H1 (`Dr. Chas.` and `Dr. Dean` read family). The words were narrowed to the code, the cost moved into a new Accepted bullet with `Chas. née Jones` and `Van née Jones` as its examples, and the Except's "which is nobody's family name" went, being false under both family-first orders, where an initial reads family by position (`J. née Jones Smith V` → family 'J.'). Nothing in the parser moved. Found by the third review round of #815 (PR #1107), whose O5 edit had copied the wider words.
34+
- 2026-11-05 #815 — THE BOUND-GIVEN CARVE-OUT SAYS WHAT IT READS, AND THE FLIP OF EVERY OTHER GIVEN READING IS A STATED COST (decided). The Except said "a word the vocabulary has claimed as a given name keeps that reading", while the guard has always read only the `vocab:bound-given` tag (`_NEVER_FLIPPED`, with `initial`). Other given-name readings were flipped from the start: at #445's own commit (976cd333) the ambiguous particles, `particles_ambiguous`, read family beside a maiden name (`Van née Jones`, `Di née Jones`), and the `given` readings the per-word vocabulary added later on particles, titles and credentials (from 2026-10-19: #765, #769, #773, #794, #796, #806, #858, #876, and #883 on 2026-10-25, which turned phase 1's `may_be_given` flag into the `given` readings the ambiguous particles carry, `van` among them), on titles that are also given names (#752's phase 2i) and on given names written short (#789) read family too (`Chas. née Jones`, `Dean née Jones` → family at master 5c3c0db0, under every order). Two ways were weighed. Widening the carve-out to the given names written short, which mechanisms.md#TWO-LAYER-ASSIGN's "never overrides a vocabulary claim" could be read to ask, was declined: measured by adding `vocab:given-abbreviation` to `_NEVER_FLIPPED` over every `tools/differential/corpus*.jsonl` name under the three orders, it moves one name, this entry's own `Chas. née Jones`, so the corpora decide nothing and the ground is the rule's. Kept instead: a bound given name and an initial claim what a word IS, while a plain `given` reading says only that it may be a given name, and the maiden marker answers that, naming the word beside it as the surname the bearer carries now. H1 reads such a word as the family name too (`Dr. Chas.`, `Dr. Dean`), though not by this line, flipping an initial as well (`Dr. J.` → family 'J.'), so the line M4 draws rests on its Except's own reason; mechanisms.md#TWO-LAYER-ASSIGN now says that a `given` reading is no claim in its sense. The words were narrowed to the code, the cost moved into a new Accepted bullet with `Chas. née Jones` and `Van née Jones` as its examples, and the Except's "which is nobody's family name" went, being false under both family-first orders, where an initial reads family by position (`J. née Jones Smith V` → family 'J.'). Nothing in the parser moved. Found by the third review round of #815 (PR #1107), whose O5 edit had copied the wider words.

‎docs/design/mechanisms.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ This catalog converts discovery into a one-time cost — it does not remove disc
9898
**Contract statement.** A vocabulary layer first claims words for what they ARE, wherever they sit; a positional layer then reads every unclaimed word by where it STANDS. Every rule belongs to exactly one layer — with one named exception: the leading-abbreviation shape (rule H2) fires before the suffix vocabulary is consulted, so
9999
"Esq. Smith" reads title, not suffix.
100100

101-
**How it works.** The two layers compose without ordering bugs because the positional layer never overrides a vocabulary claim (rule O4 is the positional layer's contract). The exception is still ONE, re-checked 2026-09-08 against the trailing title run (rule H5), which reads title vocabulary in the trailing slot and is NOT a second one: it runs after the suffix peel rather than before it, so a post-nominal keeps its claim — `John Smith Esq.` reads suffix and `John Smith Prof. Jr.` reads suffix `Jr.`, both measured. That rule is also the worked answer to the Reach-for-it line below: it wanted a word's identity and its position at once and was split by SLOT, the front asking about shape (H2) and the back about vocabulary (H5), two questions with two criteria rather than one rule fighting both layers.
101+
**How it works.** The two layers compose without ordering bugs because the positional layer never overrides a vocabulary claim (rule O4 is the positional layer's contract). The exception is still ONE, re-checked 2026-09-08 against the trailing title run (rule H5), which reads title vocabulary in the trailing slot and is NOT a second one: it runs after the suffix peel rather than before it, so a post-nominal keeps its claim — `John Smith Esq.` reads suffix and `John Smith Prof. Jr.` reads suffix `Jr.`, both measured. That rule is also the worked answer to the Reach-for-it line below: it wanted a word's identity and its position at once and was split by SLOT, the front asking about shape (H2) and the back about vocabulary (H5), two questions with two criteria rather than one rule fighting both layers. A claim here is a word's role, not every reading the vocabulary records: a `given` reading says only that a word may be a given name, and the rules that decide a lone word's field read past it, H1 and M4 both reading such a word as the family name (`Dr. Chas.`, `Chas. née Jones`), M4 keeping only a bound given name and an initial (decisions/M4's 2026-11-05 #815 entry).
102102

103103
**Lives in.** _classify/_group (vocabulary side), _assign (positional side).
104104

‎docs/design/rules/M4-maiden-marker-makes-the-lone-name-word-the-family.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
**Accepted:**
3939

40-
- A word the vocabulary reads as possibly a given name, without the claim a bound given name makes, is the family name all the same — a given name written short, a title or a particle that may also be a given name — since the marker names the word beside it as the surname the bearer carries now, as a title does under H1.
40+
- A word the vocabulary reads as possibly a given name, without the claim a bound given name makes, is the family name all the same — a given name written short, a title or a particle that may also be a given name — since the marker names the word beside it as the surname the bearer carries now.
4141
```
4242
"Chas. née Jones" → family="Chas."
4343
"Van née Jones" → family="Van"

‎tests/v2/rules_budget.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"M1": {"words": 239, "then_words": 119, "because_sentences": 2, "except": 1, "precedence": 2, "accepted": 0, "accepted_words": 0},
3131
"M2": {"words": 755, "then_words": 435, "because_sentences": 1, "except": 4, "precedence": 1, "accepted": 6, "accepted_words": 204},
3232
"M3": {"words": 239, "then_words": 84, "because_sentences": 2, "except": 2, "precedence": 2, "accepted": 1, "accepted_words": 93},
33-
"M4": {"words": 325, "then_words": 168, "because_sentences": 2, "except": 1, "precedence": 1, "accepted": 1, "accepted_words": 65},
33+
"M4": {"words": 325, "then_words": 168, "because_sentences": 2, "except": 1, "precedence": 1, "accepted": 1, "accepted_words": 59},
3434
"N1": {"words": 95, "then_words": 62, "because_sentences": 1, "except": 0, "precedence": 0, "accepted": 0, "accepted_words": 0},
3535
"N2": {"words": 131, "then_words": 79, "because_sentences": 1, "except": 0, "precedence": 0, "accepted": 0, "accepted_words": 0},
3636
"N3": {"words": 156, "then_words": 34, "because_sentences": 1, "except": 1, "precedence": 1, "accepted": 5, "accepted_words": 249},

0 commit comments

Comments
 (0)