Allow progressive insight, and apply two to the bus record

A record can assert a fact that goes stale while the decision it supports
stays right. Superseding for that buries a sound record under a second one
and makes every reader work out which is live. So a correction of fact is
now made in place, marked and dated, with the old wording quoted — bounded
by three conditions and checked by records.py, which fires on an unmarked,
undated or back-dated note. Judgements still supersede.

Applied to 0115: no conformance suite exists to recapture, and the full
genesis bed cannot run until the links exist. Designs 25 and 28 follow.
This commit is contained in:
2026-09-26 18:39:38 +02:00
parent 6ab113e6c6
commit 1c808898a5
7 changed files with 205 additions and 64 deletions
+54
View File
@@ -284,6 +284,59 @@ def check_numbering(failures, records):
)
def check_progressive_insights(failures, records):
"""A correction made inside a record is marked and dated, or it is a silent rewrite.
A record may be corrected in place when a *fact* in it went stale and the decision still
stands (`02-DECISIONS/README.md`, "Progressive insight"). The whole safety of that allowance
is that the correction is legible in the record rather than only in a diff nobody reads, so
the form is what is checked here: every mention of an insight is the marker, the marker
carries an ISO date, and that date is not earlier than the decision's own — an insight
predating the decision it corrects is a copied marker, not a correction.
What this cannot check is an edit made with no marker at all. Nothing mechanical can; that
one is the reviewer's, reading the diff. The check keeps the *marked* path honest so that an
unmarked change stands out as the anomaly it is.
"""
phrase = re.compile(r"progressive insight", re.I)
marker = re.compile(r"\*\*Progressive insights?\s*[\u2014\u2013-]\s*(\d{4}-\d{2}-\d{2})\.?\*\*")
loose = re.compile(r"\*\*[^*]*[Pp]rogressive insights?[^*]*\*\*")
iso = re.compile(r"^\d{4}-\d{2}-\d{2}$")
for number, record in sorted(records.items()):
text = record["text"]
if not phrase.search(text):
continue
decided = str(record["front"].get("date", ""))
good = [(m.start(), m.end(), m.group(1)) for m in marker.finditer(text)]
for m in loose.finditer(text):
if any(s <= m.start() and m.end() <= e for s, e, _ in good):
continue
failures.add("insights", rel(record["path"]),
"a progressive insight is not in the dated marked form "
"'**Progressive insight \u2014 YYYY-MM-DD.**': %s" % m.group(0))
for _, _, stamp in good:
if decided and iso.match(decided) and stamp < decided:
failures.add("insights", rel(record["path"]),
"a progressive insight dated %s predates the decision (%s)"
% (stamp, decided))
covered = [(s, e) for s, e, _ in good]
for m in phrase.finditer(text):
if any(s <= m.start() and m.end() <= e for s, e in covered):
continue
line = text.rfind("\n", 0, m.start()) + 1
if text[line:m.start()].lstrip().startswith("#"):
continue
if loose.search(text, line, text.find("\n", m.end()) + 1 or len(text)):
continue
failures.add("insights", rel(record["path"]),
"'progressive insight' appears unmarked; a correction is marked and "
"dated, or it is a silent rewrite")
def check_status_against_code(failures):
"""A design document naming specific code may not still call itself `designed`.
@@ -325,6 +378,7 @@ def main():
check_numbering(failures, records)
check_topics(failures, records)
check_status_against_code(failures)
check_progressive_insights(failures, records)
print(f"records: {len(records)} decision records checked")
return failures.report()
+6 -2
View File
@@ -33,7 +33,10 @@
A design changes only through a decision.
1. Write the decision record. If it reverses an earlier one, the earlier record's `status:`
becomes `superseded-by: 02-DECISIONS/NNNN-....md` — **its text is never edited**.
becomes `superseded-by: 02-DECISIONS/NNNN-....md` — **its reasoning is never rewritten**. If the
earlier record is sound and only a *fact* in it went stale, that is a **progressive insight**,
corrected in place and marked in the record rather than superseded
([`02-DECISIONS/README.md`](../../02-DECISIONS/README.md)).
2. Edit the to-be design document and set `updated:` to today.
3. If the amendment came from an issue, set that issue's `amended-design:` to the document
path.
@@ -54,4 +57,5 @@ Implementation state is a third axis, independent of both design and decision.
- Do not move a to-be document into `00-as-is/`. Write the as-is document; both stand.
- Do not edit an as-is document to describe an intention. That is what the to-be layer is for.
- Do not change a decision record's meaning. Supersede it.
- Do not change a decision record's meaning. Supersede it. Correcting a fact it got wrong, while
the decision stands, is a progressive insight — marked and dated in the record, never silent.