codingbuddy-rules 4.2.0 → 4.4.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/.ai-rules/adapters/antigravity.md +648 -160
- package/.ai-rules/adapters/codex.md +500 -10
- package/.ai-rules/adapters/cursor.md +252 -8
- package/.ai-rules/adapters/kiro.md +551 -93
- package/.ai-rules/adapters/opencode-skills.md +179 -188
- package/.ai-rules/adapters/opencode.md +251 -47
- package/.ai-rules/agents/README.md +179 -9
- package/.ai-rules/agents/act-mode.json +14 -7
- package/.ai-rules/agents/data-scientist.json +156 -0
- package/.ai-rules/agents/security-engineer.json +98 -0
- package/.ai-rules/agents/software-engineer.json +74 -0
- package/.ai-rules/agents/systems-developer.json +83 -0
- package/.ai-rules/agents/test-engineer.json +69 -0
- package/.ai-rules/skills/README.md +92 -24
- package/.ai-rules/skills/agent-design/SKILL.md +269 -0
- package/.ai-rules/skills/code-explanation/SKILL.md +259 -0
- package/.ai-rules/skills/context-management/SKILL.md +244 -0
- package/.ai-rules/skills/deployment-checklist/SKILL.md +233 -0
- package/.ai-rules/skills/documentation-generation/SKILL.md +293 -0
- package/.ai-rules/skills/error-analysis/SKILL.md +250 -0
- package/.ai-rules/skills/legacy-modernization/SKILL.md +292 -0
- package/.ai-rules/skills/mcp-builder/SKILL.md +356 -0
- package/.ai-rules/skills/prompt-engineering/SKILL.md +318 -0
- package/.ai-rules/skills/rule-authoring/SKILL.md +273 -0
- package/.ai-rules/skills/security-audit/SKILL.md +241 -0
- package/.ai-rules/skills/tech-debt/SKILL.md +224 -0
- package/package.json +1 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-analysis
|
|
3
|
+
description: Use when encountering error messages, stack traces, or unexpected application behavior. Provides structured analysis to understand root cause before attempting any fix.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Error Analysis
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Errors are information. Stack traces are maps. Reading them carefully reveals root cause faster than guessing.
|
|
11
|
+
|
|
12
|
+
**Core principle:** Classify the error before diagnosing it. Different error classes have different diagnostic approaches.
|
|
13
|
+
|
|
14
|
+
**Relationship to systematic-debugging:** Use `error-analysis` to understand WHAT the error is and WHERE it originates. Use `systematic-debugging` to find WHY it happens and implement the fix.
|
|
15
|
+
|
|
16
|
+
**Iron Law:**
|
|
17
|
+
```
|
|
18
|
+
READ THE ENTIRE STACK TRACE BEFORE FORMING ANY HYPOTHESIS
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The answer is almost always in the error message. Most debugging failures are reading failures.
|
|
22
|
+
|
|
23
|
+
## When to Use
|
|
24
|
+
|
|
25
|
+
- Encountering a new error message
|
|
26
|
+
- Stack trace from production logs
|
|
27
|
+
- Unexpected application behavior (silent failure)
|
|
28
|
+
- CI/CD pipeline failures
|
|
29
|
+
- Type errors, runtime errors, build errors
|
|
30
|
+
|
|
31
|
+
## Error Classification
|
|
32
|
+
|
|
33
|
+
First, classify the error type:
|
|
34
|
+
|
|
35
|
+
| Class | Symptoms | Common Causes |
|
|
36
|
+
|-------|----------|--------------|
|
|
37
|
+
| **Syntax Error** | Fails at parse/compile time | Typo, missing bracket, wrong syntax |
|
|
38
|
+
| **Type Error** | TypeScript compiler error | Wrong type, missing null check |
|
|
39
|
+
| **Runtime Error** | Fails during execution | Null reference, division by zero |
|
|
40
|
+
| **Logic Error** | Wrong output, no crash | Algorithm mistake, off-by-one |
|
|
41
|
+
| **Network Error** | Connection failures | Service down, timeout, firewall |
|
|
42
|
+
| **Config Error** | App won't start | Missing env var, wrong path |
|
|
43
|
+
| **Concurrency Error** | Intermittent failures | Race condition, deadlock |
|
|
44
|
+
| **Memory Error** | Growing memory, crash | Memory leak, large allocation |
|
|
45
|
+
|
|
46
|
+
## Reading Stack Traces
|
|
47
|
+
|
|
48
|
+
### Anatomy of a Stack Trace
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Error: Cannot read properties of undefined (reading 'name') ← Error type + message
|
|
52
|
+
at RulesService.getRule (/app/src/rules/rules.service.ts:42:18) ← Closest to error
|
|
53
|
+
at McpService.handleTool (/app/src/mcp/mcp.service.ts:87:32)
|
|
54
|
+
at McpModule.dispatch (/app/src/mcp/mcp.module.ts:23:12) ← Furthest from error
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Reading order:**
|
|
58
|
+
1. **Error message** — WHAT went wrong
|
|
59
|
+
2. **First frame** — WHERE it broke (your code closest to error)
|
|
60
|
+
3. **Subsequent frames** — HOW we got there (call chain)
|
|
61
|
+
4. **Last frame** — ENTRY POINT that triggered the chain
|
|
62
|
+
|
|
63
|
+
### Stack Trace Analysis Template
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
## Error Analysis
|
|
67
|
+
|
|
68
|
+
**Error type:** [TypeError / ReferenceError / etc.]
|
|
69
|
+
**Error message:** [Exact message]
|
|
70
|
+
**File:** [filename:line:column]
|
|
71
|
+
**Function:** [function where error occurred]
|
|
72
|
+
|
|
73
|
+
**Call chain:** (read bottom to top)
|
|
74
|
+
1. Entry: [how it started]
|
|
75
|
+
2. → [intermediate call]
|
|
76
|
+
3. → [proximate cause]
|
|
77
|
+
|
|
78
|
+
**Initial hypothesis:** [What do I think is undefined/null/wrong?]
|
|
79
|
+
**Evidence needed:** [What do I need to verify the hypothesis?]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Common Error Patterns
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// ❌ "Cannot read properties of undefined (reading 'X')"
|
|
86
|
+
// → Something is undefined that you expected to exist
|
|
87
|
+
// → Look at the line: what object is being accessed?
|
|
88
|
+
// → Trace back: where was this object supposed to come from?
|
|
89
|
+
|
|
90
|
+
const user = await getUser(id);
|
|
91
|
+
console.log(user.name); // → user is undefined when id not found
|
|
92
|
+
// Fix: check if user exists before accessing properties
|
|
93
|
+
|
|
94
|
+
// ❌ "is not a function"
|
|
95
|
+
// → Called something that isn't a function
|
|
96
|
+
// → Often: wrong import, undefined module, this binding issue
|
|
97
|
+
import { something } from './module'; // wrong path → undefined
|
|
98
|
+
something(); // → TypeError: something is not a function
|
|
99
|
+
|
|
100
|
+
// ❌ "Cannot find module"
|
|
101
|
+
// → Module doesn't exist at specified path
|
|
102
|
+
// → Check: path correct? file exists? compiled?
|
|
103
|
+
|
|
104
|
+
// ❌ "ENOENT: no such file or directory"
|
|
105
|
+
// → File system path doesn't exist
|
|
106
|
+
// → Check: relative vs absolute path, working directory
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Diagnostic Process
|
|
110
|
+
|
|
111
|
+
### Phase 1: Classify and Locate
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
1. What class of error is this? (see table above)
|
|
115
|
+
2. What file and line number? (first frame in stack)
|
|
116
|
+
3. What was the application doing when it failed?
|
|
117
|
+
(context: which API endpoint, which user action, which test)
|
|
118
|
+
4. Is it reproducible? (always / sometimes / once)
|
|
119
|
+
5. When did it start? (new error or regression?)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Phase 2: Understand the Context
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// For "Cannot read properties of undefined"
|
|
126
|
+
// Add temporary logging to understand what's actually there:
|
|
127
|
+
|
|
128
|
+
// Before:
|
|
129
|
+
const result = await this.rulesService.getRule(name);
|
|
130
|
+
return result.content; // ← crashes
|
|
131
|
+
|
|
132
|
+
// Add logging:
|
|
133
|
+
const result = await this.rulesService.getRule(name);
|
|
134
|
+
console.error('DEBUG result:', JSON.stringify(result, null, 2));
|
|
135
|
+
return result.content;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Common context questions:**
|
|
139
|
+
- What is the actual value vs expected value?
|
|
140
|
+
- What are the function inputs?
|
|
141
|
+
- What state was the application in?
|
|
142
|
+
- Is this error path tested?
|
|
143
|
+
|
|
144
|
+
### Phase 3: Trace to Origin
|
|
145
|
+
|
|
146
|
+
Follow the error backward through the call chain:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Frame 1: rules.service.ts:42 — result.content crashes
|
|
150
|
+
→ result is undefined
|
|
151
|
+
→ What could make getRule return undefined?
|
|
152
|
+
|
|
153
|
+
Frame 2: rules.service.ts:35 — find() returns undefined when no match
|
|
154
|
+
→ Why didn't it find the rule?
|
|
155
|
+
|
|
156
|
+
Frame 3: rules.service.ts:28 — rules array
|
|
157
|
+
→ How was rules array populated?
|
|
158
|
+
→ Ah: readRulesDirectory() failed silently on missing directory
|
|
159
|
+
→ ROOT CAUSE: directory path wrong, no error thrown
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Phase 4: Form Hypothesis
|
|
163
|
+
|
|
164
|
+
```markdown
|
|
165
|
+
**Hypothesis:** [Specific, testable statement]
|
|
166
|
+
|
|
167
|
+
Example: "The rules directory path is built from `__dirname` which
|
|
168
|
+
resolves to the dist/ folder in production, but .ai-rules is at
|
|
169
|
+
the project root, so the path is wrong."
|
|
170
|
+
|
|
171
|
+
**Evidence to gather:**
|
|
172
|
+
- Log the actual `rulesDir` path at startup
|
|
173
|
+
- Check if directory exists at that path in production
|
|
174
|
+
|
|
175
|
+
**Falsification:** If the path is correct, this hypothesis is wrong
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Error Catalog
|
|
179
|
+
|
|
180
|
+
### TypeScript Errors
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// TS2345: Argument of type 'X' is not assignable to parameter of type 'Y'
|
|
184
|
+
// → Type mismatch. Use explicit casting only if you know the type is correct.
|
|
185
|
+
|
|
186
|
+
// TS2339: Property 'X' does not exist on type 'Y'
|
|
187
|
+
// → Accessing property that doesn't exist. Check interface definition.
|
|
188
|
+
|
|
189
|
+
// TS7006: Parameter 'X' implicitly has an 'any' type
|
|
190
|
+
// → TypeScript strict mode requires explicit types. Add the type.
|
|
191
|
+
|
|
192
|
+
// TS2532: Object is possibly 'undefined'
|
|
193
|
+
// → Add null check: if (x !== undefined) or use optional chaining x?.y
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Node.js Runtime Errors
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
ECONNREFUSED → Service not running or wrong port
|
|
200
|
+
EADDRINUSE → Port already in use
|
|
201
|
+
ENOENT → File/directory doesn't exist
|
|
202
|
+
EMFILE → Too many open file handles (leak)
|
|
203
|
+
ENOMEM → Out of memory
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### NestJS / MCP Errors
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// "Nest can't resolve dependencies"
|
|
210
|
+
// → Circular dependency or missing provider in module
|
|
211
|
+
// → Check: is the service in the module's providers array?
|
|
212
|
+
|
|
213
|
+
// "Cannot GET /endpoint" (404)
|
|
214
|
+
// → Route not registered or wrong HTTP method
|
|
215
|
+
// → Check: @Controller prefix + @Get/Post path
|
|
216
|
+
|
|
217
|
+
// MCP: "Method not found"
|
|
218
|
+
// → Tool/Resource/Prompt name not registered
|
|
219
|
+
// → Check: capability registration in McpService
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Quick Reference
|
|
223
|
+
|
|
224
|
+
| Error Pattern | First Check |
|
|
225
|
+
|--------------|------------|
|
|
226
|
+
| `undefined reading 'X'` | What should X be? Where does it come from? |
|
|
227
|
+
| `is not a function` | Is the import correct? Is it actually exported? |
|
|
228
|
+
| `Cannot find module` | Does the file exist? Is the path correct? |
|
|
229
|
+
| `ENOENT` | Is the file path absolute? Does it exist? |
|
|
230
|
+
| Intermittent failure | Is there shared mutable state? Race condition? |
|
|
231
|
+
| Works locally, fails in CI | Environment variable missing? Path difference? |
|
|
232
|
+
|
|
233
|
+
## Output Format
|
|
234
|
+
|
|
235
|
+
```markdown
|
|
236
|
+
## Error Analysis Summary
|
|
237
|
+
|
|
238
|
+
**Error:** [class] — [message]
|
|
239
|
+
**Location:** [file:line]
|
|
240
|
+
**Reproducible:** Yes / No / Intermittent
|
|
241
|
+
|
|
242
|
+
**Root Cause:** [One clear sentence]
|
|
243
|
+
|
|
244
|
+
**Evidence:** [What confirms the root cause]
|
|
245
|
+
|
|
246
|
+
**Fix:** [What needs to change]
|
|
247
|
+
**Prevents recurrence:** [Test to add or check to add]
|
|
248
|
+
|
|
249
|
+
→ Hand off to systematic-debugging skill for implementation
|
|
250
|
+
```
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legacy-modernization
|
|
3
|
+
description: Use when modernizing legacy code or migrating outdated patterns to current best practices. Covers assessment, strangler fig pattern, incremental migration, and risk management.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legacy Modernization
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Legacy code isn't bad code — it's code that solved a real problem when it was written. Modernization is the process of adapting it to current requirements without breaking what works.
|
|
11
|
+
|
|
12
|
+
**Core principle:** Never rewrite from scratch. Strangle it incrementally. Each step must leave the system in a working state.
|
|
13
|
+
|
|
14
|
+
**Iron Law:**
|
|
15
|
+
```
|
|
16
|
+
THE SYSTEM MUST WORK AFTER EVERY CHANGE
|
|
17
|
+
There is no "temporarily broken while we modernize"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- Migrating from CommonJS to ESM
|
|
23
|
+
- Upgrading major framework versions (NestJS 9 → 10)
|
|
24
|
+
- Replacing callback patterns with async/await
|
|
25
|
+
- Moving from JavaScript to TypeScript
|
|
26
|
+
- Replacing deprecated APIs
|
|
27
|
+
- Architectural migration (monolith → modules)
|
|
28
|
+
|
|
29
|
+
## Assessment Phase
|
|
30
|
+
|
|
31
|
+
### Inventory
|
|
32
|
+
|
|
33
|
+
Before any changes, understand what you have:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Size and complexity
|
|
37
|
+
find src/ -name "*.ts" -o -name "*.js" | \
|
|
38
|
+
xargs wc -l | sort -rn | head -20
|
|
39
|
+
|
|
40
|
+
# Dependency graph
|
|
41
|
+
npx madge --circular src/
|
|
42
|
+
|
|
43
|
+
# Test coverage (what's protected)
|
|
44
|
+
npx jest --coverage --coverageReporters text-summary
|
|
45
|
+
|
|
46
|
+
# Outdated packages
|
|
47
|
+
npm outdated
|
|
48
|
+
|
|
49
|
+
# Known patterns to modernize
|
|
50
|
+
grep -rn "require\(" src/ --include="*.ts" | wc -l # CommonJS in TypeScript
|
|
51
|
+
grep -rn "callback\|\.then\|\.catch" src/ --include="*.ts" | wc -l # Promises vs async
|
|
52
|
+
grep -rn ": any" src/ --include="*.ts" | wc -l # Untyped code
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Risk Assessment
|
|
56
|
+
|
|
57
|
+
Rate each area for modernization risk:
|
|
58
|
+
|
|
59
|
+
```markdown
|
|
60
|
+
## Modernization Risk Register
|
|
61
|
+
|
|
62
|
+
| Module | Lines | Test Coverage | External Deps | Criticality | Risk |
|
|
63
|
+
|--------|-------|---------------|---------------|-------------|------|
|
|
64
|
+
| rules.service.ts | 120 | 85% | None | High | LOW |
|
|
65
|
+
| mcp.service.ts | 450 | 45% | MCP SDK | High | HIGH |
|
|
66
|
+
| main.ts | 60 | 0% | NestJS | Medium | MEDIUM |
|
|
67
|
+
|
|
68
|
+
Risk = (Criticality × (100 - Coverage%)) / 100
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Modernization Backlog
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
## Modernization Items
|
|
75
|
+
|
|
76
|
+
| ID | Pattern | Count | Files | Effort |
|
|
77
|
+
|----|---------|-------|-------|--------|
|
|
78
|
+
| M-001 | `any` type → explicit types | 23 | 8 files | 2h |
|
|
79
|
+
| M-002 | Callbacks → async/await | 12 | 4 files | 4h |
|
|
80
|
+
| M-003 | CommonJS → ESM imports | 45 | 15 files | 1h |
|
|
81
|
+
| M-004 | NestJS 9 → NestJS 10 | 1 | package.json | 8h |
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Migration Strategies
|
|
85
|
+
|
|
86
|
+
### Strategy 1: Strangler Fig (Recommended)
|
|
87
|
+
|
|
88
|
+
Build new behavior alongside old behavior, gradually replacing old with new.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Phase 1: New implementation behind feature flag
|
|
92
|
+
async getRules(): Promise<Rule[]> {
|
|
93
|
+
if (process.env.USE_NEW_RULES_ENGINE === 'true') {
|
|
94
|
+
return this.newRulesEngine.getRules(); // New implementation
|
|
95
|
+
}
|
|
96
|
+
return this.legacyGetRules(); // Old implementation still works
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Phase 2: Enable in staging, verify
|
|
100
|
+
// Phase 3: Enable in production (10% → 50% → 100%)
|
|
101
|
+
// Phase 4: Remove old implementation
|
|
102
|
+
async getRules(): Promise<Rule[]> {
|
|
103
|
+
return this.newRulesEngine.getRules(); // Old code removed
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Strategy 2: Branch by Abstraction
|
|
108
|
+
|
|
109
|
+
1. Create abstraction over legacy code
|
|
110
|
+
2. Implement new code behind abstraction
|
|
111
|
+
3. Switch abstraction to new code
|
|
112
|
+
4. Remove old code
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Step 1: Introduce interface
|
|
116
|
+
interface RulesEngine {
|
|
117
|
+
getRules(): Promise<Rule[]>;
|
|
118
|
+
searchRules(query: string): Promise<Rule[]>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Step 2: Wrap legacy code
|
|
122
|
+
class LegacyRulesEngine implements RulesEngine {
|
|
123
|
+
// Existing code, now behind interface
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Step 3: New implementation
|
|
127
|
+
class NewRulesEngine implements RulesEngine {
|
|
128
|
+
// Modern implementation
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Step 4: Switch (one line change)
|
|
132
|
+
const rulesEngine: RulesEngine = new NewRulesEngine();
|
|
133
|
+
// Was: new LegacyRulesEngine()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Common Modernization Patterns
|
|
137
|
+
|
|
138
|
+
### JavaScript → TypeScript
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Before (JavaScript)
|
|
142
|
+
function getUser(id) {
|
|
143
|
+
return fetch('/api/users/' + id)
|
|
144
|
+
.then(function(response) {
|
|
145
|
+
return response.json();
|
|
146
|
+
})
|
|
147
|
+
.then(function(data) {
|
|
148
|
+
return data.user;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// After (TypeScript + async/await)
|
|
155
|
+
async function getUser(id: string): Promise<User> {
|
|
156
|
+
const response = await fetch(`/api/users/${id}`);
|
|
157
|
+
const data: { user: User } = await response.json();
|
|
158
|
+
return data.user;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Callbacks → Async/Await
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
// Before (callbacks)
|
|
166
|
+
function readRule(path, callback) {
|
|
167
|
+
fs.readFile(path, 'utf8', function(err, content) {
|
|
168
|
+
if (err) return callback(err);
|
|
169
|
+
callback(null, parseRule(content));
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// After (async/await)
|
|
176
|
+
async function readRule(path: string): Promise<Rule> {
|
|
177
|
+
const content = await fs.promises.readFile(path, 'utf-8');
|
|
178
|
+
return parseRule(content);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Removing `any` Types
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Before
|
|
186
|
+
function processRule(rule: any): any {
|
|
187
|
+
return { name: rule.name, content: rule.content };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// After (step 1: define interface)
|
|
191
|
+
interface RuleInput {
|
|
192
|
+
name: string;
|
|
193
|
+
content: string;
|
|
194
|
+
[key: string]: unknown; // allow extra properties
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface ProcessedRule {
|
|
198
|
+
name: string;
|
|
199
|
+
content: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// After (step 2: type the function)
|
|
203
|
+
function processRule(rule: RuleInput): ProcessedRule {
|
|
204
|
+
return { name: rule.name, content: rule.content };
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Safe Migration Process
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
For EACH modernization item:
|
|
212
|
+
|
|
213
|
+
1. WRITE TESTS (if coverage < 80%)
|
|
214
|
+
- Tests must cover current behavior
|
|
215
|
+
- These tests protect against regression
|
|
216
|
+
|
|
217
|
+
2. MODERNIZE one file at a time
|
|
218
|
+
- Apply pattern change
|
|
219
|
+
- Keep behavior identical
|
|
220
|
+
|
|
221
|
+
3. RUN ALL TESTS
|
|
222
|
+
- All existing tests must still pass
|
|
223
|
+
- No "we'll fix the tests later"
|
|
224
|
+
|
|
225
|
+
4. COMMIT
|
|
226
|
+
- One commit per file or per pattern type
|
|
227
|
+
- Message: "refactor: migrate X to Y in Z"
|
|
228
|
+
|
|
229
|
+
5. VERIFY in staging before next item
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Version Upgrade Process (Major Versions)
|
|
233
|
+
|
|
234
|
+
```markdown
|
|
235
|
+
## NestJS 9 → 10 Migration Plan
|
|
236
|
+
|
|
237
|
+
### Preparation
|
|
238
|
+
- [ ] Read migration guide: https://docs.nestjs.com/migration-guide
|
|
239
|
+
- [ ] Test suite at 80%+ coverage
|
|
240
|
+
- [ ] Feature branch created
|
|
241
|
+
|
|
242
|
+
### Steps
|
|
243
|
+
1. [ ] Update peer dependencies first
|
|
244
|
+
2. [ ] Update NestJS packages
|
|
245
|
+
3. [ ] Fix breaking API changes (see migration guide)
|
|
246
|
+
4. [ ] Run test suite
|
|
247
|
+
5. [ ] Fix type errors
|
|
248
|
+
6. [ ] Test in staging
|
|
249
|
+
7. [ ] Deploy to production
|
|
250
|
+
|
|
251
|
+
### Rollback
|
|
252
|
+
- git revert to previous package.json
|
|
253
|
+
- npm install
|
|
254
|
+
- Deploy previous version
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Risk Mitigation
|
|
258
|
+
|
|
259
|
+
| Risk | Mitigation |
|
|
260
|
+
|------|-----------|
|
|
261
|
+
| Breaking working functionality | Write tests before modernizing |
|
|
262
|
+
| Long migration blocks features | Use strangler fig pattern |
|
|
263
|
+
| Merge conflicts | Small, frequent commits |
|
|
264
|
+
| Regression in edge cases | Test coverage for edge cases first |
|
|
265
|
+
| Team unfamiliar with new patterns | Document new patterns + pair programming |
|
|
266
|
+
|
|
267
|
+
## Red Flags — STOP
|
|
268
|
+
|
|
269
|
+
| Thought | Reality |
|
|
270
|
+
|---------|---------|
|
|
271
|
+
| "Let's rewrite it from scratch" | Rewrites take 3× longer and miss edge cases |
|
|
272
|
+
| "We'll fix tests later" | Tests are the safety net — fix them now |
|
|
273
|
+
| "One big refactoring PR" | Small PRs are safer and reviewable |
|
|
274
|
+
| "The new code is obviously correct" | Verify with tests, not confidence |
|
|
275
|
+
| "We can modernize while adding features" | Keep modernization commits separate |
|
|
276
|
+
|
|
277
|
+
## Quick Reference
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
Migration Patterns:
|
|
281
|
+
──────────────────────────────
|
|
282
|
+
Strangler Fig → New code wraps old, gradual replacement
|
|
283
|
+
Branch by Abstraction → Interface first, then implementations
|
|
284
|
+
Parallel Run → Old and new run simultaneously, compare results
|
|
285
|
+
Expand-Contract → Database: add new → migrate → remove old
|
|
286
|
+
|
|
287
|
+
Priority Order:
|
|
288
|
+
──────────────────────────────
|
|
289
|
+
1. Highest risk (low coverage, high criticality) → test first
|
|
290
|
+
2. Quick wins (high impact, low effort)
|
|
291
|
+
3. Architectural changes (last, requires stability)
|
|
292
|
+
```
|