Three Python skills: best-practices v1.5.0, async-best-practices v1.0.0, pytest v1.0.0 + claim-proof harness - #3
Conversation
…(v1.0.0), claim-proof harness python-best-practices 1.3.0 -> 1.4.0 (79 rules, 9 sections): - new Concurrency & Async section: no-blocking-event-loop, own-your-tasks, bound-concurrency, generator-cleanup (grounded against pydantic-ai's async machinery and tests) - new rules: types-modern-syntax, types-sequence-over-list-params, data-reject-bool-as-int, error-match-types-not-messages, imports-lightweight-init - accuracy fixes: cached_property lock semantics by version, lru_cache instance retention, TYPE_CHECKING runtime-annotation caveat, gather return_exceptions typing, httpx client lifetime, datetime.UTC, api-required-before-optional impact recalibration python-pytest 1.0.0 (15 rules, 5 sections): test value, determinism, fixtures, mocking, structure — observational voice, same build pipeline. proofs/: uv + pytest + Makefile harness; 29 executable proofs for version-sensitive claims, green on CPython 3.11-3.14. Docs standardized on uv run / make.
python-best-practices 1.4.0 -> 1.5.0: back to 75 rules / 8 sections; async guidance moved out, description points at the companion skill. Cancellation semantics for except clauses stay in error-specific-exceptions. python-async-best-practices 1.0.0: no-blocking-event-loop, own-your-tasks, bound-concurrency, generator-cleanup — same build pipeline, independently vendorable. Cross-skill references qualified by skill name; proofs citations updated.
…actices (5 rules) error-specific-exceptions keeps broad-catch hygiene plus a one-paragraph cancellation-safety note pointing at the async skill; the asyncio depth (gather return_exceptions handling, shielded cleanup, framework MRO caveat) now lives in async-preserve-cancellation with a full incorrect/correct pair. Cancellation proofs relocated to test_async_claims.py and extended with the isinstance(r, Exception)-misses-CancelledError trap.
…semantics Absorbed cancellation does not hang the canceller — it reports success: task.cancelled() is False and a surrounding asyncio.timeout expires without raising, silently losing the deadline. Both premises now have executable proofs (31 proofs green on 3.11-3.14). Inline await asyncio.shield() removed from the correct example: it is not a must-complete guarantee (the awaiting line still raises; detached work needs an owner) — cleanup is brief-then-raise, with owned-task shield/drain reserved for genuinely non-interruptible cleanup.
…ors and proof matrix - error-trust-validated-state: frozen=True is shallow — example now uses tuple[Item, ...]; 'was validated once is not remains valid' - types-fix-types-not-cast: Correct example now validates at the parse boundary instead of annotating unvalidated json.loads output - async-own-your-tasks: shutdown drain now observes pre-cancellation failures (await + cancelled() check) instead of discarding them via gather(return_exceptions=True); TaskGroup fate-coupling stated - async-bound-concurrency: in-flight vs admission bounding distinguished (worker pool / bounded queue / windowing for large or streaming inputs); bound validated >= 1 - perf-dict-index-over-nested-loops: duplicate-key policy — scan is first-match, plain dict comprehension is last-wins; example uses setdefault and states the policy - imports-optional-dependencies: guard moved to the integration-specific module; ModuleNotFoundError.name distinguishes missing from broken - perf-lru-cache-pure-fns: stale-file example replaced with a pure one; key-completeness, result-ownership, and concurrent-miss caveats - error-consolidate-try-except: scope-widening caveat + shared-handler helper alternative for distinct-stage diagnostics - structure-unique-module-names: lone tests/__init__.py does not disambiguate (proven: both trees become tests.test_utils); options are unique filenames, importlib mode, or full package chains - light reframes: mutation APIs returning new information are fine; keyword-only name-surface trade + positional-only; instants vs civil time; transitive immutability for safe defaults; pytest test-level, named smoke contracts, and explicit quarantine carve-outs - proofs: +1 (package-identity nuance); 32 green on 3.11-3.14 - .github/workflows/ci.yml: skill validation + generated-output drift check + proof matrix as required evidence
|
Thanks — this is a strong review. Fixed in
Queued for maintainer decision (will follow up on this PR): the template/eval architecture (#1), Current state: 95 rules across three skills, all validators at 0 failures, 32 proofs × {3.11.14, 3.12.12, 3.13.8, 3.14.3} green. |
…idence lane
Architecture decisions from PR review, as resolved by maintainer:
- validate.py now requires a counter-signal passage (when NOT to apply /
what to preserve) on every MEDIUM+ rule; 14 rules gained explicit
counter-signals, including the review's flatness (api-model-cohesion),
open-union (assert_never), non-strict-xfail-matrix, and clock-injection
carve-outs. Template stays lean per repo philosophy.
- extract_tests.py exports counter_signals per case and the payload
declares the scoring contract: condition-aware application and
preservation, not similarity to the Correct block.
- proofs/typing_tests/: checker-fixture lane running mypy, pyright, and
ty with per-checker expected verdicts (invariance, Sequence covariance,
assert_never exhaustiveness, cast unchecked) — verdicts observed before
encoding. Wired into make and CI.
- Style rules stay in place (impact levels communicate priority).
3 validators at 0 failures; 32 runtime proofs x {3.11..3.14} and 12
typing verdicts green.
|
Follow-up on the queued architecture items — maintainer decisions landed in
State: 3 validators at 0 failures with enforcement active; 32 runtime proofs × {3.11.14, 3.12.12, 3.13.8, 3.14.3} and 12 typing verdicts green; CI runs all of it per PR. |
…make counter-signals structural
Re-review blockers:
- async-own-your-tasks: task.cancelled() cannot identify whose CancelledError
was caught (owner cancellation delegates to the awaited child) — the aclose
example now consults owner.cancelling() first. Two regression proofs:
owner-cancellation-during-drain propagates; pre-cancellation failure
surfaces through the drain.
- data-mutable-defaults: function / dataclass / Pydantic-v2 behaviors
separated (shared object / ValueError / per-instance deep copy) — Pydantic
model defaults are no longer flagged as the function-argument bug.
- counter-signals are now structural: detection requires a standalone
paragraph opening with an approved marker (When/Scope/Preserve/Exception/
Keep/Caveat/Don't/Watch); fuzzy inline phrase matching removed; requirement
extended to ALL impacts; 40 rules gained marker-opened counter-signal
paragraphs (mostly promoting existing prose); detector unit tests added
(thesis 'Keep the old name' is not extracted; code blocks never match).
- _template.md documents the required counter-signal; SKILL.md maps carry
'triggers, not licenses — check the rule's counter-signal' in all three
skills; data-mutation-contract quick-ref and body allow new-info returns
and explicit fluent builders; empty_parameter_set_mark scoped to suites
where nonempty is contractual.
- Smaller re-review items: trust-validated comment precision, config example
checks dict shape and rejects bool-as-int via _is_int helper.
3 validators x 0 failures; 39 runtime proofs x {3.11..3.14}; 12 typing
verdicts; detector unit tests green.
|
Re-review blockers addressed in
Smaller items: trust-validated comment precision, dict-shape + bool-rejecting State: 3 validators × 0 failures under structural enforcement; 39 runtime proofs × {3.11.14, 3.12.12, 3.13.8, 3.14.3}; 12 checker verdicts; detector unit tests green. |
…ment markers Semantic audit of every counter_signals export across the three skills (the surface the structural detector cannot judge): 93 are genuine preserve/when-not passages. Two were a rule thesis wearing a marker — exactly the false-positive class the re-review flagged: - api-underscore-for-private exported the sibling rule's thesis (don't reach into _private) as its counter-signal; de-marked, and a real one added (string-dispatched names are public contracts; leaf application modules don't need exhaustive underscoring). - error-validate-at-boundaries had its own thesis renamed to **Scope:** to satisfy the validator; restored to plain prose, with a real counter-signal on deliberate layered enforcement (DB constraints, domain constructors, security-sensitive ops).
…pace counter-signal label - data-mutable-defaults: default_factory does not validate its output; point at Field(default_factory=..., validate_default=True) for defaults that must be validated (per reviewer note + Pydantic fields docs). - api-instance-vs-module-fn: relabel counter-signal to 'When module scope is right:' so the exported eval intent reads as a condition, not reinforcement.
Splits the repo into three delineated skills, adds executable claim verification (runtime + typing-checker lanes) with CI, and lands two review cycles of semantic and architectural fixes.
Skills
python-best-practicespython-async-best-practicespython-pytestpython-best-practices 1.3.0 → 1.5.0: five new rules (
types-modern-syntax,types-sequence-over-list-params,data-reject-bool-as-int,error-match-types-not-messages,imports-lightweight-init) plus accuracy fixes throughout:cached_propertylock semantics by version,lru_cacheretention,TYPE_CHECKINGruntime-annotation consumers, duplicate-key policy in dict indexing, optional-import scoping viaModuleNotFoundError.name, boundary-validatedTypedDictnarrowing, shallow-vs-transitive immutability, instants vs civil time, and function/dataclass/Pydantic mutable-default behaviors separated.python-async-best-practices (new): event-loop discipline grounded against pydantic-ai's async machinery and proven against CPython —
async-no-blocking-event-loop,async-own-your-tasks(owner-cancellation-safe shutdown drain viaowner.cancelling()),async-bound-concurrency(in-flight vs admission),async-generator-cleanup,async-preserve-cancellation(absorbed cancellation reports success and silently defeatsasyncio.timeout— both proven).python-pytest (new): test value (observable contracts, independent oracles), determinism (events not sleeps, no flake masking, strict xfail), fixtures, mocking (patch-where-used, wire-format assertions), structure (import identities incl. the lone-
tests/__init__.pycollision, proven; plugin hygiene scoped to observed drift).Judgment architecture (from review)
**When ...**/**Scope:**/**Preserve ...**/**Exception ...**/ ...) saying when NOT to apply the rule.validate.pyenforces presence on all impacts; detection is positional, never natural-language classification (unit-tested: an affirmative thesis containing "keep" is not extracted; code blocks never match).test-cases.jsonexportscounter_signalsper case and declares the scoring contract: condition-aware application and restraint, not similarity to the Correct block.SKILL.mdmaps state: quick-reference lines are triggers, not licenses — open the rule and check its counter-signal before applying.Executable claim verification (
proofs/, not vendored)make -C proofs). Covers version splits (cached_property.lock,utcnowdeprecation, executorcpu_count→process_cpu_count) and counterintuitive semantics (gather orphans, absorbed cancellation false-success, timeout silently lost, owner-cancellation delegation during shutdown drain,lru_cacheretention, import-identity collisions).Sequencecovariance,assert_neverexhaustiveness,castunchecked) — verdicts observed before being encoded.Notes
uv runandmake.