devflow-kit 3.11.0 → 3.12.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/CHANGELOG.md +43 -0
- package/dist/agents/architect.md +87 -0
- package/dist/agents/code.md +21 -25
- package/dist/agents/debug.md +21 -49
- package/dist/agents/design.md +9 -43
- package/dist/agents/fix.md +15 -29
- package/dist/agents/git.md +19 -22
- package/dist/agents/harden.md +14 -19
- package/dist/agents/knowledge.md +11 -19
- package/dist/agents/refactor.md +9 -14
- package/dist/agents/research.md +11 -34
- package/dist/agents/review.md +22 -52
- package/dist/agents/skim.md +7 -17
- package/dist/agents/triage.md +7 -14
- package/dist/commands/bug-analysis.md +31 -62
- package/dist/commands/code-review.md +38 -87
- package/dist/commands/debug.md +32 -82
- package/dist/commands/dynamic-build.md +155 -211
- package/dist/commands/dynamic-plan.md +71 -93
- package/dist/commands/dynamic-profile.md +7 -155
- package/dist/commands/dynamic-tickets.md +65 -186
- package/dist/commands/explore.md +27 -70
- package/dist/commands/implement.md +98 -186
- package/dist/commands/plan.md +60 -107
- package/dist/commands/release.md +25 -91
- package/dist/commands/research.md +34 -103
- package/dist/commands/resolve.md +64 -128
- package/dist/commands/self-review.md +35 -99
- package/dist/compliance-off/agents/git.md +15 -18
- package/dist/compliance-off/agents/triage.md +7 -14
- package/dist/compliance-off/commands/bug-analysis.md +31 -62
- package/dist/compliance-off/commands/code-review.md +34 -82
- package/dist/compliance-off/commands/dynamic-build.md +149 -205
- package/dist/compliance-off/commands/dynamic-tickets.md +65 -186
- package/dist/compliance-off/commands/implement.md +94 -180
- package/dist/compliance-off/commands/plan.md +60 -107
- package/dist/compliance-off/commands/release.md +25 -90
- package/dist/compliance-off/commands/resolve.md +54 -128
- package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
- package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
- package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
- package/dist/core/plugins.js +3 -3
- package/dist/curation-compliance-off/agents/triage.md +7 -13
- package/dist/curation-compliance-off/commands/bug-analysis.md +21 -41
- package/dist/curation-compliance-off/commands/code-review.md +25 -62
- package/dist/curation-compliance-off/commands/dynamic-build.md +142 -194
- package/dist/curation-compliance-off/commands/dynamic-tickets.md +54 -173
- package/dist/curation-compliance-off/commands/implement.md +86 -161
- package/dist/curation-compliance-off/commands/plan.md +51 -86
- package/dist/curation-compliance-off/commands/release.md +17 -78
- package/dist/curation-compliance-off/commands/resolve.md +45 -108
- package/dist/curation-off/agents/architect.md +81 -0
- package/dist/curation-off/agents/code.md +20 -23
- package/dist/curation-off/agents/debug.md +19 -47
- package/dist/curation-off/agents/design.md +8 -41
- package/dist/curation-off/agents/fix.md +14 -27
- package/dist/curation-off/agents/harden.md +13 -18
- package/dist/curation-off/agents/knowledge.md +9 -17
- package/dist/curation-off/agents/refactor.md +8 -12
- package/dist/curation-off/agents/research.md +9 -32
- package/dist/curation-off/agents/review.md +11 -40
- package/dist/curation-off/agents/skim.md +7 -17
- package/dist/curation-off/agents/triage.md +7 -13
- package/dist/curation-off/commands/bug-analysis.md +21 -41
- package/dist/curation-off/commands/code-review.md +29 -67
- package/dist/curation-off/commands/debug.md +24 -63
- package/dist/curation-off/commands/dynamic-build.md +148 -200
- package/dist/curation-off/commands/dynamic-plan.md +60 -80
- package/dist/curation-off/commands/dynamic-tickets.md +54 -173
- package/dist/curation-off/commands/explore.md +18 -50
- package/dist/curation-off/commands/implement.md +90 -167
- package/dist/curation-off/commands/plan.md +51 -86
- package/dist/curation-off/commands/release.md +17 -79
- package/dist/curation-off/commands/research.md +23 -81
- package/dist/curation-off/commands/resolve.md +55 -108
- package/dist/curation-off/commands/self-review.md +26 -78
- package/dist/skills/git/references/pr/update-pr-evidence.md +2 -1
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
- package/dist/targets/claude-code/curation-install.js +2 -2
- package/dist/variant-axes.json +5 -1
- package/package.json +1 -1
- package/src/assets/agents/_partials/_code.mds +3 -5
- package/src/assets/agents/_partials/_design.mds +86 -0
- package/src/assets/agents/architect.mds +41 -0
- package/src/assets/agents/code.mds +18 -20
- package/src/assets/agents/curate.md +26 -35
- package/src/assets/agents/debug.mds +21 -49
- package/src/assets/agents/design.mds +11 -114
- package/src/assets/agents/evaluate.md +6 -16
- package/src/assets/agents/explore.md +1 -2
- package/src/assets/agents/fix.mds +12 -24
- package/src/assets/agents/git.mds +20 -23
- package/src/assets/agents/harden.mds +14 -19
- package/src/assets/agents/knowledge.mds +10 -38
- package/src/assets/agents/polish.md +13 -39
- package/src/assets/agents/refactor.mds +6 -9
- package/src/assets/agents/research.mds +11 -34
- package/src/assets/agents/review.mds +12 -84
- package/src/assets/agents/skim.mds +7 -17
- package/src/assets/agents/synthesize.md +3 -21
- package/src/assets/agents/test.md +31 -32
- package/src/assets/agents/tracker.md +116 -229
- package/src/assets/agents/triage.mds +7 -26
- package/src/assets/agents/validate.md +1 -3
- package/src/assets/commands/_partials/_compliance.mds +2 -2
- package/src/assets/commands/_partials/_decisions.mds +17 -24
- package/src/assets/commands/_partials/_docs_root.mds +31 -10
- package/src/assets/commands/_partials/_engine.mds +34 -56
- package/src/assets/commands/_partials/_evidence_policy.mds +1 -1
- package/src/assets/commands/_partials/_factory.mds +10 -104
- package/src/assets/commands/_partials/_knowledge.mds +47 -51
- package/src/assets/commands/_partials/_plan_contract.mds +2 -2
- package/src/assets/commands/_partials/_preamble.mds +21 -21
- package/src/assets/commands/_partials/_publication.mds +3 -3
- package/src/assets/commands/_partials/_roster.mds +12 -13
- package/src/assets/commands/_partials/_settings.mds +6 -3
- package/src/assets/commands/_partials/_ticket_template.mds +3 -7
- package/src/assets/commands/_partials/_tracker.mds +10 -5
- package/src/assets/commands/_partials/_wave.mds +23 -32
- package/src/assets/commands/bug-analysis.mds +3 -7
- package/src/assets/commands/code-review.mds +12 -33
- package/src/assets/commands/debug.mds +5 -47
- package/src/assets/commands/dynamic-build.mds +48 -70
- package/src/assets/commands/dynamic-plan.mds +23 -42
- package/src/assets/commands/dynamic-profile.mds +7 -57
- package/src/assets/commands/dynamic-tickets.mds +9 -29
- package/src/assets/commands/explore.mds +5 -44
- package/src/assets/commands/implement.mds +75 -117
- package/src/assets/commands/plan.mds +27 -57
- package/src/assets/commands/release.mds +4 -62
- package/src/assets/commands/research.mds +7 -53
- package/src/assets/commands/resolve.mds +40 -87
- package/src/assets/commands/self-review.mds +5 -45
- package/src/assets/mds/git/_ops_pr.mds +1 -0
- package/src/assets/mds/git/_ops_steps.mds +4 -4
- package/src/assets/mds/git/_pr.mds +1 -1
- package/src/assets/rules/engineering.md +1 -1
- package/src/assets/rules/quality.md +2 -2
- package/src/assets/scripts/ci-wait.cjs +150 -18
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +3 -3
- package/src/assets/scripts/hooks/preamble +2 -3
- package/src/assets/scripts/pr-evidence.cjs +1 -0
- package/src/assets/scripts/resolve-evidence-policy.cjs +14 -13
- package/src/assets/scripts/resolve-root.cjs +186 -0
- package/src/assets/scripts/resolve-settings.cjs +14 -9
- package/src/assets/scripts/verify-evidence.cjs +355 -22
- package/src/assets/skills/accessibility/SKILL.md +28 -95
- package/src/assets/skills/agent-references/SKILL.md +2 -4
- package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +1 -1
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +4 -7
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +1 -1
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +2 -2
- package/src/assets/skills/apply-decisions/SKILL.md +5 -6
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +3 -13
- package/src/assets/skills/architecture/SKILL.md +29 -105
- package/src/assets/skills/boundary-validation/SKILL.md +27 -78
- package/src/assets/skills/complexity/SKILL.md +8 -104
- package/src/assets/skills/compliance/SKILL.md +9 -67
- package/src/assets/skills/consistency/SKILL.md +7 -107
- package/src/assets/skills/database/SKILL.md +7 -72
- package/src/assets/skills/dependencies/SKILL.md +9 -109
- package/src/assets/skills/dependencies/references/detection.md +10 -0
- package/src/assets/skills/dependency-research/SKILL.md +9 -63
- package/src/assets/skills/design-review/SKILL.md +1 -35
- package/src/assets/skills/docs-framework/SKILL.md +4 -47
- package/src/assets/skills/documentation/SKILL.md +7 -71
- package/src/assets/skills/documentation/references/patterns.md +1 -1
- package/src/assets/skills/documentation/references/violations.md +1 -1
- package/src/assets/skills/feature-knowledge/SKILL.md +19 -222
- package/src/assets/skills/feature-knowledge/references/new-kb.md +128 -0
- package/src/assets/skills/gap-analysis/SKILL.md +1 -31
- package/src/assets/skills/git/SKILL.md +2 -22
- package/src/assets/skills/go/SKILL.md +24 -113
- package/src/assets/skills/java/SKILL.md +12 -98
- package/src/assets/skills/patterns/SKILL.md +8 -93
- package/src/assets/skills/performance/SKILL.md +29 -88
- package/src/assets/skills/python/SKILL.md +22 -120
- package/src/assets/skills/qa/SKILL.md +16 -54
- package/src/assets/skills/qa/references/browser-testing.md +0 -24
- package/src/assets/skills/qa/references/sources.md +2 -2
- package/src/assets/skills/quality-gates/SKILL.md +13 -100
- package/src/assets/skills/react/SKILL.md +33 -95
- package/src/assets/skills/regression/SKILL.md +8 -73
- package/src/assets/skills/reliability/SKILL.md +11 -120
- package/src/assets/skills/research-codebase/SKILL.md +7 -49
- package/src/assets/skills/research-competitor/SKILL.md +4 -39
- package/src/assets/skills/research-external/SKILL.md +5 -43
- package/src/assets/skills/research-market/SKILL.md +5 -43
- package/src/assets/skills/research-technology/SKILL.md +8 -68
- package/src/assets/skills/review-methodology/SKILL.md +10 -56
- package/src/assets/skills/rust/SKILL.md +19 -109
- package/src/assets/skills/security/SKILL.md +39 -66
- package/src/assets/skills/software-design/SKILL.md +20 -105
- package/src/assets/skills/software-design/references/patterns.md +84 -2
- package/src/assets/skills/software-design/references/violations.md +1 -1
- package/src/assets/skills/test-driven-development/SKILL.md +32 -107
- package/src/assets/skills/test-driven-development/references/rationalization-prevention.md +33 -1
- package/src/assets/skills/testing/SKILL.md +35 -53
- package/src/assets/skills/typescript/SKILL.md +23 -102
- package/src/assets/skills/ui-design/SKILL.md +26 -74
- package/src/assets/skills/worktree-support/SKILL.md +4 -10
- package/dist/curation-off/commands/dynamic-profile.md +0 -214
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: software-design
|
|
3
|
-
description: This skill should be used when the user asks to "
|
|
3
|
+
description: This skill should be used when the user asks to "inject dependencies", "return Result", "make it immutable", or implements business logic or error handling.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
allowed-tools: Read, Grep, Glob, AskUserQuestion
|
|
6
6
|
---
|
|
@@ -11,119 +11,36 @@ The canonical source of architectural patterns and principles for consistent, hi
|
|
|
11
11
|
|
|
12
12
|
## Iron Law
|
|
13
13
|
|
|
14
|
-
> **
|
|
14
|
+
> **Never throw in business logic**
|
|
15
15
|
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
> in business logic is a violation.
|
|
16
|
+
> Every operation that can fail must return a Result type. Exceptions are allowed
|
|
17
|
+
> only at system boundaries (API handlers, database adapters). A `throw` statement
|
|
18
|
+
> in business logic is a violation.
|
|
19
19
|
|
|
20
20
|
## Philosophy
|
|
21
21
|
|
|
22
|
-
1. **Functional Core, Imperative Shell**
|
|
23
|
-
2. **Explicit Error Handling**
|
|
24
|
-
3. **Immutability by Default**
|
|
25
|
-
4. **Dependency Injection**
|
|
26
|
-
5. **Make Illegal States Unrepresentable**
|
|
27
|
-
6. **Parse, Don't Validate**
|
|
22
|
+
1. **Functional Core, Imperative Shell** — Pure business logic, side effects at boundary
|
|
23
|
+
2. **Explicit Error Handling** — Result types, no exceptions in business logic
|
|
24
|
+
3. **Immutability by Default** — Return new objects, never mutate (copy before `.sort()`)
|
|
25
|
+
4. **Dependency Injection** — All deps injected, nothing instantiated internally
|
|
26
|
+
5. **Make Illegal States Unrepresentable** — Types enforce invariants at compile time; discriminated unions with exhaustive switches; each error variant carries its full context
|
|
27
|
+
6. **Parse, Don't Validate** — Schema transforms at boundaries
|
|
28
|
+
7. **Compose with pipes**, and clean up resources in `finally`
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Pattern 1: Result Types [1][5][6][18]
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
|
|
35
|
-
|
|
36
|
-
function createUser(data: unknown): Result<User, ValidationError> {
|
|
37
|
-
if (!valid(data)) return Err({ type: 'ValidationFailed', details: validate(data).errors });
|
|
38
|
-
return Ok(buildUser(data));
|
|
39
|
-
}
|
|
40
|
-
// Libraries: neverthrow [18], ts-results [19]. Theory: Moggi [5] + Wadler [6].
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Pattern 2: Dependency Injection [3]
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
class UserService {
|
|
47
|
-
constructor(private db: Database, private emailer: EmailService) {}
|
|
48
|
-
// Test: new UserService(mockDb, mockEmailer) — never new Database() inside [3]
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Pattern 3: Immutability [7][14]
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
// New object, never mutate input; copy before .sort() [7][14]
|
|
56
|
-
function updateUser(user: User, changes: Partial<User>): User {
|
|
57
|
-
return { ...user, ...changes };
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Pattern 4: Functional Core, Imperative Shell [11]
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
// PURE CORE: no I/O, deterministic [11]
|
|
65
|
-
function calculateTotal(items: Item[], taxRate: number): number {
|
|
66
|
-
return items.reduce((sum, i) => sum + i.price, 0) * (1 + taxRate);
|
|
67
|
-
}
|
|
68
|
-
// IMPERATIVE SHELL: I/O at boundary only [11]
|
|
69
|
-
async function processOrder(id: string): Promise<Result<Order, Error>> {
|
|
70
|
-
const order = await db.getOrder(id);
|
|
71
|
-
return Ok(await db.save({ ...order, total: calculateTotal(order.items, 0.1) }));
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Pattern 5: Type Safety [4][2][21]
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
// Discriminated unions — compiler enforces exhaustiveness [4][21]
|
|
79
|
-
type UserError =
|
|
80
|
-
| { type: 'NotFound'; userId: string } // carries full context [2]
|
|
81
|
-
| { type: 'ValidationFailed'; field: string; message: string };
|
|
82
|
-
|
|
83
|
-
type Status = 'pending' | 'completed' | 'failed';
|
|
84
|
-
function handleStatus(status: Status): string {
|
|
85
|
-
switch (status) {
|
|
86
|
-
case 'pending': return 'Waiting';
|
|
87
|
-
case 'completed': return 'Done';
|
|
88
|
-
case 'failed': return 'Error';
|
|
89
|
-
} // Exhaustive — no default needed [21]
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Pattern 6: Pipe Composition [20][13]
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
const pipe = <T>(...fns: Array<(x: T) => T>) => (x: T) => fns.reduce((v, f) => f(v), x);
|
|
97
|
-
const process = pipe(validate, normalize, enrich); // Composition as glue [20][13]
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Pattern 7: Resource Cleanup + Documentation [7]
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
const handle = await fs.open(path);
|
|
104
|
-
try { return Ok(parse(await handle.readFile())); }
|
|
105
|
-
finally { await handle.close(); }
|
|
106
|
-
|
|
107
|
-
// ARCHITECTURE: Repository returns domain objects only
|
|
108
|
-
// ARCHITECTURE EXCEPTION: Direct DB for health check — must work if service layer down
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
30
|
+
`references/patterns.md` shows each pattern in code.
|
|
112
31
|
|
|
113
32
|
## Consistency Rules
|
|
114
33
|
|
|
115
|
-
- Result types: if one method returns Result,
|
|
116
|
-
- DI: apply consistently throughout
|
|
34
|
+
- Result types: if one method returns Result, all must
|
|
35
|
+
- DI: apply consistently throughout
|
|
117
36
|
- Async: single pattern (don't mix callbacks/promises)
|
|
118
37
|
|
|
119
38
|
## Anti-Patterns
|
|
120
39
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
| Mutable state — return new objects | [7][14] |
|
|
126
|
-
| Service locator — inject instead | [3] |
|
|
40
|
+
- Throwing in business logic — use Result
|
|
41
|
+
- Silent failures — swallowed catch blocks
|
|
42
|
+
- Mutable state — return new objects
|
|
43
|
+
- Service locator — inject instead
|
|
127
44
|
|
|
128
45
|
### Workaround Labeling (Required)
|
|
129
46
|
|
|
@@ -131,13 +48,11 @@ finally { await handle.close(); }
|
|
|
131
48
|
|
|
132
49
|
Unlabeled workarounds are violations. See `references/code-smell-violations.md`.
|
|
133
50
|
|
|
134
|
-
---
|
|
135
|
-
|
|
136
51
|
## Extended References
|
|
137
52
|
|
|
138
53
|
- `references/sources.md` — Full bibliography (25 sources with access links)
|
|
139
54
|
- `references/violations.md` — Violation patterns with citations
|
|
140
|
-
- `references/patterns.md` —
|
|
55
|
+
- `references/patterns.md` — The core patterns and extended correct patterns, with citations
|
|
141
56
|
- `references/checklist.md` — Pre-implementation and review checklists
|
|
142
57
|
- `references/code-smell-violations.md` — Fake solutions, deceptive code, magic values
|
|
143
58
|
- `references/detection.md` — Grep patterns for automated detection
|
|
@@ -1,10 +1,92 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Correct Pattern Examples
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Correct implementations: the seven core patterns of SKILL.md, then extended examples.
|
|
4
4
|
All patterns cite `references/sources.md`.
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## Pattern 1: Result Types [1][5][6][18]
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
|
|
12
|
+
|
|
13
|
+
function createUser(data: unknown): Result<User, ValidationError> {
|
|
14
|
+
if (!valid(data)) return Err({ type: 'ValidationFailed', details: validate(data).errors });
|
|
15
|
+
return Ok(buildUser(data));
|
|
16
|
+
}
|
|
17
|
+
// Libraries: neverthrow [18], ts-results [19]. Theory: Moggi [5] + Wadler [6].
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Pattern 2: Dependency Injection [3]
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
class UserService {
|
|
24
|
+
constructor(private db: Database, private emailer: EmailService) {}
|
|
25
|
+
// Test: new UserService(mockDb, mockEmailer) — never new Database() inside [3]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Pattern 3: Immutability [7][14]
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// New object, never mutate input; copy before .sort() [7][14]
|
|
33
|
+
function updateUser(user: User, changes: Partial<User>): User {
|
|
34
|
+
return { ...user, ...changes };
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Pattern 4: Functional Core, Imperative Shell [11]
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// PURE CORE: no I/O, deterministic [11]
|
|
42
|
+
function calculateTotal(items: Item[], taxRate: number): number {
|
|
43
|
+
return items.reduce((sum, i) => sum + i.price, 0) * (1 + taxRate);
|
|
44
|
+
}
|
|
45
|
+
// IMPERATIVE SHELL: I/O at boundary only [11]
|
|
46
|
+
async function processOrder(id: string): Promise<Result<Order, Error>> {
|
|
47
|
+
const order = await db.getOrder(id);
|
|
48
|
+
return Ok(await db.save({ ...order, total: calculateTotal(order.items, 0.1) }));
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Pattern 5: Type Safety [4][2][21]
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Discriminated unions — compiler enforces exhaustiveness [4][21]
|
|
56
|
+
type UserError =
|
|
57
|
+
| { type: 'NotFound'; userId: string } // carries full context [2]
|
|
58
|
+
| { type: 'ValidationFailed'; field: string; message: string };
|
|
59
|
+
|
|
60
|
+
type Status = 'pending' | 'completed' | 'failed';
|
|
61
|
+
function handleStatus(status: Status): string {
|
|
62
|
+
switch (status) {
|
|
63
|
+
case 'pending': return 'Waiting';
|
|
64
|
+
case 'completed': return 'Done';
|
|
65
|
+
case 'failed': return 'Error';
|
|
66
|
+
} // Exhaustive — no default needed [21]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Pattern 6: Pipe Composition [20][13]
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const pipe = <T>(...fns: Array<(x: T) => T>) => (x: T) => fns.reduce((v, f) => f(v), x);
|
|
74
|
+
const process = pipe(validate, normalize, enrich); // Composition as glue [20][13]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Pattern 7: Resource Cleanup + Documentation [7]
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const handle = await fs.open(path);
|
|
81
|
+
try { return Ok(parse(await handle.readFile())); }
|
|
82
|
+
finally { await handle.close(); }
|
|
83
|
+
|
|
84
|
+
// ARCHITECTURE: Repository returns domain objects only
|
|
85
|
+
// ARCHITECTURE EXCEPTION: Direct DB for health check — must work if service layer down
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
8
90
|
## Result Types — Extended Patterns [1][5][6]
|
|
9
91
|
|
|
10
92
|
### Chaining Results [1]
|
|
@@ -19,18 +19,15 @@ activation:
|
|
|
19
19
|
|
|
20
20
|
# Test-Driven Development
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Use the RED-GREEN-REFACTOR cycle for all implementation work. Tests define the design. Code satisfies the tests. Refactoring improves the design without changing behavior.
|
|
23
23
|
|
|
24
24
|
## Iron Law
|
|
25
25
|
|
|
26
|
-
> **
|
|
26
|
+
> **Tests first, always.**
|
|
27
27
|
>
|
|
28
|
-
> Write the failing test before the production code.
|
|
29
|
-
>
|
|
30
|
-
>
|
|
31
|
-
> to make it pass. The test IS the specification.
|
|
32
|
-
|
|
33
|
-
---
|
|
28
|
+
> Write the failing test before the production code. If you catch yourself writing
|
|
29
|
+
> production code without a failing test, stop, delete that code, write the test,
|
|
30
|
+
> watch it fail, then write the minimum code to make it pass. The test is the specification.
|
|
34
31
|
|
|
35
32
|
## The Cycle
|
|
36
33
|
|
|
@@ -38,117 +35,50 @@ Enforce the RED-GREEN-REFACTOR cycle for all implementation work. Tests define t
|
|
|
38
35
|
|
|
39
36
|
### Step 1: RED — Write a Failing Test
|
|
40
37
|
|
|
41
|
-
Write a test that describes the behavior you want. Run it. Watch it fail. The failure message
|
|
38
|
+
Write a test that describes the behavior you want. Run it. Watch it fail. The failure message is your specification. Describe what the code should do, not how. One behavior per test, and one assertion per test where you can. Name tests as sentences: "returns error when email is invalid".
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
Describe what the code SHOULD do, not how it does it.
|
|
45
|
-
One behavior per test. One assertion per test (ideally).
|
|
46
|
-
Name tests as sentences: "returns error when email is invalid"
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Checkpoint:** The test MUST fail before proceeding. A test that passes immediately proves nothing.
|
|
40
|
+
**Checkpoint:** The test must fail before you go on. A test that passes at once proves nothing.
|
|
50
41
|
|
|
51
42
|
### Step 2: GREEN — Write Minimum Code to Pass
|
|
52
43
|
|
|
53
|
-
Write the simplest production code that makes the failing test pass. No
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
Hardcode first if that's simplest. Generalize when the next test forces it.
|
|
57
|
-
Don't write code "you'll need later." Write code the test demands NOW.
|
|
58
|
-
Don't optimize. Don't refactor. Don't clean up. Just pass the test.
|
|
59
|
-
```
|
|
44
|
+
Write the simplest production code that makes the failing test pass. Hardcode first if that is simplest; generalize when the next test forces it. No code for later, no optimizing, no cleanup.
|
|
60
45
|
|
|
61
46
|
**Checkpoint:** All affected tests pass. If any test fails, fix it before moving on.
|
|
62
47
|
|
|
63
48
|
### Step 3: REFACTOR — Improve Without Changing Behavior
|
|
64
49
|
|
|
65
|
-
|
|
50
|
+
Extract helpers, rename, simplify, remove duplication. Run the affected tests after every refactoring step. If a test breaks during refactor, undo: you changed behavior.
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
Run the affected tests after every refactoring step.
|
|
69
|
-
If a test breaks during refactor, undo immediately — you changed behavior.
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Checkpoint:** All affected tests still pass. Code is clean. Repeat from Step 1 for next behavior.
|
|
73
|
-
|
|
74
|
-
---
|
|
52
|
+
**Checkpoint:** All affected tests still pass. Repeat from Step 1 for the next behavior.
|
|
75
53
|
|
|
76
54
|
## Cycle Verification
|
|
77
55
|
|
|
78
|
-
After each
|
|
56
|
+
After each cycle, all of these must hold:
|
|
79
57
|
|
|
80
58
|
- [ ] Test existed BEFORE production code (not concurrent, not after)
|
|
81
|
-
- [ ] Test failed for the
|
|
82
|
-
- [ ] Production code is minimal —
|
|
59
|
+
- [ ] Test failed for the right reason (expected behavior absent, not a syntax or import error)
|
|
60
|
+
- [ ] Production code is minimal — nothing beyond what the test demands
|
|
83
61
|
- [ ] ALL affected tests pass, not just the new one
|
|
84
62
|
- [ ] Refactoring happened in Step 3 (or code is already clean — state explicitly)
|
|
85
63
|
- [ ] No untested production code remains
|
|
86
64
|
|
|
87
|
-
If any fails
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Rationalization Prevention
|
|
92
|
-
|
|
93
|
-
These are the excuses developers use to skip TDD. Recognize and reject them.
|
|
94
|
-
|
|
95
|
-
| Excuse | Why It Feels Right | Why It's Wrong | Correct Action |
|
|
96
|
-
|--------|-------------------|----------------|----------------|
|
|
97
|
-
| "I'll write tests after" | Need to see the shape first | Tests ARE the shape — they define the interface before implementation exists | Write the test first |
|
|
98
|
-
| "Too simple to test" | It's just a getter/setter | Getters break, defaults change, edge cases hide in "simple" code | Write it — takes 30 seconds |
|
|
99
|
-
| "I'll refactor later" | Just get it working now | "Later" never comes; technical debt compounds silently | Refactor now in Step 3 |
|
|
100
|
-
| "Test is too hard to write" or "the test setup is too complex" | Mocking is painful | Hard-to-test code = bad design, and complex setup = too much coupling; the test is telling you the interface is wrong | Simplify the interface first |
|
|
101
|
-
| "Need to see the whole picture" or "the architecture first" | Can't test what I haven't designed or structured yet | TDD IS design; each test reveals the next piece of the interface, and tests DEFINE the architecture | Let the tests drive the design and structure |
|
|
102
|
-
| "Tests slow me down" | Faster to just write the code | Faster until the first regression; TDD is faster for anything > 50 lines | Trust the cycle |
|
|
103
|
-
| "Framework is hard to set up" | Setup is complex | One-time cost vs recurring regression cost; untested code compounds debt | Set up the framework first — that IS the work |
|
|
104
|
-
| "This is infrastructure, not logic" | Plumbing doesn't need tests | Infrastructure carries data; broken plumbing floods everything downstream | Test the contract, not the internals |
|
|
105
|
-
| "Deadline is tight, no time for tests" | Ship now, test later | Untested code ships bugs; fixing bugs under deadline is slower than TDD | TDD is faster under pressure, not slower |
|
|
106
|
-
|
|
107
|
-
See `references/rationalization-prevention.md` for extended examples with code.
|
|
108
|
-
|
|
109
|
-
### Red Flags — STOP Immediately
|
|
65
|
+
If any fails, you skipped TDD: back up and redo the cycle.
|
|
110
66
|
|
|
111
|
-
|
|
67
|
+
An excuse to skip the test-first step is a rationalization: reject it. `references/rationalization-prevention.md` lists the common excuses, the mid-work red flags and a test-first example.
|
|
112
68
|
|
|
113
|
-
|
|
114
|
-
|---------|------------|
|
|
115
|
-
| "Let me write the implementation first, tests after" | Delete the code. Write the test. Watch it fail. Then rewrite. |
|
|
116
|
-
| "I'll just spike this and add tests later" | Unless the user said "spike" — you're rationalizing, not prototyping. |
|
|
117
|
-
| "Let me get it working, then lock it with tests" | Those tests verify your implementation, not the requirement. Backwards. |
|
|
118
|
-
| "I know this works, I've written it before" | Past code passed past tests. This code needs its own failing test. |
|
|
119
|
-
| "One more function, then I'll write the test" | STOP. Write the test for what you have now. Increments, not batches. |
|
|
120
|
-
|
|
121
|
-
### Test-First vs Code-First
|
|
122
|
-
|
|
123
|
-
**Code-first** (wrong): write `parseConfig()`, then a test that mirrors it (`parseConfig("key=val")` passes). Empty input, malformed lines, multi-value keys and whitespace stay hidden until production.
|
|
124
|
-
|
|
125
|
-
**Test-first** (correct): "ignores comment lines", then "handles empty input", then "rejects malformed lines", each failing first and each driving the next slice of `parseConfig()`, so it handles the edges from the start.
|
|
126
|
-
|
|
127
|
-
Code-first tests verify what you *happened to build*. Test-first tests specify what *should exist*.
|
|
128
|
-
|
|
129
|
-
### When Stuck
|
|
69
|
+
## When Stuck
|
|
130
70
|
|
|
131
71
|
| Blocker | Solution |
|
|
132
72
|
|---------|----------|
|
|
133
|
-
| Don't know what to test first | Test the simplest input/output pair
|
|
134
|
-
| Test needs complex setup
|
|
73
|
+
| Don't know what to test first | Test the simplest input/output pair: "Given X, expect Y." |
|
|
74
|
+
| Test needs complex setup or state | Extract the logic into a pure function. Test that. Integrate after. |
|
|
135
75
|
| Behavior depends on external state (DB, API, clock) | Inject the dependency as a parameter. Pass a fake in tests. |
|
|
136
|
-
| Multiple behaviors tangled together |
|
|
137
|
-
| Modifying legacy code with no tests | Write a characterization test first
|
|
138
|
-
|
|
139
|
-
---
|
|
76
|
+
| Multiple behaviors tangled together | One test = one behavior. If you can't isolate it, split the design. |
|
|
77
|
+
| Modifying legacy code with no tests | Write a characterization test first: it captures the current behavior, even if wrong. Then change the code and see what breaks. |
|
|
140
78
|
|
|
141
|
-
##
|
|
79
|
+
## What to Test
|
|
142
80
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
### File Organization
|
|
146
|
-
|
|
147
|
-
- Test file lives next to production file: `user.ts` → `user.test.ts`
|
|
148
|
-
- Follow project's existing test conventions (Jest, Vitest, pytest, etc.)
|
|
149
|
-
- Import the module under test, not internal helpers
|
|
150
|
-
|
|
151
|
-
### What to Test
|
|
81
|
+
Follow the project's test layout and conventions, and import the module under test, not its internal helpers.
|
|
152
82
|
|
|
153
83
|
| Test | Don't Test |
|
|
154
84
|
|------|------------|
|
|
@@ -157,23 +87,18 @@ When implementing any feature under ambient IMPLEMENT, start from the simplest t
|
|
|
157
87
|
| Integration points (boundaries) | Third-party library correctness |
|
|
158
88
|
| State transitions | Getter/setter plumbing (unless non-trivial) |
|
|
159
89
|
|
|
160
|
-
---
|
|
161
|
-
|
|
162
90
|
## When TDD Does Not Apply
|
|
163
91
|
|
|
164
|
-
- **Quick
|
|
165
|
-
- **Non-code tasks
|
|
166
|
-
- **Exploratory prototyping
|
|
167
|
-
- **Existing test suite changes
|
|
168
|
-
|
|
169
|
-
When skipping TDD, never rationalize. State clearly: "Skipping TDD because: [specific reason from list above]."
|
|
92
|
+
- **Quick or chat tasks**: trivial edits, exploration, conversational requests
|
|
93
|
+
- **Non-code tasks**: documentation, configuration, CI changes
|
|
94
|
+
- **Exploratory prototyping**: the user explicitly says "just spike this" or "prototype"
|
|
95
|
+
- **Existing test suite changes**: modifying tests themselves (devflow:testing skill applies instead)
|
|
170
96
|
|
|
171
|
-
|
|
97
|
+
When you skip TDD, state the reason from this list: "Skipping TDD because: [reason]."
|
|
172
98
|
|
|
173
|
-
##
|
|
99
|
+
## By Mode
|
|
174
100
|
|
|
175
|
-
- **IMPLEMENT
|
|
176
|
-
- **DEBUG
|
|
177
|
-
- **PLAN
|
|
178
|
-
- **RESOLVE
|
|
179
|
-
- **PIPELINE** → TDD inherited transitively through `/implement` → the Code agent.
|
|
101
|
+
- **IMPLEMENT**: write the failing test before production code, one behavior at a time. The Code agent preloads this skill.
|
|
102
|
+
- **DEBUG**: write a test that reproduces the bug first, then fix.
|
|
103
|
+
- **PLAN**: the plan has a test strategy and orders test files first.
|
|
104
|
+
- **RESOLVE**: the Code agent (issue-fix mode) writes a failing-then-passing regression test for every fix.
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# TDD Rationalization Prevention — Extended Examples
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The excuses table, the mid-work red flags, a test-first example, and detailed code examples that show how each rationalization leads to worse outcomes.
|
|
4
|
+
|
|
5
|
+
## Excuses and corrections
|
|
6
|
+
|
|
7
|
+
| Excuse | Why It Feels Right | Why It's Wrong | Correct Action |
|
|
8
|
+
|--------|-------------------|----------------|----------------|
|
|
9
|
+
| "I'll write tests after" | Need to see the shape first | Tests ARE the shape — they define the interface before implementation exists | Write the test first |
|
|
10
|
+
| "Too simple to test" | It's just a getter/setter | Getters break, defaults change, edge cases hide in "simple" code | Write it — takes 30 seconds |
|
|
11
|
+
| "I'll refactor later" | Just get it working now | "Later" never comes; technical debt compounds silently | Refactor now in Step 3 |
|
|
12
|
+
| "Test is too hard to write" or "the test setup is too complex" | Mocking is painful | Hard-to-test code = bad design, and complex setup = too much coupling; the test is telling you the interface is wrong | Simplify the interface first |
|
|
13
|
+
| "Need to see the whole picture" or "the architecture first" | Can't test what I haven't designed or structured yet | TDD IS design; each test reveals the next piece of the interface, and tests DEFINE the architecture | Let the tests drive the design and structure |
|
|
14
|
+
| "Tests slow me down" | Faster to just write the code | Faster until the first regression; TDD is faster for anything > 50 lines | Trust the cycle |
|
|
15
|
+
| "Framework is hard to set up" | Setup is complex | One-time cost vs recurring regression cost; untested code compounds debt | Set up the framework first — that IS the work |
|
|
16
|
+
| "This is infrastructure, not logic" | Plumbing doesn't need tests | Infrastructure carries data; broken plumbing floods everything downstream | Test the contract, not the internals |
|
|
17
|
+
| "Deadline is tight, no time for tests" | Ship now, test later | Untested code ships bugs; fixing bugs under deadline is slower than TDD | TDD is faster under pressure, not slower |
|
|
18
|
+
|
|
19
|
+
## Red flags mid-work
|
|
20
|
+
|
|
21
|
+
| Thought | Correction |
|
|
22
|
+
|---------|------------|
|
|
23
|
+
| "Let me write the implementation first, tests after" | Delete the code. Write the test. Watch it fail. Then rewrite. |
|
|
24
|
+
| "I'll just spike this and add tests later" | Unless the user said "spike" — you're rationalizing, not prototyping. |
|
|
25
|
+
| "Let me get it working, then lock it with tests" | Those tests verify your implementation, not the requirement. Backwards. |
|
|
26
|
+
| "I know this works, I've written it before" | Past code passed past tests. This code needs its own failing test. |
|
|
27
|
+
| "One more function, then I'll write the test" | STOP. Write the test for what you have now. Increments, not batches. |
|
|
28
|
+
|
|
29
|
+
## Test-first vs code-first
|
|
30
|
+
|
|
31
|
+
**Code-first** (wrong): write `parseConfig()`, then a test that mirrors it (`parseConfig("key=val")` passes). Empty input, malformed lines, multi-value keys and whitespace stay hidden until production.
|
|
32
|
+
|
|
33
|
+
**Test-first** (correct): "ignores comment lines", then "handles empty input", then "rejects malformed lines", each failing first and each driving the next slice of `parseConfig()`, so it handles the edges from the start.
|
|
34
|
+
|
|
35
|
+
Code-first tests verify what you *happened to build*. Test-first tests specify what *should exist*.
|
|
4
36
|
|
|
5
37
|
## "I'll write tests after"
|
|
6
38
|
|
|
@@ -18,25 +18,21 @@ activation:
|
|
|
18
18
|
|
|
19
19
|
## Iron Law
|
|
20
20
|
|
|
21
|
-
> **
|
|
21
|
+
> **Tests validate behavior, not implementation.**
|
|
22
22
|
>
|
|
23
23
|
> A test should fail when behavior breaks, not when implementation changes. Mock at
|
|
24
24
|
> boundaries, not internals. Test the contract, not the code path. If tests are hard to
|
|
25
|
-
> write, the design is wrong — fix the architecture, not the tests.
|
|
25
|
+
> write, the design is wrong — fix the architecture, not the tests.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## Testing Shapes [6][7][10]
|
|
27
|
+
## Testing Shapes
|
|
30
28
|
|
|
31
29
|
| Shape | Guidance |
|
|
32
30
|
|-------|---------|
|
|
33
|
-
| Pyramid
|
|
34
|
-
| Trophy
|
|
35
|
-
| Google
|
|
31
|
+
| Pyramid | Many unit → fewer integration → fewest E2E |
|
|
32
|
+
| Trophy | Integration tests give best ROI for UI-heavy code |
|
|
33
|
+
| Google | 70% unit / 20% integration / 10% E2E; avoid E2E excess |
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## Test Doubles Taxonomy [1][9]
|
|
35
|
+
## Test Doubles Taxonomy
|
|
40
36
|
|
|
41
37
|
| Type | When to Use | Example |
|
|
42
38
|
|------|------------|---------|
|
|
@@ -46,92 +42,78 @@ activation:
|
|
|
46
42
|
| **Mock** | Pre-programmed expectations | `expect(fn).toHaveBeenCalledWith(x)` |
|
|
47
43
|
| **Fake** | Working substitute (in-memory DB) | `InMemoryUserRepo` |
|
|
48
44
|
|
|
49
|
-
"Mock roles, not objects" — mock interfaces you own, never third-party internals
|
|
50
|
-
|
|
51
|
-
---
|
|
45
|
+
"Mock roles, not objects" — mock interfaces you own, never third-party internals.
|
|
52
46
|
|
|
53
47
|
## Test Design Red Flags
|
|
54
48
|
|
|
55
49
|
| Red Flag | Symptom | Root Cause | Fix |
|
|
56
50
|
|----------|---------|-----------|-----|
|
|
57
|
-
| Complex setup >10 lines
|
|
58
|
-
| Repetitive try/catch
|
|
59
|
-
| Nested mock structures
|
|
60
|
-
| Spying on private methods
|
|
51
|
+
| Complex setup >10 lines | `beforeEach` with 6+ mocks | Too many dependencies | Split service; use fakes |
|
|
52
|
+
| Repetitive try/catch | Same pattern >3 times | API throws, not Result | Migrate to Result types |
|
|
53
|
+
| Nested mock structures | `mockDb.orders.create: jest.fn()` | Tight coupling | Extract interface; use fake |
|
|
54
|
+
| Spying on private methods | `jest.spyOn(obj as any, '_method')` | Tests implementation | Assert observable output |
|
|
61
55
|
|
|
62
56
|
```typescript
|
|
63
|
-
// VIOLATION: Tests private implementation
|
|
57
|
+
// VIOLATION: Tests private implementation
|
|
64
58
|
jest.spyOn(cart as any, 'updateTotal');
|
|
65
59
|
expect(spy).toHaveBeenCalled(); // Tests HOW
|
|
66
60
|
|
|
67
|
-
// CORRECT: Tests observable behavior
|
|
61
|
+
// CORRECT: Tests observable behavior
|
|
68
62
|
cart.addItem({ id: '1', price: 10 });
|
|
69
63
|
expect(cart.getTotal()).toBe(10); // Tests WHAT
|
|
70
64
|
```
|
|
71
65
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
## Property-Based Testing [5][14]
|
|
66
|
+
## Property-Based Testing
|
|
75
67
|
|
|
76
|
-
State invariants; let the framework generate inputs and shrink failures
|
|
68
|
+
State invariants; let the framework generate inputs and shrink failures:
|
|
77
69
|
|
|
78
70
|
```typescript
|
|
79
|
-
// fast-check: property must hold for all valid inputs
|
|
71
|
+
// fast-check: property must hold for all valid inputs
|
|
80
72
|
fc.assert(fc.property(fc.string(), (s) => decode(encode(s)) === s));
|
|
81
73
|
```
|
|
82
74
|
|
|
83
|
-
Use for: parsers/serializers, arithmetic, sorting, state machines
|
|
84
|
-
|
|
85
|
-
---
|
|
75
|
+
Use for: parsers/serializers, arithmetic, sorting, state machines.
|
|
86
76
|
|
|
87
|
-
## Flaky Tests
|
|
77
|
+
## Flaky Tests
|
|
88
78
|
|
|
89
79
|
| Root Cause | Fix |
|
|
90
80
|
|-----------|-----|
|
|
91
|
-
| Async/timing races | Use fake timers; `await` all async ops
|
|
92
|
-
| Order dependencies | Each test self-contained; fresh state
|
|
93
|
-
| Shared mutable state | Reset in `afterEach`; use DI
|
|
94
|
-
|
|
95
|
-
Quarantine flaky tests immediately — a suite that sometimes passes is worse than no suite [11].
|
|
81
|
+
| Async/timing races | Use fake timers; `await` all async ops |
|
|
82
|
+
| Order dependencies | Each test self-contained; fresh state |
|
|
83
|
+
| Shared mutable state | Reset in `afterEach`; use DI |
|
|
96
84
|
|
|
97
|
-
|
|
85
|
+
Quarantine flaky tests immediately — a suite that sometimes passes is worse than no suite.
|
|
98
86
|
|
|
99
|
-
## Coverage & Severity
|
|
87
|
+
## Coverage & Severity
|
|
100
88
|
|
|
101
89
|
| Severity | Criteria |
|
|
102
90
|
|----------|----------|
|
|
103
|
-
| **CRITICAL** | Tests don't verify behavior; critical paths untested; everything mocked
|
|
104
|
-
| **HIGH** | Missing error paths; flaky tests
|
|
105
|
-
| **MEDIUM** | Missing edge cases; weak assertions; unclear AAA structure
|
|
91
|
+
| **CRITICAL** | Tests don't verify behavior; critical paths untested; everything mocked |
|
|
92
|
+
| **HIGH** | Missing error paths; flaky tests; slow (>10s); setup >10 lines |
|
|
93
|
+
| **MEDIUM** | Missing edge cases; weak assertions; unclear AAA structure |
|
|
106
94
|
| **LOW** | Organization; naming clarity |
|
|
107
95
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
## Test Suite Safety [19]
|
|
96
|
+
## Test Suite Safety
|
|
111
97
|
|
|
112
98
|
```typescript
|
|
113
99
|
{ fileParallelism: false, maxWorkers: 1, testTimeout: 10000 } // vitest / jest
|
|
114
100
|
```
|
|
115
101
|
|
|
116
|
-
---
|
|
117
|
-
|
|
118
102
|
## Extended References
|
|
119
103
|
|
|
120
104
|
| Reference | Contents |
|
|
121
105
|
|-----------|----------|
|
|
122
106
|
| `references/sources.md` | Full bibliography (20 sources) |
|
|
123
|
-
| `references/violations.md` | Extended violations with citations
|
|
124
|
-
| `references/patterns.md` | Correct patterns with citations
|
|
107
|
+
| `references/violations.md` | Extended violations with citations |
|
|
108
|
+
| `references/patterns.md` | Correct patterns with citations |
|
|
125
109
|
| `references/detection.md` | Bash commands for automated detection |
|
|
126
110
|
| `references/report-template.md` | Report format for documenting issues |
|
|
127
111
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
## Quality Gates [4][8][17]
|
|
112
|
+
## Quality Gates
|
|
131
113
|
|
|
132
|
-
- [ ] Setup <10 lines; use fakes over mocks for complex dependencies
|
|
114
|
+
- [ ] Setup <10 lines; use fakes over mocks for complex dependencies
|
|
133
115
|
- [ ] Each new assertion would fail, not error, with the change reverted: its RED run counts, else a bad input or a temporary uncommitted revert of your own edit, never a stash
|
|
134
116
|
- [ ] All branches covered: happy path + errors + edge cases
|
|
135
|
-
- [ ] Test names describe expected behavior
|
|
136
|
-
- [ ] Tests follow Arrange-Act-Assert structure
|
|
137
|
-
- [ ] No flaky patterns
|
|
117
|
+
- [ ] Test names describe expected behavior
|
|
118
|
+
- [ ] Tests follow Arrange-Act-Assert structure
|
|
119
|
+
- [ ] No flaky patterns
|