clay-borg/evidence/CB-EV-0028-a-number-that-does-not-move.md
tegwick d7279483f6
Some checks failed
ci / check (push) Failing after 4s
CB-WP-0030: a control for the wrong-subject family
Seven claims in this project have been wrong the same way — the arithmetic
right, the subject wrong. Four reached a document or another repo.

ADR-0018 states the rule: a measured claim names the variable it depends
on and shows the measurement moving with it. GameDesign §1.4 adds it as a
fourth admissibility clause; the existing three are untouched.

Honest yield is 3 clear + 1 partial of 7. It misses a count never made and
a claim that is not a number, and D3 names those so nobody stops looking.
The tempting fix — closing facts-check's 62 untagged literals — would have
caught 1 of 7 and is deferred as separate work rather than bundled.

loop-lint gains check_sensitivity_stated over arithmetic register rows,
mutation-proven red on F17 and green when restored, with four self-test
controls. It checks presence, never adequacy, and says so in its output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:35:41 +02:00

7.6 KiB
Raw Blame History

CB-EV-0028 — a number that does not move

CB-WP-0030 T04. Tier M (structural M — adds an admissibility requirement; chaos d8 = 7 → no override). Declaration 1 of chaos window 3, opened 2026-08-07 by ADR-0017. Closed 2026-08-07.

Delivered: ADR-0018, GameDesign.md §1.4, check_sensitivity_stated in loop-lint with four self-test controls, and a mutation proof that it goes red on a real row.


1. The seven instances, re-run against the rule

The workplan's own falsifier: if fewer than 3 of 7, the rule is not the one.

# the claim caught? by what, exactly
1 csv costs 21,613 against 3,798 of headroom yes vary which crates AM-4a scopes and the headroom moves — that is the error
2 "12 in the file" no §1.2's row-level rule, born from it, does
3 SOLVE offered on a face-down Problem no not a number
4 112161 µs per node yes cost must rise with branching; it fell
5 too easy at 56 seats yes vary the policy, the rate goes 100% → 0% on the same deals
6 2 Focus/Blame conflicts partly varying seat count scales a real conflict; a phantom one need not
7 window 2 had zero overrides no a count never made has no sensitivity

Three clear, one partial, three missed. Above the falsifier, and not by much.

The distribution matters more than the count. The two it catches outright, 4 and 5, are the two that travelled furthest — instance 4 sat in a published survey, instance 5 was queued for ground-game, which was blocked on that exact number. The three it misses were each caught by a human re-reading, which is the mechanism the rule generalises and cannot replace.

Row 6 is honestly "partly" and stays that way. A phantom conflict from comparing the wrong disc set might scale with seats too. The variation would have prompted the question what am I comparing, which is what actually found it — but that is the rule working as a prompt, not as a test, and writing it down as a catch would inflate the yield.

2. What the untagged surface is worth, since it was measured

facts-check reports 62 untagged literal copies across 7 registry keys and fails on none.

Against this family it is worth 1 of 7, and arguably 0. Instance 1's denominator was a registry fact and was correct — 3,798 is AM-4a's target. The error was that AM-4a does not cover the code being priced. A provenance tag would have reproduced the wrong subject faithfully and with a citation.

A tag proves a number came from somewhere. It cannot prove the somewhere was the right place.

Instances 2, 4, 5 and 6 were fresh measurements — there was no registry key to tag.

It is still worth closing, for a different failure mode: a literal that drifts from its registry key is a copy that disagrees, and facts-check exists for exactly that. Named as separate work and not done here — bundling it would have let this pass claim a victory it did not win, which is this family's own error applied to itself.

3. Is a presence-only lint worth having

The strongest argument against: a green lint reads as "the claim was verified." If it trains the eye to stop at green, it is worse than nothing, because five of the seven instances were caught by an eye that did not stop.

Three things decide it in favour.

It says what it is, in its own output. The finding text ends "NOTE: this checks presence, not adequacy." A reader who stops at green is stopping against an explicit statement rather than an implied one.

Its cost is bounded by scope. It binds arithmetic register rows, not every number in every artifact — 62 untagged literals are this project's own evidence of what an unenforced everywhere-rule produces (ADR-0018 D4).

The failure it prevents is forgetting, and forgetting is what happened. RetrospectiveAnalysis §4.1's policy panel and attack-value.rs's one-varying-number sweep both exist. Both were built after an instance. Nothing asked for either before.

Verdict: worth having, on the condition it never grows a claim it cannot cash. The moment its output implies verification, ADR-0006 D3 and ADR-0017 D2 both apply and it should be deleted.

4. The check fired on three real rows, and all three were wrong to fire

First run: F12, F15, F21 — every one a note.

A note is by definition a finding without a reproduction (GameDesign §3.1). There is no measurement, so there is nothing for a sensitivity statement to be about; the check was demanding one anyway.

The fix went into the check, not into three exemptions. Three hand-written sensitivity-exempt comments would have produced green with the rule still wrong, and the next note would have needed a fourth. That is the difference between a rule and a pile of special cases, and the exemption mechanism exists for genuine one-offs, not for a category the rule should never have covered.

5. The mutation, and the moment it nearly passed as proof

The control is that the check fails on a real row — a lint that cannot go red is decoration.

The first mutation attempt did not fire, and I nearly read that as a failed check. I had rewritten two phrases in F17's prose ("varies exactly one number" → "uses a policy") and expected red. Green. A debug probe showed F17 was being reached, kind degenerate, state raised, prose found — and still matched, because the text elsewhere said "one number varied."

The check was right and the mutation was incomplete. Stripping every trigger word produces:

[sensitivity] specs/FindingRegister.md
    F17 (degenerate) states a quantity and names no variable it depends
    on (GameDesign §1.4). ... NOTE: this checks presence, not adequacy.

and restoring the file returns it to green.

This is worth recording because the near-miss is the same family. "The lint does not fire" was a correct observation about the wrong subject — I had measured my mutation, not the check. A debug probe printing what the check actually saw settled it in one run, which is the second-computation mechanism §1 credits with catching all seven.

Four self-test controls, because a check that cannot say NO is decoration and one that cannot say YES fires on everything: it catches a bare arithmetic claim, clears one that names its variable, skips non-arithmetic kinds, and skips notes.

6. A vocabulary defect, caught by a gate that already existed

This workplan shipped as kind: process. The vocabulary is product | meta | mixed, and make self-tests said so immediately.

No new control was needed and none was added. Corrected to meta — the workplan changes how the loop constrains its own operation, which is what meta means. Worth one line here because the pass that added a gate was itself caught by an older one, working exactly as intended.

7. Cost

make cost, not inlined (§Single source of fact). CB-EV-0019 §4's unbounded chain is still unbounded.

Open after this pass

  • The untagged-facts surface (§2) — 62 copies, measured, deferred, unclosed.
  • The rule catches 3½ of 7 and the family is not closed. Instances 3 and 7 need different controls: a wrong condition is not a number, and a count never made needs counting.
  • The lint's honesty is a claim about readers, not code (§3), and only a later pass reading a green run tests it.
  • F18Relations, DARVO, Player_Mats, Glossary unvendored; still the only open register row with no reproduction.
  • Three of four scenarios never dealt, carried from ADR-0015 D5.