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