<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rulesets/languages/python, branch main</title>
<subtitle>Claude Code skills, rules, and language bundles
</subtitle>
<id>https://git.cjennings.net/rulesets/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/rulesets/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/'/>
<updated>2026-05-31T17:31:35+00:00</updated>
<entry>
<title>feat(python): add coverage-summary to the Python bundle</title>
<updated>2026-05-31T17:31:35+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-31T17:31:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=af478a42b18c4d5e0712c4cb43036126d36c56b5'/>
<id>urn:sha1:af478a42b18c4d5e0712c4cb43036126d36c56b5</id>
<content type='text'>
Second language in the coverage-summary fan-out, after the Elisp pilot. Same kernel: a module no test imports never appears in coverage.py's report, so a line-weighted total skips it silently and the suite looks healthier than it is. This counts every source file on disk that's absent from the report as 0% and weights the project number by file, so untested modules stay visible.

The script at languages/python/claude/scripts/coverage-summary.py parses coverage.py's JSON (files[path].summary.covered_lines / num_statements), resolves report paths against the report's directory since coverage records them relative to where it ran, and recurses the source dir for *.py. Unlike the Elisp version it doesn't print a per-file table, because coverage.py's own coverage report already does. The script adds the missing-file accounting that report lacks. It uses only the standard library, parsing the report rather than importing coverage.

The Python run confirmed the plumbing from the pilot is genuinely generic. install-lang and sync deliver the script and the project-owned coverage-makefile.txt with no Python-specific code. The one gap I had to close: the Python bundle shipped without a gitignore-add.txt, so the .claude/ footprint wasn't ignored and the script would have been committable. Added one mirroring the Elisp footprint plus Python artifacts (__pycache__, .coverage, coverage.json). make test gained a languages/*/tests/test_*.py discovery path alongside the existing Elisp ERT one.

Tests: 12 pytest covering the parser, the file-weighted number, and the missing-file detection including subpackage recursion, plus an install-lang check that the script lands in the gitignored footprint. I proved it against a report matching coverage.py's documented schema and the CLI end to end, but not against a live coverage json run, because coverage.py isn't installed in this repo's env. The first project to adopt it should sanity-check against a real report.
</content>
</entry>
<entry>
<title>docs(languages): revise python-testing SQLite and ORM-mocking guidance</title>
<updated>2026-05-22T20:07:32+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-22T20:07:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=7f17f6116f846ce0817da2caca4855cc7e72d576'/>
<id>urn:sha1:7f17f6116f846ce0817da2caca4855cc7e72d576</id>
<content type='text'>
Two audit fixes. The "prefer in-memory SQLite" advice is risky when prod is Postgres or MySQL — SQLite diverges on query semantics, constraints, transactions, JSON, time zones, and indexes, so a test can pass on SQLite and fail in prod. ORM/query tests now use a production-like DB, with SQLite reserved for pure unit tests. The "never mock the ORM" rule is also clarified: don't mock ORM internals, but a thin orchestration unit can inject a fake at a deliberate data-access port it owns.
</content>
</entry>
<entry>
<title>feat: adopt pairwise-tests (PICT combinatorial) + cross-reference from existing testing skills</title>
<updated>2026-04-19T21:12:02+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-19T21:12:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=b11cfd66b185a253fecf10ad06080ae165f32a74'/>
<id>urn:sha1:b11cfd66b185a253fecf10ad06080ae165f32a74</id>
<content type='text'>
Forked verbatim from omkamal/pypict-claude-skill (MIT). LICENSE preserved.
Renamed from `pict-test-designer` to `pairwise-tests` — technique-first
naming so users invoking "pairwise" or "combinatorial" find it; PICT
remains the tool under the hood.

Bundle (skill-runtime only):
  pairwise-tests/SKILL.md                    (renamed, description rewritten)
  pairwise-tests/LICENSE                     (MIT, preserved)
  pairwise-tests/references/pict_syntax.md
  pairwise-tests/references/examples.md
  pairwise-tests/scripts/pict_helper.py      (Python CLI for model gen / output fmt)
  pairwise-tests/scripts/README.md

Upstream's repo-level docs (README, QUICKSTART, CONTRIBUTING, etc.) and
`examples/` dir (ATM + gearbox walkthroughs — useful as reading, not as
skill-runtime) omitted from the fork. Attribution footer added.

Cross-references so /add-tests naturally routes to /pairwise-tests when
warranted:

- add-tests/SKILL.md Phase 2 step 8: if a function in scope has 3+ parameters
  each taking multiple values, surface `/pairwise-tests` to the user before
  proposing normal category coverage. Default continues with /add-tests;
  user picks pairwise explicitly.
- claude-rules/testing.md: new "Combinatorial Coverage" section after the
  Normal/Boundary/Error categories. Explains when pairwise wins, when to
  skip (regulated / provably exhaustive contexts, ≤2 parameters, non-
  parametric testing), and points at /pairwise-tests.
- languages/python/claude/rules/python-testing.md: new "Pairwise /
  Combinatorial for Parameter-Heavy Functions" subsection under the
  parametrize guidance. Explains the pytest workflow: /pairwise-tests
  generates the matrix, paste into pytest parametrize block, or use
  pypict helper directly.

Mechanism note: cross-references are judgment-based — Claude reads the
nudges in add-tests/testing/python-testing and acts on them when appropriate,
not automatic dispatch. Craig can still invoke /pairwise-tests directly when
he already knows he wants combinatorial coverage.

Makefile SKILLS extended; make install symlinks /pairwise-tests globally.
</content>
</entry>
<entry>
<title>refactor: generalize testing.md, split Python specifics, DRY install</title>
<updated>2026-04-19T17:36:04+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-19T17:36:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=019db5f9677902ba02d703a8554667d1b6e88f6b'/>
<id>urn:sha1:019db5f9677902ba02d703a8554667d1b6e88f6b</id>
<content type='text'>
claude-rules/testing.md is now language-agnostic (TDD principles, test
categories, coverage targets, anti-patterns). Scope header widened to
**/*. Python-specific content (pytest, fixtures, parametrize, anyio,
Django DB testing) moved to languages/python/claude/rules/python-testing.md.

Added languages/python/ bundle (rules only so far; no CLAUDE.md template
or hooks yet — Python validation tooling differs from Elisp). Added
install-python shortcut to the Makefile.

Updated scripts/install-lang.sh to copy claude-rules/*.md into each
target project's .claude/rules/. Bundles no longer need to carry their
own verification.md copy — deleted languages/elisp/claude/rules/verification.md.
Single source of truth in claude-rules/, fans out via install.

Elisp-testing.md now references testing.md as its base (matches the
python-testing.md pattern).
</content>
</entry>
</feed>
