From 17e163f15c69c25934430dc4949bbd30151b70a7 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sat, 5 Sep 2026 16:45:57 -0400 Subject: [PATCH] docs(#4333): document the ADR Amends/Amended-by convention (#4334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(#4333): document the ADR Amends/Amended-by convention Two patterns for amending an accepted ADR are established practice — an in-place `## Amendment (YYYY-MM-DD)` section, and a separate ADR that declares `Amends` with a reciprocal `Amended by` back-link — but only the first was ever written down. #4030 shows the cost: a contributor concluded no ADR owned a contract that ADR-857 already covers, because nothing said the second pattern (used by ADR-1244 and ADR-2782 to extend ADR-857 itself) existed. Document both patterns in docs/contributor-standards.md, note the Amends/Amended-by reciprocity rule in docs/adr/README.md alongside the existing Supersedes/Subsumes rule (and that it isn't yet gated by scripts/gen-adr-index.cjs the way those are), and point CONTRIBUTING.md's new-ADR process at the amendment path for revisiting an existing one. Closes #4333 Co-Authored-By: Claude Sonnet 5 * docs(#4333): fix imprecise Amends/Amended-by precedent citations Orthogonal review caught two inaccuracies: PR #1643 doesn't match the in-place dated-section pattern (it rewrites the original Decision text rather than appending an untouched dated section), and ADR-1244's relationship to ADR-857 is prose ("extended by"), not the structured Amends/Amended-by header field. ADR-2782 is the verified precedent for the structured field pair — its one Amends field names four targets (857, 894, 1016, 1244), all four carrying the reciprocal back-link. Co-Authored-By: Claude Sonnet 5 --------- Co-authored-by: sim Co-authored-by: Claude Sonnet 5 --- CONTRIBUTING.md | 2 ++ docs/adr/README.md | 6 ++++++ docs/contributor-standards.md | 22 +++++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd8e00ed8..c916ab889 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,6 +102,8 @@ An ADR (Architecture Decision Record) documents a significant architectural deci **Rejection reasons:** Issue not approved before file was created, filename uses local-compute sequential number instead of issue#, multiple decisions bundled in one PR, file placed in wrong directory (`docs/adr/` vs `docs/prd/`). +**This process is for a *new* ADR file.** An accepted ADR is never rewritten from scratch — check `docs/adr/` first for a broader ADR that already owns the area. Amending one is a separate, lighter-weight path: see **[`docs/contributor-standards.md` — "Amending an accepted ADR"](docs/contributor-standards.md#amending-an-accepted-adr)** for the two established patterns (an in-place dated section, or a new ADR that declares `Amends`/gets the reciprocal `Amended by` back-link). + --- ## The Issue-First Rule — No Exceptions diff --git a/docs/adr/README.md b/docs/adr/README.md index 97a558239..a01b9ce82 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -80,6 +80,12 @@ If A declares either relation toward B, **B must record the reciprocal.** A one- Only an `Accepted` ADR is owed the back-link. A `Proposed` ADR's claim is **prospective**: it has not taken effect, so its target is not marked. On ratification, the check begins demanding the back-links. +### 3a. Amendment is symmetric too — but not yet gated + +A same-file `## Amendment (YYYY-MM-DD): ` section (see `docs/contributor-standards.md`'s "Amending an accepted ADR") needs no back-link — there is only one file. A **separate** ADR that amends another is the same relation as Supersedes/Subsumes and follows the same rule: if A declares `**Amends:** [ADR-B]`, B **must** carry the reciprocal `**Amended by:** [ADR-A]` in the same PR. [ADR-2782](2782-reviewer-lane-capability-surface.md)'s single `Amends` field names four targets — [ADR-857](857-capability-system.md), [ADR-894](894-capability-declaration-format.md), [ADR-1016](1016-runtime-capability-descriptor.md), [ADR-1244](1244-capability-ecosystem.md) — and all four carry the reciprocal `Amended by` back-link. + +Unlike `Supersedes`/`Subsumes`, this is not yet enforced by `scripts/gen-adr-index.cjs` — `relationSections()` only recognizes `## Supersedes` / `## Subsumes` headings, and the header-field parity check does not walk `Amends`. Get the back-link right by review until that gap closes. + ### 4. The declared id matches the filename An H1 of `# ADR-0175: …` in a file named `218-*.md` is a rename that never finished. The id in the title must match the filename's prefix. diff --git a/docs/contributor-standards.md b/docs/contributor-standards.md index 69d3c3b41..471ab6bcf 100644 --- a/docs/contributor-standards.md +++ b/docs/contributor-standards.md @@ -119,7 +119,27 @@ Every ADR must open with: Body: one-paragraph decision summary, then `## Decision` (specifics), then `## Consequences` (behavioral changes downstream callers can rely on). -Amendments are appended as `## Amendment (YYYY-MM-DD): ` sections — the original body is never rewritten. +### Amending an accepted ADR + +**An accepted ADR is never rewritten — it is amended.** Before concluding that a change needs a brand-new ADR, check whether a broader existing ADR already owns the area: `857-capability-system.md`'s Consequences and Ratification sections, for example, explicitly name the Loop Extension Points and their render-hook call sites — a change to that contract amends 857, it does not leave the area without a governing ADR. Two patterns are established, chosen by size: + +**1. In-place dated section (the default; use this first).** For an addition that stays within the ADR's existing decision, append a `## Amendment (YYYY-MM-DD): ` section to the *end of the same file* — the original `## Decision` / `## Consequences` body is never rewritten, and the dated marker can be the heading itself or the section's opening line. This is the common case: see `1239-gsd-embeddable-orchestration-engine.md` (PR [#4146](https://github.com/open-gsd/gsd-core/pull/4146)) and `1411-resolution-provenance.md` (PR [#2678](https://github.com/open-gsd/gsd-core/pull/2678)). + +**2. A separate ADR that `Amends` the original.** When the addition is substantial enough to warrant its own issue and its own `## Decision` / `## Consequences` — not just a section — write it as its own file (`docs/adr/-.md`, per "Naming conventions" above) and declare the relation in its header: + +```md +- **Amends:** [ADR-](-slug.md) — +``` + +The amended ADR **must record the reciprocal pointer in its own header, in the same PR**: + +```md +- **Amended by:** [ADR-](-slug.md) — +``` + +This mirrors the `Supersedes`/`Superseded by` and `Subsumes`/`Subsumed by` reciprocity rule in [`docs/adr/README.md`](adr/README.md#3-supersession-and-subsumption-are-symmetric) — a one-way `Amends` pointer is the same failure mode: a reader who lands on the original ADR has no way to know it was extended. See `2782-reviewer-lane-capability-surface.md`, whose single `Amends` field lists four targets (`857-capability-system.md`, `894-capability-declaration-format.md`, `1016-runtime-capability-descriptor.md`, `1244-capability-ecosystem.md`) — all four carry the reciprocal `**Amended by:** [ADR-2782]` back-link, added in the same PR. + +**Note:** unlike `Supersedes`/`Subsumes`, `Amends`/`Amended by` reciprocity is convention, not yet machine-checked by `scripts/gen-adr-index.cjs` — get the back-link right by hand and by review. ### Status block format