115 lines
10 KiB
Markdown
115 lines
10 KiB
Markdown
# Checks
|
|
|
|
```
|
|
python3 00-META/checks/records.py structure: links, citations, supersession, topics
|
|
python3 00-META/checks/index.py every record's topic is in the reading order, and no list of records is stored
|
|
python3 00-META/checks/index.py --print the records, by topic, in reading order (generated, never written)
|
|
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) |
|
|
| `rests-on` | `decisions:` and `extends:` name records that exist and are **accepted** | the class behind both incidents |
|
|
| `live-citation` | a governing document citing a **superseded** record names its replacement in the same paragraph | `01-to-be/README.md` citing ADR 0022 as live guidance |
|
|
| `supersession` | if A says it was superseded by B, B says it supersedes A | ADR 0012 never declared that it superseded 0011 |
|
|
| `partial-supersession` | a record's `supersedes-in-part:` names records that exist, each carrying a dated *Superseded in part* note naming it under its heading; and every such note is named back by its superseder's field | 11 of 21 partial supersessions had no note on the record they change, and 6 more were said only in prose ([research 045](../../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md)) |
|
|
| `clauses` | an accepted record dated from 2026-10-11 writes its `## Decision` section as numbered clauses with a bold lead ([ADR 0290](../../02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md) rule 3) | 226 of 263 decision records wrote their decision as prose, so the knowledge base must draft their clauses |
|
|
| `numbering` | the number in the filename is the number in the heading | — |
|
|
| `topics` | every record names a topic of the reading order in `02-DECISIONS/README.md` | — |
|
|
| *(index.py)* | the reading order is written, every record's topic is one of it, and the README stores no list of records ([ADR 0248](../../02-DECISIONS/0248-the-decision-index-is-generated-when-it-is-read-and-never-stored.md)) | a stored list made every two open decisions conflict ([issue 297](../../04-ISSUES/297-two-open-decisions-always-conflict/00-report.md)); 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 |
|
|
|
|
## What is deliberately not checked
|
|
|
|
- **`02-DECISIONS/` and `01-RESEARCH/` may cite superseded records freely.** A decision record
|
|
discusses history; research records what was observed. Flagging those would produce noise on
|
|
correct documents, and a check that cries wolf gets suppressed — which costs more than not
|
|
having it.
|
|
- **`03-DESIGN/00-as-is/` may rest on a superseded record.** It describes what runs, and what
|
|
runs was built under whatever was decided at the time
|
|
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md):
|
|
*as-is describing a superseded decision is exactly what as-is is for*).
|
|
- **Whether a citation's prose is still true.** Only whether the record it points at is live.
|
|
A document can cite an accepted record and describe it wrongly, and nothing here notices.
|
|
|
|
So "governing" means `00-META/` and `03-DESIGN/01-to-be/` — the documents that tell somebody
|
|
what to do.
|
|
|
|
## 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](../../02-DECISIONS/0080-the-development-cycle-is-checked.md)):
|
|
a to-be design names a decision, an in-progress/implemented design names its owning code, a graduated
|
|
research overview says what it became, 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](../../02-DECISIONS/0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md));
|
|
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](../../02-DECISIONS/0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md))
|
|
— are refused at the write by `issue-tracker.move`. And an accepted record that puts work
|
|
off — "until renamed", "left for later", "not decided here", "postponed", "future work", "deferred", "a later
|
|
change" — names the issue that tracks it, as tracking it ("tracked by issue N", or "issue N tracks"), in that
|
|
paragraph or list item, or in a dated progressive insight that speaks about it: one in the same section, or one
|
|
that quotes it. An issue cited for another reason tracks nothing, and one insight does not excuse every deferral
|
|
in a record. The tracking issue counts when it has a folder in `04-ISSUES/`, or when its number is above every
|
|
folder's: since ADR 0275 an issue from 365 on lives only in the issue tracker, which a checkout cannot read, and the
|
|
tracker hands out numbers in order (issue 436). A made-up number above the folders therefore passes; the reviewer
|
|
checks that the issue exists, with `issue-tracker.get`. A rejected option is not work put off and is not held, judged by its `##` section, so an option under a
|
|
`###` subheading of "Considered Options" is skipped too
|
|
([issue 354](../../04-ISSUES/354-a-decided-rename-was-never-scheduled-and-the-operator-believed-it-live/00-report.md):
|
|
ADR 0244 deferred the code renames with no issue, and two days later the operator believed them done). Held to
|
|
it: a record dated from 2026-10-09, and an older one corrected under the rule. Measured from ADR 0244's date
|
|
it found deferrals without an issue in ADR 0241, 0244 and 0270; held from 2026-10-09 it failed on 0270 and 0273
|
|
(whose "not decided here" sits beside a citation of issue 340 that tracks none of it), and on 0244's four
|
|
deferral places once its insight brought it under the rule — on three of them while the insight, in §6, named
|
|
the issue without quoting them — before each named its issue (355, 357, 354). `python3 00-META/checks/cycle.py`
|
|
|
|
## words.py
|
|
|
|
One word per thing, checked ([ADR 0244](../../02-DECISIONS/0244-the-mesh-is-described-in-domains-and-one-word-names-one-thing.md)).
|
|
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 research and issues dated from 2026-10-07. Decision records are
|
|
never checked. It also fails when a glossary head word heads two entries or is also retired.
|
|
[`words-allowed.md`](words-allowed.md) names a document that could not be reworded at once, with a date, or
|
|
a graduated research effort kept as written. 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](../../02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md),
|
|
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 research and 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.
|