Skip to content

Add quality registries and validation scripts for example pages#2

Merged
adewale merged 4 commits into
mainfrom
claude/comparison-examples-and-quality-gates
May 10, 2026
Merged

Add quality registries and validation scripts for example pages#2
adewale merged 4 commits into
mainfrom
claude/comparison-examples-and-quality-gates

Conversation

@adewale
Copy link
Copy Markdown
Owner

@adewale adewale commented May 10, 2026

Summary

This PR introduces a quality assurance framework for the example pages catalog:

  1. Quality Registries (docs/quality-registries.toml): A centralized source of truth that pins specific Python concepts to their owning pages:

    • Confusable pairs: Concepts learners commonly confuse (e.g., is vs ==, list vs tuple, @classmethod vs @staticmethod)
    • Footguns: Common Python pitfalls with broken and fixed patterns (e.g., mutable default arguments, shallow vs deep copy)
    • Broad surface tours: Pages that should demonstrate a comprehensive set of related tokens
    • Paired pages: Pages whose titles differ only by a suffix/modifier that should demonstrate their relationship
  2. Validation Scripts: Three new scripts enforce the registry contracts:

    • check_confusable_pairs.py: Verifies each confusable pair appears on its owning page
    • check_footgun_coverage.py: Ensures each footgun shows both broken and fixed forms
    • check_broad_surface_tours.py: Validates broad-tour pages cover required tokens or opt out with scope_first_pass=true
    • check_notes_supported.py: Heuristic check that :::note bullets are grounded in page content
  3. New Example Pages: Added focused pages for concepts previously scattered or missing:

    • abstract-base-classes.md: ABC vs Protocol contrast
    • classmethods-and-staticmethods.md: Three method shapes explained
    • structured-data-shapes.md: dataclass vs NamedTuple vs TypedDict
    • bound-and-unbound-methods.md: Method binding mechanics
    • iterator-vs-iterable.md: The critical distinction for API design
  4. Enhanced Existing Pages: Updated pages to demonstrate confusable pairs and footguns:

    • classes.md: Added class attributes and mutable default footgun
    • generators.md: Added eager vs lazy production contrast
    • functions.md: Added mutable default argument footgun
    • exceptions.md: Added bare except footgun
    • special-methods.md: Added __str__ vs __repr__ contrast
    • tuples.md: Added list vs tuple contrast
    • dicts.md: Added dictionary mutation during iteration footgun
    • numbers.md: Added floating-point equality footgun
    • Multiple pages: Added see_also links and scope_first_pass flags
  5. Documentation: Updated docs/example-quality-rubric.md with new quality checks and a confusable-pair index.

Verification

  • make verify (all validation scripts pass)
  • scripts/check_example_migration_parity.py
  • scripts/format_examples.py --check
  • make verify-python-version VERSION=3.13
  • git diff --check

