Correction (2026-09-02): two figures below were measured with a hand-built
file→tier map that wrongly marked corpus.jsonl as contract; it is radar. The
split is 326 contract / 790 radar, not 786/330, and the jr rule's reach is
2 contract / 3 radar, not 3/2. The argument and the five radar-only pairs are
unaffected — see the correction comment for the recompute.
Rationale
#488 demoted every composed comma/Latin-wrapper form around a CJK name to
tolerated input and split the projection: corpus_cjk_tolerated.jsonl is
radar tier, where an unmatched diff is "reported, never fatal" and
"cannot fail the run or demand a rule" (_CORPUS_TIERS, #468).
The two fix(cjk-comma-*) ledger families were kept — #488's verification
records them "still classify 11 + 7, now radar-sourced". That is a
measurement, not an argued decision: decisions.md#cjk-comma-demotion
records the format-purity line and the C1→W3 move, and says nothing about
whether the rules that classify the demoted names should stay.
Measurement (2026-09-02, c1a98a9)
Of the 1116 distinct corpus texts, 786 are contract tier and 330 radar.
Scanning expected_since_1.4.0.toml for same-tier rule pairs whose fields
are strictly nested and whose regexes reach a common corpus name gives 11
pairs; 5 of them are contested only over radar names:
| earlier (wide) → later (narrow) |
co-matched |
fix(#296) credential-only comma → fix(comma-family) lone post-comma |
2 |
fix(#296) credential-only comma → fix(comma-precomma-family) |
2 |
fix(cjk-comma-compound) → fix(cjk-glued-honorific-peel) |
17 |
fix(cjk-glued-honorific-peel) → fix(suffix-routing) numeral |
1 |
fix(cjk-glued-honorific-peel) → fix(suffix-routing) jr |
1 |
Sharper, and the number that makes this actionable: three of the five rules
can never classify a contract name at all, because their name_regex
reaches none. Regex reach is an upper bound on what a rule explains — a rule
cannot explain a name it does not match — so this is sound without a run:
| rule |
contract reach |
radar reach |
fix(#296) a credential-only comma string... |
0 |
2 |
fix(cjk-comma-compound) |
0 |
23 |
fix(suffix-routing) roman numeral |
0 |
4 |
fix(cjk-glued-honorific-peel) |
16 |
21 |
fix(suffix-routing) jr |
3 |
2 |
Recompute: load the ledger with tomllib, take each rule's regex reach over
the distinct name values in corpus*.jsonl, and split by _CORPUS_TIERS
(a text held by both tiers reads contract, matching main()'s dedup).
The question
A rule nothing demands is not automatically a rule to delete — it still
classifies a diff rather than leaving it merely reported, and the radar tier
exists so those diffs stay watched. But nothing has re-argued the case since
the demotion, and the rules carry ongoing cost: _CORPUS_CLAIMS entries,
_CROSS_RULE_WINNERS rows, and — once #382 lands — a precedes_narrower
exemption each, whose why today says only "radar-only since #488, kept so
the diff stays explained".
Options
- Keep them, and say so. A
decisions.md#cjk-comma-demotion bullet
arguing that a radar diff is worth classifying rather than merely
reporting. Cost: none, beyond writing the argument.
- Delete the three rules with zero contract reach. They are the clean
case: nothing they could ever classify can fail a run. Cost: each deletion
moves a _CORPUS_CLAIMS entry and any _CROSS_RULE_WINNERS rows, the
dormancy check has to be re-reasoned for whatever survives, and the
demoted diffs start reporting as UNCLASSIFIED on every run — visible
noise that a reader has to learn to skip.
- Case by case, which the reach table argues for.
fix(cjk-comma-compound)
has 23 radar names and no contract reach, and is the classifier-of-record
for shapes _CROSS_RULE_WINNERS pins — the strongest keep-or-delete
argument either way. fix(cjk-glued-honorific-peel) and
fix(suffix-routing) jr still reach contract names and are not candidates
for deletion at all; they appear here only as the narrower half of a
contested pair.
Not in scope
Rule ORDER. #382 settles that separately: all five pairs get a
precedes_narrower exemption there, so this issue is only about whether the
rules should exist, not about which one wins while they do.
Blocked by
#382 — its exemptions are what make the current state legible, and its
_ORDER_EXEMPTION_EFFECT roster is what would have to be re-recorded here.
Rationale
#488 demoted every composed comma/Latin-wrapper form around a CJK name to
tolerated input and split the projection:
corpus_cjk_tolerated.jsonlisradar tier, where an unmatched diff is "reported, never fatal" and
"cannot fail the run or demand a rule" (
_CORPUS_TIERS, #468).The two
fix(cjk-comma-*)ledger families were kept — #488's verificationrecords them "still classify 11 + 7, now radar-sourced". That is a
measurement, not an argued decision:
decisions.md#cjk-comma-demotionrecords the format-purity line and the C1→W3 move, and says nothing about
whether the rules that classify the demoted names should stay.
Measurement (2026-09-02, c1a98a9)
Of the 1116 distinct corpus texts, 786 are contract tier and 330 radar.
Scanning
expected_since_1.4.0.tomlfor same-tier rule pairs whosefieldsare strictly nested and whose regexes reach a common corpus name gives 11
pairs; 5 of them are contested only over radar names:
fix(#296)credential-only comma →fix(comma-family)lone post-commafix(#296)credential-only comma →fix(comma-precomma-family)fix(cjk-comma-compound)→fix(cjk-glued-honorific-peel)fix(cjk-glued-honorific-peel)→fix(suffix-routing)numeralfix(cjk-glued-honorific-peel)→fix(suffix-routing)jrSharper, and the number that makes this actionable: three of the five rules
can never classify a contract name at all, because their
name_regexreaches none. Regex reach is an upper bound on what a rule explains — a rule
cannot explain a name it does not match — so this is sound without a run:
fix(#296) a credential-only comma string...fix(cjk-comma-compound)fix(suffix-routing)roman numeralfix(cjk-glued-honorific-peel)fix(suffix-routing)jrRecompute: load the ledger with
tomllib, take each rule's regex reach overthe distinct
namevalues incorpus*.jsonl, and split by_CORPUS_TIERS(a text held by both tiers reads contract, matching
main()'s dedup).The question
A rule nothing demands is not automatically a rule to delete — it still
classifies a diff rather than leaving it merely reported, and the radar tier
exists so those diffs stay watched. But nothing has re-argued the case since
the demotion, and the rules carry ongoing cost:
_CORPUS_CLAIMSentries,_CROSS_RULE_WINNERSrows, and — once #382 lands — aprecedes_narrowerexemption each, whose
whytoday says only "radar-only since #488, kept sothe diff stays explained".
Options
decisions.md#cjk-comma-demotionbulletarguing that a radar diff is worth classifying rather than merely
reporting. Cost: none, beyond writing the argument.
case: nothing they could ever classify can fail a run. Cost: each deletion
moves a
_CORPUS_CLAIMSentry and any_CROSS_RULE_WINNERSrows, thedormancy check has to be re-reasoned for whatever survives, and the
demoted diffs start reporting as UNCLASSIFIED on every run — visible
noise that a reader has to learn to skip.
fix(cjk-comma-compound)has 23 radar names and no contract reach, and is the classifier-of-record
for shapes
_CROSS_RULE_WINNERSpins — the strongest keep-or-deleteargument either way.
fix(cjk-glued-honorific-peel)andfix(suffix-routing)jr still reach contract names and are not candidatesfor deletion at all; they appear here only as the narrower half of a
contested pair.
Not in scope
Rule ORDER. #382 settles that separately: all five pairs get a
precedes_narrowerexemption there, so this issue is only about whether therules should exist, not about which one wins while they do.
Blocked by
#382 — its exemptions are what make the current state legible, and its
_ORDER_EXEMPTION_EFFECTroster is what would have to be re-recorded here.