claude-dev-env 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/agents/agent-writer.md +157 -0
  4. package/agents/clasp-deployment-orchestrator.md +609 -0
  5. package/agents/clean-coder.md +295 -0
  6. package/agents/code-quality-agent.md +40 -0
  7. package/agents/code-standards-agent.md +93 -0
  8. package/agents/config-centralizer.md +686 -0
  9. package/agents/config-extraction-agent.md +225 -0
  10. package/agents/doc-orchestrator.md +47 -0
  11. package/agents/docs-agent.md +112 -0
  12. package/agents/docx-agent.md +211 -0
  13. package/agents/git-commit-crafter.md +100 -0
  14. package/agents/magic-value-eliminator-agent.md +72 -0
  15. package/agents/mandatory-agent-workflow-agent.md +88 -0
  16. package/agents/parallel-workflow-coordinator.md +779 -0
  17. package/agents/pdf-agent.md +302 -0
  18. package/agents/plan-executor.md +226 -0
  19. package/agents/pr-description-writer.md +87 -0
  20. package/agents/project-context-loader.md +238 -0
  21. package/agents/project-docs-analyzer.md +54 -0
  22. package/agents/project-structure-organizer-agent.md +72 -0
  23. package/agents/readability-review-agent.md +76 -0
  24. package/agents/refactoring-specialist.md +69 -0
  25. package/agents/right-sized-engineer.md +129 -0
  26. package/agents/session-continuity-manager.md +53 -0
  27. package/agents/skill-to-agent-converter.md +371 -0
  28. package/agents/skill-writer-agent.md +470 -0
  29. package/agents/stub-detector-agent.md +140 -0
  30. package/agents/tdd-test-writer.md +62 -0
  31. package/agents/test-data-builder.md +68 -0
  32. package/agents/tooling-builder.md +78 -0
  33. package/agents/user-docs-writer.md +67 -0
  34. package/agents/validation-expert.md +71 -0
  35. package/agents/workflow-visual-documenter.md +82 -0
  36. package/agents/xlsx-agent.md +169 -0
  37. package/bin/install.mjs +256 -0
  38. package/commands/commit.md +28 -0
  39. package/commands/docupdate.md +322 -0
  40. package/commands/implement.md +102 -0
  41. package/commands/initialize.md +91 -0
  42. package/commands/plan.md +63 -0
  43. package/commands/pr-comments.md +47 -0
  44. package/commands/readability-review.md +20 -0
  45. package/commands/review-plan.md +7 -0
  46. package/commands/right-size.md +15 -0
  47. package/commands/stubcheck.md +89 -0
  48. package/commands/sum.md +30 -0
  49. package/docs/CODE_RULES.md +186 -0
  50. package/docs/DJANGO_PATTERNS.md +80 -0
  51. package/docs/REACT_PATTERNS.md +185 -0
  52. package/docs/TEST_QUALITY.md +104 -0
  53. package/hooks/advisory/migration-safety-advisor.py +49 -0
  54. package/hooks/advisory/refactor-guard.py +205 -0
  55. package/hooks/blocking/block-main-commit.py +168 -0
  56. package/hooks/blocking/code-rules-enforcer.py +549 -0
  57. package/hooks/blocking/destructive-command-blocker.py +107 -0
  58. package/hooks/blocking/docker-settings-guard.py +44 -0
  59. package/hooks/blocking/hedging-language-blocker.py +130 -0
  60. package/hooks/blocking/parallel-task-blocker.py +69 -0
  61. package/hooks/blocking/pr-description-enforcer.py +87 -0
  62. package/hooks/blocking/pyautogui-scroll-blocker.py +74 -0
  63. package/hooks/blocking/sensitive-file-protector.py +70 -0
  64. package/hooks/blocking/tdd-enforcer.py +62 -0
  65. package/hooks/blocking/test-preflight-check.py +343 -0
  66. package/hooks/blocking/write-existing-file-blocker.py +63 -0
  67. package/hooks/git-hooks/post-commit.py +103 -0
  68. package/hooks/github-action/test_workflow.py +33 -0
  69. package/hooks/hooks.json +246 -0
  70. package/hooks/lifecycle/config-change-guard.py +84 -0
  71. package/hooks/lifecycle/session-end-cleanup.py +59 -0
  72. package/hooks/notification/attention-needed-notify.py +63 -0
  73. package/hooks/notification/claude-notification-handler.py +59 -0
  74. package/hooks/notification/notification_utils.py +206 -0
  75. package/hooks/rewrite-plugin-paths.py +116 -0
  76. package/hooks/session/bulk-edit-reminder.py +30 -0
  77. package/hooks/session/code-rules-reminder.py +97 -0
  78. package/hooks/session/compact-context-reinject.py +39 -0
  79. package/hooks/session/hook-structure-context.py +140 -0
  80. package/hooks/session/plugin-data-dir-cleanup.py +39 -0
  81. package/hooks/validation/code-style-validator.py +145 -0
  82. package/hooks/validation/e2e-test-validator.py +142 -0
  83. package/hooks/validation/hook-format-validator.py +66 -0
  84. package/hooks/validation/mypy_validator.py +180 -0
  85. package/hooks/validators/README.md +125 -0
  86. package/hooks/validators/VALIDATION_REPORT.md +287 -0
  87. package/hooks/validators/__init__.py +19 -0
  88. package/hooks/validators/abbreviation_checks.py +82 -0
  89. package/hooks/validators/code_quality_checks.py +133 -0
  90. package/hooks/validators/comment_checks.py +188 -0
  91. package/hooks/validators/file_structure_checks.py +182 -0
  92. package/hooks/validators/git_checks.py +107 -0
  93. package/hooks/validators/health_check.py +214 -0
  94. package/hooks/validators/magic_value_checks.py +81 -0
  95. package/hooks/validators/mypy_integration.py +52 -0
  96. package/hooks/validators/output_formatter.py +266 -0
  97. package/hooks/validators/pr_reference_checks.py +72 -0
  98. package/hooks/validators/python_antipattern_checks.py +110 -0
  99. package/hooks/validators/python_style_checks.py +364 -0
  100. package/hooks/validators/react_checks.py +90 -0
  101. package/hooks/validators/ruff_integration.py +80 -0
  102. package/hooks/validators/run_all_validators.py +772 -0
  103. package/hooks/validators/security_checks.py +135 -0
  104. package/hooks/validators/test_abbreviation_checks.py +76 -0
  105. package/hooks/validators/test_bad.tsx +7 -0
  106. package/hooks/validators/test_code_quality_checks.py +129 -0
  107. package/hooks/validators/test_file_structure_checks.py +307 -0
  108. package/hooks/validators/test_files/01_basic_component.tsx +10 -0
  109. package/hooks/validators/test_files/02_component_without_react.tsx +10 -0
  110. package/hooks/validators/test_files/03_pure_component.tsx +10 -0
  111. package/hooks/validators/test_files/04_pure_component_import.tsx +10 -0
  112. package/hooks/validators/test_files/05_typescript_generics.tsx +14 -0
  113. package/hooks/validators/test_files/06_typescript_two_generics.tsx +18 -0
  114. package/hooks/validators/test_files/07_multiline_declaration.tsx +11 -0
  115. package/hooks/validators/test_files/08_error_boundary_valid.tsx +14 -0
  116. package/hooks/validators/test_files/09_error_boundary_with_other_class.tsx +20 -0
  117. package/hooks/validators/test_files/10_inheritance_chain.tsx +16 -0
  118. package/hooks/validators/test_files/11_ts_file.ts +10 -0
  119. package/hooks/validators/test_files/12_non_react_class.tsx +14 -0
  120. package/hooks/validators/test_files/13_functional_component.tsx +8 -0
  121. package/hooks/validators/test_files/14_indented_class.tsx +13 -0
  122. package/hooks/validators/test_files/15_getDerivedStateFromError.tsx +14 -0
  123. package/hooks/validators/test_files/16_mixed_components.tsx +20 -0
  124. package/hooks/validators/test_files/EXECUTIVE_SUMMARY.md +175 -0
  125. package/hooks/validators/test_files/TEST_RESULTS_TABLE.txt +60 -0
  126. package/hooks/validators/test_files/VALIDATION_REPORT.md +201 -0
  127. package/hooks/validators/test_files/async_views.py +23 -0
  128. package/hooks/validators/test_files/async_with_imports.py +14 -0
  129. package/hooks/validators/test_files/bad_inline_imports.py +37 -0
  130. package/hooks/validators/test_files/management/commands/cmd_01_no_debug_check.py +10 -0
  131. package/hooks/validators/test_files/management/commands/cmd_02_proper_debug_check.py +14 -0
  132. package/hooks/validators/test_files/management/commands/cmd_03_debug_check_with_return.py +14 -0
  133. package/hooks/validators/test_files/management/commands/cmd_04_imported_DEBUG.py +14 -0
  134. package/hooks/validators/test_files/management/commands/cmd_05_debug_check_in_helper.py +16 -0
  135. package/hooks/validators/test_files/management/commands/cmd_06_debug_check_late.py +22 -0
  136. package/hooks/validators/test_files/management/commands/cmd_07_positive_debug_check.py +15 -0
  137. package/hooks/validators/test_files/management/commands/cmd_08_debug_with_and.py +14 -0
  138. package/hooks/validators/test_files/not_management_command.py +10 -0
  139. package/hooks/validators/test_files/skip_decorators/test_01_simple_skip.py +8 -0
  140. package/hooks/validators/test_files/skip_decorators/test_02_pytest_skipif.py +8 -0
  141. package/hooks/validators/test_files/skip_decorators/test_03_unittest_skipIf.py +8 -0
  142. package/hooks/validators/test_files/skip_decorators/test_04_skip_with_parens.py +8 -0
  143. package/hooks/validators/test_files/skip_decorators/test_05_xfail.py +7 -0
  144. package/hooks/validators/test_files/skip_decorators/test_06_custom_skip.py +11 -0
  145. package/hooks/validators/test_files/skip_decorators/test_07_capital_Skip.py +8 -0
  146. package/hooks/validators/test_files/skip_decorators/test_08_skipUnless.py +7 -0
  147. package/hooks/validators/test_files/skip_decorators/test_09_pytest_mark_skip_simple.py +7 -0
  148. package/hooks/validators/test_files/test_async_functions.py +45 -0
  149. package/hooks/validators/test_files/test_purecomponent/PureComponentExample.tsx +7 -0
  150. package/hooks/validators/test_files/test_purecomponent/ReactPureComponentExample.tsx +7 -0
  151. package/hooks/validators/test_git_checks.py +295 -0
  152. package/hooks/validators/test_good.tsx +5 -0
  153. package/hooks/validators/test_health_check.py +57 -0
  154. package/hooks/validators/test_magic_value_checks.py +63 -0
  155. package/hooks/validators/test_mypy_integration.py +27 -0
  156. package/hooks/validators/test_output_formatter.py +150 -0
  157. package/hooks/validators/test_pr_reference_checks.py +41 -0
  158. package/hooks/validators/test_python_antipattern_checks.py +113 -0
  159. package/hooks/validators/test_python_style_checks.py +439 -0
  160. package/hooks/validators/test_react_checks.py +213 -0
  161. package/hooks/validators/test_results.txt +25 -0
  162. package/hooks/validators/test_ruff_integration.py +27 -0
  163. package/hooks/validators/test_run_all_validators.py +228 -0
  164. package/hooks/validators/test_run_all_validators_integration.py +48 -0
  165. package/hooks/validators/test_safety_checks.py +243 -0
  166. package/hooks/validators/test_security_checks.py +105 -0
  167. package/hooks/validators/test_test_safety_checks.py +321 -0
  168. package/hooks/validators/test_todo_checks.py +39 -0
  169. package/hooks/validators/test_type_safety_checks.py +85 -0
  170. package/hooks/validators/test_useless_test_checks.py +55 -0
  171. package/hooks/validators/test_validator_base.py +26 -0
  172. package/hooks/validators/test_verify_paths.py +34 -0
  173. package/hooks/validators/todo_checks.py +59 -0
  174. package/hooks/validators/type_safety_checks.py +101 -0
  175. package/hooks/validators/useless_test_checks.py +92 -0
  176. package/hooks/validators/validator_base.py +19 -0
  177. package/hooks/validators/verify_paths.py +57 -0
  178. package/hooks/workflow/auto-formatter.py +114 -0
  179. package/hooks/workflow/investigation-tracker-reset.py +46 -0
  180. package/package.json +30 -0
  181. package/rules/agent-spawn-protocol.md +47 -0
  182. package/rules/cleanup-temp-files.md +27 -0
  183. package/rules/code-reviews.md +11 -0
  184. package/rules/code-standards.md +43 -0
  185. package/rules/conservative-action.md +20 -0
  186. package/rules/context7.md +12 -0
  187. package/rules/explore-thoroughly.md +27 -0
  188. package/rules/git-workflow.md +42 -0
  189. package/rules/parallel-tools.md +23 -0
  190. package/rules/research-mode.md +23 -0
  191. package/rules/right-sized-engineering.md +28 -0
  192. package/rules/tdd.md +7 -0
  193. package/rules/testing.md +12 -0
  194. package/skills/agent-prompt/SKILL.md +102 -0
  195. package/skills/anthropic-plan/SKILL.md +107 -0
  196. package/skills/everything-search/SKILL.md +144 -0
  197. package/skills/ingest/SKILL.md +40 -0
  198. package/skills/npm-creator/SKILL.md +183 -0
  199. package/skills/pr-review-responder/EXAMPLES.md +590 -0
  200. package/skills/pr-review-responder/PRINCIPLES.md +539 -0
  201. package/skills/pr-review-responder/README.md +209 -0
  202. package/skills/pr-review-responder/SKILL.md +202 -0
  203. package/skills/pr-review-responder/TESTING.md +407 -0
  204. package/skills/pr-review-responder/scripts/respond_to_reviews.py +376 -0
  205. package/skills/pr-review-responder/update_skill.py +297 -0
  206. package/skills/prompt-generator/REFERENCE.md +150 -0
  207. package/skills/prompt-generator/SKILL.md +154 -0
  208. package/skills/readability-review/SKILL.md +127 -0
  209. package/skills/recall/SKILL.md +27 -0
  210. package/skills/remember/SKILL.md +63 -0
  211. package/skills/rule-audit/SKILL.md +307 -0
  212. package/skills/rule-creator/SKILL.md +150 -0
  213. package/skills/skill-writer/REFERENCE.md +246 -0
  214. package/skills/skill-writer/SKILL.md +270 -0
  215. package/skills/tdd-team/SKILL.md +128 -0
@@ -0,0 +1,287 @@
1
+ # Test Safety Checks Validator - Comprehensive Validation Report
2
+
3
+ ## Executive Summary
4
+
5
+ **Critical Gaps Found: 2**
6
+ **Minor Issues: 1**
7
+ **Tests Passed: 14/17**
8
+
9
+ ---
10
+
11
+ ## Check 1: No Skip Decorators
12
+
13
+ ### Test Results
14
+
15
+ | Test Case | Expected | Result | Status |
16
+ |-----------|----------|--------|--------|
17
+ | `@skip` | CAUGHT | CAUGHT | PASS |
18
+ | `@pytest.mark.skipif(...)` | CAUGHT | CAUGHT | PASS |
19
+ | `@unittest.skipIf(...)` | CAUGHT | CAUGHT | PASS |
20
+ | `@skip()` with parentheses | CAUGHT | CAUGHT | PASS |
21
+ | `@pytest.mark.xfail` | ALLOWED | ALLOWED | PASS |
22
+ | `@skip_on_windows` custom | ALLOWED | ALLOWED | PASS |
23
+ | `@Skip` (capital S) | CAUGHT | **ALLOWED** | **FAIL** |
24
+ | `@unittest.skipUnless(...)` | CAUGHT | CAUGHT | PASS |
25
+ | `@pytest.mark.skip` (no args) | CAUGHT | CAUGHT | PASS |
26
+
27
+ ### GAP #1: Case-Sensitive Decorator Matching
28
+
29
+ **Severity: MEDIUM**
30
+
31
+ **Issue:** The validator uses case-sensitive matching, so `@Skip` (capital S) is NOT caught.
32
+
33
+ **Current Code (lines 16-22):**
34
+ ```python
35
+ SKIP_DECORATOR_NAMES = frozenset([
36
+ "skip",
37
+ "skipif",
38
+ "skipunless",
39
+ "skipIf",
40
+ "skipUnless",
41
+ ])
42
+ ```
43
+
44
+ **Problem:** This misses decorators with different capitalization like `@Skip`, `@SkipIf`, `@SKIP`, etc.
45
+
46
+ **Recommended Fix:**
47
+ ```python
48
+ def _get_decorator_name(decorator: ast.expr) -> str:
49
+ """Extract the name from a decorator node (lowercase for comparison)."""
50
+ # ... existing logic ...
51
+ return name.lower() # Convert to lowercase for case-insensitive matching
52
+ ```
53
+
54
+ Then update the frozenset to all lowercase:
55
+ ```python
56
+ SKIP_DECORATOR_NAMES = frozenset([
57
+ "skip",
58
+ "skipif",
59
+ "skipunless",
60
+ ])
61
+ ```
62
+
63
+ **Impact:** Currently allows `@Skip`, `@SkipIf`, `@SkipUnless` to slip through.
64
+
65
+ ---
66
+
67
+ ## Check 2: DEBUG Guard in Management Commands
68
+
69
+ ### Test Results
70
+
71
+ | Test Case | Expected | Result | Status |
72
+ |-----------|----------|--------|--------|
73
+ | No DEBUG check | CAUGHT | CAUGHT | PASS |
74
+ | `if not settings.DEBUG: raise` | ALLOWED | ALLOWED | PASS |
75
+ | `if not settings.DEBUG: return` | ALLOWED | ALLOWED | PASS |
76
+ | Using imported `DEBUG` variable | CAUGHT | CAUGHT | PASS |
77
+ | DEBUG check in helper function | CAUGHT | CAUGHT | PASS |
78
+ | DEBUG check after 5 statements | CAUGHT | CAUGHT | PASS |
79
+ | `if settings.DEBUG: ... else: raise` | ALLOWED | **CAUGHT** | **FAIL** |
80
+ | `if not settings.DEBUG and X:` | DEBATABLE | CAUGHT | WARN |
81
+ | File not in `management/commands/` | IGNORED | IGNORED | PASS |
82
+
83
+ ### GAP #2: Positive DEBUG Check Pattern Rejected
84
+
85
+ **Severity: HIGH**
86
+
87
+ **Issue:** The validator incorrectly rejects the pattern `if settings.DEBUG: ... else: raise`.
88
+
89
+ **Test File:** `cmd_07_positive_debug_check.py`
90
+ ```python
91
+ def handle(self, *args, **options):
92
+ if settings.DEBUG:
93
+ print("Running in DEBUG mode")
94
+ else:
95
+ raise CommandError("This command can only be run in DEBUG mode")
96
+ ```
97
+
98
+ **Expected:** ALLOWED (this is a valid DEBUG guard)
99
+ **Actual:** CAUGHT (flagged as violation)
100
+
101
+ **Root Cause (lines 186-187):**
102
+ ```python
103
+ if _is_debug_check(test) and stmt.orelse:
104
+ return False # This returns False when it should return True!
105
+ ```
106
+
107
+ **The Logic Flaw:**
108
+ - Line 186: Detects `if settings.DEBUG:` and checks if there's an `else` clause
109
+ - Line 187: Returns `False` (no DEBUG guard found)
110
+ - **BUG:** This should return `True` because the pattern IS a valid guard!
111
+
112
+ **Recommended Fix:**
113
+ ```python
114
+ def _has_debug_guard(func: ast.FunctionDef) -> bool:
115
+ """Check if a function has a settings.DEBUG guard at the start."""
116
+ if not func.body:
117
+ return False
118
+
119
+ for stmt in func.body[:5]:
120
+ if isinstance(stmt, ast.If):
121
+ test = stmt.test
122
+
123
+ # Pattern 1: if not settings.DEBUG: raise/return
124
+ if isinstance(test, ast.UnaryOp) and isinstance(test.op, ast.Not):
125
+ if _is_debug_check(test.operand):
126
+ return True
127
+
128
+ # Pattern 2: if settings.DEBUG: ... else: raise/return
129
+ if _is_debug_check(test):
130
+ if stmt.orelse:
131
+ # Check if else clause has raise/return
132
+ if _has_early_exit(stmt.orelse):
133
+ return True
134
+ # if settings.DEBUG: with no else is also valid
135
+ return True
136
+
137
+ return False
138
+
139
+
140
+ def _has_early_exit(statements: List[ast.stmt]) -> bool:
141
+ """Check if statements contain raise or return."""
142
+ for stmt in statements:
143
+ if isinstance(stmt, (ast.Raise, ast.Return)):
144
+ return True
145
+ # Check nested if/else
146
+ if isinstance(stmt, ast.If):
147
+ if _has_early_exit(stmt.body) or (stmt.orelse and _has_early_exit(stmt.orelse)):
148
+ return True
149
+ return False
150
+ ```
151
+
152
+ **Impact:** Currently REJECTS valid DEBUG guard patterns, forcing developers to use only negative checks.
153
+
154
+ ### MINOR ISSUE: Complex Boolean Expressions
155
+
156
+ **Severity: LOW**
157
+
158
+ **Issue:** The validator rejects `if not settings.DEBUG and other_condition:`.
159
+
160
+ **Test File:** `cmd_08_debug_with_and.py`
161
+ ```python
162
+ if not settings.DEBUG and True:
163
+ raise CommandError("This command can only be run in DEBUG mode")
164
+ ```
165
+
166
+ **Expected:** DEBATABLE (could be allowed if DEBUG is the primary condition)
167
+ **Actual:** CAUGHT (flagged as violation)
168
+
169
+ **Analysis:**
170
+ - Current code only checks for simple `UnaryOp(Not)` with `settings.DEBUG`
171
+ - Doesn't handle `BoolOp` (and/or) expressions
172
+ - This is arguably correct behavior - keeps the check simple and strict
173
+
174
+ **Recommendation:** Document this limitation. Developers should use:
175
+ ```python
176
+ if not settings.DEBUG:
177
+ raise CommandError("...")
178
+ # Then check other conditions separately
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Additional Edge Cases Tested
184
+
185
+ ### Nested Directory Structure
186
+ - File in `management/commands/subdir/command.py` - NOT tested
187
+ - **Recommendation:** Add test case to verify path matching works with subdirectories
188
+
189
+ ### File Encoding Issues
190
+ - Files with syntax errors - Handled gracefully (returns empty violations)
191
+ - Files that don't exist - Handled with error message
192
+
193
+ ### Multiple Commands in One File
194
+ - NOT tested
195
+ - **Recommendation:** Add test case with multiple Command classes in one file
196
+
197
+ ---
198
+
199
+ ## Recommended Priority Fixes
200
+
201
+ 1. **HIGH PRIORITY:** Fix GAP #2 (positive DEBUG check pattern)
202
+ - Current behavior rejects valid code
203
+ - Breaking change for developers using this pattern
204
+
205
+ 2. **MEDIUM PRIORITY:** Fix GAP #1 (case-sensitive skip decorators)
206
+ - Low probability but easy to fix
207
+ - Prevents trivial evasion
208
+
209
+ 3. **LOW PRIORITY:** Add test for nested management commands
210
+ - Verify path matching works with subdirectories
211
+
212
+ ---
213
+
214
+ ## Test Coverage Summary
215
+
216
+ **Skip Decorators:**
217
+ - Simple decorators: TESTED
218
+ - Attribute decorators: TESTED
219
+ - Called decorators: TESTED
220
+ - Case variations: **GAP FOUND**
221
+ - Custom decorators: TESTED (correctly allowed)
222
+
223
+ **DEBUG Guards:**
224
+ - No check: TESTED
225
+ - Negative check (`if not`): TESTED
226
+ - Positive check (`if ... else`): **GAP FOUND**
227
+ - Imported DEBUG: TESTED (correctly rejected)
228
+ - Helper function: TESTED (correctly rejected)
229
+ - Late check (>5 statements): TESTED (correctly rejected)
230
+ - Path matching: TESTED
231
+ - Complex boolean: TESTED (debatable behavior)
232
+
233
+ ---
234
+
235
+ ## Files Created for Testing
236
+
237
+ ### Skip Decorators (9 files)
238
+ ```
239
+ test_files/skip_decorators/
240
+ ├── test_01_simple_skip.py
241
+ ├── test_02_pytest_skipif.py
242
+ ├── test_03_unittest_skipIf.py
243
+ ├── test_04_skip_with_parens.py
244
+ ├── test_05_xfail.py
245
+ ├── test_06_custom_skip.py
246
+ ├── test_07_capital_Skip.py (GAP)
247
+ ├── test_08_skipUnless.py
248
+ └── test_09_pytest_mark_skip_simple.py
249
+ ```
250
+
251
+ ### Management Commands (9 files)
252
+ ```
253
+ test_files/management/commands/
254
+ ├── cmd_01_no_debug_check.py
255
+ ├── cmd_02_proper_debug_check.py
256
+ ├── cmd_03_debug_check_with_return.py
257
+ ├── cmd_04_imported_DEBUG.py
258
+ ├── cmd_05_debug_check_in_helper.py
259
+ ├── cmd_06_debug_check_late.py
260
+ ├── cmd_07_positive_debug_check.py (GAP)
261
+ ├── cmd_08_debug_with_and.py
262
+ test_files/
263
+ └── not_management_command.py
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Conclusion
269
+
270
+ The validator is **mostly effective** but has **2 critical gaps**:
271
+
272
+ 1. **Case-sensitive decorator matching** - Easy fix, low impact
273
+ 2. **Positive DEBUG check rejection** - HIGH PRIORITY, rejects valid code
274
+
275
+ The implementation correctly handles:
276
+ - Most skip decorator patterns
277
+ - Simple DEBUG guard patterns
278
+ - Path filtering for management commands
279
+ - Graceful error handling
280
+
281
+ **Overall Assessment: 82% effective (14/17 test cases passed)**
282
+
283
+ **Action Required:**
284
+ 1. Fix GAP #2 immediately (breaking valid code)
285
+ 2. Fix GAP #1 for completeness
286
+ 3. Add test for nested management command directories
287
+ 4. Document the complex boolean limitation
@@ -0,0 +1,19 @@
1
+ """Python style validation package."""
2
+
3
+ from .python_style_checks import (
4
+ Violation,
5
+ check_imports_at_top,
6
+ check_no_empty_line_after_decorators,
7
+ check_single_empty_line_between_functions,
8
+ check_view_function_naming,
9
+ validate_file,
10
+ )
11
+
12
+ __all__ = [
13
+ "Violation",
14
+ "check_imports_at_top",
15
+ "check_no_empty_line_after_decorators",
16
+ "check_single_empty_line_between_functions",
17
+ "check_view_function_naming",
18
+ "validate_file",
19
+ ]
@@ -0,0 +1,82 @@
1
+ """Abbreviation detection validator.
2
+
3
+ Implements check 5: No single-letter variable names (except i, j, k for loop counters).
4
+
5
+ Detects:
6
+ - Single-letter assignments: t = value
7
+ - Single-letter loop variables: for f in files
8
+ - Single-letter comprehension variables: [x for x in items]
9
+ """
10
+
11
+ import ast
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import List, Set
15
+
16
+ from validator_base import Violation
17
+
18
+
19
+ ALLOWED_SINGLE_LETTERS: Set[str] = frozenset({"i", "j", "k", "_"})
20
+
21
+
22
+ def check_single_letter_variables(tree: ast.AST, filename: str) -> List[Violation]:
23
+ violations: List[Violation] = []
24
+
25
+ for node in ast.walk(tree):
26
+ if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store):
27
+ if len(node.id) == 1 and node.id not in ALLOWED_SINGLE_LETTERS:
28
+ violations.append(
29
+ Violation(
30
+ filename,
31
+ node.lineno,
32
+ f"Single-letter variable '{node.id}' - use descriptive name",
33
+ )
34
+ )
35
+
36
+ return violations
37
+
38
+
39
+ def validate_file(file_path: Path) -> List[Violation]:
40
+ violations: List[Violation] = []
41
+ filename = str(file_path)
42
+
43
+ try:
44
+ source = file_path.read_text(encoding="utf-8")
45
+ except Exception as error:
46
+ violations.append(Violation(filename, 0, f"Error reading file: {error}"))
47
+ return violations
48
+
49
+ try:
50
+ tree = ast.parse(source)
51
+ except SyntaxError as error:
52
+ violations.append(
53
+ Violation(filename, error.lineno or 0, f"Syntax error: {error.msg}")
54
+ )
55
+ return violations
56
+
57
+ violations.extend(check_single_letter_variables(tree, filename))
58
+ return violations
59
+
60
+
61
+ def main() -> int:
62
+ if len(sys.argv) < 2:
63
+ print("Usage: abbreviation_checks.py <file1.py> [file2.py ...]", file=sys.stderr)
64
+ return 1
65
+
66
+ all_violations: List[Violation] = []
67
+
68
+ for file_arg in sys.argv[1:]:
69
+ file_path = Path(file_arg)
70
+ if not file_path.exists():
71
+ print(f"Error: File not found: {file_path}", file=sys.stderr)
72
+ return 1
73
+ all_violations.extend(validate_file(file_path))
74
+
75
+ for violation in all_violations:
76
+ print(violation)
77
+
78
+ return 1 if all_violations else 0
79
+
80
+
81
+ if __name__ == "__main__":
82
+ sys.exit(main())
@@ -0,0 +1,133 @@
1
+ """Code quality checks validator.
2
+
3
+ Implements:
4
+ - Check 30: Function too long (max 30 lines)
5
+ - Check 31: Nesting too deep (max 2 levels)
6
+ - Check 32: File too long (max 400 lines)
7
+ """
8
+
9
+ import ast
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import List
13
+
14
+ from validator_base import Violation
15
+
16
+
17
+ MAX_FUNCTION_LINES = 30
18
+ MAX_NESTING_DEPTH = 2
19
+ MAX_FILE_LINES = 400
20
+
21
+
22
+ def check_function_length(tree: ast.AST, filename: str) -> List[Violation]:
23
+ violations: List[Violation] = []
24
+
25
+ for node in ast.walk(tree):
26
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
27
+ if node.end_lineno and node.lineno:
28
+ length = node.end_lineno - node.lineno + 1
29
+ if length > MAX_FUNCTION_LINES:
30
+ violations.append(
31
+ Violation(
32
+ filename,
33
+ node.lineno,
34
+ f"Function '{node.name}' is {length} lines (max {MAX_FUNCTION_LINES})",
35
+ )
36
+ )
37
+
38
+ return violations
39
+
40
+
41
+ def check_nesting_depth(tree: ast.AST, filename: str) -> List[Violation]:
42
+ violations: List[Violation] = []
43
+
44
+ for node in ast.walk(tree):
45
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
46
+ max_depth = _get_max_nesting_depth(node, 0)
47
+ if max_depth > MAX_NESTING_DEPTH:
48
+ violations.append(
49
+ Violation(
50
+ filename,
51
+ node.lineno,
52
+ f"Function '{node.name}' has nesting depth {max_depth} (max {MAX_NESTING_DEPTH})",
53
+ )
54
+ )
55
+
56
+ return violations
57
+
58
+
59
+ def _get_max_nesting_depth(node: ast.AST, current_depth: int) -> int:
60
+ max_depth = current_depth
61
+
62
+ for child in ast.iter_child_nodes(node):
63
+ if isinstance(child, (ast.If, ast.For, ast.While, ast.With, ast.Try)):
64
+ child_depth = _get_max_nesting_depth(child, current_depth + 1)
65
+ max_depth = max(max_depth, child_depth)
66
+ else:
67
+ child_depth = _get_max_nesting_depth(child, current_depth)
68
+ max_depth = max(max_depth, child_depth)
69
+
70
+ return max_depth
71
+
72
+
73
+ def check_file_length(file_path: Path) -> List[Violation]:
74
+ violations: List[Violation] = []
75
+ filename = str(file_path)
76
+
77
+ try:
78
+ lines = file_path.read_text(encoding="utf-8").splitlines()
79
+ except Exception as error:
80
+ return [Violation(filename, 0, f"Error reading file: {error}")]
81
+
82
+ if len(lines) > MAX_FILE_LINES:
83
+ violations.append(
84
+ Violation(
85
+ filename,
86
+ 1,
87
+ f"File is {len(lines)} lines (max {MAX_FILE_LINES}) - consider splitting",
88
+ )
89
+ )
90
+
91
+ return violations
92
+
93
+
94
+ def validate_file(file_path: Path) -> List[Violation]:
95
+ violations: List[Violation] = []
96
+ filename = str(file_path)
97
+
98
+ violations.extend(check_file_length(file_path))
99
+
100
+ try:
101
+ source = file_path.read_text(encoding="utf-8")
102
+ tree = ast.parse(source)
103
+ except Exception as error:
104
+ return violations + [Violation(filename, 0, f"Error: {error}")]
105
+
106
+ violations.extend(check_function_length(tree, filename))
107
+ violations.extend(check_nesting_depth(tree, filename))
108
+
109
+ return violations
110
+
111
+
112
+ def main() -> int:
113
+ if len(sys.argv) < 2:
114
+ print("Usage: code_quality_checks.py <file1.py> [file2.py ...]", file=sys.stderr)
115
+ return 1
116
+
117
+ all_violations: List[Violation] = []
118
+
119
+ for file_arg in sys.argv[1:]:
120
+ file_path = Path(file_arg)
121
+ if not file_path.exists():
122
+ print(f"Error: File not found: {file_path}", file=sys.stderr)
123
+ return 1
124
+ all_violations.extend(validate_file(file_path))
125
+
126
+ for violation in all_violations:
127
+ print(violation)
128
+
129
+ return 1 if all_violations else 0
130
+
131
+
132
+ if __name__ == "__main__":
133
+ sys.exit(main())
@@ -0,0 +1,188 @@
1
+ """Comment detection validator.
2
+
3
+ Implements check 26: No comments in code (self-documenting code principle).
4
+
5
+ Detects:
6
+ - Python comments (# ...)
7
+ - TypeScript/JavaScript comments (// ... and /* ... */)
8
+
9
+ Exceptions (NOT flagged):
10
+ - Shebang lines (#!/...)
11
+ - Type annotations (type:, noqa, eslint-disable)
12
+ - Docstrings (triple-quoted strings for function contracts)
13
+
14
+ Note: Docstrings documenting function Args/Returns/Raises are acceptable
15
+ per CODE_RULES.md. This validator only flags # and // style comments.
16
+ """
17
+
18
+ import re
19
+ import sys
20
+ from dataclasses import dataclass
21
+ from pathlib import Path
22
+ from typing import List
23
+
24
+
25
+ SHEBANG_PATTERN = re.compile(r"^#!")
26
+ PYTHON_COMMENT_PATTERN = re.compile(r"(?<!.)#(?!!).+$|(?<=\s)#.+$", re.MULTILINE)
27
+ JS_SINGLE_COMMENT_PATTERN = re.compile(r"//.*$", re.MULTILINE)
28
+ JS_BLOCK_COMMENT_PATTERN = re.compile(r"/\*[\s\S]*?\*/", re.MULTILINE)
29
+
30
+
31
+ @dataclass
32
+ class Violation:
33
+ """Represents a comment violation."""
34
+
35
+ file: str
36
+ line: int
37
+ message: str
38
+
39
+ def __str__(self) -> str:
40
+ """Format as file:line: message."""
41
+ return f"{self.file}:{self.line}: {self.message}"
42
+
43
+
44
+ def check_python_comments(source: str, filename: str) -> List[Violation]:
45
+ """Check for comments in Python files.
46
+
47
+ Args:
48
+ source: Source code as string
49
+ filename: Name of file being checked
50
+
51
+ Returns:
52
+ List of violations found
53
+ """
54
+ violations: List[Violation] = []
55
+ lines = source.splitlines()
56
+
57
+ for line_num, line in enumerate(lines, start=1):
58
+ stripped = line.lstrip()
59
+
60
+ if not stripped:
61
+ continue
62
+
63
+ if stripped.startswith("#"):
64
+ if SHEBANG_PATTERN.match(stripped):
65
+ continue
66
+
67
+ comment_text = stripped[1:].strip()[:40]
68
+ violations.append(
69
+ Violation(
70
+ filename,
71
+ line_num,
72
+ f"Comment found: '# {comment_text}...' - code should be self-documenting",
73
+ )
74
+ )
75
+
76
+ elif "#" in line:
77
+ code_part, _, comment_part = line.partition("#")
78
+ if code_part.count('"') % 2 == 0 and code_part.count("'") % 2 == 0:
79
+ comment_text = comment_part.strip()[:40]
80
+ violations.append(
81
+ Violation(
82
+ filename,
83
+ line_num,
84
+ f"Inline comment found: '# {comment_text}...' - code should be self-documenting",
85
+ )
86
+ )
87
+
88
+ return violations
89
+
90
+
91
+ def check_js_comments(source: str, filename: str) -> List[Violation]:
92
+ """Check for comments in JavaScript/TypeScript files.
93
+
94
+ Args:
95
+ source: Source code as string
96
+ filename: Name of file being checked
97
+
98
+ Returns:
99
+ List of violations found
100
+ """
101
+ violations: List[Violation] = []
102
+ lines = source.splitlines()
103
+
104
+ for line_num, line in enumerate(lines, start=1):
105
+ stripped = line.lstrip()
106
+
107
+ if stripped.startswith("//"):
108
+ comment_text = stripped[2:].strip()[:40]
109
+ violations.append(
110
+ Violation(
111
+ filename,
112
+ line_num,
113
+ f"Comment found: '// {comment_text}...' - code should be self-documenting",
114
+ )
115
+ )
116
+
117
+ for match in JS_BLOCK_COMMENT_PATTERN.finditer(source):
118
+ start_pos = match.start()
119
+ line_num = source[:start_pos].count("\n") + 1
120
+ comment_preview = match.group()[:40].replace("\n", " ")
121
+ violations.append(
122
+ Violation(
123
+ filename,
124
+ line_num,
125
+ f"Block comment found: '{comment_preview}...' - code should be self-documenting",
126
+ )
127
+ )
128
+
129
+ return violations
130
+
131
+
132
+ def validate_file(file_path: Path) -> List[Violation]:
133
+ """Validate a file for comment violations.
134
+
135
+ Args:
136
+ file_path: Path to file to validate
137
+
138
+ Returns:
139
+ List of all violations found
140
+ """
141
+ violations: List[Violation] = []
142
+ filename = str(file_path)
143
+
144
+ try:
145
+ source = file_path.read_text(encoding="utf-8")
146
+ except Exception as error:
147
+ violations.append(Violation(filename, 0, f"Error reading file: {error}"))
148
+ return violations
149
+
150
+ suffix = file_path.suffix.lower()
151
+
152
+ if suffix == ".py":
153
+ violations.extend(check_python_comments(source, filename))
154
+ elif suffix in (".ts", ".tsx", ".js", ".jsx"):
155
+ violations.extend(check_js_comments(source, filename))
156
+
157
+ return violations
158
+
159
+
160
+ def main() -> int:
161
+ """Main entry point for command-line usage.
162
+
163
+ Returns:
164
+ Exit code: 0 if all files pass, 1 if violations found
165
+ """
166
+ if len(sys.argv) < 2:
167
+ print("Usage: comment_checks.py <file1> [file2 ...]", file=sys.stderr)
168
+ return 1
169
+
170
+ all_violations: List[Violation] = []
171
+
172
+ for file_arg in sys.argv[1:]:
173
+ file_path = Path(file_arg)
174
+ if not file_path.exists():
175
+ print(f"Error: File not found: {file_path}", file=sys.stderr)
176
+ return 1
177
+
178
+ violations = validate_file(file_path)
179
+ all_violations.extend(violations)
180
+
181
+ for violation in all_violations:
182
+ print(violation)
183
+
184
+ return 1 if all_violations else 0
185
+
186
+
187
+ if __name__ == "__main__":
188
+ sys.exit(main())