From fc6d5628a722c7aba5fe2c1bd2f903b323c0a641 Mon Sep 17 00:00:00 2001 From: Mathias Date: Sat, 5 Sep 2026 12:25:10 +0200 Subject: [PATCH] fix(adr): template emitted invalid YAML frontmatter The frontmatter exists to be machine-read. Two shapes this template suggested do not parse, so any ADR that copied them dropped silently out of every "what is still open?" query while looking correct: supersedes: - a bare dash is a YAML sequence entry deciders: pending: Mathias the unquoted second colon reads as a nested mapping Both were found live during an estate-wide ADR survey on 2026-09-05: openbanking-api ADR-0001 (the one genuinely open decision in the estate -- invisible to the survey until fixed) and infra ADR-0019, each copied verbatim from here. Template corrected to `null` and a quoted `"pending: "`, plus a short section after the fence explaining why and giving a one-line yaml.safe_load check to run before committing. The explanation is deliberately OUTSIDE the fenced block so it is not copied into the ADR being written. --- skills/adr/SKILL.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/skills/adr/SKILL.md b/skills/adr/SKILL.md index b9058d0..596c61e 100644 --- a/skills/adr/SKILL.md +++ b/skills/adr/SKILL.md @@ -58,8 +58,8 @@ adr: 0004 title: status: proposed | accepted | superseded | amended date: 2026-08-29 -deciders: " while proposed> -supersedes: +deciders: " (QUOTED) while proposed> +supersedes: --- # ADR-0004 — @@ -97,6 +97,25 @@ the condition that fires a revisit. An ADR with no validation section is a prefe with a template around it. ``` +### The frontmatter must actually parse + +It exists to be machine-read, so a block that does not load is worse than no block at +all: it drops that ADR silently out of every "what is still open?" query, while looking +correct. Two shapes this template used to suggest are invalid YAML, and both were found +live in the estate on 2026-09-05 — `openbanking-api` ADR-0001 and `infra` ADR-0019, each +copied verbatim from here: + +| Wrong | Why | Right | +|---|---|---| +| `supersedes: -` | a bare dash is a YAML *sequence entry*, not a string | `supersedes: null` | +| `deciders: pending: Mathias` | the second, unquoted colon reads as a nested mapping | `deciders: "pending: Mathias"` | + +Check before committing: + +```sh +python3 -c "import yaml,sys;yaml.safe_load(open(sys.argv[1]).read().split('---')[1]);print('ok')" docs/adr/0004-*.md +``` + ## Preserving a productive tension Some tradeoffs are not unresolved because nobody thought hard enough. They are