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

5.8 KiB
Raw Blame History

id kind title status
CB-WP-0030 process A number that does not move: a control for the wrong-subject family 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

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

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

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

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.