Checks
python3 00-META/checks/records.py structure: links, no record written here, citations in the form "ADR NNNN"
python3 00-META/checks/index.py the reading order's topics are written, and no list of records is stored
python3 00-META/checks/cycle.py the development cycle: a design's layer, status, decisions and code; an issue report's frontmatter
python3 00-META/checks/words.py the glossary's retired words are not used, no daemon's line is written, and no word is defined twice
python3 00-META/checks/words.py --list tools the words the catalogue's copy must list
python3 00-META/checks/words.py --list lines the daemons' lines the catalogue's copy must list
Non-zero exit on any problem, so it can be a gate rather than a report.
Why this exists. Until now nothing in this repository was verified by anything but reading,
which is how a superseded decision stayed live in the constitution for days and in
01-to-be/README.md alongside it. Both were found by a person looking. how-we-build §5 says
an unenforced rule is indistinguishable from a wrong one, and costs more, because people
believe it — this repository was carrying several.
Every check here failed on something real before it passed. A check that has never failed is indistinguishable from one that cannot.
| Check | Asserts | Found |
|---|---|---|
links |
every relative link resolves | — (run ad hoc during authoring; now permanent) |
no-records |
02-DECISIONS/ and 01-RESEARCH/ hold their README and nothing else: a decision record or research effort lives in the knowledge base (ADR 0290 rule 9) |
written with the change that removed the records (issue 426); it failed on a record file put back in 02-DECISIONS/ before it passed |
decisions-form |
every entry of a design's decisions: is "ADR NNNN", four digits |
written with issue 426; it failed on an entry ADR 290 before it passed |
mention-form |
every "ADR N" in the text has four digits, and every "research N" three; a code span is an example and is not read | written with issue 426; it failed on ADR 12 and research 45 before it passed |
| (index.py) | the reading order's six topics are written in 02-DECISIONS/README.md, none twice, and the README stores no list of records (ADR 0248). The knowledge base reads these lines and refuses a record whose topic is not one of them |
a stored list made every two open decisions conflict (issue 297); it failed on the README of main before the list was removed |
status-vs-code |
a to-be document naming specific code is not still designed |
ten documents, several with a What was built section, describing lab-proven code |
Where the rules on records went
The decision records and research efforts left this repository for the knowledge base (ADR 0290, issue 426),
and the rules these checks held over them left with them. The knowledge base holds each as a rule of its own,
named in its refusal: knowledge-base.propose refuses a record that breaks one of the rules that judge one
record, naming every reason at once, and the four rules that judge the whole record set run after every
acceptance and raise a condition when one fails (mesh-knowledge's rules.go, one table-test case per rule).
| Rule here until issue 426 | Where it lives now |
|---|---|
records.py rests-on, for a record's extends: |
the knowledge base's rests-on at propose, and the whole-set rule rests-on-live |
records.py rests-on, for a design's decisions: naming an accepted record |
nowhere yet: this repository cannot read the knowledge base. The reviewer checks each new entry with knowledge-base.get. Designs become the knowledge base's own kind under issue 428 |
records.py live-citation, in a record |
the knowledge base's live-citation |
records.py live-citation, in 00-META/ and 03-DESIGN/01-to-be/ |
nowhere yet, as above: the reviewer checks a cited record's status with knowledge-base.get; issue 428 |
records.py supersession |
the knowledge base's supersedes-accepted and self-link, and the whole-set rule supersession |
records.py partial-supersession |
the knowledge base's changes link to a clause, changes-in-force and supersedes-accepted, and the whole-set rule partial |
records.py clauses |
the knowledge base's has-clause, clause-numbering, clause-lead and clause-size |
records.py numbering |
the knowledge base's title and reserved |
records.py topics, index.py (a record's topic) |
the knowledge base's topic, against the reading order index.py still checks |
records.py insights |
the knowledge base's insight-form; an accepted record changes by a new version marked as a progressive insight |
index.py --print |
knowledge-base.holds with a topic |
cycle.py research: a known status, became: when graduated |
the knowledge base's research-status, overview and became |
cycle.py no two decision records share a number |
the knowledge base's reserved, and the issue tracker's counter behind knowledge-base.reserve |
cycle.py an accepted decision cited by nothing |
the knowledge base's whole-set rule cited: a record accepted there is cited by another record or names a home (homes at propose) |
cycle.py a deferral names the issue that tracks it |
the knowledge base's deferral |
words.py over research efforts from 2026-10-07, and kept in words-allowed.md |
the knowledge base's retired-word and daemon-line, from this glossary |
What is deliberately not checked
- Whether a record a document cites exists, or is still accepted. A checkout cannot read the knowledge
base, and a check that called the mesh would make every merge here depend on it. Until designs become the
knowledge base's own kind (issue 428), the reviewer asks
knowledge-base.getfor each record a change cites in00-META/or03-DESIGN/01-to-be/(the documents that tell somebody what to do). An as-is document may rest on a superseded record: it describes what runs, and what runs was built under whatever was decided at the time (ADR 0006: as-is describing a superseded decision is exactly what as-is is for). - Whether a citation's prose is still true. A document can cite an accepted record and describe it wrongly, and nothing here notices.
Adding a check
State what incident it would have caught, and make it fail before you make it pass. A check whose failure has never been observed is a guess about its own correctness.
cycle.py
The development cycle, checked (ADR 0080):
every design parses, its layer: matches its folder and its status: is known; a to-be design names a
decision in decisions:; an in-progress or implemented design names its owning code; and no two issue
records share a number (issue 155 — the number is how a record is cited, and main lags every open pull
request, so two people reading it allocate the same one). An issue report carries the day it was opened:
and no status key — status:, located-in:, fixed-by:, amended-design:, replay:, replay-none: or
resolved: — because an issue's status lives in the issue tracker (ADR 0275); it failed on all 361 reports
that carried them before they were removed. The rules on an issue's status this check held until then — an
owner for a located issue, a fix for a resolved one, and a core issue's replay or replay-none (ADR 0237)
— are refused at the write by issue-tracker.move. Its rules on research efforts and decision records left
with them (the table above). python3 00-META/checks/cycle.py
words.py
One word per thing, checked (ADR 0244).
It reads the glossary's Not: lines (the retired words, each with its scope) and Identifier until
renamed lines, and fails on a retired word or a bare identifier in running prose — what is left once code,
quotations, struck-through text, link targets, comments and frontmatter are taken out — in 00-META/,
03-DESIGN/, AGENTS.md, README.md, and issues opened from 2026-10-07. Decision records and research
efforts live in the knowledge base, which holds a proposed record to the same words (the table above). It
also fails when a glossary head word heads two entries or is also retired.
words-allowed.md names a document that could not be reworded at once, with a date. With MESH_CATALOG_DIR set it compares the catalogue's copy
of the tools' retired words (retired-words) with the glossary.
It also fails on a daemon's line (ADR 0272,
its insight of 2026-10-09): the operator types one command, nox, and a document names a nox line, never the
controller's or the node-engine's binary followed by one of its commands. The lines are the check's own list
(DAEMON_LINES); a command that is a line only with an argument after it is matched as a line is written. Looked
for in the same documents, from 2026-10-09 for issues, in the document's own words — code blocks and
spans included, quotations and block quotes taken out. With MESH_CATALOG_DIR set it compares the catalogue's copy
(retired-lines) with the list.
It failed on something real before it passed: 581 uses of retired words in 63 documents on its first run, besides the glossary itself and research 034 —
"the host" for the node-engine in 30 designs, "control plane" in 10, the glossary's own entry for the tool runner —
and two glossary contradictions (the "console", the deprecated broker's seat), fixed in the change that
added it. A retired word's plural (s or es on its last word) is matched as the word: until 2026-10-07
it was not, so "alerts", "rollouts" and "the hosts" (the node-engines) passed while their singulars
failed; the plural failed on 15 uses in 10 documents before it passed. A verb that reads like a plural
("a node hosts") is a finding too, and is reworded. Homonyms (plan, gate, tier, ask, store, record, check) are not checked by it: a
word list cannot tell one sense from another, so they are reviewed.