docs/design/AGENTS.md lists ten review axes. .claude/agents/design-docs-reviewer.md opens ## The nine axes and stops at axis 9. Nothing compares the two, and the agent file is untracked — so it is neither reviewed nor diffable, while the document it implements is both.
The missing one is axis 10, "Re-run every capability claim":
Axis 1 recomputes numbers; this one recomputes CAN and CANNOT. A statement that the parser never or cannot produce some reading is measured by a parse run written now, never derived from a mechanism — most of all when it justifies building something.
That is precisely the check #467 needed. rules.md#P6's rationale said a never-given particle "cannot be a name at all". Measured, all 33 members report given == themselves when parsed bare (parse("de") → given de). The claim stood in three files (rules.md, _lexicon.py, config/particles.py), was the sole argument for a design that was built, reviewed by four agents, opened as #466 and closed unmerged — and it survived that review round, because the agent running the design-docs axes does not have the axis that asks CAN/CANNOT claims to be run.
It is also the second correction of that same over-claim: decisions.md#P6 already records dropping "no particle is a name by itself" for the identical reason, which is what earned axis 4.
1. Track the agent file and pin it against AGENTS.md
Move .claude/agents/design-docs-reviewer.md into version control and add a test that the axis headings in it match the axis list in docs/design/AGENTS.md.
This is the same shape as the STABLE_TAGS twin already recorded in nameparser/_types.py:
This prose is the hand-maintained twin of docs/modules.rst's STABLE_TAGS block; nothing pins the two against each other (the test only compares the frozenset), so edit both or neither.
Here the drift already happened, silently, and cost a closed PR.
2. Add an axis: check the rule against something that is not the code
Every current axis compares a document to another document, to its own examples, or to the implementation. All ten are therefore blind to a rule that is simply wrong — they can only find code that disagrees with it.
An invariant relating two inputs is not blind that way, because it consults no rule at all:
For a name of the form Family Given [Particle], the family-comma writing under the default order and the comma-less writing under FAMILY_FIRST parse identically.
Measured across #467: 0 of 216 → 216 of 216, and it holds 450/450 over a wider matrix including middles, suffix commas and titles. It would have failed #466's design at 72 of 216 — the ambiguous-particle half — with no argument about vocabulary and no reading of any rule.
The executable form of that particular invariant is proposed in #469. What belongs here is the general axis: when a rule implies a relationship between two DIFFERENT inputs, state it and test it; that is the only check in the set that can catch a false rule.
Why this is worth a rule rather than a habit
Two review rounds this month found real defects and missed the premise underneath them — #461 (backed out after the rule turned out wrong) and #466 (closed unmerged for the same reason). In both, every reviewer checked the code against the rule and the rule was the thing at fault. Recorded in decisions.md for #461 as: "they all checked the code against the rule and THE RULE was wrong."
docs/design/AGENTS.mdlists ten review axes..claude/agents/design-docs-reviewer.mdopens## The nine axesand stops at axis 9. Nothing compares the two, and the agent file is untracked — so it is neither reviewed nor diffable, while the document it implements is both.The missing one is axis 10, "Re-run every capability claim":
That is precisely the check #467 needed.
rules.md#P6's rationale said a never-given particle "cannot be a name at all". Measured, all 33 members reportgiven== themselves when parsed bare (parse("de")→ givende). The claim stood in three files (rules.md,_lexicon.py,config/particles.py), was the sole argument for a design that was built, reviewed by four agents, opened as #466 and closed unmerged — and it survived that review round, because the agent running the design-docs axes does not have the axis that asks CAN/CANNOT claims to be run.It is also the second correction of that same over-claim:
decisions.md#P6already records dropping "no particle is a name by itself" for the identical reason, which is what earned axis 4.1. Track the agent file and pin it against AGENTS.md
Move
.claude/agents/design-docs-reviewer.mdinto version control and add a test that the axis headings in it match the axis list indocs/design/AGENTS.md.This is the same shape as the
STABLE_TAGStwin already recorded innameparser/_types.py:Here the drift already happened, silently, and cost a closed PR.
2. Add an axis: check the rule against something that is not the code
Every current axis compares a document to another document, to its own examples, or to the implementation. All ten are therefore blind to a rule that is simply wrong — they can only find code that disagrees with it.
An invariant relating two inputs is not blind that way, because it consults no rule at all:
Measured across #467: 0 of 216 → 216 of 216, and it holds 450/450 over a wider matrix including middles, suffix commas and titles. It would have failed #466's design at 72 of 216 — the ambiguous-particle half — with no argument about vocabulary and no reading of any rule.
The executable form of that particular invariant is proposed in #469. What belongs here is the general axis: when a rule implies a relationship between two DIFFERENT inputs, state it and test it; that is the only check in the set that can catch a false rule.
Why this is worth a rule rather than a habit
Two review rounds this month found real defects and missed the premise underneath them — #461 (backed out after the rule turned out wrong) and #466 (closed unmerged for the same reason). In both, every reviewer checked the code against the rule and the rule was the thing at fault. Recorded in
decisions.mdfor #461 as: "they all checked the code against the rule and THE RULE was wrong."