devflow-kit 3.10.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.
Files changed (229) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/agents/architect.md +87 -0
  3. package/dist/agents/code.md +21 -25
  4. package/dist/agents/debug.md +21 -49
  5. package/dist/agents/design.md +9 -43
  6. package/dist/agents/fix.md +15 -29
  7. package/dist/agents/git.md +19 -22
  8. package/dist/agents/harden.md +14 -19
  9. package/dist/agents/knowledge.md +11 -19
  10. package/dist/agents/refactor.md +9 -14
  11. package/dist/agents/research.md +11 -34
  12. package/dist/agents/review.md +22 -52
  13. package/dist/agents/skim.md +7 -17
  14. package/dist/agents/triage.md +7 -14
  15. package/dist/cli/commands/backup-session.js +131 -0
  16. package/dist/cli/commands/compliance.js +16 -3
  17. package/dist/cli/commands/curation.js +12 -4
  18. package/dist/cli/commands/init.js +36 -55
  19. package/dist/cli/commands/install-report.js +95 -0
  20. package/dist/cli/commands/legacy-sweep.js +140 -45
  21. package/dist/cli/commands/rules.js +50 -13
  22. package/dist/cli/commands/uninstall.js +62 -24
  23. package/dist/commands/bug-analysis.md +31 -62
  24. package/dist/commands/code-review.md +38 -87
  25. package/dist/commands/debug.md +32 -82
  26. package/dist/commands/dynamic-build.md +155 -211
  27. package/dist/commands/dynamic-plan.md +71 -93
  28. package/dist/commands/dynamic-profile.md +7 -155
  29. package/dist/commands/dynamic-tickets.md +65 -186
  30. package/dist/commands/explore.md +27 -70
  31. package/dist/commands/implement.md +98 -186
  32. package/dist/commands/plan.md +60 -107
  33. package/dist/commands/release.md +25 -91
  34. package/dist/commands/research.md +34 -103
  35. package/dist/commands/resolve.md +64 -128
  36. package/dist/commands/self-review.md +35 -99
  37. package/dist/compliance-off/agents/git.md +15 -18
  38. package/dist/compliance-off/agents/triage.md +7 -14
  39. package/dist/compliance-off/commands/bug-analysis.md +31 -62
  40. package/dist/compliance-off/commands/code-review.md +34 -82
  41. package/dist/compliance-off/commands/dynamic-build.md +149 -205
  42. package/dist/compliance-off/commands/dynamic-tickets.md +65 -186
  43. package/dist/compliance-off/commands/implement.md +94 -180
  44. package/dist/compliance-off/commands/plan.md +60 -107
  45. package/dist/compliance-off/commands/release.md +25 -90
  46. package/dist/compliance-off/commands/resolve.md +54 -128
  47. package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
  48. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
  49. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
  50. package/dist/core/compliance.js +14 -0
  51. package/dist/core/fs-atomic.js +5 -1
  52. package/dist/core/orphan-sweep.js +20 -2
  53. package/dist/core/path-set.js +15 -0
  54. package/dist/core/plugins.js +6 -5
  55. package/dist/core/reference-sweep.js +42 -25
  56. package/dist/core/retired-shipped-names.js +278 -0
  57. package/dist/curation-compliance-off/agents/triage.md +7 -13
  58. package/dist/curation-compliance-off/commands/bug-analysis.md +21 -41
  59. package/dist/curation-compliance-off/commands/code-review.md +25 -62
  60. package/dist/curation-compliance-off/commands/dynamic-build.md +142 -194
  61. package/dist/curation-compliance-off/commands/dynamic-tickets.md +54 -173
  62. package/dist/curation-compliance-off/commands/implement.md +86 -161
  63. package/dist/curation-compliance-off/commands/plan.md +51 -86
  64. package/dist/curation-compliance-off/commands/release.md +17 -78
  65. package/dist/curation-compliance-off/commands/resolve.md +45 -108
  66. package/dist/curation-off/agents/architect.md +81 -0
  67. package/dist/curation-off/agents/code.md +20 -23
  68. package/dist/curation-off/agents/debug.md +19 -47
  69. package/dist/curation-off/agents/design.md +8 -41
  70. package/dist/curation-off/agents/fix.md +14 -27
  71. package/dist/curation-off/agents/harden.md +13 -18
  72. package/dist/curation-off/agents/knowledge.md +9 -17
  73. package/dist/curation-off/agents/refactor.md +8 -12
  74. package/dist/curation-off/agents/research.md +9 -32
  75. package/dist/curation-off/agents/review.md +11 -40
  76. package/dist/curation-off/agents/skim.md +7 -17
  77. package/dist/curation-off/agents/triage.md +7 -13
  78. package/dist/curation-off/commands/bug-analysis.md +21 -41
  79. package/dist/curation-off/commands/code-review.md +29 -67
  80. package/dist/curation-off/commands/debug.md +24 -63
  81. package/dist/curation-off/commands/dynamic-build.md +148 -200
  82. package/dist/curation-off/commands/dynamic-plan.md +60 -80
  83. package/dist/curation-off/commands/dynamic-tickets.md +54 -173
  84. package/dist/curation-off/commands/explore.md +18 -50
  85. package/dist/curation-off/commands/implement.md +90 -167
  86. package/dist/curation-off/commands/plan.md +51 -86
  87. package/dist/curation-off/commands/release.md +17 -79
  88. package/dist/curation-off/commands/research.md +23 -81
  89. package/dist/curation-off/commands/resolve.md +55 -108
  90. package/dist/curation-off/commands/self-review.md +26 -78
  91. package/dist/skills/git/references/pr/update-pr-evidence.md +2 -1
  92. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
  93. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
  94. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
  95. package/dist/targets/claude-code/compliance-install.js +38 -13
  96. package/dist/targets/claude-code/compliance-off-files.js +5 -1
  97. package/dist/targets/claude-code/curation-install.js +77 -32
  98. package/dist/targets/claude-code/folder-swap.js +142 -0
  99. package/dist/targets/claude-code/install-backup.js +780 -0
  100. package/dist/targets/claude-code/installer.js +383 -192
  101. package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
  102. package/dist/targets/claude-code/linked-folder.js +5 -11
  103. package/dist/targets/claude-code/reference-converge.js +15 -2
  104. package/dist/targets/claude-code/rules-folder.js +34 -0
  105. package/dist/targets/claude-code/shipped-set.js +160 -0
  106. package/dist/targets/claude-code/workflow-folder-install.js +32 -12
  107. package/dist/variant-axes.json +5 -1
  108. package/package.json +1 -1
  109. package/src/assets/agents/_partials/_code.mds +3 -5
  110. package/src/assets/agents/_partials/_design.mds +86 -0
  111. package/src/assets/agents/architect.mds +41 -0
  112. package/src/assets/agents/code.mds +18 -20
  113. package/src/assets/agents/curate.md +26 -35
  114. package/src/assets/agents/debug.mds +21 -49
  115. package/src/assets/agents/design.mds +11 -114
  116. package/src/assets/agents/evaluate.md +6 -16
  117. package/src/assets/agents/explore.md +1 -2
  118. package/src/assets/agents/fix.mds +12 -24
  119. package/src/assets/agents/git.mds +20 -23
  120. package/src/assets/agents/harden.mds +14 -19
  121. package/src/assets/agents/knowledge.mds +10 -38
  122. package/src/assets/agents/polish.md +13 -39
  123. package/src/assets/agents/refactor.mds +6 -9
  124. package/src/assets/agents/research.mds +11 -34
  125. package/src/assets/agents/review.mds +12 -84
  126. package/src/assets/agents/skim.mds +7 -17
  127. package/src/assets/agents/synthesize.md +3 -21
  128. package/src/assets/agents/test.md +31 -32
  129. package/src/assets/agents/tracker.md +116 -229
  130. package/src/assets/agents/triage.mds +7 -26
  131. package/src/assets/agents/validate.md +1 -3
  132. package/src/assets/commands/_partials/_compliance.mds +2 -2
  133. package/src/assets/commands/_partials/_decisions.mds +17 -24
  134. package/src/assets/commands/_partials/_docs_root.mds +31 -10
  135. package/src/assets/commands/_partials/_engine.mds +34 -56
  136. package/src/assets/commands/_partials/_evidence_policy.mds +1 -1
  137. package/src/assets/commands/_partials/_factory.mds +10 -104
  138. package/src/assets/commands/_partials/_knowledge.mds +47 -51
  139. package/src/assets/commands/_partials/_plan_contract.mds +2 -2
  140. package/src/assets/commands/_partials/_preamble.mds +21 -21
  141. package/src/assets/commands/_partials/_publication.mds +3 -3
  142. package/src/assets/commands/_partials/_roster.mds +12 -13
  143. package/src/assets/commands/_partials/_settings.mds +6 -3
  144. package/src/assets/commands/_partials/_ticket_template.mds +3 -7
  145. package/src/assets/commands/_partials/_tracker.mds +10 -5
  146. package/src/assets/commands/_partials/_wave.mds +23 -32
  147. package/src/assets/commands/bug-analysis.mds +3 -7
  148. package/src/assets/commands/code-review.mds +12 -33
  149. package/src/assets/commands/debug.mds +5 -47
  150. package/src/assets/commands/dynamic-build.mds +48 -70
  151. package/src/assets/commands/dynamic-plan.mds +23 -42
  152. package/src/assets/commands/dynamic-profile.mds +7 -57
  153. package/src/assets/commands/dynamic-tickets.mds +9 -29
  154. package/src/assets/commands/explore.mds +5 -44
  155. package/src/assets/commands/implement.mds +75 -117
  156. package/src/assets/commands/plan.mds +27 -57
  157. package/src/assets/commands/release.mds +4 -62
  158. package/src/assets/commands/research.mds +7 -53
  159. package/src/assets/commands/resolve.mds +40 -87
  160. package/src/assets/commands/self-review.mds +5 -45
  161. package/src/assets/mds/git/_ops_pr.mds +1 -0
  162. package/src/assets/mds/git/_ops_steps.mds +4 -4
  163. package/src/assets/mds/git/_pr.mds +1 -1
  164. package/src/assets/rules/engineering.md +1 -1
  165. package/src/assets/rules/quality.md +2 -2
  166. package/src/assets/scripts/ci-wait.cjs +150 -18
  167. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +3 -3
  168. package/src/assets/scripts/hooks/preamble +2 -3
  169. package/src/assets/scripts/pr-evidence.cjs +1 -0
  170. package/src/assets/scripts/resolve-evidence-policy.cjs +14 -13
  171. package/src/assets/scripts/resolve-root.cjs +186 -0
  172. package/src/assets/scripts/resolve-settings.cjs +14 -9
  173. package/src/assets/scripts/verify-evidence.cjs +355 -22
  174. package/src/assets/skills/accessibility/SKILL.md +28 -95
  175. package/src/assets/skills/agent-references/SKILL.md +2 -4
  176. package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +1 -1
  177. package/src/assets/skills/agent-references/references/commands/implement-levels.md +4 -7
  178. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +1 -1
  179. package/src/assets/skills/agent-references/references/commands/plan-levels.md +2 -2
  180. package/src/assets/skills/apply-decisions/SKILL.md +5 -6
  181. package/src/assets/skills/apply-feature-knowledge/SKILL.md +3 -13
  182. package/src/assets/skills/architecture/SKILL.md +29 -105
  183. package/src/assets/skills/boundary-validation/SKILL.md +27 -78
  184. package/src/assets/skills/complexity/SKILL.md +8 -104
  185. package/src/assets/skills/compliance/SKILL.md +9 -67
  186. package/src/assets/skills/consistency/SKILL.md +7 -107
  187. package/src/assets/skills/database/SKILL.md +7 -72
  188. package/src/assets/skills/dependencies/SKILL.md +9 -109
  189. package/src/assets/skills/dependencies/references/detection.md +10 -0
  190. package/src/assets/skills/dependency-research/SKILL.md +9 -63
  191. package/src/assets/skills/design-review/SKILL.md +1 -35
  192. package/src/assets/skills/docs-framework/SKILL.md +4 -47
  193. package/src/assets/skills/documentation/SKILL.md +7 -71
  194. package/src/assets/skills/documentation/references/patterns.md +1 -1
  195. package/src/assets/skills/documentation/references/violations.md +1 -1
  196. package/src/assets/skills/feature-knowledge/SKILL.md +19 -222
  197. package/src/assets/skills/feature-knowledge/references/new-kb.md +128 -0
  198. package/src/assets/skills/gap-analysis/SKILL.md +1 -31
  199. package/src/assets/skills/git/SKILL.md +2 -22
  200. package/src/assets/skills/go/SKILL.md +24 -113
  201. package/src/assets/skills/java/SKILL.md +12 -98
  202. package/src/assets/skills/patterns/SKILL.md +8 -93
  203. package/src/assets/skills/performance/SKILL.md +29 -88
  204. package/src/assets/skills/python/SKILL.md +22 -120
  205. package/src/assets/skills/qa/SKILL.md +16 -54
  206. package/src/assets/skills/qa/references/browser-testing.md +0 -24
  207. package/src/assets/skills/qa/references/sources.md +2 -2
  208. package/src/assets/skills/quality-gates/SKILL.md +13 -100
  209. package/src/assets/skills/react/SKILL.md +33 -95
  210. package/src/assets/skills/regression/SKILL.md +8 -73
  211. package/src/assets/skills/reliability/SKILL.md +11 -120
  212. package/src/assets/skills/research-codebase/SKILL.md +7 -49
  213. package/src/assets/skills/research-competitor/SKILL.md +4 -39
  214. package/src/assets/skills/research-external/SKILL.md +5 -43
  215. package/src/assets/skills/research-market/SKILL.md +5 -43
  216. package/src/assets/skills/research-technology/SKILL.md +8 -68
  217. package/src/assets/skills/review-methodology/SKILL.md +10 -56
  218. package/src/assets/skills/rust/SKILL.md +19 -109
  219. package/src/assets/skills/security/SKILL.md +39 -66
  220. package/src/assets/skills/software-design/SKILL.md +20 -105
  221. package/src/assets/skills/software-design/references/patterns.md +84 -2
  222. package/src/assets/skills/software-design/references/violations.md +1 -1
  223. package/src/assets/skills/test-driven-development/SKILL.md +32 -107
  224. package/src/assets/skills/test-driven-development/references/rationalization-prevention.md +33 -1
  225. package/src/assets/skills/testing/SKILL.md +35 -53
  226. package/src/assets/skills/typescript/SKILL.md +23 -102
  227. package/src/assets/skills/ui-design/SKILL.md +26 -74
  228. package/src/assets/skills/worktree-support/SKILL.md +4 -10
  229. 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 "handle errors", "inject dependencies", "return Result", "make it immutable", or implements business logic or error handling.
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
- > **NEVER THROW IN BUSINESS LOGIC** [1][11]
14
+ > **Never throw in business logic**
15
15
  >
