Skip to content

Measured claims in the differential comments go stale unnoticed (a reviewer read "751 names" as fact; the corpus holds 1116) #497

Description

@derek73

Rationale

The differential harness keeps measured facts in prose — how many names a rule
explains, what shape a name diffs, how large a corpus is. Nothing recomputes
them. Three have now been caught stale in a single session, one of them while
actively misleading a reader.

docs/design/AGENTS.md already states the convention: "A count in a dated
entry is evidence, not a live fact"
, and "A count that carries no argument is
better deleted than dated."
These sites predate or ignore it.

The three, measured 2026-09-02

1. tests/v2/_differential_fixtures.py — the comment above
_UNCLASSIFIED_NAMES says the old expression "rescanned all 751 names per
candidate name rather than per rule". len(_CORPUS_NAMES) is 1116. During a
code review the same day, a reviewer read 751 off this comment and reported it
as the live corpus population in a review of unrelated code. The count carries a
real argument (why a rescan was expensive — a measured ~400x) so the fix is to
keep the argument and drop the digits: "rescanned every corpus name per
candidate rather than per rule".

2. _CROSS_RULE_WINNERS, the 田中さん II row — recorded the diff shape as
("given", "suffix"); measured against the 1.4.0 wheel it is
{family, given, suffix} (first '田中さん'→'', last 'II'→'田中',
suffix ''→'さん, II'). Four sites carried the wrong shape — the row, a
neighbouring note, the _MUST_NOT_MATCH comment, and two more in
expected_since_1.4.0.toml. Fixed in the #382 branch; listed here because
of what it exposes, below.

3. expected_since_1.4.0.toml, fix(comma-family) lone post-comma piece routes to suffix/title, not first — its comment says "this rule now claims
exactly one name, 'Andrews, M.D.'". A differential run at baseline 1.4.0
measures eight. Not fixed; it is the reason this issue exists rather than a
fourth commit on #382.

The structural half, which matters more than the three

test_the_recorded_rule_still_wins_each_contested_name cannot catch a wrong
diff shape.
It feeds classify() the recorded shape and asserts the
recorded winner — so a guessed shape agrees with itself forever. That is how
田中さん II sat wrong under a roster whose own docstring says "The diff shapes
are measured against the 1.4.0 wheel, not guessed."
The roster is a
mechanisms.md#RECORDED-ROSTERS instance whose recorded half is unverified in
one dimension.

A guard that compares each _CROSS_RULE_WINNERS key's shape against a real
comparison would close it. That needs the pinned-wheel worker pass, so it
belongs in the differential run rather than the unit suite — which is the same
placement undeclared_contests uses in #382.

A trap for whoever does this. "How many names does a rule explain" cannot be
answered by driving classify() over the names its regex reaches at its own
declared fields — that asks which rule would win if a name diffed in the
widest shape the rule admits, and returns 278 for the rule in item 3. A rule
explains a name only when that name ACTUALLY diffs and the rule classifies that
real diff, which requires the 1.4.0 worker pass. The cheap proxy is off by a
factor of thirty here, and it is the obvious thing to reach for.

Scope

  1. Sweep expected_since_*.toml, tests/v2/test_ledger_guards.py and
    tests/v2/_differential_fixtures.py for measured claims in prose — counts of
    names, diff shapes, reach figures, corpus sizes.
  2. For each: reground it with a stated recompute, or rephrase so the argument
    outlives the digits, or delete it where it carries no argument. Prefer the
    rephrasing — AGENTS.md gives "the two shares differ by orders of magnitude"
    outliving "58% vs 0.65%" as the model.
  3. Add the diff-shape guard to the differential run so item 2's class cannot
    recur silently.

Recorded roster VALUES are ground truth and must not be edited to match a new
measurement — a moved row is a finding. This issue is about the prose around
them, plus the one guard that would make the values self-checking.

Not in scope

#382's own exemption reasons. Every claim in those was measured in the pass that
wrote them, and each names its recompute.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions