code-ratchets
Implement code quality ratchets to prevent proliferation of deprecated patterns. Use when (1) migrating away from legacy code patterns, (2) enforcing gradual codebase improvements, (3) preventing copy-paste proliferation of deprecated practices, or (4) setting up pre-commit hooks to count and limit specific code patterns. A ratchet fails if pattern count exceeds OR falls below expected—ensuring patterns never increase and prompting updates when they decrease.
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
Code Ratchets
A ratchet is a pre-commit check that counts deprecated patterns in your codebase against a hard-coded expected count. It fails in two cases:
- Too many instances: Prevents proliferation via copy-paste
- Too few instances: Congratulates you and prompts lowering the expected count
This automates the manual code review process of saying "don't do this, we've stopped doing this."
Core Workflow
1. Identify the Pattern
Define what to count. Patterns work best when they're:
- Simple text or regex matches (grep-able)
- Unambiguous (low false positive rate)
- Discrete instances (countable)
Examples:
-
TODO:comments -
# type: ignoreannotations -
vardeclarations (vslet/const) -
Anytype annotations - Specific function calls:
unsafe_parse(,legacy_auth( - Import statements:
from old_module import
2. Create the Ratchet Script
Create scripts/ratchet.py (or .sh):
#!/usr/bin/env python3
"""
Code ratchet: prevents deprecated patterns from proliferating.
Fails if count > expected (proliferation) or count < expected (time to ratchet down).
"""
import subprocess
import sys
# ============================================================
# RATCHET CONFIGURATION - Edit counts here as patterns decrease
# ============================================================
RATCHETS = {
"TODO comments": {
"pattern": r"TODO:",
"expected": 47,
"glob": "**/*.py",
"reason": "Resolve TODOs before adding new ones",
},
"Type ignores": {
"pattern": r"# type: ignore",
"expected": 23,
"glob": "**/*.py",
"reason": "Fix type errors instead of ignoring them",
},
"Any types": {
"pattern": r": Any[,\)\]]",
"expected": 12,
"glob": "**/*.py",
"reason": "Use specific types instead of Any",
},
}
def count_pattern(pattern: str, glob: str) -> int:
"""Count pattern occurrences using grep."""
try:
result = subprocess.run(
["grep", "-r", "-E", "--include", glob, "-c", pattern, "."],
capture_output=True,
text=True,
)
# Sum counts from all files (grep -c outputs "filename:count" per file)
total = sum(
int(line.split(":")[-1])
for line in result.stdout.strip().split("\n")
if line and ":" in line
)
return total
except Exception:
return 0
def main() -> int:
failed = False
for name, config in RATCHETS.items():
actual = count_pattern(config["pattern"], config["glob"])
expected = config["expected"]
if actual > expected:
print(f"❌ RATCHET FAILED: {name}")
print(f" Expected ≤{expected}, found {actual} (+{actual - expected})")
print(f" Reason: {config['reason']}")
print(f" Pattern: {config['pattern']}")
print()
failed = True
elif actual < expected:
print(f"🎉 RATCHET DOWN: {name}")
print(f" Expected {expected}, found {actual} (-{expected - actual})")
print(f" Update expected count in ratchet.py: {expected} → {actual}")
print()
failed = True # Still fail to prompt the update
else:
print(f"✓ {name}: {actual}/{expected}")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())
3. Configure Pre-commit
Add to .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: code-ratchets
name: Code Ratchets
entry: python scripts/ratchet.py
language: python
pass_filenames: false
always_run: true
Install hooks:
pip install pre-commit
pre-commit install
4. Initialize Counts
Run the script once to get current counts, then set those as expected values:
# Get current counts
grep -r -E "TODO:" --include="*.py" -c . | awk -F: '{sum+=$2} END {print sum}'
# Update RATCHETS dict with actual counts
5. Maintain the Ratchet
When the ratchet fails with "too few":
- Celebrate—someone removed deprecated patterns!
- Update the expected count in the script
- Commit the updated script
Alternative: Shell-based Ratchet
For simpler setups, use scripts/ratchet.sh:
#!/bin/bash
set -e
check_ratchet() {
local name="$1"
local pattern="$2"
local expected="$3"
local glob="$4"
local reason="$5"
actual=$(grep -r -E "$pattern" --include="$glob" . 2>/dev/null | wc -l | tr -d ' ')
if [ "$actual" -gt "$expected" ]; then
echo "❌ RATCHET FAILED: $name"
echo " Expected ≤$expected, found $actual"
echo " Reason: $reason"
exit 1
elif [ "$actual" -lt "$expected" ]; then
echo "🎉 RATCHET DOWN: $name"
echo " Update expected: $expected → $actual"
exit 1
else
echo "✓ $name: $actual/$expected"
fi
}
# ============ RATCHET CONFIGURATION ============
check_ratchet "TODO comments" "TODO:" 47 "*.py" "Resolve TODOs first"
check_ratchet "Type ignores" "# type: ignore" 23 "*.py" "Fix type errors"
echo "All ratchets passed!"
Best Practices
-
Keep patterns simple: Basic grep/regex. Avoid complex AST analysis—fragility outweighs precision.
-
One ratchet per concern: Separate ratchets for separate issues. Easier to track progress.
-
Document the "why": Include
reasonfield explaining why the pattern is deprecated. -
Fail on decrease: Always require manual update of expected counts. This creates an audit trail of progress.
-
Escape hatch: For exceptional cases, consider allowing bypass via commit message:
# In ratchet.py, check for bypass import os if os.environ.get("RATCHET_BYPASS"): print("⚠️ Ratchet bypassed via RATCHET_BYPASS env var") sys.exit(0)Usage:
RATCHET_BYPASS=1 git commit -m "Emergency fix, ratchet bypass justified: ..." -
Gradual rollout: Start with high counts and let them naturally decrease. Don't set expected=0 on day one.
Common Ratchet Patterns
| Pattern | Regex | Use Case |
|---|---|---|
| TODO comments | TODO: |
Track technical debt |
| Type ignores | # type: ignore |
Enforce typing |
| Any types | : Any[,\)\]] |
Specific types |
| Console logs | console\.log\( |
Remove debug code |
| Legacy imports | from legacy_module |
Track migrations |
| Deprecated calls | deprecated_func\( |
API migrations |
| Broad exceptions | except: or except Exception: |
Specific exceptions |
| Magic numbers | \b\d{3,}\b (tuned) |
Named constants |
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-01-20
- 索引更新时间
- 2026-01-31
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!