Some checks failed
ci / check (push) Failing after 4s
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>
126 lines
5.7 KiB
Markdown
126 lines
5.7 KiB
Markdown
# ADR-0018: a number that does not move when its subject moves is measuring something else
|
||
|
||
status: accepted
|
||
date: 2026-08-07
|
||
decided by: agent, under the standing loop authorization
|
||
tier: M (structural M — adds an admissibility requirement, changing how
|
||
the loop constrains its own operation; ADR-0006 D5). chaos d8 = 7 → no
|
||
override. **Declaration 1 of chaos window 3.**
|
||
references: [CB-WP-0030](../workplans/CB-WP-0030-a-number-that-does-not-move.md),
|
||
CB-EV-0019 §1 (where the family was named),
|
||
[GameDesign.md](../specs/GameDesign.md) §1,
|
||
[RetrospectiveAnalysis.md](../specs/RetrospectiveAnalysis.md) §4.1,
|
||
[ADR-0017](ADR-0017-chaos-window-2-verdict.md) (instance 7)
|
||
|
||
## Context
|
||
|
||
Seven claims in this project have been wrong in the same way: the
|
||
arithmetic was right and the **subject** was not. Four reached a document
|
||
or another repository.
|
||
|
||
## D1 — what this does not do, stated first
|
||
|
||
**`facts-check`'s untagged surface is not this family's control.** It
|
||
reports **62** untagged literal copies across 7 registry keys and fails on
|
||
none. That is a real gap, and closing it would have caught **at most one**
|
||
of the seven:
|
||
|
||
- Instance 1's denominator **was** a registry fact and **was correct** —
|
||
`am4a_target` = 3,798 is right; AM-4a simply does not cover the code
|
||
being priced.
|
||
- Instances 2, 4, 5 and 6 were **fresh measurements** with no registry key
|
||
at all.
|
||
|
||
> **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 is **named as
|
||
separate work**. Bundling it here would let this decision claim a victory
|
||
it did not win — which is the family's own error, applied to itself.
|
||
|
||
## D2 — the rule
|
||
|
||
> **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.**
|
||
|
||
This is not new machinery. It is the generalisation of two things this
|
||
project already built, each in response to one instance:
|
||
|
||
- `RetrospectiveAnalysis` §4.1's **policy panel** — born from instance 5,
|
||
which is why a single policy's win rate may not be reported as a
|
||
difficulty;
|
||
- `attack-value.rs`'s **one-varying-number sweep** — built for F17, which
|
||
varies ATTACK's rank and holds everything else fixed.
|
||
|
||
**Both were built after an instance. The rule requires them before.**
|
||
|
||
## D3 — the yield, instance by instance, including the misses
|
||
|
||
| # | the claim | would D2 have caught it? |
|
||
|---|---|---|
|
||
| 1 | `csv` against AM-4a's headroom | **yes** — vary which crates are in scope and the budget moves; that *is* the error |
|
||
| 2 | *"12 in the file"* | **no** — but §1.2's row-level rule, born from it, does |
|
||
| 3 | SOLVE's wrong condition | **no** — not a number |
|
||
| 4 | 112–161 µs per node | **yes** — cost must rise with branching; it fell, and the tell was already printed |
|
||
| 5 | too easy at 5–6 seats | **yes** — vary the policy and the rate collapses to 0% |
|
||
| 6 | 2 Focus/Blame conflicts | **partly** — varying seat count would scale a real conflict; it is the weakest row |
|
||
| 7 | window 2 had zero overrides | **no** — a count that was never made has no sensitivity to state |
|
||
|
||
**Three clear, one partial, three missed.**
|
||
|
||
**The two it catches outright are the two that travelled furthest**, and
|
||
both were bound for `ground-game`: instance 4 sat in a survey, instance 5
|
||
was queued for a repo blocked on that exact number. A control that catches
|
||
the consequential half is worth having even at 3/7.
|
||
|
||
**What it misses is stated so nobody stops looking.** Instance 7 needs
|
||
counting, not sensitivity. Instance 3 was not a number. **No syntactic gate
|
||
detects a wrong subject in general** — it is a semantic error, and
|
||
claiming otherwise would build a gate that cannot cash out (ADR-0006 D3,
|
||
ADR-0017 D2).
|
||
|
||
## D4 — where it binds
|
||
|
||
- **Register findings whose claim is arithmetic** — the same scope
|
||
GameDesign §1.2 already uses.
|
||
- **Anything leaving the repo.** Four of the seven were outbound or nearly
|
||
so, and the recipient caught one we did not.
|
||
|
||
**Not** every number in every artifact. A rule that binds everywhere is
|
||
obeyed nowhere, and this project has 62 untagged literals as evidence of
|
||
what a broad, unenforced requirement produces.
|
||
|
||
## D5 — half of it is mechanical, and only half
|
||
|
||
`loop-lint` can check that a sensitivity line **is present**. It cannot
|
||
check that the sensitivity is the **right one**, because that is the same
|
||
judgement the rule exists to force.
|
||
|
||
> **The lint checks presence, not adequacy, and must say so in its own
|
||
> output** — otherwise a green lint reads as *"the claim was verified"*,
|
||
> and the control becomes a way of not looking.
|
||
|
||
That is the honest split: the mechanical half stops the requirement being
|
||
forgotten; the judgement half stays with the author and the reviewer, who
|
||
between them caught five of the seven.
|
||
|
||
## Consequences
|
||
|
||
- `GameDesign.md` §1 gains a fourth clause. The existing three are
|
||
untouched — each was bought by an earlier instance.
|
||
- `loop-lint` gains a check over the register's arithmetic rows.
|
||
- Existing rows are brought under it or exempted **with a reason**.
|
||
- The untagged-facts surface is recorded as separate, unclosed work.
|
||
|
||
## What was rejected
|
||
|
||
| rejected | why |
|
||
|---|---|
|
||
| closing the untagged-facts surface as *the* control | 1 of 7; a tag reproduces a wrong subject faithfully |
|
||
| requiring a regenerating command on every claim | catches transcription, and six of seven were not transcription errors |
|
||
| a rule binding every number everywhere | obeyed nowhere; the 62 untagged literals are the evidence |
|
||
| a lint that claims to verify the claim | it can only see presence, and pretending otherwise trains the eye to stop at green |
|
||
| stating a yield of "the family is closed" | the family's own error, applied to itself |
|