From 772d97291690bb2cae39aca4c8120d0074eadf36 Mon Sep 17 00:00:00 2001 From: Adam Clemens Date: Sun, 23 Aug 2026 15:00:56 +0100 Subject: [PATCH] Drop the ADR count claim; give pytest<10 a stated release condition Two small corrections, one worth more than its size. adr/CLAUDE.md read "Six exist: ADR-001 ... ADR-006 -- all Accepted. The next number is 007." That was wrong within hours of being read: ADR-007 landed in the very change that introduced the merge gate requiring exactly this kind of restatement to be updated in the same branch. The gate's own first application missed it. Nothing mechanical was going to catch it -- check-references sees paths that do not resolve and a count is not a path; check-claims reports completeness claims about files, not tallies. So the count is gone rather than corrected. That paragraph now points at docs/index.md's ADR section, which is generated and checked in CI, and states the next number as a rule ("one past the highest that exists there") rather than a value. Correcting "Six" to "Seven" would have reset the drift by one and left the class of defect in place; the reasoning is the one docs/CLAUDE.md already gives for the index, dependency tree and inventory. The blast-radius grep found exactly one such ADR count claim in the repository, which is the only reason this was one line rather than a sweep. Second: practices.md's tooling dependency update policy gains a "Standing watch items" subsection, and pytest<10 is its first entry. A pin dodging a known upstream defect is different from an ordinary version choice -- it has a specific condition that releases it, and with nowhere to record that condition it becomes a pin nobody remembers the reason for. The entry records what was verified rather than assumed: pytest-bdd 8.1.0 (still latest) passes nodeid/baseid to pytest's _register_fixture/FixtureDef; a scenario run under -W error::PytestRemovedIn10Warning fails rather than warns; it passes normally only because warnings are not errors here. Upstream has acknowledged it -- issue #823 open, and PR #827 ("fix: avoid deprecated nodeid argument to _register_fixture") open as of 2026-08-05 -- which is a better position than ADR-007 could state when written, and makes "stay pinned" the obvious option rather than a hopeful one. Trigger to unpin is checkable: run that command against a released pytest-bdd containing #827 and expect a pass. make ci clean: 337 tests, all eleven gates. check-claims returns only its five known false positives. Documentation only; no code changed and TASK-018 deliberately not started. Co-Authored-By: Claude Opus 5 --- adr/CLAUDE.md | 21 +++++++++++++--- docs/CHANGELOG-DESIGN.md | 54 ++++++++++++++++++++++++++++++++++++++++ docs/practices.md | 30 ++++++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/adr/CLAUDE.md b/adr/CLAUDE.md index 23af996..0942181 100644 --- a/adr/CLAUDE.md +++ b/adr/CLAUDE.md @@ -5,10 +5,23 @@ when to write one) are already fully specified in `README.md` in this directory -- read that before adding or editing an ADR; don't duplicate it here. -Six exist: `ADR-001` (knowledge/capability graph), `ADR-002` (FVM-first), -`ADR-003` (modular numerical strategies), `ADR-004` (compute/rendering -class), `ADR-005` (compute/rendering instances), `ADR-006` -(knowledge-graph scope) -- all `Accepted`. The next number is `007`. +**For what exists, read `docs/index.md`'s ADR section** -- it is +generated from the tree by `make docs` and checked by `make ci`, so it +cannot be wrong. **The next number is one past the highest that exists +there.** + +That is deliberately a rule rather than a value. This paragraph read +"Six exist: ADR-001 ... ADR-006 -- all `Accepted`. The next number is +`007`" until 2026-08-22, and was already wrong when it was read that +day: `ADR-007` had landed hours earlier, in the same change that +introduced the merge gate requiring exactly this kind of restatement to +be updated. **Nothing mechanical caught it** -- `make check-references` +only sees paths that do not resolve, and a count is not a path -- and +nothing will catch the next one either, which is why the count is gone +rather than corrected. Same reasoning as `docs/CLAUDE.md`'s: where a +document restates a fact the repository already knows, point at the +generated version instead of keeping a copy. + Numbering is sequential and permanent; never renumber or reuse a number, even if an ADR is later superseded. diff --git a/docs/CHANGELOG-DESIGN.md b/docs/CHANGELOG-DESIGN.md index a563ac1..d101540 100644 --- a/docs/CHANGELOG-DESIGN.md +++ b/docs/CHANGELOG-DESIGN.md @@ -5539,3 +5539,57 @@ completeness. checks, so the golden demos gained no coverage and lost none), 99% coverage, `mypy --strict` clean across 62 files, all eleven gates green including the two new ones. + +### The merge gate's first miss, and a pin that now has a release condition + +**Two small corrections, one of which is worth more than its size.** + +`adr/CLAUDE.md` read "Six exist: `ADR-001` ... `ADR-006` -- all +`Accepted`. The next number is `007`." That was wrong within hours of +being read: `ADR-007` landed in the very change that introduced the +merge gate requiring exactly this kind of restatement to be updated in +the same branch. The gate's own first application missed it. + +**Nothing mechanical was ever going to catch it.** +`make check-references` sees paths that do not resolve, and a count is +not a path; `make check-claims` reports completeness claims about files, +not tallies. So the count is **gone** rather than corrected: that +paragraph now points at `docs/index.md`'s ADR section, which is +generated from the tree and checked in CI, and states the next number as +a *rule* ("one past the highest that exists there") rather than a value. +Same reasoning `docs/CLAUDE.md` already gives for the index, the +dependency tree and the inventory -- where a document restates a fact +the repository already knows, point at the generated version instead of +keeping a copy that can rot. Correcting "Six" to "Seven" would have +reset the drift by one and left the class of defect in place. + +The general lesson, which is the part worth carrying: **a hand-written +count sitting next to a generated listing of the same thing is a +liability, not a convenience.** The blast-radius grep found exactly one +such claim about ADRs in the repository; there was no second copy to +fix, which is the only reason this was a one-line class of problem +rather than a sweep. + +**Second: `pytest<10` now has a stated release condition.** +`docs/practices.md`'s tooling dependency update policy gains a +"Standing watch items" subsection, on the reasoning that a pin dodging a +known upstream defect is a different animal from an ordinary version +choice -- it has a specific condition that releases it, and with nowhere +to write that down it becomes a pin nobody remembers the reason for. + +The entry records what was verified rather than assumed: pytest-bdd +8.1.0 (still the latest release) passes `nodeid`/`baseid` to pytest's +`_register_fixture`/`FixtureDef`; running a scenario under +`-W error::pytest.PytestRemovedIn10Warning` fails rather than warns; it +passes normally only because warnings are not errors here. Upstream has +acknowledged it -- issue #823, open, and PR #827 (`fix: avoid deprecated +nodeid argument to _register_fixture`), open as of 2026-08-05 -- which +is a materially better position than the ADR could state when it was +written, and makes "stay pinned" the obvious option rather than a +hopeful one. The trigger to unpin is checkable: run that command against +a released pytest-bdd containing #827 and expect a pass. + +- *Verified by:* `make ci` clean (337 tests, all eleven gates); + `make check-claims` returning only its five known false positives. + Documentation only -- no code changed, and TASK-018 deliberately not + started. diff --git a/docs/practices.md b/docs/practices.md index d965418..a9159c4 100644 --- a/docs/practices.md +++ b/docs/practices.md @@ -922,6 +922,36 @@ same check already required when Python itself moves, above -- since a hook or package that silently drops support for the pinned interpreter is a CI break waiting to happen, not a hypothetical. +### Standing watch items + +A pin that exists to dodge a *known upstream defect* is different from +an ordinary version choice: it has a specific condition that releases +it, and without somewhere to write that condition down it becomes a pin +nobody remembers the reason for. List those here, with the trigger +stated as something checkable rather than a feeling. + +- **`pytest<10`** (`pyproject.toml`, pinned 2026-08-22). `pytest-bdd` + 8.1.0 -- still the latest release -- passes `nodeid`/`baseid` to + pytest's `_register_fixture`/`FixtureDef`, which pytest 9 reports as + `PytestRemovedIn10Warning`. Verified by running a scenario under + `-W error::pytest.PytestRemovedIn10Warning`, where it fails rather + than warns; it passes normally only because warnings are not errors + here. + **Why this one matters more than a usual pin:** since + `adr/ADR-007-executable-acceptance-criteria.md`, feature files *are* + the acceptance criteria for Stage 4+ simulation work, so the failure + mode is not "some tests break", it is "the acceptance criteria stop + executing". + **Trigger to unpin:** pytest-bdd releases a version containing the fix + in its PR #827 (`fix: avoid deprecated nodeid argument to + _register_fixture`, open as of 2026-08-05, against issue #823). Check + by running the command above against the released version and + expecting a pass. Until then the pin stays, and the exposure is + narrow: only a pytest 10 release carrying something this project + actually needs would make it cost anything. + **If the fix never lands**, ADR-007 names the fallbacks in order -- + stay pinned, vendor a minimal Gherkin runner, or reverse the ADR. + --- # Blast Radius