@sandrinio/vbounce 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.
- package/README.md +107 -0
- package/bin/vbounce.mjs +165 -0
- package/brains/AGENTS.md +129 -0
- package/brains/CLAUDE.md +146 -0
- package/brains/GEMINI.md +134 -0
- package/brains/SETUP.md +180 -0
- package/brains/claude-agents/architect.md +140 -0
- package/brains/claude-agents/developer.md +69 -0
- package/brains/claude-agents/devops.md +219 -0
- package/brains/claude-agents/qa.md +112 -0
- package/brains/claude-agents/scribe.md +141 -0
- package/brains/cursor-rules/vbounce-docs.mdc +41 -0
- package/brains/cursor-rules/vbounce-process.mdc +45 -0
- package/brains/cursor-rules/vbounce-rules.mdc +26 -0
- package/package.json +40 -0
- package/skills/agent-team/SKILL.md +425 -0
- package/skills/doc-manager/SKILL.md +278 -0
- package/skills/lesson/SKILL.md +90 -0
- package/skills/react-best-practices/SKILL.md +3014 -0
- package/skills/react-best-practices/rules/_sections.md +46 -0
- package/skills/react-best-practices/rules/_template.md +28 -0
- package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/skills/react-best-practices/rules/async-dependencies.md +51 -0
- package/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/vibe-code-review/SKILL.md +70 -0
- package/skills/vibe-code-review/references/deep-audit.md +259 -0
- package/skills/vibe-code-review/references/pr-review.md +234 -0
- package/skills/vibe-code-review/references/quick-scan.md +178 -0
- package/skills/vibe-code-review/references/report-template.md +189 -0
- package/skills/vibe-code-review/references/trend-check.md +224 -0
- package/skills/vibe-code-review/scripts/generate-snapshot.sh +89 -0
- package/skills/vibe-code-review/scripts/pr-analyze.sh +180 -0
- package/skills/write-skill/SKILL.md +133 -0
- package/templates/charter.md +144 -0
- package/templates/delivery_plan.md +188 -0
- package/templates/epic.md +200 -0
- package/templates/hotfix.md +57 -0
- package/templates/risk_registry.md +89 -0
- package/templates/roadmap.md +176 -0
- package/templates/sprint_report.md +151 -0
- package/templates/story.md +150 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Deep Audit Mode
|
|
2
|
+
|
|
3
|
+
A comprehensive analysis of the entire codebase. This takes longer but gives a complete picture of architectural health, coupling, duplication, and sustainability.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Before a major release or launch
|
|
8
|
+
- When the user suspects the codebase is getting "too complex to change"
|
|
9
|
+
- Quarterly or monthly health assessments
|
|
10
|
+
- Before hiring a new developer or onboarding someone
|
|
11
|
+
- When feature velocity is noticeably declining
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
### 1. Project Census
|
|
16
|
+
|
|
17
|
+
Get a full picture of the codebase size and shape:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
echo "=== Project Census ==="
|
|
21
|
+
|
|
22
|
+
# Count files by type
|
|
23
|
+
echo "--- Files by extension ---"
|
|
24
|
+
find . -type f \
|
|
25
|
+
-not -path "*/node_modules/*" \
|
|
26
|
+
-not -path "*/.next/*" \
|
|
27
|
+
-not -path "*/dist/*" \
|
|
28
|
+
-not -path "*/build/*" \
|
|
29
|
+
-not -path "*/__pycache__/*" \
|
|
30
|
+
-not -path "*/.git/*" \
|
|
31
|
+
-not -path "*/coverage/*" \
|
|
32
|
+
| sed 's/.*\.//' | sort | uniq -c | sort -rn | head -20
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "--- Total lines of code ---"
|
|
36
|
+
find . -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" -o -name "*.go" -o -name "*.rs" \
|
|
37
|
+
| grep -v node_modules | grep -v .next | grep -v dist | grep -v __pycache__ \
|
|
38
|
+
| xargs wc -l 2>/dev/null | tail -1
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
echo "--- Directory structure (2 levels) ---"
|
|
42
|
+
find . -maxdepth 2 -type d \
|
|
43
|
+
-not -path "*/node_modules/*" \
|
|
44
|
+
-not -path "*/.git/*" \
|
|
45
|
+
-not -path "*/.next/*" \
|
|
46
|
+
| sort
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Architectural Consistency Analysis
|
|
50
|
+
|
|
51
|
+
This is the most important check. AI agents drift between patterns across sessions.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
echo "=== Architectural Pattern Map ==="
|
|
55
|
+
|
|
56
|
+
# Detect all patterns in use
|
|
57
|
+
echo "--- State Management ---"
|
|
58
|
+
grep -rl "createSlice\|configureStore\|createStore" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Redux: {} files"
|
|
59
|
+
grep -rl "zustand\|create(" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Zustand: {} files"
|
|
60
|
+
grep -rl "createContext\|useContext" --include="*.tsx" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Context API: {} files"
|
|
61
|
+
grep -rl "makeAutoObservable\|makeObservable" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "MobX: {} files"
|
|
62
|
+
grep -rl "@tanstack/react-query\|useQuery\|useMutation" --include="*.ts" --include="*.tsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "React Query: {} files"
|
|
63
|
+
|
|
64
|
+
echo ""
|
|
65
|
+
echo "--- API Patterns ---"
|
|
66
|
+
grep -rl "fetch(" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Raw fetch: {} files"
|
|
67
|
+
grep -rl "axios" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Axios: {} files"
|
|
68
|
+
grep -rl "ky\b\|import.*from.*'ky'" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Ky: {} files"
|
|
69
|
+
|
|
70
|
+
echo ""
|
|
71
|
+
echo "--- Component Patterns ---"
|
|
72
|
+
grep -rl "class.*extends.*Component\|class.*extends.*React" --include="*.tsx" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Class components: {} files"
|
|
73
|
+
grep -rl "export default function\|export const.*=.*(" --include="*.tsx" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Functional components: {} files"
|
|
74
|
+
|
|
75
|
+
echo ""
|
|
76
|
+
echo "--- Styling Patterns ---"
|
|
77
|
+
find . -name "*.module.css" -o -name "*.module.scss" | grep -v node_modules | wc -l | xargs -I{} echo "CSS Modules: {} files"
|
|
78
|
+
grep -rl "styled\." --include="*.ts" --include="*.tsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Styled-components: {} files"
|
|
79
|
+
grep -rl "className=\".*tailwind\|className={.*cn(" --include="*.tsx" --include="*.jsx" . 2>/dev/null | grep -v node_modules | wc -l | xargs -I{} echo "Tailwind: {} files"
|
|
80
|
+
find . -name "*.css" -not -name "*.module.css" | grep -v node_modules | wc -l | xargs -I{} echo "Plain CSS: {} files"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Analysis rule:** If multiple competing patterns exist for the same concern (e.g., Redux AND Zustand for state, or both class and functional components), flag as architectural inconsistency. One pattern should dominate (>80% usage).
|
|
84
|
+
|
|
85
|
+
### 3. Full Duplication Analysis
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Install jscpd if needed
|
|
89
|
+
npx jscpd --version 2>/dev/null || npm install -g jscpd
|
|
90
|
+
|
|
91
|
+
# Run full-project duplication scan
|
|
92
|
+
npx jscpd . \
|
|
93
|
+
--min-lines 5 \
|
|
94
|
+
--min-tokens 50 \
|
|
95
|
+
--reporters "console,json" \
|
|
96
|
+
--output /tmp/jscpd-report \
|
|
97
|
+
--ignore "node_modules,dist,build,.next,__pycache__,coverage,*.test.*,*.spec.*" \
|
|
98
|
+
2>/dev/null
|
|
99
|
+
|
|
100
|
+
# Parse results if JSON available
|
|
101
|
+
if [ -f /tmp/jscpd-report/jscpd-report.json ]; then
|
|
102
|
+
python3 -c "
|
|
103
|
+
import json
|
|
104
|
+
with open('/tmp/jscpd-report/jscpd-report.json') as f:
|
|
105
|
+
data = json.load(f)
|
|
106
|
+
total = data.get('statistics', {}).get('total', {})
|
|
107
|
+
print(f'Total duplicated lines: {total.get(\"duplicatedLines\", 0)}')
|
|
108
|
+
print(f'Duplication percentage: {total.get(\"percentage\", 0):.1f}%')
|
|
109
|
+
dupes = data.get('duplicates', [])
|
|
110
|
+
print(f'Duplicate blocks found: {len(dupes)}')
|
|
111
|
+
for d in dupes[:10]:
|
|
112
|
+
first = d['firstFile']
|
|
113
|
+
second = d['secondFile']
|
|
114
|
+
print(f' {first[\"name\"]}:{first[\"startLoc\"][\"line\"]} ↔ {second[\"name\"]}:{second[\"startLoc\"][\"line\"]} ({d[\"lines\"]} lines)')
|
|
115
|
+
"
|
|
116
|
+
fi
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Thresholds:**
|
|
120
|
+
- 🟢 Under 3%: Excellent
|
|
121
|
+
- 🟡 3–8%: Normal, but watch it
|
|
122
|
+
- 🔴 Over 8%: Significant duplication — AI is reinventing solutions
|
|
123
|
+
|
|
124
|
+
### 4. Dependency Graph and Coupling
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# For JavaScript/TypeScript
|
|
128
|
+
npx dependency-cruiser --version 2>/dev/null || npm install -g dependency-cruiser
|
|
129
|
+
|
|
130
|
+
# Generate dependency graph
|
|
131
|
+
npx depcruise --include-only "^src" --output-type text src/ 2>/dev/null | head -100
|
|
132
|
+
|
|
133
|
+
# Count circular dependencies
|
|
134
|
+
echo "=== Circular Dependencies ==="
|
|
135
|
+
npx depcruise --include-only "^src" --output-type err src/ 2>/dev/null | grep "circular" | head -20
|
|
136
|
+
|
|
137
|
+
# Identify most-imported modules (coupling hotspots)
|
|
138
|
+
echo ""
|
|
139
|
+
echo "=== Most-imported modules (coupling hotspots) ==="
|
|
140
|
+
grep -rh "from ['\"]" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . \
|
|
141
|
+
| grep -v node_modules \
|
|
142
|
+
| sed "s/.*from ['\"]//;s/['\"].*//" \
|
|
143
|
+
| sort | uniq -c | sort -rn | head -20
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**What to flag:**
|
|
147
|
+
- Circular dependencies (always 🔴)
|
|
148
|
+
- Any module imported by more than 30% of files (coupling hotspot)
|
|
149
|
+
- God modules that import more than 15 other project modules
|
|
150
|
+
|
|
151
|
+
### 5. Dead Code Detection
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# JavaScript/TypeScript
|
|
155
|
+
echo "=== Dead Code Analysis ==="
|
|
156
|
+
npx knip --no-exit-code 2>/dev/null
|
|
157
|
+
|
|
158
|
+
# If knip unavailable
|
|
159
|
+
npx ts-unused-exports tsconfig.json 2>/dev/null
|
|
160
|
+
|
|
161
|
+
# Count files not imported by anything
|
|
162
|
+
echo ""
|
|
163
|
+
echo "=== Potentially orphaned files ==="
|
|
164
|
+
for file in $(find src -name "*.ts" -o -name "*.tsx" | grep -v test | grep -v spec | grep -v index); do
|
|
165
|
+
BASENAME=$(basename "$file" | sed 's/\.\(ts\|tsx\)$//')
|
|
166
|
+
REFS=$(grep -rl "$BASENAME" --include="*.ts" --include="*.tsx" src/ | grep -v "$file" | wc -l)
|
|
167
|
+
if [ "$REFS" -eq 0 ]; then
|
|
168
|
+
echo " ⚠️ $file — not imported anywhere"
|
|
169
|
+
fi
|
|
170
|
+
done
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 6. Error Handling Comprehensive Audit
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
echo "=== Error Handling Audit ==="
|
|
177
|
+
|
|
178
|
+
echo "--- Empty catch blocks ---"
|
|
179
|
+
grep -rn "catch" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" -A 2 . \
|
|
180
|
+
| grep -v node_modules \
|
|
181
|
+
| grep -E "catch.*\{$" -A 1 | grep "^\-\-$\|^\s*\}" | head -20
|
|
182
|
+
|
|
183
|
+
echo ""
|
|
184
|
+
echo "--- Console-only error handling ---"
|
|
185
|
+
grep -rn "catch" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" -A 5 . \
|
|
186
|
+
| grep -v node_modules \
|
|
187
|
+
| grep -c "console\.\(log\|error\|warn\)"
|
|
188
|
+
echo " instances of console-only error handling"
|
|
189
|
+
|
|
190
|
+
echo ""
|
|
191
|
+
echo "--- Missing try/catch around async operations ---"
|
|
192
|
+
# Find await statements not inside try blocks (heuristic)
|
|
193
|
+
grep -rn "await " --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . \
|
|
194
|
+
| grep -v node_modules | grep -v test | grep -v spec | wc -l
|
|
195
|
+
echo " total await statements"
|
|
196
|
+
|
|
197
|
+
echo ""
|
|
198
|
+
echo "--- Error boundaries (React) ---"
|
|
199
|
+
grep -rl "ErrorBoundary\|componentDidCatch\|getDerivedStateFromError" --include="*.tsx" --include="*.jsx" . \
|
|
200
|
+
| grep -v node_modules | wc -l
|
|
201
|
+
echo " error boundary implementations"
|
|
202
|
+
|
|
203
|
+
echo ""
|
|
204
|
+
echo "--- API error responses ---"
|
|
205
|
+
grep -rn "res\.\(status\|json\)" --include="*.ts" --include="*.js" -B2 -A2 . \
|
|
206
|
+
| grep -v node_modules | grep -E "4[0-9]{2}|5[0-9]{2}" | head -10
|
|
207
|
+
echo "(Checking for proper HTTP error status codes)"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 7. Test Quality Assessment
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
echo "=== Test Quality Assessment ==="
|
|
214
|
+
|
|
215
|
+
echo "--- Test file inventory ---"
|
|
216
|
+
find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" \
|
|
217
|
+
| grep -v node_modules | grep -v __pycache__
|
|
218
|
+
|
|
219
|
+
echo ""
|
|
220
|
+
echo "--- Assertion patterns ---"
|
|
221
|
+
# Check if tests have real assertions or just smoke tests
|
|
222
|
+
grep -rn "expect\|assert\|should" --include="*.test.*" --include="*.spec.*" . \
|
|
223
|
+
| grep -v node_modules | wc -l
|
|
224
|
+
echo " total assertions"
|
|
225
|
+
|
|
226
|
+
# Check for weak assertions
|
|
227
|
+
echo ""
|
|
228
|
+
echo "--- Weak assertions (testing existence, not behavior) ---"
|
|
229
|
+
grep -rn "toBeDefined\|toBeTruthy\|not\.toBeNull\|to\.exist" --include="*.test.*" --include="*.spec.*" . \
|
|
230
|
+
| grep -v node_modules | wc -l
|
|
231
|
+
echo " weak assertions (only check that something exists)"
|
|
232
|
+
|
|
233
|
+
# Check for snapshot tests (often low value in AI codebases)
|
|
234
|
+
echo ""
|
|
235
|
+
grep -rn "toMatchSnapshot\|toMatchInlineSnapshot" --include="*.test.*" --include="*.spec.*" . \
|
|
236
|
+
| grep -v node_modules | wc -l
|
|
237
|
+
echo " snapshot tests (often brittle in AI-generated code)"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 8. The "Explain It" Consistency Test
|
|
241
|
+
|
|
242
|
+
This is unique to vibe-coded projects. Ask the AI to describe the architecture, then compare it against what the code actually shows.
|
|
243
|
+
|
|
244
|
+
**Instructions for Claude:**
|
|
245
|
+
1. Read the project's README, any architecture docs, and the top-level directory structure
|
|
246
|
+
2. Write a plain-language architectural description based ONLY on the actual code structure
|
|
247
|
+
3. Compare this against any existing documentation
|
|
248
|
+
4. Flag contradictions — these mean the codebase has drifted from its intended design
|
|
249
|
+
|
|
250
|
+
## Report Output
|
|
251
|
+
|
|
252
|
+
Use `references/report-template.md` with the **Deep Audit** section. The report should be comprehensive enough to hand to a new team member or a code reviewer as a briefing document.
|
|
253
|
+
|
|
254
|
+
Structure findings into:
|
|
255
|
+
- **Architecture** — Pattern map, consistency score, coupling graph
|
|
256
|
+
- **Code Health** — Duplication, dead code, file sizes
|
|
257
|
+
- **Reliability** — Error handling, test quality
|
|
258
|
+
- **Sustainability** — Dependency health, complexity trends
|
|
259
|
+
- **Recommendations** — Prioritized action items with effort estimates
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# PR Review Mode
|
|
2
|
+
|
|
3
|
+
Analyze only the changed files in a PR or git diff. This is the scalable daily-driver — it runs on every merge and catches problems before they enter the main branch.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- User wants to review a PR before merging
|
|
8
|
+
- User has a set of changed files to evaluate
|
|
9
|
+
- User asks "is this diff safe to merge?"
|
|
10
|
+
- Continuous integration / pre-merge quality gate
|
|
11
|
+
|
|
12
|
+
## Input
|
|
13
|
+
|
|
14
|
+
The user should provide one of:
|
|
15
|
+
- A branch name to compare against main/master
|
|
16
|
+
- A commit range
|
|
17
|
+
- A set of files to review
|
|
18
|
+
|
|
19
|
+
If no input is given, default to:
|
|
20
|
+
```bash
|
|
21
|
+
git diff main...HEAD
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
### 1. Identify Changed Files
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Get list of changed files (excluding generated/config)
|
|
30
|
+
CHANGED=$(git diff --name-only main...HEAD 2>/dev/null || git diff --name-only HEAD~1)
|
|
31
|
+
echo "$CHANGED" | grep -v "package-lock.json\|yarn.lock\|.lock$\|node_modules\|dist/\|build/"
|
|
32
|
+
|
|
33
|
+
echo ""
|
|
34
|
+
echo "=== Change Summary ==="
|
|
35
|
+
echo "Files changed: $(echo "$CHANGED" | wc -l)"
|
|
36
|
+
echo "Insertions/Deletions:"
|
|
37
|
+
git diff --stat main...HEAD 2>/dev/null || git diff --stat HEAD~1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Flag if a PR touches more than 15 files across more than 5 directories — this is a coupling red flag.
|
|
41
|
+
|
|
42
|
+
### 2. Complexity Delta
|
|
43
|
+
|
|
44
|
+
For each changed file, measure complexity before and after:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# For JavaScript/TypeScript — install if needed
|
|
48
|
+
npm list -g cr 2>/dev/null || npm install -g complexity-report
|
|
49
|
+
|
|
50
|
+
# Analyze only changed source files
|
|
51
|
+
for file in $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$' | grep -v node_modules); do
|
|
52
|
+
if [ -f "$file" ]; then
|
|
53
|
+
echo "=== $file ==="
|
|
54
|
+
cr "$file" 2>/dev/null || npx cr "$file" 2>/dev/null || echo " (complexity-report not available, skipping)"
|
|
55
|
+
fi
|
|
56
|
+
done
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Alternative approach if cr is not available — count nesting depth as a proxy for complexity:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
for file in $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx|py)$' | grep -v node_modules); do
|
|
63
|
+
if [ -f "$file" ]; then
|
|
64
|
+
MAX_INDENT=$(cat "$file" | sed 's/[^ \t].*//' | awk '{print length}' | sort -rn | head -1)
|
|
65
|
+
LINES=$(wc -l < "$file")
|
|
66
|
+
echo "$file — $LINES lines, max indent: $MAX_INDENT spaces"
|
|
67
|
+
if [ "$MAX_INDENT" -gt 20 ]; then
|
|
68
|
+
echo " ⚠️ Deep nesting detected — likely complex logic"
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Duplication Check Against Existing Code
|
|
75
|
+
|
|
76
|
+
This is the most important check for AI-generated code. The agent writing new code may not know what already exists.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Install jscpd if not available
|
|
80
|
+
npx jscpd --version 2>/dev/null || npm install -g jscpd
|
|
81
|
+
|
|
82
|
+
# Run duplication detection focused on changed files
|
|
83
|
+
# Create a temp file with changed file list
|
|
84
|
+
git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx|py)$' | grep -v node_modules > /tmp/changed_files.txt
|
|
85
|
+
|
|
86
|
+
# Run jscpd on the whole project but focus report on matches involving changed files
|
|
87
|
+
npx jscpd . \
|
|
88
|
+
--min-lines 5 \
|
|
89
|
+
--min-tokens 50 \
|
|
90
|
+
--reporters "console" \
|
|
91
|
+
--ignore "node_modules,dist,build,.next,__pycache__,coverage" \
|
|
92
|
+
2>/dev/null || echo "jscpd not available — manual duplication check needed"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If jscpd is not available, do a manual heuristic check:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Find function names in changed files and check if they exist elsewhere
|
|
99
|
+
for file in $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$'); do
|
|
100
|
+
FUNCS=$(grep -oE '(function|const|let|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)' "$file" | awk '{print $2}')
|
|
101
|
+
for func in $FUNCS; do
|
|
102
|
+
MATCHES=$(grep -rl "$func" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" . \
|
|
103
|
+
| grep -v node_modules | grep -v "$file" | head -3)
|
|
104
|
+
if [ -n "$MATCHES" ]; then
|
|
105
|
+
echo "⚠️ '$func' in $file also appears in:"
|
|
106
|
+
echo " $MATCHES"
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
done
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. New Dependency Audit
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Check if package.json was modified
|
|
116
|
+
if git diff --name-only main...HEAD | grep -q "package.json"; then
|
|
117
|
+
echo "=== New Dependencies ==="
|
|
118
|
+
# Show what was added to dependencies
|
|
119
|
+
git diff main...HEAD -- package.json | grep "^+" | grep -v "^+++" | grep -E '"[^"]+":' | head -20
|
|
120
|
+
|
|
121
|
+
echo ""
|
|
122
|
+
echo "=== Dependency diff ==="
|
|
123
|
+
# Count before and after
|
|
124
|
+
BEFORE=$(git show main:package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('dependencies',{})))" 2>/dev/null || echo "?")
|
|
125
|
+
AFTER=$(cat package.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('dependencies',{})))")
|
|
126
|
+
echo "Dependencies before: $BEFORE → after: $AFTER"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# Same for Python
|
|
130
|
+
if git diff --name-only main...HEAD | grep -q "requirements.txt"; then
|
|
131
|
+
echo "=== New Python Dependencies ==="
|
|
132
|
+
git diff main...HEAD -- requirements.txt | grep "^+" | grep -v "^+++"
|
|
133
|
+
fi
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For each new dependency, ask: Is this necessary? Does the project already have something that does the same thing?
|
|
137
|
+
|
|
138
|
+
### 5. Error Handling Audit on Diff
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
echo "=== Error handling in changed code ==="
|
|
142
|
+
|
|
143
|
+
# Get the actual diff content
|
|
144
|
+
DIFF=$(git diff main...HEAD -- $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx|py)$' | grep -v node_modules))
|
|
145
|
+
|
|
146
|
+
# Check for empty catch blocks in new code
|
|
147
|
+
echo "$DIFF" | grep "^+" | grep -E "catch.*\{" -A 2 | grep -E "^\+\s*\}" | head -10
|
|
148
|
+
if [ $? -eq 0 ]; then
|
|
149
|
+
echo "🔴 Empty catch blocks found in new code"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Check for console.log-only error handling
|
|
153
|
+
echo "$DIFF" | grep "^+" | grep -B1 -A3 "catch" | grep "console\.\(log\|error\)" | head -10
|
|
154
|
+
if [ $? -eq 0 ]; then
|
|
155
|
+
echo "🟡 Console-only error handling in new code"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Check for TODO/FIXME in new code
|
|
159
|
+
echo "$DIFF" | grep "^+" | grep -i "TODO\|FIXME\|HACK\|XXX" | head -10
|
|
160
|
+
if [ $? -eq 0 ]; then
|
|
161
|
+
echo "🟡 TODO/FIXME markers in new code — unfinished work"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# Check for missing null/undefined checks on new function params
|
|
165
|
+
echo "$DIFF" | grep "^+" | grep -E "function|=>\s*\{" | head -10
|
|
166
|
+
echo "(Review above functions for parameter validation)"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 6. Test Coverage for Changed Files
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
echo "=== Test coverage for changed files ==="
|
|
173
|
+
|
|
174
|
+
for file in $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$' | grep -v node_modules | grep -v test | grep -v spec); do
|
|
175
|
+
BASENAME=$(basename "$file" | sed 's/\.\(ts\|tsx\|js\|jsx\)$//')
|
|
176
|
+
TEST_EXISTS=$(find . -name "${BASENAME}.test.*" -o -name "${BASENAME}.spec.*" | grep -v node_modules | head -1)
|
|
177
|
+
|
|
178
|
+
if [ -n "$TEST_EXISTS" ]; then
|
|
179
|
+
# Check if test file was also updated
|
|
180
|
+
if echo "$CHANGED" | grep -q "$TEST_EXISTS"; then
|
|
181
|
+
echo "🟢 $file — test exists AND was updated"
|
|
182
|
+
else
|
|
183
|
+
echo "🟡 $file — test exists but was NOT updated with this change"
|
|
184
|
+
fi
|
|
185
|
+
else
|
|
186
|
+
echo "🔴 $file — no corresponding test file found"
|
|
187
|
+
fi
|
|
188
|
+
done
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 7. Coupling Analysis
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
echo "=== Cross-module impact ==="
|
|
195
|
+
|
|
196
|
+
# Count how many different directories the PR touches
|
|
197
|
+
DIRS=$(git diff --name-only main...HEAD | grep -v node_modules | xargs -I{} dirname {} | sort -u)
|
|
198
|
+
DIR_COUNT=$(echo "$DIRS" | wc -l)
|
|
199
|
+
echo "Directories touched: $DIR_COUNT"
|
|
200
|
+
echo "$DIRS"
|
|
201
|
+
|
|
202
|
+
if [ "$DIR_COUNT" -gt 5 ]; then
|
|
203
|
+
echo "🔴 High cross-module impact — this PR reaches across $DIR_COUNT directories"
|
|
204
|
+
echo " Consider breaking into smaller, focused PRs"
|
|
205
|
+
elif [ "$DIR_COUNT" -gt 3 ]; then
|
|
206
|
+
echo "🟡 Moderate cross-module impact"
|
|
207
|
+
else
|
|
208
|
+
echo "🟢 Focused change"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
echo ""
|
|
212
|
+
echo "=== Import analysis on changed files ==="
|
|
213
|
+
# Show what each changed file imports
|
|
214
|
+
for file in $(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$' | grep -v node_modules); do
|
|
215
|
+
if [ -f "$file" ]; then
|
|
216
|
+
IMPORTS=$(grep "^import" "$file" | wc -l)
|
|
217
|
+
echo "$file — $IMPORTS imports"
|
|
218
|
+
if [ "$IMPORTS" -gt 15 ]; then
|
|
219
|
+
echo " ⚠️ High import count — potential coupling issue"
|
|
220
|
+
fi
|
|
221
|
+
fi
|
|
222
|
+
done
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Report Output
|
|
226
|
+
|
|
227
|
+
Use `references/report-template.md` with the **PR Review** section. The report must answer one clear question: **"Is this safe to merge?"**
|
|
228
|
+
|
|
229
|
+
Verdict options:
|
|
230
|
+
- ✅ **Ship it** — No blocking issues found
|
|
231
|
+
- ⚠️ **Ship with notes** — Minor issues documented, merge is OK but address soon
|
|
232
|
+
- 🛑 **Hold** — Blocking issues that should be fixed before merge
|
|
233
|
+
|
|
234
|
+
Include the specific files and line references for each finding.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Quick Scan Mode
|
|
2
|
+
|
|
3
|
+
A fast health check that gives you a snapshot of project quality in under 5 minutes. No git history needed — just the current state of the codebase.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- First look at a new project
|
|
8
|
+
- "Is my codebase healthy?" type questions
|
|
9
|
+
- Quick assessment before deciding if a deep audit is needed
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
### 1. Detect Stack
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Find project root markers
|
|
17
|
+
ls package.json requirements.txt go.mod Cargo.toml composer.json Gemfile pom.xml build.gradle 2>/dev/null
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Identify: language, framework, package manager, test framework.
|
|
21
|
+
|
|
22
|
+
### 2. File Size Check
|
|
23
|
+
|
|
24
|
+
Flag files that are suspiciously large — a signature of AI-generated code dumping logic into monoliths.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Find files over 400 lines (adjust for language)
|
|
28
|
+
find . -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" -o -name "*.go" -o -name "*.rs" \
|
|
29
|
+
| grep -v node_modules | grep -v __pycache__ | grep -v .next \
|
|
30
|
+
| while read f; do
|
|
31
|
+
lines=$(wc -l < "$f")
|
|
32
|
+
if [ "$lines" -gt 400 ]; then
|
|
33
|
+
echo "⚠️ $f — $lines lines"
|
|
34
|
+
fi
|
|
35
|
+
done
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Thresholds:**
|
|
39
|
+
- 🟢 Under 200 lines: Good
|
|
40
|
+
- 🟡 200–400 lines: Acceptable but watch it
|
|
41
|
+
- 🔴 Over 400 lines: Likely needs decomposition
|
|
42
|
+
|
|
43
|
+
### 3. Function/Method Size Check
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# For TypeScript/JavaScript — find functions over 50 lines
|
|
47
|
+
# This is a heuristic: count lines between function declarations
|
|
48
|
+
grep -rn "function \|const .* = \(.*\) =>\|async function\|export default function\|export function" \
|
|
49
|
+
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
|
|
50
|
+
. | grep -v node_modules | head -50
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For Python:
|
|
54
|
+
```bash
|
|
55
|
+
grep -rn "def " --include="*.py" . | grep -v __pycache__ | head -50
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Manually spot-check the largest files for functions exceeding 50 lines.
|
|
59
|
+
|
|
60
|
+
### 4. Dependency Count
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Node.js
|
|
64
|
+
cat package.json | python3 -c "
|
|
65
|
+
import sys, json
|
|
66
|
+
pkg = json.load(sys.stdin)
|
|
67
|
+
deps = len(pkg.get('dependencies', {}))
|
|
68
|
+
dev = len(pkg.get('devDependencies', {}))
|
|
69
|
+
print(f'Dependencies: {deps}')
|
|
70
|
+
print(f'Dev dependencies: {dev}')
|
|
71
|
+
print(f'Total: {deps + dev}')
|
|
72
|
+
if deps > 30: print('⚠️ High dependency count — review for unnecessary packages')
|
|
73
|
+
"
|
|
74
|
+
|
|
75
|
+
# Python
|
|
76
|
+
pip list 2>/dev/null | wc -l
|
|
77
|
+
# or
|
|
78
|
+
cat requirements.txt 2>/dev/null | grep -v "^#" | grep -v "^$" | wc -l
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Thresholds (production deps only):**
|
|
82
|
+
- 🟢 Under 15: Lean
|
|
83
|
+
- 🟡 15–30: Normal
|
|
84
|
+
- 🔴 Over 30: Review for bloat — AI agents over-install
|
|
85
|
+
|
|
86
|
+
### 5. Dead Import Detection
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# For TypeScript/JavaScript projects with knip installed
|
|
90
|
+
npx knip --no-exit-code 2>/dev/null || echo "Install knip: npm install -D knip"
|
|
91
|
+
|
|
92
|
+
# Quick alternative: find unused exports
|
|
93
|
+
npx ts-unused-exports tsconfig.json 2>/dev/null || true
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For Python:
|
|
97
|
+
```bash
|
|
98
|
+
# Check if vulture is available, suggest install if not
|
|
99
|
+
python3 -m vulture . --min-confidence 80 2>/dev/null || echo "Install vulture: pip install vulture"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 6. Error Handling Audit
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Find empty or weak catch blocks
|
|
106
|
+
echo "=== Empty catch blocks ==="
|
|
107
|
+
grep -rn "catch" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" -A 2 . \
|
|
108
|
+
| grep -v node_modules \
|
|
109
|
+
| grep -E "catch.*\{$|catch.*\{\s*\}" | head -20
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
echo "=== Console.log-only error handling ==="
|
|
113
|
+
grep -rn "catch" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" -A 3 . \
|
|
114
|
+
| grep -v node_modules \
|
|
115
|
+
| grep -B1 "console\.\(log\|error\)" | head -20
|
|
116
|
+
|
|
117
|
+
echo ""
|
|
118
|
+
echo "=== TODO/FIXME/HACK markers ==="
|
|
119
|
+
grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" --include="*.py" . \
|
|
120
|
+
| grep -v node_modules | grep -v __pycache__ | head -20
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 7. Test Presence Check
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Check if tests exist at all
|
|
127
|
+
echo "=== Test files ==="
|
|
128
|
+
find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" -o -name "*_test.*" \
|
|
129
|
+
| grep -v node_modules | grep -v __pycache__
|
|
130
|
+
|
|
131
|
+
echo ""
|
|
132
|
+
echo "=== Test file count vs source file count ==="
|
|
133
|
+
SRC=$(find . -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" \
|
|
134
|
+
| grep -v node_modules | grep -v __pycache__ | grep -v test | grep -v spec | wc -l)
|
|
135
|
+
TEST=$(find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" -o -name "*_test.*" \
|
|
136
|
+
| grep -v node_modules | grep -v __pycache__ | wc -l)
|
|
137
|
+
echo "Source files: $SRC"
|
|
138
|
+
echo "Test files: $TEST"
|
|
139
|
+
if [ "$TEST" -eq 0 ]; then
|
|
140
|
+
echo "🔴 No tests found"
|
|
141
|
+
elif [ "$TEST" -lt "$((SRC / 3))" ]; then
|
|
142
|
+
echo "🟡 Low test coverage — fewer than 1 test file per 3 source files"
|
|
143
|
+
else
|
|
144
|
+
echo "🟢 Reasonable test file count"
|
|
145
|
+
fi
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 8. Architectural Pattern Detection
|
|
149
|
+
|
|
150
|
+
Scan for common patterns to check consistency:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
echo "=== Framework patterns detected ==="
|
|
154
|
+
# React patterns
|
|
155
|
+
grep -rl "useEffect\|useState\|useContext" --include="*.tsx" --include="*.jsx" . 2>/dev/null | wc -l | xargs -I{} echo "React hooks files: {}"
|
|
156
|
+
grep -rl "class.*extends.*Component" --include="*.tsx" --include="*.jsx" . 2>/dev/null | wc -l | xargs -I{} echo "React class component files: {}"
|
|
157
|
+
|
|
158
|
+
# API patterns
|
|
159
|
+
grep -rl "express\|app\.get\|app\.post\|router\." --include="*.ts" --include="*.js" . 2>/dev/null | wc -l | xargs -I{} echo "Express route files: {}"
|
|
160
|
+
grep -rl "NextResponse\|NextRequest" --include="*.ts" --include="*.js" . 2>/dev/null | wc -l | xargs -I{} echo "Next.js API route files: {}"
|
|
161
|
+
|
|
162
|
+
# State management
|
|
163
|
+
grep -rl "createSlice\|configureStore" --include="*.ts" --include="*.js" . 2>/dev/null | wc -l | xargs -I{} echo "Redux files: {}"
|
|
164
|
+
grep -rl "create.*store\|zustand" --include="*.ts" --include="*.js" . 2>/dev/null | wc -l | xargs -I{} echo "Zustand files: {}"
|
|
165
|
+
grep -rl "useContext\|createContext" --include="*.tsx" --include="*.jsx" . 2>/dev/null | wc -l | xargs -I{} echo "Context API files: {}"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
If multiple competing patterns are found (e.g., both Redux AND Zustand, or both class components AND hooks), flag as architectural inconsistency.
|
|
169
|
+
|
|
170
|
+
## Report Output
|
|
171
|
+
|
|
172
|
+
Use the template from `references/report-template.md` with the **Quick Scan** section. Produce a severity-sorted summary:
|
|
173
|
+
|
|
174
|
+
- 🔴 **Critical** — Will cause problems soon (no tests, empty error handling, massive files)
|
|
175
|
+
- 🟡 **Warning** — Technical debt accumulating (high deps, mild duplication, mixed patterns)
|
|
176
|
+
- 🟢 **Healthy** — No action needed
|
|
177
|
+
|
|
178
|
+
End with a plain-language summary: "If this were a building inspection, here's what I'd flag..."
|