16
- > All operations that can fail MUST return Result types. Exceptions are allowed
17
- > ONLY at system boundaries (API handlers, database adapters). Any `throw` statement
18
- > in business logic is a violation. No exceptions.
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** [11] — Pure business logic, side effects at boundary
23
- 2. **Explicit Error Handling** [1][8] — Result types, no exceptions in business logic
24
- 3. **Immutability by Default** [7][14] — Return new objects, never mutate
25
- 4. **Dependency Injection** [3] — All deps injected, nothing instantiated internally
26
- 5. **Make Illegal States Unrepresentable** [4][2] — Types enforce invariants at compile time
27
- 6. **Parse, Don't Validate** [12] — Schema transforms at boundaries
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, ALL must [1]
116
- - DI: apply consistently throughout [3]
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
- | Pattern | Source |
122
- |---------|--------|
123
- | Throwing in business logic — use Result | [1][11] |
124
- | Silent failures — swallowed catch blocks | [10] |
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` — Extended correct patterns with citations
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
- # Extended Correct Pattern Examples
1
+ # Correct Pattern Examples
2
2
 
3
- Additional examples of correct implementations beyond the core examples in SKILL.md.
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]
@@ -1,6 +1,6 @@
1
1
  # Extended Violation Examples
2
2
 
3
- Additional code smell patterns and violations beyond the core examples in SKILL.md.
3
+ Additional code smell patterns and violations beyond the anti-patterns in SKILL.md.
4
4
  All violations cite `references/sources.md`.
5
5
 
6
6
  ---
@@ -19,18 +19,15 @@ activation:
19
19
 
20
20
  # Test-Driven Development
21
21
 
22
- Enforce the RED-GREEN-REFACTOR cycle for all implementation work. Tests define the design. Code satisfies the tests. Refactoring improves the design without changing behavior.
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
- > **TESTS FIRST, ALWAYS**
26
+ > **Tests first, always.**
27
27
  >
28
- > Write the failing test before the production code. No exceptions. If you catch
29
- > yourself writing production code without a failing test, stop immediately, delete
30
- > the production code, write the test, watch it fail, then write the minimum code
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 IS your specification.
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 more, no less.
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
- Now clean up: extract helpers, rename, simplify, apply DRY. Tests stay green throughout.
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 RED-GREEN-REFACTOR cycle, ALL must hold:
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 RIGHT reason (expected behavior absent, not syntax/import error)
82
- - [ ] Production code is minimal — no speculative additions beyond what the test demands
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: you skipped TDD. Back up and redo the cycle correctly.
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
- The table above catches excuses *before starting*. These catch you *mid-work*: thoughts that signal you are about to skip a step.
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
- | Thought | Correction |
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. "Given X, expect Y." Start there. |
134
- | Test needs complex setup/state | Extract the logic into a pure function. Test that. Integrate after. |
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 | Decompose. One test = one behavior. If you can't isolate it, the design needs splitting. |
137
- | Modifying legacy code with no tests | Write a characterization test first — a test that captures the current behavior, even if wrong. Then make your change and see what breaks. |
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
- ## Process Enforcement
79
+ ## What to Test
142
80
 
143
- When implementing any feature under ambient IMPLEMENT, start from the simplest thing it must do, take that one behavior through RED, GREEN and REFACTOR, then repeat for the next behavior.
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/chat tasks** — Trivial edits, exploration, conversational requests
165
- - **Non-code tasks** — Documentation, configuration, CI changes
166
- - **Exploratory prototyping** — User explicitly says "just spike this" or "prototype"
167
- - **Existing test suite changes** — Modifying tests themselves (devflow:testing skill applies instead)
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
- ## Integration with Ambient Mode
99
+ ## By Mode
174
100
 
175
- - **IMPLEMENT** → TDD enforced. Write the failing test before production code. Skill loaded via Code agent frontmatter.
176
- - **DEBUG** → TDD applies to the fix: write a test that reproduces the bug first, then fix.
177
- - **PLAN** → TDD shapes the plan: test strategy section, test-first file ordering, RED-GREEN-REFACTOR cycle awareness.
178
- - **RESOLVE** → TDD enforced via the Code agent (issue-fix mode). Every fix needs a failing-then-passing regression test first.
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
- Detailed code examples showing how each rationalization leads to worse outcomes.
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
- > **TESTS VALIDATE BEHAVIOR, NOT IMPLEMENTATION** [4][8]
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. [3][8]
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 [6] | Many unit → fewer integration → fewest E2E |
34
- | Trophy [7] | Integration tests give best ROI for UI-heavy code |
35
- | Google [4] | 70% unit / 20% integration / 10% E2E; avoid E2E excess [12] |
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 [3][9].
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 [8] | `beforeEach` with 6+ mocks | Too many dependencies | Split service; use fakes [1][4] |
58
- | Repetitive try/catch [8] | Same pattern >3 times | API throws, not Result | Migrate to Result types [4] |
59
- | Nested mock structures [1][3] | `mockDb.orders.create: jest.fn()` | Tight coupling | Extract interface; use fake [9] |
60
- | Spying on private methods [8] | `jest.spyOn(obj as any, '_method')` | Tests implementation | Assert observable output [4] |
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 [8]
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 [4]
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 [5]:
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 [14]
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 [5][13][14].
84
-
85
- ---
75
+ Use for: parsers/serializers, arithmetic, sorting, state machines.
86
76
 
87
- ## Flaky Tests [11][18]
77
+ ## Flaky Tests
88
78
 
89
79
  | Root Cause | Fix |
90
80
  |-----------|-----|
91
- | Async/timing races | Use fake timers; `await` all async ops [19] |
92
- | Order dependencies | Each test self-contained; fresh state [4] |
93
- | Shared mutable state | Reset in `afterEach`; use DI [4] |
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 [4][8]
87
+ ## Coverage & Severity
100
88
 
101
89
  | Severity | Criteria |
102
90
  |----------|----------|
103
- | **CRITICAL** | Tests don't verify behavior; critical paths untested; everything mocked [4] |
104
- | **HIGH** | Missing error paths; flaky tests [11]; slow (>10s); setup >10 lines [8] |
105
- | **MEDIUM** | Missing edge cases; weak assertions; unclear AAA structure [17] |
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 [1][4][8][11] |
124
- | `references/patterns.md` | Correct patterns with citations [1][2][5][14] |
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 [1]
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 [4]
136
- - [ ] Tests follow Arrange-Act-Assert structure [17]
137
- - [ ] No flaky patterns [11][18]
117
+ - [ ] Test names describe expected behavior
118
+ - [ ] Tests follow Arrange-Act-Assert structure
119
+ - [ ] No flaky patterns