Example changes

  • Updated files under src/example_sources/*.md
  • Kept exactly one :::program block per example
  • Kept :::cell source/output deterministic and executable
  • Ran make verify-examples
  • Ran make check-generated
  • New validation scripts integrated into Makefile quality-checks target

https://claude.ai/code/session_0181PYZFG6LpBDTwNsLKxRcf

claude added 4 commits May 9, 2026 20:32
Catalog additions
- iterator-vs-iterable: contrasts iterables (replayable) with iterators
  (one-pass), shows iter() returning fresh vs same object, and the API
  boundary where the distinction silently breaks generic helpers.
- classmethods-and-staticmethods: contrasts the three method shapes
  (instance, @classmethod, @staticmethod) using a Date class with an
  alternate constructor and a leap-year helper.
- abstract-base-classes: ABC with @AbstractMethod, instantiation
  failure for incomplete subclasses, and a side-by-side contrast with
  Protocol (nominal vs structural typing).
- structured-data-shapes: dataclass, typing.NamedTuple, and TypedDict
  side by side, including their distinct runtime identities.
- bound-and-unbound-methods: instance.method binds self automatically;
  Class.method is the plain function; the descriptor protocol explains
  the binding.

Existing-page upgrades
- special-methods: __str__ alongside __repr__ with the print() vs repr()
  contrast, plus scope_first_pass framing and see_also links to the
  focused dunder pages.
- generators: yield-vs-return cell (eager list vs lazy stream, list
  reusable vs generator one-pass) and a class-iterator vs generator
  cell showing the same Countdown two ways.
- classes: class-vs-instance attributes, the mutable-default-class-
  attribute footgun and its per-instance fix in __init__.
- tuples: explicit list-vs-tuple contrast cell.
- functions: mutable default argument footgun with the None-sentinel
  fix.
- dicts: dictionary-mutation-during-iteration footgun with the
  list(d.keys()) snapshot fix.
- numbers: floating-point equality footgun with math.isclose.
- exceptions: bare/broad-except footgun with the ValueError fix.
- Several pages get scope_first_pass=true plus richer see_also where
  the broad title genuinely surveys a wider area.

Rubric and enforcement
- Quality rubric gains a confusable-pair index, broad-surface
  checklists, footgun coverage list, paired-page rule, additional weak-
  example smells, and two new strengthening-checklist questions.
- docs/quality-registries.toml is the source of truth for the three
  machine-checkable registries.
- scripts/check_confusable_pairs.py, check_broad_surface_tours.py, and
  check_footgun_coverage.py are strict gates wired into make verify
  via a new quality-checks target. check_notes_supported.py runs as a
  warning-only heuristic.

Cross-link sweep
- Iteration, class, type, and data-model neighbors gain see_also
  entries pointing at the new pages so navigation reflects the new
  graph.
Follow-up to af7bde4. The earlier commit's checks passed via token
matching, but several owner pages did not actually demonstrate the
lesson the registry claimed they owned. This commit closes those gaps
and tightens the surrounding tooling.

Footgun cells added where missing
- closures.md: late-binding-in-a-loop trap with the lambda i=i fix.
- equality-and-identity.md: small-int identity caching trap; `is`
  returning False for two equal large integers, with == as the
  reliable comparison.
- booleans.md: bool-as-subclass-of-int trap (`isinstance(True, int)`,
  arithmetic on booleans), with an is_strict_int helper.

Registry token tightening
- Late-binding closure, integer identity, mutable default argument,
  bool subclass, and bare-except entries now use specific tokens
  ("lambda i=i", "small_a is small_b", "items=None", "is_strict_int",
  "except ValueError") so the check actually proves the lesson is
  present rather than matching incidental words.

Reader-experience fixes
- bound-and-unbound-methods.md cells are now self-contained: each
  cell uses its own counter so outputs do not depend on cumulative
  state from previous cells.
- structured-data-shapes.md uses b[1] instead of b[0] so the
  attribute-vs-index cell shows distinct values, and labels _replace
  as a NamedTuple helper.

Cross-link sweep
- descriptors -> bound-and-unbound-methods
- decorators -> classmethods-and-staticmethods
- callable-objects -> bound-and-unbound-methods
- runtime-type-checks -> abstract-base-classes

Notes-supported check
- Six previously-warning bullets are now grounded by either an added
  cell (literals empty-{} vs set(), operators short-circuit) or a
  reworked intro paragraph (literal-and-final, logging, paramspec,
  sentinel-iteration). The script is now strict and fails the build
  on ungrounded bullets.

Tooling
- check_registry_integrity.py validates that every owner slug in
  quality-registries.toml exists in manifest.toml and that token
  fields are non-empty. Wired into make quality-checks first so a
  typo fails fast with a clear message.
- tests/test_quality_checks.py covers all five scripts: smoke tests
  against the shipped catalog, plus targeted failure tests for
  registry integrity (unknown owner, unknown slug, missing tokens)
  and the notes-supported tokenizer.
- CONTRIBUTING.md gains a section explaining each check and pointing
  contributors at the registry as the source of truth.
The previous commit shipped three stale artifacts that the CI verify
job catches and that I missed locally:

- src/asset_manifest.py held a HTML_CACHE_VERSION that did not match
  the embedded sources (the fingerprint step had not been re-run after
  the last embed). lint_seo_cache.py compares the two and fails when
  they drift; refreshed by make build.
- tests/fixtures/golden_examples.py was the pre-rewrite frozen
  catalog. It needs an intentional refresh after example rewrites; the
  five new pages and the cells added to existing pages were not yet
  reflected. Regenerated from load_examples() output.
- scripts/format_examples.py FRONTMATTER_ORDER did not list the new
  scope_first_pass key, so the eight broad-surface pages that took
  the scope-down shortcut were reported as misformatted. Added it
  between doc_path and see_also so the formatter has a stable slot.

The full local gauntlet now passes: embed-examples, fingerprint,
verify-examples (under Python 3.13), quality-checks, unittest (39),
ruff, lint_seo_cache, migration parity, format --check, git diff
--check.
Removes the scope_first_pass shortcut from every broad-title page that
took it. Each page now demonstrates the canonical forms its title
promises rather than scoping itself down with a link list.

Broad-page expansions
- literals: hex/binary/octal/underscore numeric literals; f-string
  shown alongside raw and bytes literals.
- operators: bitwise & added with | and ^ to make the masking surface
  complete.
- type-hints: union (`X | Y`), `Optional[X]`, and `TypeAlias` cells.
- testing: setUp fixture, assertEqual, and assertRaises in a single
  TestCase. Runner output now reflects three test methods.
- async-await: async-with / async-for cell with an async context
  manager and async generator, linking to async-iteration-and-context.
- packages: builds a temporary `shapes` package on disk to make
  `from .submodule import name` and `__all__` concrete.
- regular-expressions: re.match vs re.search, re.compile, re.IGNORECASE
  flag, and re.sub each in their own cell.
- special-methods: equality/hashing/ordering, container protocols,
  callable, and context-manager dunders. The page is now a real tour.

Graph hygiene
- Trimmed see_also on literals, operators, inheritance-and-super,
  special-methods, and type-hints to ≤4 entries so audit_example_graph
  passes without warnings.

Doc-path correction
- bound-and-unbound-methods: doc_path was /reference/datamodel.html
  #methods (no such anchor); corrected to #instance-methods.

Verification
- All 109 examples verify under Python 3.13.
- 39 unit tests pass.
- Quality checks all green: registry-integrity, confusable-pairs,
  broad-surface-tours, footgun-coverage, notes-supported.
- score_examples reports every new page at 8.87 or higher (gate is 8.5).
- audit_example_graph --check exits 0.
- ruff, lint_seo_cache, format-examples --check, migration-parity all
  pass. Golden fixture refreshed to reflect the new cells.
@adewale adewale merged commit c885194 into main May 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants