clay-borg/workplans/CB-WP-0030-a-number-that-does-not-move.md
tegwick 3a47e263df
Some checks are pending
ci / check (push) Waiting to run
CB-WP-0030: a control for the wrong-subject family — declare and register
Declaration 1 of chaos window 3 (opened by ADR-0017), tier M, chaos d8=7,
no override.

Seven claims in this project have been wrong the same way, and the
workplan tabulates all seven with what caught each.

MEASURED BEFORE PROPOSING: facts-check reports 62 untagged literal copies
and fails on none, which is a real drift surface it names and does not
close. CLOSING IT WOULD HAVE CAUGHT AT MOST ONE OF THE SEVEN. Instance 1's
denominator WAS a registry fact and WAS correct -- the error was that
AM-4a does not cover the code. Four others were fresh measurements with no
registry key. A tag proves a number came from somewhere; it cannot prove
the somewhere was the right place. Named as separate work rather than
bundled, because bundling would let this pass claim a victory it did not
win.

What did work: every instance was caught when the number was computed a
SECOND TIME by something with a different purpose. Two of them share a
sharper property -- the claim was tested against a variation. #4's cost
FELL as branching ROSE, which no per-node cost can do, and the tell was in
the published output. #5's win rate was attributed to the game, and a
second policy on the same deals gave 0% where the first gave 100%.

So the rule generalises what this project already builds after each
instance (the policy panel, the attack-value sweep) and requires it
before: a measured claim must name the variable it depends on and show the
measurement moving with it. A number that does not move when its subject
moves is measuring something else.

HONEST YIELD: 3 or 4 of 7, and it catches the two that travelled furthest.
It does not catch a count never made, or a claim that is not a number.
Claiming it closes the family would be the family's own error applied to
itself.

T03 requires the lint to fail on a real row by mutation, and to say in its
own output that it checks PRESENCE and not ADEQUACY -- so nobody reads a
green lint as 'the claim was verified'.

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

157 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: CB-WP-0030
kind: process
title: "A number that does not move: a control for the wrong-subject family"
status: ready
---
# Purpose
```
structural tier M (changes how the loop constrains its own operation —
it adds an admissibility requirement, ADR-0006 D5)
chaos d8 = 7 → no override
declared tier M
```
**Declaration 1 of chaos window 3**, opened 2026-08-07 at d8 by ADR-0017.
## The family, with every instance
Seven claims in this project have been wrong in the same way. CB-EV-0019
§1 named it: *this project's arithmetic errors are not in the arithmetic.*
| # | pass | the claim | what was wrong | caught by |
|---|---|---|---|---|
| 1 | CB-WP-0021 | `csv` costs 21,613 against 3,798 of headroom | AM-4a **never sees** that code | re-deriving in ADR-0011 |
| 2 | → ground-game | *"12 in the file"* | a sum with no deal table | **the recipient** |
| 3 | CB-WP-0018 | SOLVE offered on a face-down Problem | the wrong condition named | implementing the ruling |
| 4 | CB-WP-0025 | 112161 µs per node | the timer bracketed whole games | **adversarial review** |
| 5 | CB-WP-0025 | the game is too easy at 56 seats | a win rate attributed to the game | **adversarial review** |
| 6 | CB-WP-0029 | 2 Focus/Blame conflicts | compared *other* players' discs | re-reading the check |
| 7 | ADR-0017 | window 2 had zero overrides | never counted; cited 4× | writing the verdict |
## What will not work, measured before proposing anything
**`facts-check` has a real gap and it is not this one.** It reports **62
untagged literal copies** across 7 registry keys and fails on none of
them — a drift surface it names and does not close.
**Closing it would have caught at most one of the seven.** Instance 1's
denominator *was* a registry fact and was *correct*; the error was that
AM-4a does not cover the code. Instances 2, 4, 5, 6 were **fresh
measurements** — no registry key existed, and a provenance tag reproduces
a wrong subject faithfully.
> **A tag proves a number came from somewhere. It cannot prove the
> somewhere was the right place.**
The untagged surface is worth closing on its own merits, and **bundling it
here would let this pass claim a victory it did not win.** Named as
separate work, not done here.
## What did work, and it is one thing
Read the *caught by* column. Every instance was caught when **the number
was computed a second time by something with a different purpose** — a
later pass, a reviewer, the recipient, or the author re-reading.
Two of them, 4 and 5, share a sharper property: **the claim was tested
against a variation.**
- #4's cost **fell** as branching **rose**. A per-node cost cannot do that.
The tell was in the published output.
- #5's win rate was attributed to the game; a second policy on the same
deals gave 0% where the first gave 100%.
And #1 has it too: vary which crates are in scope and the budget changes,
which is the whole error.
**So the control is to generalise the thing this project already builds
after each instance** — RetrospectiveAnalysis §4.1's policy panel,
CB-WP-0029's attack-value sweep — and require it *before*:
> **A measured claim must name the variable it depends on, and show the
> measurement moving with it. A number that does not move when its subject
> moves is measuring something else.**
**Honest yield: 3 or 4 of 7**, and it catches the two that travelled
furthest. It does **not** catch #7 (a count never made) or #3 (not a
number). **Claiming it closes the family would be the family's own error
applied to itself.**
## Task: decide the rule and its limits
```task
id: CB-WP-0030-T01
status: todo
priority: high
```
`decisions/ADR-0018-*.md`.
- **State the rule** and where it binds: register findings that carry
arithmetic, and anything leaving the repo.
- **State the yield honestly**, instance by instance, including what it
misses. A control whose reach is overstated is worse than none, because
it stops people looking.
- **Decide whether it is a gate or a discipline.** A sensitivity claim is
prose; `loop-lint` can check *presence*, never *adequacy*. Say which
half is mechanical.
- **Do not bundle the untagged-facts surface.** Name it as separate.
## Task: the rule, in the spec that governs findings
```task
id: CB-WP-0030-T02
status: todo
priority: high
```
`specs/GameDesign.md` §1 already requires a reproduction that **exists**,
has the **ruled shape**, and **can fail**. This adds the fourth clause,
because §1.2's row-level rule was itself born from instance 2 and covers
only sums.
**Controls:**
- the clause names the variable and the expected direction, or it is a
sentence with no content;
- **the existing three clauses are unchanged** — this is an addition, and
a rewrite would silently drop what earlier instances bought.
## Task: make the mechanical half mechanical
```task
id: CB-WP-0030-T03
status: todo
priority: high
```
`loop-lint` fails when a register row of an arithmetic kind lacks a
sensitivity line.
**Controls:**
- the check must **fail on a real row**, demonstrated by mutation — a lint
that cannot go red is decoration (ADR-0006 D3, ADR-0017 D2);
- **it checks presence, not adequacy**, and its output says so, so nobody
reads a green lint as *"the claim was verified"*;
- existing register rows are brought under it or explicitly exempted with
a reason — a rule that only binds future rows leaves the six instances
unprotected.
## Task: evidence
```task
id: CB-WP-0030-T04
status: todo
priority: medium
```
`evidence/CB-EV-0028-*.md`.
- **Re-run the seven instances against the rule** and report how many it
would have caught. If the answer is below 3, the rule is not the one.
- **What the untagged surface is worth**, since it was measured here and
deferred.
- **Whether a lint that checks presence is worth having at all**, or
whether it trains the eye to stop at green.