You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(differential,docs): the review findings on the fields ban
One real coverage loss and two falsified sentences, all from the
focused review of #457.
test_main_compares_the_v2_surface_from_baseline_2_0 stopped catching
its own mutation. Its diff IS the ambiguity-only one, and the blanket
`fields = ["family"]` my fixture sweep gave it refuses that shape, so
the ZZZ rule stayed inert even with name narrowing disabled: measured,
that mutant failed 11 tests on master and 10 here. The fixture now
declares `_ambiguities`, the role its diff actually moves, and the
mutant is back to 11. This is exactly the weakening the sweep's own
commit message claimed not to have caused, in the one fixture whose
diff is not {family}.
"127 of 127" is wrong at both 2.x baselines, including the default.
_RULE_FIELDS has eight members, and from 2.0 on main unions
`_ambiguities` into the same diff set, so the banned shape claims 255
there and 127 below. A live count with no date, quoted in an error
message a contributor reads while a 2.1.0 gate is failing. Both
figures now, in the message, the README and decisions.md.
validate_rules' docstring said the fields-without-name_regex check was
"the family's sharpest example: no other malformed shape can widen
invisibly". #456 is the counterexample, and worse -- over_declared_rules
skips a fieldless rule, so nothing narrows it either. The paragraph
names both now.
Also: `dormant` gains a pin, since disabling this check otherwise
failed exactly one test where #451's fails three; the README's "It may
narrow further with `fields`" is folded into the required list rather
than left contradicting the sentence eight lines below it;
over_declared_rules' and classify's docstrings stop presenting the
banned shape as legal; the decisions.md entry moves after the #452
entry it cites, restoring date order; and the inversion note moves to
the assertion that was actually inverted, where a `git log -L` finds
it.
5350 passed; gates 229/0, 194/0, 102/0.
Refs #456
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/design/decisions.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -635,8 +635,8 @@ Decisions that landed:
635
635
- 2026-08-27 #451 — past-tense counts stay in a ledger comment; live ones do not. "It claimed 25 until #372" is a fixed fact. "Four corpus names, and the prose fits all four" was written when the rule explained four and still read that way at fourteen, because nothing recomputes it. Where a count is owned by another comment, point at the owner rather than restating it — two copies means one gets updated and the other does not.
636
636
- 2026-08-28 #452 — a rule's declared `fields` must EQUAL the union of the diffs it explains, checked by `compare.py` at the end of every run and failing it like an unexplained diff. The statement is exact rather than heuristic, which is what makes it cheap: `classify()` already requires `declared >= union` for the rule to match the names it matches, so the only possible error is the other direction, and the union is simultaneously the check and the repair. Narrowing to it cannot orphan a name, since every name a rule explains contributed to it. Measured before landing: 3 of 67 explaining rules over-declared at 1.4.0, 5 of 58 at 2.0.0, 6 of 51 at 2.1.0 — all fourteen narrowed first, so the check was silent the day it arrived.
637
637
- 2026-08-28 #452 — over-declaration is BASELINE-RELATIVE, and each ledger is measured on its own run rather than copied. `fix(#296) a lone post-comma credential is a suffix` declared `{family, given, suffix, title}` in all three ledgers: exactly exercised at 1.4.0, where v1 reads the pre-comma word as `first` and all four roles move, and over-declared at both 2.x baselines, where the same behaviour moves only `{suffix, title}` — which is all it declares in those two files now. A reader comparing the three sees one rule with TWO different field lists and should read that as correct rather than as drift. Two and not three, measured: the 2.x pair narrowed to the same set, so the split is 1.4.0 against both 2.x ledgers, not one list per file.
638
-
- 2026-08-29 #456 — a rule carrying `name_regex` and no `fields` is REJECTED, the symmetric twin of #451's ban. It narrows by name and by nothing else, so on any name its regex reaches it claims every diff shape there is — measured, 127 of 127. #452 is what made it urgent rather than merely untidy: `over_declared_rules` skips a rule with no `fields`, correctly, since one declaring no roles cannot over-declare them — so deleting the line is the cheapest way to silence an OVER-DECLARED failure AND the most permissive thing that can be done to the rule, which is the #372 failure mode reached by following a gate error message. Free to enforce on #451's own terms: measured, 0 of 179 rules across the three ledgers had the shape. After it, every rule carries both keys, and the three rejections in `validate_rules` read as one rule — narrow by name and by role, or it is not a rule. NO escape hatch for a "genuinely unbounded" rule, declined until one appears, same call and same reason as #452's.
639
638
- 2026-08-28 #452 — NO escape hatch, decided rather than deferred. `dormant` already covers the explains-nothing case in both directions, a rule with no `fields` has nothing to over-declare, and the ledger's own doctrine — "a rule that pre-claims shapes it has never seen is the #372 failure mode" — makes strictness the existing principle. Accepted cost, stated so it is not rediscovered as a surprise: the first rule that genuinely needs a wider declaration has to argue for a key the way `dormant` was argued for in #373, rather than reaching for one that already exists.
639
+
- 2026-08-29 #456 — a rule carrying `name_regex` and no `fields` is REJECTED, the symmetric twin of #451's ban. It narrows by name and by nothing else, so on any name its regex reaches it claims every diff shape there is — measured, 255 shapes from baseline 2.0 on and 127 below it. #452 is what made it urgent rather than merely untidy: `over_declared_rules` skips a rule with no `fields`, correctly, since one declaring no roles cannot over-declare them — so deleting the line is the cheapest way to silence an OVER-DECLARED failure AND the most permissive thing that can be done to the rule, which is the #372 failure mode reached by following a gate error message. Free to enforce on #451's own terms: measured, 0 of 179 rules across the three ledgers had the shape. After it, every rule carries both keys, and the three rejections in `validate_rules` read as one rule — narrow by name and by role, or it is not a rule. NO escape hatch for a "genuinely unbounded" rule, declined until one appears, same call and same reason as #452's.
0 commit comments