Every folder-scoped REVIEW.md is a binding per-change review checklist for the files under
its folder: run it on every such change before it ships, including a change to the checklist
itself. This file is the part all checklists share; a checklist's own text carries only its
folder's criteria, and its opening block points here. An external repo that adopts REVIEW.md
vendors a copy of this file at its root. A statement's home is the folder's architecture doc -
ARCHITECTURE_COMMON.md (repo root) is that document type's contract.
What stays in a checklist: rules that can be checked against a diff. Nothing else. A reader must be able to apply every rule without reading the code and without prior knowledge of the folder.
A term of art is defined in place, in a dozen words, or the rule is rewritten around plain words.
A checklist never quotes, cites, or restates another checklist, a skill, or a CLAUDE.md -
coupling between rule documents is ROUTING ("a diff touching X applies that checklist too", "a [tune] change is
reviewed with skills/tune.md").
Every checklist reviews itself: a rule a reviewer cannot apply as written is a defect of the checklist. Mark it like any other finding - a checklist defect blocks nothing, but its fix (a rewrite or a move, never silent tolerance) lands in the same batch as the round's other fixes.
New functionality ships with tests - same PR, no follow-up promises. A new or changed
reachable branch ships a test that fails without it; a diff that adds a branch no test
distinguishes is a defect. The audit procedure - including how to settle "would this test fail
without the change?" - is skills/tdd_audit.md.
A diff that changes a function carrying [arch(at="<doc>.md#<anchor>")], or C++ under a
// <doc>.md#<anchor> pointer - beyond comments - audits the anchor's other citing functions
and the cited section: read the section, check it still describes the code and each citer
still conforms, and records a verdict per function in the PR description. The citers of one
anchor share one mechanism; MCP arch_sites lists them, both spellings. An edit made during that
audit does not start another audit of the same anchor.
A diff that adds, removes, or retargets an [arch(at=...)] citation or a
// <doc>.md#<anchor> pointer audits the cited section against the code - both sections on a
retarget - and records the verdict in the PR description. The citation claims the section
describes this function; verify it does.
A diff that changes an anchored section audits every function citing that anchor, and records a verdict per function in the PR description.
A diff that moves a fact out of a function's comment into an ARCHITECTURE*.md lands three
things in the same change: the statement, a {#anchor} on the heading of the section it joins,
and a citation on that function - [arch(at=...)] on a daslang function, a // <doc>.md#<anchor>
pointer on a C or C++ one - and the comment goes. The citation is
what keeps the section true: a section nothing cites is never re-checked when the code changes.
A rule that a test, a lint, or the folder's REVIEW.das enforces is deleted. Automation
replaces the rule; the checklist keeps at most "weakening that check is a defect." A gate that
enforces part of a rule leaves only the uncovered part as prose. A rule that COULD be automated
is a lint or REVIEW.das candidate - say so in the review round.
A REVIEW.das that does not run standalone as daslang <folder>/REVIEW.das from the repo
root, print one path: finding line per finding (path:line: finding when a line is known),
and exit nonzero when any fired, is a defect. Support library: dastest/review_gate.
A diff that leaves its folder's REVIEW.das red is a defect.
A diff that adds a REVIEW.das adds its sibling REVIEW.md in the same change; weakening a
check that enforces this is a defect.
A rule is absolute; sanctioned violations live in the architecture doc. No "except", "exempt", "carve-out", or "the one sanctioned" - move the boundary inside the trigger, fix the code so the exception has no reason to exist, or ledger the case in the architecture doc. A ledgered case firing the absolute rule is expected: the author answers "yes, ledgered," and that handshake is the system working.
A rule lives in the checklist of the narrowest folder that contains its trigger.
Subfolder-scoped rules move to that subfolder's own REVIEW.md - creating it is never an
objection; checklists are cheap, thousands can sit in a repository and few fire per PR. A rule
whose trigger lies entirely outside the folder can never fire and is deleted.
A checklist whose subfolders carry their own REVIEW.md states so, and routes a file placed
outside its kind's subfolder by KIND, not by location - "a [test] file, wherever the diff
puts it, answers to the tests/ subfolder's checklist".
One rule is one short paragraph - bold criterion first, blank line between rules. A rule that needs more than that is describing how to write code, not how to review it. Split it or move it.
A checklist entry that lists files to touch is a defect - a files-to-touch how-to is procedure, and it moves to the architecture doc or the skill that owns the task.
A rule tells the diff what it must or must not do - it never describes what the system is. A ban says what the system must not be: "never X - do Y instead", or "a diff that adds X ... is a defect" - the defect spelling binds the reviewer's verdict. A duty says what a change must also do: "a diff that changes X also does Y, in the same change". A sentence that describes how the code is ("state is a stack", "X and Y agree") is a statement: the first violating diff turns it false. Rewrite it as the ban or duty of the diff that could break it, or move it to the architecture doc.
A rule is written in plain English - short sentences, common words, no idioms. A rule that needs a second read is a defect of the rule.
A rule spends no spare words. A clause that restates what the head already binds - a defect verdict repeating its own duty, a doubled negation, a filler phrase - is cut.
No sections. A section header is a bucket asking to be filled: a grouping either decouples into the flat list or is a separable concern that earns its own routed file.
Rules are unnumbered and unnicknamed - numbering invites citation. Anything that needs a stable reference lives in the checklist's architecture doc.
A path in a rule resolves against the checklist's own folder. A path from the repo root
starts with a root directory the folder does not contain (modules/..., daslib/...) or says
"(repo root)"; when both readings exist - a tests/ beside the checklist and one at the
root - the rule must say which.
Cite files by name; cite an architecture doc the checklist's opening names by anchor
(<doc>.md#<anchor>), and never require the cited section to be read before the rule can be
applied; a criterion whose home is an architecture doc the opening does not name is restated in
place and cited nowhere.
No file cites a checklist rule by number, position, or nickname. A file outside the rule documents - source, commit message, doc - quotes the rule's words. A quote states the reason the code is shaped this way and survives any rewording; a position points at whatever sits there today.
Name the API a rule is about; never name an example of it. A rule governing specific functions or files must name them or it cannot be checked - that name is the criterion. An illustrative aside has no such excuse: nothing keeps it in sync, and a stale example is worse than none.
A ban names its replacement. "Never X" is half a rule; " - do Y instead" completes it for a few words.
One sentence of WHY is allowed where it makes the criterion decidable; anything longer belongs in the architecture doc. No history, no PR numbers, no direction of travel; planned work lives in the folder's follow-up ledger (a checklist that keeps one elsewhere names it in its opening).
The placement block, when a checklist carries one, closes the file: one bold criterion
("Placement - one file, one line: a diff keeps each file inside its line, and a new file adds
its line here, with its tests, in the same change.") over `file` - role lines, optionally
a bare never-phrase ("Zero network"). A clause with its own defect-verdict or same-change
obligation is a rule, and it lives in the flat list above.
A diff that adds a rule restating one already in the checklist is a defect - extend the existing rule instead.
No diff makes a rule longer, counted in words, than the longest rule its file had before the diff - split the rule, or move the extra prose to the architecture doc.