diff --git a/00-META/checks/records.py b/00-META/checks/records.py index aaa1d0f0..6bd0c086 100644 --- a/00-META/checks/records.py +++ b/00-META/checks/records.py @@ -269,6 +269,10 @@ PARTIAL_MARK = re.compile( ) +# The form these notes had before the check: it named the later record but nothing read it. +NARROWED_MARK = re.compile(r"^> \*\*Narrowed, not replaced — [^\n]*\[ADR \d{4}\]\(", re.M) + + def check_partial_supersession(failures, records): """A record superseded in part says so under its heading, and its superseder names it. @@ -276,6 +280,8 @@ def check_partial_supersession(failures, records): 21 `supersedes-in-part:` links had no note on the record they change, so a reader who arrived at the older record by a citation read a rule that no longer held. Both directions are checked: the field on the newer record and the dated note on the older one, naming each other. + The note is dated by the newer record's `date:`, and the older form of the note, which named a + later record and was read by nothing, is refused so it cannot be a way round this check. """ for number, record in records.items(): claimed = record["front"].get("supersedes-in-part", []) @@ -295,7 +301,22 @@ def check_partial_supersession(failures, records): f"ADR {number} supersedes this in part; this record carries no " f"'> **Superseded in part — YYYY-MM-DD, by [ADR {number}](…).**' note", ) - for _, by in PARTIAL_MARK.findall(record["text"]): + for line in NARROWED_MARK.findall(record["text"]): + failures.add( + "partial-supersession", + rel(record["path"]), + f"a note names a later record in the old form ({line.strip()[:60]}…); write it as " + f"'> **Superseded in part — YYYY-MM-DD, by [ADR NNNN](…).**' and declare it in that " + f"record's `supersedes-in-part:`", + ) + for date, by in PARTIAL_MARK.findall(record["text"]): + if by in records and date != str(records[by]["front"].get("date", "")): + failures.add( + "partial-supersession", + rel(record["path"]), + f"the note for ADR {by} is dated {date}; ADR {by} is dated " + f"{records[by]['front'].get('date', 'nowhere')}", + ) if by not in records: failures.add("partial-supersession", rel(record["path"]), f"note names no such record: ADR {by}") continue diff --git a/02-DECISIONS/0009-modules-and-the-graph.md b/02-DECISIONS/0009-modules-and-the-graph.md index a12796d2..44b6f96f 100644 --- a/02-DECISIONS/0009-modules-and-the-graph.md +++ b/02-DECISIONS/0009-modules-and-the-graph.md @@ -43,7 +43,7 @@ hand. ### What a domain module turns out to be, and why it is not the one refused above -> **Narrowed, not replaced — 2026-10-06, by [ADR 0226](0226-the-private-network-is-assigned-by-its-own-name-and-the-proxy-names-its-public-issuer.md).** The catalogue no longer +> **Superseded in part — 2026-10-06, by [ADR 0226](0226-the-private-network-is-assigned-by-its-own-name-and-the-proxy-names-its-public-issuer.md).** The catalogue no longer > holds a domain module: `networking` was retired, and every machine is assigned the private network's > own module. A module with requirements and no files stays a thing a module may be; "why it is worth > having" below describes what this record decided for `networking`, not what runs. diff --git a/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md index c32e499d..7947cbdb 100644 --- a/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md +++ b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md @@ -80,7 +80,7 @@ records the state it first found the unit in, and undeclaring returns the unit t manager: running before the mesh arrived, running after it leaves. - **A unit the mesh started is stopped again**, and one it enabled is disabled again — the packet filter a converge loaded, which returning to adopted unloads. -> **Narrowed, not replaced — 2026-10-09, by [ADR 0269](0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md).** +> **Superseded in part — 2026-10-09, by [ADR 0269](0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md).** > "Never started on the way out" has one exception. The host now records what the mesh declared beside > what it found. A unit found running or enabled that the mesh's own declaration held stopped or disabled > is started or enabled again when that declaration goes, but only while it is still exactly as the mesh diff --git a/02-DECISIONS/0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md b/02-DECISIONS/0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md index a2b4ae7a..e790b8a7 100644 --- a/02-DECISIONS/0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md +++ b/02-DECISIONS/0269-what-the-meshs-own-declaration-stopped-is-started-again-when-it-goes.md @@ -5,6 +5,8 @@ date: 2026-10-09 deciders: jochen reconstructed: false extends: 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md +supersedes-in-part: + - 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md --- # 269. What the mesh's own declaration stopped is started again when it goes diff --git a/02-DECISIONS/0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md b/02-DECISIONS/0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md index 58333346..38248b47 100644 --- a/02-DECISIONS/0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md +++ b/02-DECISIONS/0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md @@ -18,7 +18,8 @@ extends: 02-DECISIONS/0249-a-delivery-groups-order-rules-have-a-precedence-and-a > Decision 4's "one walk at a time", and decision 1's window for every merge, no longer hold: a lone merge is > cut at once, and walks that share no repository, module or edge of the module graph run at once, one > first-node judgement per node at a time. Two walks of one repository never at once, no walk superseded once -> it started, and the window for a merge that waits for its delivery group stand as decided here. +> it started, and the window for a merge that waits for its delivery group or arrives while a batch assembles +> stand as decided here. ## Context diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index ffda2c5a..a9080ed5 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -81,7 +81,8 @@ heading and newest first, a note in the form > as decided here. dated by the newer record's `date:`. `00-META/checks/records.py` (`partial-supersession`) fails when -either half is missing. Saying "this narrows" or "this replaces" an older record in prose alone is not +either half is missing, when the note's date is not the newer record's, and on a note in the older form +*Narrowed, not replaced*. Where the note sits is the reviewer's to see in the diff. Saying "this narrows" or "this replaces" an older record in prose alone is not enough: on 2026-10-11, 6 records did only that, and 11 of 21 declared links had no note on the record they changed.