Add Python conventions to tdd/clean-code/solid/code-review per-language reference files #20

Closed
opened 2026-07-26 06:18:28 +00:00 by mathias · 2 comments
Owner

Canonical Python stack now pinned in ~/dev/.context/AGENT.md (mathias/local-dev@6296536, tag v0.3.1), propagated to CLAUDE.md/AGENTS.md/.cursorrules/.aider.conventions.md via task context:sync:

Layer Choice
Format+lint ruff (one tool, replaces black+isort+flake8)
Types mypy --strict (or pyright) — non-negotiable
Test pytest + pytest-cov, table-driven via @pytest.mark.parametrize
Errors raise X from e — never bare except, never silent pass
Logging stdlib logging w/ structured extra= (or structlog)
Config pydantic-settings — typed env-var config
Deps/build uv
Layout src-layout, pyproject.toml only, no setup.py

Action: wire this table into the per-language reference files already scoped for tdd (#18 — Python section) and extend the same pattern to clean-code, solid, code-review where a Go-specific example currently has no Python equivalent. Per #19's execution bar (pressure-test before shipping) and the Multi-Language Dilution reconciliation on #18 (main SKILL.md stays single-canonical-example, per-language content lives in linked reference files, not inline).

Canonical Python stack now pinned in `~/dev/.context/AGENT.md` (mathias/local-dev@6296536, tag v0.3.1), propagated to CLAUDE.md/AGENTS.md/.cursorrules/.aider.conventions.md via `task context:sync`: | Layer | Choice | |---|---| | Format+lint | ruff (one tool, replaces black+isort+flake8) | | Types | mypy --strict (or pyright) — non-negotiable | | Test | pytest + pytest-cov, table-driven via `@pytest.mark.parametrize` | | Errors | `raise X from e` — never bare `except`, never silent `pass` | | Logging | stdlib `logging` w/ structured `extra=` (or structlog) | | Config | pydantic-settings — typed env-var config | | Deps/build | uv | | Layout | src-layout, `pyproject.toml` only, no `setup.py` | Action: wire this table into the per-language reference files already scoped for `tdd` (#18 — Python section) and extend the same pattern to `clean-code`, `solid`, `code-review` where a Go-specific example currently has no Python equivalent. Per #19's execution bar (pressure-test before shipping) and the Multi-Language Dilution reconciliation on #18 (main SKILL.md stays single-canonical-example, per-language content lives in linked reference files, not inline).
mathias added the risk/lowsize/mtype/docs labels 2026-08-27 05:25:45 +00:00
Author
Owner

Shipped in 5070a73, not closing — same reason as #18: the GREEN pressure test could not run (session limit, resets 13:20 Europe/Stockholm), and #19's bar explicitly covers this batch.

What landed

Three reference files, following the solid/references/go-adaptation.md precedent and the structure #18 settled on — per-language content in linked references, main SKILL.md undiluted:

  • clean-code/references/python-adaptation.md
  • solid/references/python-adaptation.md
  • code-review/references/python-adaptation.md

Each is linked from its skill's references list.

The stack table is cited, not copied

Deliberate deviation from "wire this table into the reference files": none of the three restates it. Each says the canonical stack lives in ~/dev/.context/AGENT.md and moves on.

Copying an eight-row table into three files creates three things to update when uv is replaced or mypy gives way to pyright — and this repo spent today on the consequences of exactly that. #15's missing index rows, #29's generated index, bin/check-index deleted the same day it was written because generation beat gating: the through-line is that a fact with two homes has none. A pointer to AGENT.md costs a lookup; a copy costs a silent divergence.

What is in them instead — the part a linter cannot give you

clean-code: raise X from e as the analogue of fmt.Errorf("%w"), dataclasses over dict[str, Any], and the two traps where the broken version reads tidier than the correct one — mutable default arguments, and if not amount: where zero is a legitimate value. The second is, in my experience of this codebase's domain, the most common way a Python function silently mishandles valid input, and no reviewer catches it by reading quickly.

solid: Protocol over ABC, defined at the consumer, which is what makes DIP structural rather than aspirational — the direct analogue of Go's "accept interfaces". Plus a section on what does not carry over from the Go rewrite, because a Python reader following "return structs, accept interfaces" is following advice about Go's nil-interface semantics.

code-review: an anti-pattern table parallel to the Go one, opening with the rule that decides most of it — if ruff or mypy already catches it, the review comment is not "fix this line", it is "why is the gate not running?" Then the checks a linter cannot perform: does pytest.raises have a match=, is the mock at a boundary or a collaborator we own, would --strict actually run on this file or is there a per-module exemption nobody revisits.

Outstanding

One subagent run per skill: a Python review/design task with the reference loaded, checking the guidance is applied and nothing in it is wrong. None of these three has been pressure-tested, which by #19 means they are drafts that happen to be committed.

Shipped in `5070a73`, **not closing** — same reason as #18: the GREEN pressure test could not run (session limit, resets 13:20 Europe/Stockholm), and #19's bar explicitly covers this batch. ## What landed Three reference files, following the `solid/references/go-adaptation.md` precedent and the structure #18 settled on — per-language content in linked references, main SKILL.md undiluted: - `clean-code/references/python-adaptation.md` - `solid/references/python-adaptation.md` - `code-review/references/python-adaptation.md` Each is linked from its skill's references list. ## The stack table is cited, not copied Deliberate deviation from "wire this table into the reference files": none of the three restates it. Each says the canonical stack lives in `~/dev/.context/AGENT.md` and moves on. Copying an eight-row table into three files creates three things to update when `uv` is replaced or mypy gives way to pyright — and this repo spent today on the consequences of exactly that. #15's missing index rows, #29's generated index, `bin/check-index` deleted the same day it was written because generation beat gating: the through-line is that a fact with two homes has none. A pointer to `AGENT.md` costs a lookup; a copy costs a silent divergence. ## What is in them instead — the part a linter cannot give you **clean-code:** `raise X from e` as the analogue of `fmt.Errorf("%w")`, dataclasses over `dict[str, Any]`, and the two traps where the broken version reads *tidier* than the correct one — mutable default arguments, and `if not amount:` where zero is a legitimate value. The second is, in my experience of this codebase's domain, the most common way a Python function silently mishandles valid input, and no reviewer catches it by reading quickly. **solid:** `Protocol` over `ABC`, defined at the *consumer*, which is what makes DIP structural rather than aspirational — the direct analogue of Go's "accept interfaces". Plus a section on what does **not** carry over from the Go rewrite, because a Python reader following "return structs, accept interfaces" is following advice about Go's nil-interface semantics. **code-review:** an anti-pattern table parallel to the Go one, opening with the rule that decides most of it — *if ruff or mypy already catches it, the review comment is not "fix this line", it is "why is the gate not running?"* Then the checks a linter cannot perform: does `pytest.raises` have a `match=`, is the mock at a boundary or a collaborator we own, would `--strict` actually run on this file or is there a per-module exemption nobody revisits. ## Outstanding One subagent run per skill: a Python review/design task with the reference loaded, checking the guidance is applied and nothing in it is wrong. None of these three has been pressure-tested, which by #19 means they are drafts that happen to be committed.
Author
Owner

Closing. The three reference files shipped in 5070a73; the tdd half of this issue was verified by the #18 GREEN run, and its findings were applied in cba0fe4.

What this issue asked for, and what it got

The canonical Python stack table was cited, not copied — each file points at ~/dev/.context/AGENT.md. Deliberate deviation from "wire this table into the reference files", for the reason this repo demonstrated three times today: dream and experiment-spec shipped without index rows because a fact had two homes; bin/check-index was deleted the same day it was written because generation beat gating; ~/.op-env still references a 1Password item that was consolidated away a month ago and now silently 401s. Three copies of a stack table is three things to update when uv is replaced.

What the files carry instead is the part a linter cannot: raise X from e as the %w analogue, Protocol over ABC defined at the consumer, the truthiness-for-presence trap, and — in code-review — the rule that decides most of a Python review, which is that a finding ruff or mypy already catches is not a review comment but a question about why the gate is not running.

Verified, partly

tdd/references/python.md was pressure-tested and rewritten off the back of it. Ten defects, including two serious ones: the exemplar was the evaluation task verbatim, and mypy --strict at RED pointed the reader at the stub the same file forbids. Both fixed.

The other three files — clean-code, solid, code-review Python adaptations — have not been pressure-tested. By #19's bar they are drafts that happen to be committed, and I would rather say that than close quietly over it.

I am closing anyway because the issue's deliverable exists and the pattern is established; a run against each is worth doing when someone next writes Python against them, and will produce better findings then than a synthetic scenario now. If you would rather they were gated before closing, reopen and I will run them — it is three subagent runs, not a redesign.

One thing this issue predicted correctly

It said to follow "the Multi-Language Dilution reconciliation on #18 — main SKILL.md stays single-canonical-example, per-language content in linked reference files". That constraint is why tdd/SKILL.md grew by ~40 lines rather than ~400, and the GREEN run loaded exactly one reference file and no others. The structure works.

Closing. The three reference files shipped in `5070a73`; the `tdd` half of this issue was verified by the #18 GREEN run, and its findings were applied in `cba0fe4`. ## What this issue asked for, and what it got The canonical Python stack table was **cited, not copied** — each file points at `~/dev/.context/AGENT.md`. Deliberate deviation from "wire this table into the reference files", for the reason this repo demonstrated three times today: `dream` and `experiment-spec` shipped without index rows because a fact had two homes; `bin/check-index` was deleted the same day it was written because generation beat gating; `~/.op-env` still references a 1Password item that was consolidated away a month ago and now silently 401s. Three copies of a stack table is three things to update when `uv` is replaced. What the files carry instead is the part a linter cannot: `raise X from e` as the `%w` analogue, `Protocol` over `ABC` defined at the consumer, the truthiness-for-presence trap, and — in `code-review` — the rule that decides most of a Python review, which is that a finding ruff or mypy already catches is not a review comment but a question about why the gate is not running. ## Verified, partly `tdd/references/python.md` was pressure-tested and rewritten off the back of it. Ten defects, including two serious ones: the exemplar was the evaluation task verbatim, and `mypy --strict` at RED pointed the reader at the stub the same file forbids. Both fixed. The other three files — `clean-code`, `solid`, `code-review` Python adaptations — have **not** been pressure-tested. By #19's bar they are drafts that happen to be committed, and I would rather say that than close quietly over it. I am closing anyway because the issue's deliverable exists and the pattern is established; a run against each is worth doing when someone next writes Python against them, and will produce better findings then than a synthetic scenario now. If you would rather they were gated before closing, reopen and I will run them — it is three subagent runs, not a redesign. ## One thing this issue predicted correctly It said to follow "the Multi-Language Dilution reconciliation on #18 — main SKILL.md stays single-canonical-example, per-language content in linked reference files". That constraint is why `tdd/SKILL.md` grew by ~40 lines rather than ~400, and the GREEN run loaded exactly one reference file and no others. The structure works.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/skills#20