sdlc-framework 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/LICENSE +21 -0
- package/README.md +321 -0
- package/bin/install.js +193 -0
- package/package.json +39 -0
- package/src/commands/close.md +200 -0
- package/src/commands/debug.md +124 -0
- package/src/commands/fast.md +149 -0
- package/src/commands/fix.md +104 -0
- package/src/commands/help.md +144 -0
- package/src/commands/hotfix.md +99 -0
- package/src/commands/impl.md +142 -0
- package/src/commands/init.md +93 -0
- package/src/commands/milestone.md +136 -0
- package/src/commands/pause.md +115 -0
- package/src/commands/research.md +136 -0
- package/src/commands/resume.md +103 -0
- package/src/commands/review.md +195 -0
- package/src/commands/spec.md +164 -0
- package/src/commands/status.md +118 -0
- package/src/commands/verify.md +153 -0
- package/src/references/clarification-strategy.md +352 -0
- package/src/references/engineering-laws.md +374 -0
- package/src/references/loop-phases.md +331 -0
- package/src/references/playwright-testing.md +298 -0
- package/src/references/prompt-detection.md +264 -0
- package/src/references/sub-agent-strategy.md +260 -0
- package/src/rules/commands.md +180 -0
- package/src/rules/style.md +354 -0
- package/src/rules/templates.md +238 -0
- package/src/rules/workflows.md +314 -0
- package/src/templates/HANDOFF.md +121 -0
- package/src/templates/LAWS.md +521 -0
- package/src/templates/PROJECT.md +112 -0
- package/src/templates/REVIEW.md +145 -0
- package/src/templates/ROADMAP.md +101 -0
- package/src/templates/SPEC.md +231 -0
- package/src/templates/STATE.md +106 -0
- package/src/templates/SUMMARY.md +126 -0
- package/src/workflows/close-phase.md +189 -0
- package/src/workflows/debug-flow.md +302 -0
- package/src/workflows/fast-forward.md +340 -0
- package/src/workflows/fix-findings.md +235 -0
- package/src/workflows/hotfix-flow.md +190 -0
- package/src/workflows/impl-phase.md +229 -0
- package/src/workflows/init-project.md +249 -0
- package/src/workflows/milestone-management.md +169 -0
- package/src/workflows/pause-work.md +153 -0
- package/src/workflows/research.md +219 -0
- package/src/workflows/resume-project.md +159 -0
- package/src/workflows/review-phase.md +337 -0
- package/src/workflows/spec-phase.md +379 -0
- package/src/workflows/transition-phase.md +203 -0
- package/src/workflows/verify-phase.md +280 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# Engineering Laws Reference
|
|
2
|
+
|
|
3
|
+
This document provides a deep dive into each engineering law enforced by the SDLC framework. It is loaded via `@references/engineering-laws.md` when reviewing code or when a developer needs to understand why a law exists and how it applies to AI-assisted development.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## SOLID Principles
|
|
8
|
+
|
|
9
|
+
### Plain English
|
|
10
|
+
|
|
11
|
+
SOLID is five rules for organizing code so it stays flexible as it grows:
|
|
12
|
+
|
|
13
|
+
1. **Single Responsibility (S):** Each piece of code does one thing. A user service handles user logic. It does not also send emails.
|
|
14
|
+
2. **Open/Closed (O):** Add new behavior by writing new code, not by editing existing code. Use interfaces, plugins, or strategy patterns.
|
|
15
|
+
3. **Liskov Substitution (L):** Any implementation of an interface can replace any other without breaking the system.
|
|
16
|
+
4. **Interface Segregation (I):** Do not force code to depend on methods it does not use. Keep interfaces small and focused.
|
|
17
|
+
5. **Dependency Inversion (D):** High-level code depends on abstractions (interfaces), not on low-level details (concrete classes).
|
|
18
|
+
|
|
19
|
+
### How It Applies to AI-Assisted Development
|
|
20
|
+
|
|
21
|
+
AI code generators tend to produce "complete" solutions in a single file. They pack everything together because they optimize for generating a working answer in one shot. This naturally violates Single Responsibility — the AI does not have an incentive to split code across files.
|
|
22
|
+
|
|
23
|
+
AI also tends to create concrete implementations rather than abstractions. When you ask "build a user service," the AI writes `new PostgresRepository()` directly, violating Dependency Inversion. It does not know your project has an injection system.
|
|
24
|
+
|
|
25
|
+
### Common AI-Generated Violations
|
|
26
|
+
|
|
27
|
+
**God service pattern:**
|
|
28
|
+
AI generates a service that handles authentication, profile updates, email notifications, and audit logging all in one class. Each method works, but the class has 400 lines and 6 different reasons to change.
|
|
29
|
+
|
|
30
|
+
**Concrete coupling:**
|
|
31
|
+
```typescript
|
|
32
|
+
// AI writes this because it is "complete" and works immediately
|
|
33
|
+
class OrderService {
|
|
34
|
+
private db = new PostgresClient('postgres://localhost:5432/orders')
|
|
35
|
+
private emailer = new SendGridClient('sg-api-key-here')
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
Two SOLID violations (concrete dependencies) plus a security violation (hardcoded credentials) in two lines.
|
|
39
|
+
|
|
40
|
+
**Fat interfaces:**
|
|
41
|
+
AI creates one interface with every possible method, then forces all implementations to stub out methods they do not need.
|
|
42
|
+
|
|
43
|
+
### How the Reviewer Detects Violations
|
|
44
|
+
|
|
45
|
+
- Counts methods per class. More than 7-8 methods suggests multiple responsibilities.
|
|
46
|
+
- Searches for `new` keyword inside service classes — concrete instantiation signals dependency inversion violations.
|
|
47
|
+
- Checks that every interface has multiple implementations or is designed for future replacement.
|
|
48
|
+
- Verifies that interface methods are all used by at least one consumer.
|
|
49
|
+
|
|
50
|
+
### Real-World Consequences
|
|
51
|
+
|
|
52
|
+
A monolithic service cannot be tested in isolation. To test user creation, you need a real database, a real email provider, and a real audit log. Tests become slow, flaky, and expensive. Developers stop writing them. Bugs ship. Eventually, the team says "we need to rewrite" and the cycle restarts — 3 months of work lost.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## DRY (Don't Repeat Yourself)
|
|
57
|
+
|
|
58
|
+
### Plain English
|
|
59
|
+
|
|
60
|
+
Every piece of knowledge should exist in exactly one place. If you need the same logic in two places, extract it into a shared function and call it from both places. Duplication is not just about identical code — it is about identical concepts.
|
|
61
|
+
|
|
62
|
+
### How It Applies to AI-Assisted Development
|
|
63
|
+
|
|
64
|
+
AI has no memory across prompts (unless explicitly given context). If you ask it to build Feature A and later ask it to build Feature B, it will write fresh implementations of shared logic — validation, formatting, error handling — even if identical code already exists.
|
|
65
|
+
|
|
66
|
+
This is the single most common issue with AI-generated code: it works, but it duplicates existing patterns because the AI did not search the codebase first.
|
|
67
|
+
|
|
68
|
+
### Common AI-Generated Violations
|
|
69
|
+
|
|
70
|
+
**Duplicate validation logic:**
|
|
71
|
+
The AI writes email validation in the user controller, then writes it again in the contact form handler, then again in the newsletter signup. Three identical regex checks in three files.
|
|
72
|
+
|
|
73
|
+
**Duplicate error response formatting:**
|
|
74
|
+
Every controller method manually constructs `{ status: 'error', message: err.message, code: 400 }` instead of using the existing error response factory.
|
|
75
|
+
|
|
76
|
+
**Duplicate type definitions:**
|
|
77
|
+
The AI defines `interface User { id: string; name: string; email: string }` in three different files because each prompt started fresh.
|
|
78
|
+
|
|
79
|
+
### How the Reviewer Detects Violations
|
|
80
|
+
|
|
81
|
+
- Searches for identical or near-identical code blocks across files.
|
|
82
|
+
- Checks if new utility functions duplicate existing ones in `src/common/utils/`.
|
|
83
|
+
- Looks for inline implementations of logic that exists in a shared library.
|
|
84
|
+
- Verifies that type definitions are imported from canonical sources, not redefined.
|
|
85
|
+
|
|
86
|
+
### Real-World Consequences
|
|
87
|
+
|
|
88
|
+
When a validation rule changes (email regex updated for new TLD), the developer fixes one copy and misses the others. Users see inconsistent behavior — "my email works on the signup page but not on the contact form." Debugging takes hours because the developer assumes there is one validation function, not three.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## YAGNI (You Ain't Gonna Need It)
|
|
93
|
+
|
|
94
|
+
### Plain English
|
|
95
|
+
|
|
96
|
+
Do not build things you do not need right now. If the spec says "users can log in with email and password," do not build OAuth, SAML, magic links, and biometric auth "for the future." Build email/password. When the spec says "add OAuth," build OAuth then.
|
|
97
|
+
|
|
98
|
+
### How It Applies to AI-Assisted Development
|
|
99
|
+
|
|
100
|
+
AI optimizes for impressiveness. Ask it to build a REST endpoint and it will add pagination, filtering, sorting, caching, rate limiting, and webhook support — even if you asked for a simple GET endpoint. The AI is trying to be helpful, but it is building infrastructure you did not ask for.
|
|
101
|
+
|
|
102
|
+
This extra code looks professional but it has real costs: it must be tested, maintained, and documented. It creates surface area for bugs. It confuses developers who wonder "is the caching layer required? Can I remove it?"
|
|
103
|
+
|
|
104
|
+
### Common AI-Generated Violations
|
|
105
|
+
|
|
106
|
+
**Premature abstraction layers:**
|
|
107
|
+
Spec says "store users in PostgreSQL." AI builds a generic repository pattern with adapters for five databases, a caching layer with Redis, and a query builder abstraction.
|
|
108
|
+
|
|
109
|
+
**Configuration nobody asked for:**
|
|
110
|
+
Spec says "send welcome email." AI adds configurable email templates, A/B testing support, scheduled sending, and retry queues.
|
|
111
|
+
|
|
112
|
+
**Plugin architecture for a single use case:**
|
|
113
|
+
Spec says "validate input." AI builds a pluggable validation framework with custom rule registration, async validators, and i18n error messages.
|
|
114
|
+
|
|
115
|
+
### How the Reviewer Detects Violations
|
|
116
|
+
|
|
117
|
+
- Maps every file, function, and class back to a task in the spec. Anything that cannot be traced to a spec task is YAGNI.
|
|
118
|
+
- Looks for abstract base classes with only one concrete implementation.
|
|
119
|
+
- Checks for configuration options that are not used or tested.
|
|
120
|
+
- Identifies "framework code" (event buses, plugin registries, middleware chains) when the spec asked for specific behavior.
|
|
121
|
+
|
|
122
|
+
### Real-World Consequences
|
|
123
|
+
|
|
124
|
+
Extra code is not free. A pagination system nobody uses still needs tests (which nobody writes because nobody uses it). When the real pagination requirement arrives months later, it has different needs than what was pre-built. Now the developer must either force-fit the new requirement into the old abstraction or rip out the old code and write it properly. Either way, the pre-built code wasted time twice — once to write, once to remove.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Clean Code
|
|
129
|
+
|
|
130
|
+
### Plain English
|
|
131
|
+
|
|
132
|
+
Code should be small, simple, and obvious. Functions should be short (max 40 lines), take few arguments (max 3), and have shallow nesting (max 3 levels). If you need a comment to explain what code does, the code is too complex — simplify it.
|
|
133
|
+
|
|
134
|
+
### How It Applies to AI-Assisted Development
|
|
135
|
+
|
|
136
|
+
AI generates code in large blocks. It does not naturally refactor long functions into smaller helpers because it writes code in a single pass. A 100-line function with 5 levels of nesting is common in AI output because the AI is solving the problem, not crafting maintainable code.
|
|
137
|
+
|
|
138
|
+
AI also tends to use complex expressions (nested ternaries, long chains of method calls) because they are more token-efficient than explicit if/else blocks.
|
|
139
|
+
|
|
140
|
+
### Common AI-Generated Violations
|
|
141
|
+
|
|
142
|
+
**Functions that are too long:**
|
|
143
|
+
AI writes a single function that reads a file, parses it, validates it, transforms it, and writes the output. Each step is correct, but the function is 80 lines with no helper extraction.
|
|
144
|
+
|
|
145
|
+
**Deep nesting:**
|
|
146
|
+
```typescript
|
|
147
|
+
if (user) {
|
|
148
|
+
if (user.isActive) {
|
|
149
|
+
if (user.hasPermission('admin')) {
|
|
150
|
+
if (request.isValid) {
|
|
151
|
+
// actual logic buried 4 levels deep
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Nested ternaries:**
|
|
159
|
+
```typescript
|
|
160
|
+
const label = status === 'active' ? 'Active' : status === 'pending' ? 'Pending' : status === 'suspended' ? 'Suspended' : 'Unknown'
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### How the Reviewer Detects Violations
|
|
164
|
+
|
|
165
|
+
- Counts lines per function. Any function over 40 lines is flagged.
|
|
166
|
+
- Counts parameters per function. More than 3 triggers a "group into object" suggestion.
|
|
167
|
+
- Measures nesting depth. More than 3 levels triggers a "use guard clauses" suggestion.
|
|
168
|
+
- Searches for nested ternary operators.
|
|
169
|
+
- Looks for comments that explain "what" instead of "why."
|
|
170
|
+
|
|
171
|
+
### Real-World Consequences
|
|
172
|
+
|
|
173
|
+
A 100-line function cannot be partially tested. You test the whole thing or nothing. When a bug is reported, you re-read all 100 lines to understand the flow. When a requirement changes, you must understand all 100 lines to know where to make the change. Small functions with clear names are grep-able, testable, and replaceable.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Security
|
|
178
|
+
|
|
179
|
+
### Plain English
|
|
180
|
+
|
|
181
|
+
Never hardcode secrets. Always validate user input. Always use parameterized queries. Always sanitize file paths. Security is not a feature you add — it is a constraint on every feature you build.
|
|
182
|
+
|
|
183
|
+
### How It Applies to AI-Assisted Development
|
|
184
|
+
|
|
185
|
+
AI generates examples with placeholder credentials that look like real credentials. `const API_KEY = 'sk-1234'` is meant as a placeholder but gets committed as-is. The AI does not know about your `.env` setup or your secrets manager.
|
|
186
|
+
|
|
187
|
+
AI also tends to trust input. When generating an endpoint, it reads `req.body.id` and uses it directly in a query without validation. The AI assumes the input is valid because in the prompt, it was.
|
|
188
|
+
|
|
189
|
+
### Common AI-Generated Violations
|
|
190
|
+
|
|
191
|
+
**Hardcoded credentials in examples:**
|
|
192
|
+
```typescript
|
|
193
|
+
const stripe = new Stripe('sk_live_actualkey123')
|
|
194
|
+
const db = new Client({ connectionString: 'postgres://admin:password@prod-db:5432' })
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Unvalidated user input:**
|
|
198
|
+
```typescript
|
|
199
|
+
app.get('/file/:path', (req, res) => {
|
|
200
|
+
res.sendFile(req.params.path) // directory traversal
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**String-concatenated SQL:**
|
|
205
|
+
```typescript
|
|
206
|
+
const query = `SELECT * FROM users WHERE name = '${req.body.name}'`
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### How the Reviewer Detects Violations
|
|
210
|
+
|
|
211
|
+
- Searches for patterns that look like API keys, tokens, passwords, or connection strings in source files.
|
|
212
|
+
- Checks that every route handler validates its input before processing.
|
|
213
|
+
- Searches for string interpolation or concatenation in SQL queries.
|
|
214
|
+
- Verifies that file path operations use `path.resolve` and check against a safe base directory.
|
|
215
|
+
- Confirms `.env` files are in `.gitignore`.
|
|
216
|
+
|
|
217
|
+
### Real-World Consequences
|
|
218
|
+
|
|
219
|
+
Hardcoded credentials in git history persist forever — even after deletion, they exist in commit history. Automated scanners find them within hours. SQL injection can read, modify, or delete your entire database. Path traversal can expose any file on your server. These are not theoretical risks; they are the most commonly exploited vulnerabilities in web applications.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Testing
|
|
224
|
+
|
|
225
|
+
### Plain English
|
|
226
|
+
|
|
227
|
+
If you change how code behaves, you write a test that proves the new behavior works. Every function that could fail should have a test for the success case, the failure case, and the edge cases. Tests are the proof that your code works — without them, you are guessing.
|
|
228
|
+
|
|
229
|
+
### How It Applies to AI-Assisted Development
|
|
230
|
+
|
|
231
|
+
AI can write excellent tests — but only if you ask. Left to its own devices, AI generates production code without tests or generates tests that assert nothing meaningful (`expect(result).toBeDefined()`). The SDLC framework makes testing a hard requirement, not an afterthought.
|
|
232
|
+
|
|
233
|
+
AI-generated tests also tend to test implementation rather than behavior. They mock internals and assert on internal method calls instead of testing observable outcomes. This makes tests brittle — any refactor breaks them even if behavior is preserved.
|
|
234
|
+
|
|
235
|
+
### Common AI-Generated Violations
|
|
236
|
+
|
|
237
|
+
**Tests that assert existence, not correctness:**
|
|
238
|
+
```typescript
|
|
239
|
+
test('creates user', () => {
|
|
240
|
+
const user = createUser({ name: 'Alice' })
|
|
241
|
+
expect(user).toBeDefined() // proves nothing about correctness
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Tests that test implementation:**
|
|
246
|
+
```typescript
|
|
247
|
+
test('creates user', () => {
|
|
248
|
+
const spy = jest.spyOn(repo, 'save')
|
|
249
|
+
createUser({ name: 'Alice' })
|
|
250
|
+
expect(spy).toHaveBeenCalledTimes(1) // tests HOW, not WHAT
|
|
251
|
+
})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Missing edge case tests:**
|
|
255
|
+
AI writes one happy-path test and considers testing complete. No tests for null input, empty strings, duplicate entries, or concurrent access.
|
|
256
|
+
|
|
257
|
+
### How the Reviewer Detects Violations
|
|
258
|
+
|
|
259
|
+
- Checks that every new/modified function has at least one corresponding test.
|
|
260
|
+
- Reads assertions to verify they test specific values, not just existence.
|
|
261
|
+
- Looks for edge case coverage: null, undefined, empty, boundary values.
|
|
262
|
+
- Verifies tests run independently (no shared mutable state).
|
|
263
|
+
- Confirms test names describe scenario and expected outcome.
|
|
264
|
+
|
|
265
|
+
### Real-World Consequences
|
|
266
|
+
|
|
267
|
+
Without tests, every code change is a roll of the dice. You modify a utility function and silently break three features that depend on it. You discover the breakage when a user reports it, days later. With tests, the CI pipeline catches it in 30 seconds and tells you exactly which behavior broke and where.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Naming
|
|
272
|
+
|
|
273
|
+
### Plain English
|
|
274
|
+
|
|
275
|
+
Names are the most-read documentation in your codebase. A well-named function does not need a comment. Use full words, not abbreviations. Name functions for what they do (verbs), variables for what they hold (nouns), and booleans as yes/no questions (`isValid`, `hasPermission`).
|
|
276
|
+
|
|
277
|
+
### How It Applies to AI-Assisted Development
|
|
278
|
+
|
|
279
|
+
AI tends to use short, generic names in generated code: `data`, `result`, `item`, `val`, `cb`. This is because AI training data includes millions of examples with terse naming. The AI optimizes for "plausible code" rather than "code a human will maintain."
|
|
280
|
+
|
|
281
|
+
AI also inconsistently names the same concept — `user` in one file, `account` in another, `profile` in a third — because each generation is independent.
|
|
282
|
+
|
|
283
|
+
### Common AI-Generated Violations
|
|
284
|
+
|
|
285
|
+
**Generic names:**
|
|
286
|
+
```typescript
|
|
287
|
+
function process(data: any) {
|
|
288
|
+
const result = data.map((item: any) => transform(item))
|
|
289
|
+
return result.filter((r: any) => r.valid)
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Inconsistent naming:**
|
|
294
|
+
```typescript
|
|
295
|
+
// File A: UserService with getUser()
|
|
296
|
+
// File B: AccountManager with fetchAccount()
|
|
297
|
+
// File C: ProfileHandler with loadProfile()
|
|
298
|
+
// All three refer to the same domain concept
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Abbreviations:**
|
|
302
|
+
```typescript
|
|
303
|
+
const usr = getUsr(req.params.usrId)
|
|
304
|
+
const cfg = loadCfg()
|
|
305
|
+
const btn = doc.querySelector('.btn')
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### How the Reviewer Detects Violations
|
|
309
|
+
|
|
310
|
+
- Searches for common generic names: `data`, `result`, `item`, `temp`, `val`, `cb`, `fn`.
|
|
311
|
+
- Searches for common abbreviations: `usr`, `btn`, `msg`, `cfg`, `ctx`, `req`, `res` (outside of framework conventions).
|
|
312
|
+
- Checks that boolean variables start with `is`, `has`, `can`, `should`, or similar question words.
|
|
313
|
+
- Checks that function names start with verbs.
|
|
314
|
+
- Verifies naming consistency across files for the same domain concept.
|
|
315
|
+
|
|
316
|
+
### Real-World Consequences
|
|
317
|
+
|
|
318
|
+
Bad names force every reader to build a mental translation table. "What does `d` mean here? Let me scroll up... it's the database connection." This takes 2-3 seconds per encounter, multiplied by every developer, every time they read the code. Over a year, a poorly named codebase costs the team hundreds of hours of unnecessary mental overhead.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Error Handling
|
|
323
|
+
|
|
324
|
+
### Plain English
|
|
325
|
+
|
|
326
|
+
When something goes wrong, your code must either handle it (take corrective action) or report it (log and rethrow). Silently ignoring errors is the worst possible choice — it hides bugs that surface later in harder-to-diagnose ways.
|
|
327
|
+
|
|
328
|
+
### How It Applies to AI-Assisted Development
|
|
329
|
+
|
|
330
|
+
AI wraps risky code in try/catch but often leaves the catch block empty or with just a `console.log`. This is because AI training data is full of tutorials and examples that use `catch (e) {}` as a shortcut. The AI does not know that your production system needs proper error reporting.
|
|
331
|
+
|
|
332
|
+
AI also tends to throw generic `Error` objects instead of domain-specific exceptions. `throw new Error('failed')` tells you nothing about what failed, where, or why.
|
|
333
|
+
|
|
334
|
+
### Common AI-Generated Violations
|
|
335
|
+
|
|
336
|
+
**Empty catch blocks:**
|
|
337
|
+
```typescript
|
|
338
|
+
try {
|
|
339
|
+
await sendEmail(user.email, template)
|
|
340
|
+
} catch (e) {
|
|
341
|
+
// AI left this empty "to prevent crashes"
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
The email silently fails. The user never receives it. Nobody knows.
|
|
345
|
+
|
|
346
|
+
**Generic errors:**
|
|
347
|
+
```typescript
|
|
348
|
+
if (!user) throw new Error('error')
|
|
349
|
+
if (!order) throw new Error('not found')
|
|
350
|
+
if (!payment) throw new Error('invalid')
|
|
351
|
+
```
|
|
352
|
+
When this hits the error log, the developer sees "error" with no context.
|
|
353
|
+
|
|
354
|
+
**Swallowed exceptions:**
|
|
355
|
+
```typescript
|
|
356
|
+
try {
|
|
357
|
+
await processPayment(order)
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.log('payment failed') // logged and forgotten
|
|
360
|
+
return { success: true } // lies to the caller
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### How the Reviewer Detects Violations
|
|
365
|
+
|
|
366
|
+
- Searches for empty catch blocks: `catch` followed by `{}` or just a comment.
|
|
367
|
+
- Searches for `console.log` inside catch blocks without a rethrow.
|
|
368
|
+
- Checks that custom exception classes exist and are used instead of generic `Error`.
|
|
369
|
+
- Verifies that error messages include context (entity ID, operation name, user context).
|
|
370
|
+
- Confirms that catch blocks either handle the error (retry, fallback) or rethrow it.
|
|
371
|
+
|
|
372
|
+
### Real-World Consequences
|
|
373
|
+
|
|
374
|
+
A swallowed payment error means a customer is charged but their order is not fulfilled. An empty catch on a database write means data is lost without anyone knowing. A generic error message means the on-call engineer spends 30 minutes figuring out which "not found" error triggered the alert. Proper error handling is the difference between "we fixed it in 5 minutes" and "we lost data and don't know when it started."
|