check-doc-checkpoint makes docs/USAGE.md a lock that every CMake-touching PR must write
scripts/check-doc-checkpoint.py:91 and :112 list CMakeLists.txt in the path
set that :333 classifies as user_usage, and :354 maps user_usage to
USAGE. So any edit to a CMakeLists.txt — including one that changes no
user-visible behaviour at all — obliges the same change to write
docs/USAGE.md.
CLAUDE.md names this exact shape as a defect, in the checker rather than in the
change:
Do not create a surface that every pull request must write. If N concurrent
pull requests edit file F, that file is a lock. (CLAUDE.md:379-381)
A gate often creates the lock. If a checker requires every change to edit one
shared file, the checker is defective. Move the obligation to a per-row surface.
Do not delete the obligation. (CLAUDE.md:395-397)
It is not hypothetical, and it is currently costly
docs/USAGE.md is already one of the most contended files in the tree. Today
alone it was a genuine merge conflict on #1477, and #1491 relocated a whole
section of it into docs/models/qwen3-8-27b.md, invalidating citations in a spec
that then needed their own repair. Every concurrent PR that touches build wiring
is forced into that same file.
#1532 is a clean example of the mismatch. It forwards one CMake property so the
sanitizer link works — two lines inside a sanitizer guard, tests/CMakeLists.txt
untouched, and by measurement zero recompiles and zero relinks in the default
configuration. Nothing a user can observe changes. The gate still demanded a
docs/USAGE.md edit, so one was written.
The failure mode this produces
The obligation is real often enough that nobody argues with it, which is exactly
what makes the lock expensive: authors satisfy it with the smallest paragraph
that will pass, on a file five other branches are editing. That is how a
projection document accumulates prose written to a checker rather than to a
reader — and this repository has already spent effort this week repairing
docs/USAGE.md claims that had drifted from the code.
What a fix looks like
Not deleting the obligation. A build change can be user-visible — a new
option, a changed default, a dropped platform — and those genuinely owe USAGE.
The problem is classifying every CMakeLists.txt line the same way. Options
worth weighing:
- Narrow the trigger from "the file changed" to "a user-visible surface in it
changed" — an option(...), a default, an installed target, a public
compile definition. The diff is available to the checker.
- Move the obligation to a per-row surface: the row's spec records what a build
change owes, which is the shape CLAUDE.md prescribes.
- Keep the trigger and let a change declare it is not user-visible, with the
reason landing in the commit body where it stays attached to the diff — the
project already uses that pattern for exceptions.
Option 1 fits the existing checker best; option 2 is what the Records rule
literally asks for. Either needs the usual treatment for a semantic checker
change: a spec, a red-before test, and green-after evidence.
Provenance
Found while fixing #1531, where the obligation fired on a two-line CMake change
with no user-visible effect. Not fixed in that flow because changing a checker's
semantics needs its own row, spec and red-first test per CLAUDE.md's
"Changing the rules or a checker".
check-doc-checkpointmakesdocs/USAGE.mda lock that every CMake-touching PR must writescripts/check-doc-checkpoint.py:91and:112listCMakeLists.txtin the pathset that
:333classifies asuser_usage, and:354mapsuser_usagetoUSAGE. So any edit to aCMakeLists.txt— including one that changes nouser-visible behaviour at all — obliges the same change to write
docs/USAGE.md.CLAUDE.mdnames this exact shape as a defect, in the checker rather than in thechange:
It is not hypothetical, and it is currently costly
docs/USAGE.mdis already one of the most contended files in the tree. Todayalone it was a genuine merge conflict on #1477, and #1491 relocated a whole
section of it into
docs/models/qwen3-8-27b.md, invalidating citations in a specthat then needed their own repair. Every concurrent PR that touches build wiring
is forced into that same file.
#1532 is a clean example of the mismatch. It forwards one CMake property so the
sanitizer link works — two lines inside a sanitizer guard,
tests/CMakeLists.txtuntouched, and by measurement zero recompiles and zero relinks in the default
configuration. Nothing a user can observe changes. The gate still demanded a
docs/USAGE.mdedit, so one was written.The failure mode this produces
The obligation is real often enough that nobody argues with it, which is exactly
what makes the lock expensive: authors satisfy it with the smallest paragraph
that will pass, on a file five other branches are editing. That is how a
projection document accumulates prose written to a checker rather than to a
reader — and this repository has already spent effort this week repairing
docs/USAGE.mdclaims that had drifted from the code.What a fix looks like
Not deleting the obligation. A build change can be user-visible — a new
option, a changed default, a dropped platform — and those genuinely owe
USAGE.The problem is classifying every
CMakeLists.txtline the same way. Optionsworth weighing:
changed" — an
option(...), a default, an installed target, a publiccompile definition. The diff is available to the checker.
change owes, which is the shape
CLAUDE.mdprescribes.reason landing in the commit body where it stays attached to the diff — the
project already uses that pattern for exceptions.
Option 1 fits the existing checker best; option 2 is what the Records rule
literally asks for. Either needs the usual treatment for a semantic checker
change: a spec, a red-before test, and green-after evidence.
Provenance
Found while fixing #1531, where the obligation fired on a two-line CMake change
with no user-visible effect. Not fixed in that flow because changing a checker's
semantics needs its own row, spec and red-first test per
CLAUDE.md's"Changing the rules or a checker".