Files
hq/00-META/checks/index.py
T
jschoubben 0afc8cc5f8
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery delivered
Name the commit the knowledge base's records now come from, and link research with touches and decisions with rests-on (review of #312)
2026-10-11 13:25:21 +02:00

75 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""The reading order of the decision records: its topics are written here, its records are not.
A number identifies a record and never changes, so the reading order is not the order of the numbers.
It is the six topics `02-DECISIONS/README.md` writes down, in order, and each record's own topic. The
records live in the knowledge base (ADR 0290, issue 426), which reads these lines through the records
module and refuses a record whose topic is not one of them; the list of records under a topic is its
answer to `knowledge-base.holds` with that topic, never stored here (ADR 0248, hq issue 297).
python3 00-META/checks/index.py check
It fails when the README's reading order is missing or names a topic twice, and when the README stores
a list of records again — the index markers, or a line of a generated list. The last one is what keeps
the conflict of issue 297 from coming back. Whether every record's topic is one of the six is the
knowledge base's rule `topic`, judged when a record is proposed.
"""
import io
import re
import sys
README = "02-DECISIONS/README.md"
# A topic in the README's reading order, e.g.
# 1. **What the mesh is** — `topic: the mesh`. What it is for, ...
# The knowledge base (mesh-knowledge, reference.go) reads the same line, so the form is a contract.
TOPIC_LINE = re.compile(r"^\d+\.\s+\*\*(?P<label>[^*]+)\*\*\s+—\s+`topic:\s*(?P<topic>[^`]+)`", re.M)
# What a stored list looks like: the old markers, or a line of the list index.py used to print.
STORED = [
(re.compile(r"<!--\s*index:(start|end)\s*-->"), "an index marker"),
(re.compile(r"^- \*\*\d{4}\*\* — \[", re.M), "a line of a generated list"),
]
def reading_order(text=None):
"""The topics, in order, as (topic, label) pairs, from the README."""
if text is None:
text = io.open(README, encoding='utf-8').read()
return [(m.group("topic").strip(), m.group("label").strip()) for m in TOPIC_LINE.finditer(text)]
def main():
if "--print" in sys.argv:
print("index: the records live in the knowledge base (ADR 0290). Read a topic's with "
"`knowledge-base.holds` and that topic, through the mesh MCP server.")
return 2
text = io.open(README, encoding='utf-8').read()
topics = reading_order(text)
problems = []
if not topics:
problems.append("%s writes no reading order: no line of the form "
"'1. **Label** — `topic: name`. ...'; the knowledge base refuses every "
"record without it" % README)
names = [t for t, _ in topics]
if len(set(names)) != len(names):
problems.append("%s names a topic twice in its reading order" % README)
for pattern, what in STORED:
if pattern.search(text):
problems.append("%s stores a list of records (%s). The records live in the knowledge base, "
"and a topic's list is `knowledge-base.holds` with that topic" % (README, what))
for p in problems:
print("index: " + p)
if problems:
return 1
print("index: %d topics in the reading order, no stored list" % len(topics))
return 0
if __name__ == "__main__":
sys.exit(main())