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.
- package/CHANGELOG.md +74 -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/cli/commands/backup-session.js +131 -0
- package/dist/cli/commands/compliance.js +16 -3
- package/dist/cli/commands/curation.js +12 -4
- package/dist/cli/commands/init.js +36 -55
- package/dist/cli/commands/install-report.js +95 -0
- package/dist/cli/commands/legacy-sweep.js +140 -45
- package/dist/cli/commands/rules.js +50 -13
- package/dist/cli/commands/uninstall.js +62 -24
- 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/compliance.js +14 -0
- package/dist/core/fs-atomic.js +5 -1
- package/dist/core/orphan-sweep.js +20 -2
- package/dist/core/path-set.js +15 -0
- package/dist/core/plugins.js +6 -5
- package/dist/core/reference-sweep.js +42 -25
- package/dist/core/retired-shipped-names.js +278 -0
- 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/compliance-install.js +38 -13
- package/dist/targets/claude-code/compliance-off-files.js +5 -1
- package/dist/targets/claude-code/curation-install.js +77 -32
- package/dist/targets/claude-code/folder-swap.js +142 -0
- package/dist/targets/claude-code/install-backup.js +780 -0
- package/dist/targets/claude-code/installer.js +383 -192
- package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
- package/dist/targets/claude-code/linked-folder.js +5 -11
- package/dist/targets/claude-code/reference-converge.js +15 -2
- package/dist/targets/claude-code/rules-folder.js +34 -0
- package/dist/targets/claude-code/shipped-set.js +160 -0
- package/dist/targets/claude-code/workflow-folder-install.js +32 -12
- 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
|
@@ -12,7 +12,7 @@ activation:
|
|
|
12
12
|
|
|
13
13
|
# Go Patterns
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Full bibliography: `references/sources.md`.
|
|
16
16
|
|
|
17
17
|
## Iron Law
|
|
18
18
|
|
|
@@ -22,126 +22,37 @@ Reference for Go-specific patterns, idioms, and best practices. Full bibliograph
|
|
|
22
22
|
> return must be checked, wrapped with context, or explicitly documented as intentionally
|
|
23
23
|
> ignored with `_ = fn()`. "Errors are values. Values can be programmed." — Rob Pike [5]
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Error Handling
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
- Wrap with context, `return fmt.Errorf("finding user %s: %w", id, err)`, not a bare `return err`: the caller loses context.
|
|
28
|
+
- Declare sentinel errors (`var ErrNotFound = errors.New("not found")`) and match them with `errors.Is`.
|
|
29
|
+
- Never discard an error with `val, _ := fn()`: check it, wrap it, or ignore it on purpose with `_ = fn()`.
|
|
30
|
+
- No `panic` or `log.Fatal` in library code.
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Error Handling [5][6]
|
|
32
|
-
|
|
33
|
-
```go
|
|
34
|
-
// BAD: return err — caller loses context
|
|
35
|
-
// GOOD: return fmt.Errorf("reading config %s: %w", path, err)
|
|
36
|
-
|
|
37
|
-
var ErrNotFound = errors.New("not found")
|
|
38
|
-
|
|
39
|
-
func FindUser(id string) (*User, error) {
|
|
40
|
-
u, err := db.Get(id)
|
|
41
|
-
if err != nil {
|
|
42
|
-
return nil, fmt.Errorf("finding user %s: %w", id, err)
|
|
43
|
-
}
|
|
44
|
-
if u == nil { return nil, ErrNotFound }
|
|
45
|
-
return u, nil
|
|
46
|
-
}
|
|
47
|
-
// Caller: if errors.Is(err, ErrNotFound) { ... }
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Interface Design [7][14]
|
|
32
|
+
## Interface Design
|
|
53
33
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// GOOD: func NewService(repo Repository) *Service — accept interfaces [14]
|
|
34
|
+
- Accept interfaces: `NewService(repo Repository)`, not `NewService(repo *PostgresRepo)`.
|
|
35
|
+
- Define an interface at the consumer when it is used, not at the producer before use.
|
|
36
|
+
- Keep interfaces small (1-3 methods) and compose them (`ReadWriter` embeds `Reader` and `Writer`).
|
|
58
37
|
|
|
59
|
-
|
|
60
|
-
type Reader interface { Read(p []byte) (n int, err error) }
|
|
61
|
-
type Writer interface { Write(p []byte) (n int, err error) }
|
|
62
|
-
type ReadWriter interface { Reader; Writer }
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Concurrency [9][10][13]
|
|
68
|
-
|
|
69
|
-
CSP (Hoare [9]): "Do not communicate by sharing memory; share memory by communicating." [10]
|
|
70
|
-
|
|
71
|
-
```go
|
|
72
|
-
// Context cancellation with errgroup [16][22]
|
|
73
|
-
func Process(ctx context.Context, items []Item) error {
|
|
74
|
-
g, ctx := errgroup.WithContext(ctx)
|
|
75
|
-
for _, item := range items {
|
|
76
|
-
g.Go(func() error { return processItem(ctx, item) })
|
|
77
|
-
}
|
|
78
|
-
return g.Wait()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Channel direction prevents misuse at compile time [1][8]
|
|
82
|
-
func producer(ch chan<- int) { ch <- 42 }
|
|
83
|
-
func consumer(ch <-chan int) { v := <-ch; _ = v }
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
38
|
+
## Concurrency
|
|
87
39
|
|
|
88
|
-
|
|
40
|
+
- Do not communicate by sharing memory; share memory by communicating.
|
|
41
|
+
- Pass `context.Context` as the first parameter.
|
|
42
|
+
- Give every goroutine a clear lifecycle and cancellation, for example `errgroup.WithContext`. A bare `go fn()` leaks.
|
|
43
|
+
- Specify channel direction in signatures: `chan<- int`, `<-chan int`.
|
|
89
44
|
|
|
90
|
-
|
|
91
|
-
// BAD: models/, controllers/, services/
|
|
92
|
-
// GOOD: user/, order/, payment/ — organize by domain [15]
|
|
45
|
+
## Package Design and Zero Values
|
|
93
46
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Zero Values [1]
|
|
101
|
-
|
|
102
|
-
```go
|
|
103
|
-
var mu sync.Mutex; var buf bytes.Buffer // Ready to use — no init needed
|
|
104
|
-
|
|
105
|
-
type Config struct {
|
|
106
|
-
Timeout time.Duration // zero = no timeout
|
|
107
|
-
Retries int // zero = no retries
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## Anti-Patterns
|
|
114
|
-
|
|
115
|
-
| Pattern | Violation | Source |
|
|
116
|
-
|---------|-----------|--------|
|
|
117
|
-
| Ignoring error | `val, _ := fn()` | [5][2] |
|
|
118
|
-
| Naked return | `return` in named returns | [2][4] |
|
|
119
|
-
| init() abuse | Complex `init()` with side effects | [1][12] |
|
|
120
|
-
| Interface pollution | Interface defined before use | [14][7] |
|
|
121
|
-
| Goroutine leak | `go fn()` without lifecycle | [13][16] |
|
|
122
|
-
| Panic in library | `panic(err)` in non-main code | [1][4] |
|
|
123
|
-
|
|
124
|
-
---
|
|
47
|
+
- Organize packages by domain (`user/`, `order/`), not by type (`models/`, `controllers/`). Keep internals unexported.
|
|
48
|
+
- Make zero values ready to use (`sync.Mutex`, `bytes.Buffer`; a zero `Timeout` means no timeout).
|
|
49
|
+
- No naked `return` in functions with named returns.
|
|
50
|
+
- No complex `init()` with side effects.
|
|
125
51
|
|
|
126
52
|
## Extended References
|
|
127
53
|
|
|
128
|
-
- `references/sources.md` — Full bibliography
|
|
129
|
-
- `references/violations.md` — Violations with citations
|
|
130
|
-
- `references/patterns.md` — Extended patterns with citations
|
|
54
|
+
- `references/sources.md` — Full bibliography
|
|
55
|
+
- `references/violations.md` — Violations with citations
|
|
56
|
+
- `references/patterns.md` — Extended patterns with citations
|
|
131
57
|
- `references/detection.md` — Grep patterns for automated detection
|
|
132
|
-
- `references/concurrency.md` — CSP-grounded concurrency patterns
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## Checklist
|
|
137
|
-
|
|
138
|
-
- [ ] All errors checked or explicitly ignored with `_ =` [5]
|
|
139
|
-
- [ ] Errors wrapped with `fmt.Errorf("context: %w", err)` [6]
|
|
140
|
-
- [ ] Interfaces defined at consumer, not producer [14]
|
|
141
|
-
- [ ] Interfaces kept small (1-3 methods) [7]
|
|
142
|
-
- [ ] Context as first parameter [16]
|
|
143
|
-
- [ ] Goroutines have clear lifecycle/cancellation [13]
|
|
144
|
-
- [ ] Channel direction specified in signatures [8]
|
|
145
|
-
- [ ] Packages organized by domain, not by type [15]
|
|
146
|
-
- [ ] No `init()` with side effects [1]
|
|
147
|
-
- [ ] No `panic` or `log.Fatal` in library code [4]
|
|
58
|
+
- `references/concurrency.md` — CSP-grounded concurrency patterns
|
|
@@ -13,8 +13,6 @@ activation:
|
|
|
13
13
|
|
|
14
14
|
# Java Patterns
|
|
15
15
|
|
|
16
|
-
Reference for modern Java patterns, type system, and best practices.
|
|
17
|
-
|
|
18
16
|
## Iron Law
|
|
19
17
|
|
|
20
18
|
> **FAVOR COMPOSITION OVER INHERITANCE**
|
|
@@ -24,125 +22,41 @@ Reference for modern Java patterns, type system, and best practices.
|
|
|
24
22
|
> records for data, and sealed classes for restricted hierarchies. Extend only when the
|
|
25
23
|
> "is-a" relationship is genuinely invariant. — Effective Java, Item 18 [1, Item 18]
|
|
26
24
|
|
|
27
|
-
## When This Skill Activates
|
|
28
|
-
|
|
29
|
-
- Working with Java codebases (records, sealed classes, Optional, streams)
|
|
30
|
-
- Implementing concurrent code or API design
|
|
31
|
-
- Structuring Java packages and dependencies
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
25
|
## Type System (Modern Java)
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```java
|
|
41
|
-
// BAD: Mutable POJO. GOOD: Immutable record [1, Item 17][4]
|
|
42
|
-
public record User(String name, String email, Instant createdAt) {
|
|
43
|
-
public User {
|
|
44
|
-
Objects.requireNonNull(name); Objects.requireNonNull(email);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Sealed classes** [5][9] — Close the subtype set, enabling exhaustive pattern matching. [6]
|
|
27
|
+
- Use records for pure data, not mutable POJOs with `setName()/getName()`. Validate in the compact constructor (`Objects.requireNonNull`).
|
|
28
|
+
- Use sealed interfaces for type hierarchies. They close the subtype set, so a switch over them is exhaustive with no `default`:
|
|
50
29
|
|
|
51
30
|
```java
|
|
52
31
|
public sealed interface Result<T> permits Success, Failure {
|
|
53
32
|
record Success<T>(T value) implements Result<T> {}
|
|
54
33
|
record Failure<T>(String error) implements Result<T> {}
|
|
55
34
|
}
|
|
56
|
-
// Exhaustive — no default needed [6]
|
|
57
35
|
switch (result) {
|
|
58
36
|
case Success<User> s -> handleSuccess(s.value());
|
|
59
37
|
case Failure<User> f -> handleError(f.error());
|
|
60
38
|
}
|
|
61
39
|
```
|
|
62
40
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```java
|
|
67
|
-
public Optional<User> findById(String id) { return Optional.ofNullable(userMap.get(id)); }
|
|
68
|
-
optional.map(User::name).orElse("Anonymous");
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
---
|
|
41
|
+
- Never return `null`: return `Optional`, and chain with `map`/`orElse`, not `isPresent()`/`get()`.
|
|
42
|
+
- No raw generic types: `List<User>`, not `List`.
|
|
72
43
|
|
|
73
44
|
## Error Handling
|
|
74
45
|
|
|
75
|
-
|
|
76
|
-
carry structured fields for
|
|
46
|
+
- Use try-with-resources for every `AutoCloseable` resource.
|
|
47
|
+
- Throw specific or unchecked custom exceptions that carry structured fields for context, not `throws Exception`.
|
|
77
48
|
|
|
78
|
-
|
|
79
|
-
try (var conn = dataSource.getConnection(); var stmt = conn.prepareStatement(sql)) {
|
|
80
|
-
stmt.setString(1, id); return mapResult(stmt.executeQuery());
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
49
|
+
## Immutability and Composition
|
|
85
50
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```java
|
|
91
|
-
public final class Team {
|
|
92
|
-
private final List<String> members;
|
|
93
|
-
public Team(List<String> members) { this.members = List.copyOf(members); }
|
|
94
|
-
public List<String> members() { return members; }
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Composition Over Inheritance [1, Item 18]
|
|
101
|
-
|
|
102
|
-
Constructor-inject collaborators. Never extend a class solely to reuse methods. [1, Item 18][14]
|
|
103
|
-
|
|
104
|
-
```java
|
|
105
|
-
// BAD: class UserService extends BaseService extends AbstractDAO
|
|
106
|
-
// GOOD: inject repository and eventBus as constructor parameters [1, Item 18]
|
|
107
|
-
public class UserService {
|
|
108
|
-
public UserService(UserRepository repository, EventPublisher events) { ... }
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Anti-Patterns
|
|
115
|
-
|
|
116
|
-
| Pattern | Bad | Good | Source |
|
|
117
|
-
|---------|-----|------|--------|
|
|
118
|
-
| Returning null | `return null` | `return Optional.empty()` | [1, Item 22] |
|
|
119
|
-
| Checked exception abuse | `throws Exception` | Specific or unchecked | [1] |
|
|
120
|
-
| Raw types | `List list` | `List<User> list` | [1, Item 26][3] |
|
|
121
|
-
| Deep inheritance | 4+ level hierarchy | Interfaces + composition | [1, Item 18][14] |
|
|
122
|
-
| Mutable data objects | `setName()/getName()` | Records or immutable classes | [1, Item 17][4] |
|
|
123
|
-
| Shared mutable state | `HashMap` across threads | `ConcurrentHashMap` or immutable | [2][12] |
|
|
124
|
-
|
|
125
|
-
---
|
|
51
|
+
- Prefer `List.of`/`Map.of`. Make defensive copies in constructors with `List.copyOf`.
|
|
52
|
+
- Do not share mutable state across threads (`HashMap`): use `ConcurrentHashMap` or immutable data.
|
|
53
|
+
- Constructor-inject collaborators. Never extend a class only to reuse methods; replace deep hierarchies (4+ levels) with interfaces and composition.
|
|
54
|
+
- Use streams for collection transforms.
|
|
126
55
|
|
|
127
56
|
## Extended References
|
|
128
57
|
|
|
129
|
-
- `references/sources.md` — Full bibliography
|
|
58
|
+
- `references/sources.md` — Full bibliography
|
|
130
59
|
- `references/violations.md` — Common Java violations with citations
|
|
131
60
|
- `references/patterns.md` — Extended Java patterns with citations
|
|
132
61
|
- `references/detection.md` — Detection patterns for Java issues
|
|
133
62
|
- `references/modern-java.md` — Modern Java features (17-21+) with JEP citations
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## Checklist
|
|
138
|
-
|
|
139
|
-
- [ ] Records for pure data types [4]
|
|
140
|
-
- [ ] Sealed interfaces for type hierarchies [5]
|
|
141
|
-
- [ ] Optional instead of null returns [1, Item 22]
|
|
142
|
-
- [ ] Composition over inheritance [1, Item 18]
|
|
143
|
-
- [ ] Try-with-resources for all AutoCloseable [3]
|
|
144
|
-
- [ ] Immutable collections (List.of, Map.of) [1, Item 17]
|
|
145
|
-
- [ ] No raw generic types [1, Item 26]
|
|
146
|
-
- [ ] Custom exceptions with context [1]
|
|
147
|
-
- [ ] Streams for collection transforms [10][26]
|
|
148
|
-
- [ ] Constructor injection for dependencies [1, Item 18]
|
|
@@ -7,7 +7,7 @@ allowed-tools: Read, Grep, Glob
|
|
|
7
7
|
|
|
8
8
|
# Implementation Patterns
|
|
9
9
|
|
|
10
|
-
Reference for common implementation patterns.
|
|
10
|
+
Reference for common implementation patterns.
|
|
11
11
|
|
|
12
12
|
## Iron Law
|
|
13
13
|
|
|
@@ -17,104 +17,37 @@ Reference for common implementation patterns. Use these patterns to write consis
|
|
|
17
17
|
> use Result types. If it uses exceptions, use exceptions. Consistency trumps personal
|
|
18
18
|
> preference. The best pattern is the one already in use.
|
|
19
19
|
|
|
20
|
-
## When This Skill Activates
|
|
21
|
-
|
|
22
|
-
- Implementing CRUD operations
|
|
23
|
-
- Creating API endpoints
|
|
24
|
-
- Writing event handlers
|
|
25
|
-
- Setting up configuration
|
|
26
|
-
- Adding logging
|
|
27
|
-
- Database operations
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
20
|
## Pattern Categories
|
|
32
21
|
|
|
33
22
|
### CRUD Operations
|
|
34
23
|
|
|
35
|
-
Create, Read, Update, Delete with Result types and proper error handling.
|
|
36
|
-
|
|
37
24
|
**Core pattern**: Validate -> Transform -> Persist -> Return
|
|
38
25
|
|
|
39
|
-
|
|
40
|
-
async function createUser(input: CreateUserInput): Promise<Result<User, CreateError>> {
|
|
41
|
-
const validated = validateCreateUser(input);
|
|
42
|
-
if (!validated.ok) return Err({ type: 'validation', details: validated.error });
|
|
43
|
-
|
|
44
|
-
const user: User = { id: generateId(), ...validated.value, createdAt: new Date() };
|
|
45
|
-
const saved = await userRepository.save(user);
|
|
46
|
-
if (!saved.ok) return Err({ type: 'persistence', details: saved.error });
|
|
47
|
-
|
|
48
|
-
return Ok(saved.value);
|
|
49
|
-
}
|
|
50
|
-
```
|
|
26
|
+
Return `Result<T, E>`: a failed validation returns a `validation` error, a failed save a `persistence` error, and success returns the saved value.
|
|
51
27
|
|
|
52
28
|
### API Endpoints
|
|
53
29
|
|
|
54
|
-
REST endpoint structure with auth, validation, and error mapping.
|
|
55
|
-
|
|
56
30
|
**Core pattern**: Parse request -> Validate auth -> Execute -> Format response
|
|
57
31
|
|
|
58
|
-
|
|
59
|
-
export async function handleGetUser(req: Request): Promise<Response> {
|
|
60
|
-
const id = parsePathParam(req, 'id');
|
|
61
|
-
if (!id.ok) return errorResponse(400, 'Invalid user ID');
|
|
62
|
-
|
|
63
|
-
const auth = await authenticate(req);
|
|
64
|
-
if (!auth.ok) return errorResponse(401, 'Unauthorized');
|
|
65
|
-
|
|
66
|
-
const result = await getUser(id.value);
|
|
67
|
-
if (!result.ok) return handleError(result.error);
|
|
68
|
-
|
|
69
|
-
return jsonResponse(200, result.value);
|
|
70
|
-
}
|
|
71
|
-
```
|
|
32
|
+
A bad parameter returns 400 and a failed authentication 401 before any work runs. Map a domain error to its status in one handler, and return the success value as JSON.
|
|
72
33
|
|
|
73
34
|
### Event Handlers
|
|
74
35
|
|
|
75
|
-
Async event processing with idempotency and error recovery.
|
|
76
|
-
|
|
77
36
|
**Core pattern**: Validate event -> Process -> Handle errors -> Acknowledge
|
|
78
37
|
|
|
79
|
-
|
|
80
|
-
async function handleUserCreated(event: UserCreatedEvent): Promise<void> {
|
|
81
|
-
const validated = validateEvent(event);
|
|
82
|
-
if (!validated.ok) { logger.warn('Invalid event'); return; }
|
|
83
|
-
|
|
84
|
-
await sendWelcomeEmail(event.userId);
|
|
85
|
-
await createDefaultSettings(event.userId);
|
|
86
|
-
logger.info('Event processed successfully');
|
|
87
|
-
}
|
|
88
|
-
```
|
|
38
|
+
Make each handler idempotent, so a redelivered event does no harm. Log an invalid event as a warning and drop it; do not throw.
|
|
89
39
|
|
|
90
40
|
### Configuration
|
|
91
41
|
|
|
92
|
-
Environment config with schema validation and feature flags.
|
|
93
|
-
|
|
94
42
|
**Core pattern**: Define schema -> Load from env -> Validate -> Export frozen
|
|
95
43
|
|
|
96
|
-
|
|
97
|
-
const ConfigSchema = z.object({
|
|
98
|
-
PORT: z.coerce.number().default(3000),
|
|
99
|
-
DATABASE_URL: z.string().url(),
|
|
100
|
-
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
export const config = Object.freeze(ConfigSchema.parse(process.env));
|
|
104
|
-
```
|
|
44
|
+
Parse `process.env` once at startup through a schema (coerced types, defaults, required URLs), fail fast on an error, and export the result with `Object.freeze`.
|
|
105
45
|
|
|
106
46
|
### Logging
|
|
107
47
|
|
|
108
|
-
Structured logging with context propagation and operation tracking.
|
|
109
|
-
|
|
110
48
|
**Core pattern**: Context -> Level -> Message -> Data
|
|
111
49
|
|
|
112
|
-
|
|
113
|
-
const logger = createLogger({ requestId: req.id, userId: user.id });
|
|
114
|
-
logger.info('Processing order', { orderId: order.id, items: order.items.length });
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
50
|
+
Create the logger with request context (`requestId`, `userId`), and log a message with structured data (`{ orderId, items }`).
|
|
118
51
|
|
|
119
52
|
## Anti-Patterns to Avoid
|
|
120
53
|
|
|
@@ -125,38 +58,20 @@ logger.info('Processing order', { orderId: order.id, items: order.items.length }
|
|
|
125
58
|
| Swallowing errors | Empty catch blocks | Handle or propagate with Result types |
|
|
126
59
|
| Magic values | Unexplained numbers/strings | Extract to named constants |
|
|
127
60
|
|
|
128
|
-
---
|
|
129
|
-
|
|
130
61
|
## Build Optimization
|
|
131
62
|
|
|
132
|
-
Production builds must exclude test files, debug artifacts, and sourcemaps.
|
|
133
|
-
|
|
134
|
-
```json
|
|
135
|
-
// tsconfig.prod.json
|
|
136
|
-
{
|
|
137
|
-
"exclude": ["**/*.test.ts", "**/*.spec.ts", "**/tests/**"]
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
---
|
|
63
|
+
Production builds must exclude test files, debug artifacts, and sourcemaps (for example `"exclude": ["**/*.test.ts", "**/*.spec.ts", "**/tests/**"]` in `tsconfig.prod.json`).
|
|
142
64
|
|
|
143
65
|
## Implementation Checklist
|
|
144
66
|
|
|
145
67
|
Before implementing, verify:
|
|
146
68
|
|
|
147
|
-
- [ ] Using Result types for operations that can fail
|
|
148
|
-
- [ ] Validating input at system boundaries
|
|
149
|
-
- [ ] Logging with context (requestId, userId, operation)
|
|
150
69
|
- [ ] Handling all error cases explicitly
|
|
151
|
-
- [ ] Making operations idempotent where possible
|
|
152
70
|
- [ ] Using transactions for multi-step operations
|
|
153
71
|
- [ ] No hardcoded values (use config)
|
|
154
|
-
- [ ]
|
|
155
|
-
|
|
156
|
-
---
|
|
72
|
+
- [ ] Input validated at system boundaries; operations idempotent where possible
|
|
157
73
|
|
|
158
74
|
## Extended References
|
|
159
75
|
|
|
160
|
-
For full implementation examples:
|
|
161
76
|
- `references/violations.md` - Extended violation examples (CRUD, API, Events, Config, Logging)
|
|
162
77
|
- `references/patterns.md` - Extended correct patterns (CRUD, API, Events, Config, Logging)
|
|
@@ -1,135 +1,76 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: performance
|
|
3
|
-
description:
|
|
3
|
+
description: Use when reviewing code for N+1 queries or memory leaks.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
allowed-tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Performance Patterns
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Detection patterns for performance and bottleneck review. Use with `devflow:review-methodology`.
|
|
11
11
|
|
|
12
12
|
## Iron Law
|
|
13
13
|
|
|
14
|
-
> **
|
|
14
|
+
> **Measure before optimizing.**
|
|
15
15
|
>
|
|
16
16
|
> Profile first, optimize second. Every performance claim requires benchmarks. Brendan
|
|
17
|
-
> Gregg's USE Method
|
|
17
|
+
> Gregg's USE Method (Utilization, Saturation, Errors) and Tom Wilkie's RED Method
|
|
18
18
|
> (Rate, Errors, Duration) are the systematic starting points — not guesswork.
|
|
19
|
-
> Gil Tene's coordinated omission warning
|
|
19
|
+
> Gil Tene's coordinated omission warning: averages lie — monitor P99, not mean latency.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Measurement Foundation [1][2][7][8][9]
|
|
24
|
-
|
|
25
|
-
| Method | For | Measures |
|
|
26
|
-
|--------|-----|---------|
|
|
27
|
-
| USE Method [1] | System resources | Utilization, Saturation, Errors per resource |
|
|
28
|
-
| RED Method [2] | Services | Rate, Errors, Duration per endpoint |
|
|
29
|
-
| Flame Graphs [9] | CPU hot paths | Widest frames = hottest code — optimize those |
|
|
30
|
-
| HDR Histogram [8] | Latency | Full distribution without coordinated omission |
|
|
31
|
-
|
|
32
|
-
**Latency hierarchy** [7]: L1 cache ~1ns · L2 ~4ns · L3 ~40ns · RAM ~100ns · SSD ~100µs · Network (DC) ~500µs · HDD ~10ms. Knowing these prevents optimizing the wrong layer [4].
|
|
33
|
-
|
|
34
|
-
---
|
|
21
|
+
Measurement tools: flame graphs for CPU hot paths (widest frames are hottest), HDR histograms for full latency distributions.
|
|
35
22
|
|
|
36
23
|
## Performance Categories
|
|
37
24
|
|
|
38
|
-
### 1. Algorithmic Issues
|
|
39
|
-
|
|
40
|
-
**N+1 Query Problem** — database query inside a loop. O(n) round-trips [5].
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
// VIOLATION: 1 + N queries — O(n) round-trips [5]
|
|
44
|
-
for (const user of users) {
|
|
45
|
-
user.orders = await db.orders.findByUserId(user.id);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// CORRECT: Batch query with Map lookup — O(1) per access [5]
|
|
49
|
-
const orders = await db.orders.findAll({ where: { userId: userIds } });
|
|
50
|
-
const ordersByUser = new Map(groupBy(orders, 'userId'));
|
|
51
|
-
users.forEach(u => u.orders = ordersByUser.get(u.id) || []);
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**O(n²) Patterns** — linear search inside a loop [12].
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
// VIOLATION: Array.includes is O(n), called n times → O(n²) [12]
|
|
58
|
-
items.filter(item => selected.includes(item.id));
|
|
25
|
+
### 1. Algorithmic Issues
|
|
59
26
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
items.filter(item => selectedSet.has(item.id));
|
|
63
|
-
```
|
|
27
|
+
- **N+1 queries**: a database query inside a loop, O(n) round trips. Fix: one batch query, then a Map lookup.
|
|
28
|
+
- **O(n²) patterns**: linear search inside a loop (`items.filter(i => selected.includes(i.id))`). Fix: a Set lookup.
|
|
64
29
|
|
|
65
|
-
### 2. Memory Issues
|
|
30
|
+
### 2. Memory Issues
|
|
66
31
|
|
|
67
|
-
**Memory
|
|
68
|
-
**Cache line false sharing
|
|
69
|
-
**Unbounded caches
|
|
32
|
+
- **Memory leaks**: resources not cleaned up, hidden by GC until OOM.
|
|
33
|
+
- **Cache line false sharing**: hot fields on the same 64-byte line cause inter-core invalidation in high-throughput code.
|
|
34
|
+
- **Unbounded caches**: collections that grow forever. Use LRU with a `max` limit.
|
|
70
35
|
|
|
71
|
-
### 3. I/O Issues
|
|
36
|
+
### 3. I/O Issues
|
|
72
37
|
|
|
73
|
-
**Blocking
|
|
38
|
+
- **Blocking operations**: synchronous I/O (`readFileSync`) in a request path blocks the event loop.
|
|
39
|
+
- **Sequential when parallel is possible**: independent awaits run serially, so the total is the sum, not the max. Fix: `Promise.all`.
|
|
40
|
+
- **Wrong layer**: CPU micro-tuning on a path bound by disk or network I/O (RAM ~100ns, SSD ~100µs, network ~500µs).
|
|
74
41
|
|
|
75
|
-
|
|
76
|
-
const config = fs.readFileSync('./config.json'); // VIOLATION [3]
|
|
77
|
-
const config = await fs.promises.readFile('./config.json'); // CORRECT [16]
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**Sequential When Parallel Possible** — independent operations run serially [5].
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
// VIOLATION: total = sum of all [5]
|
|
84
|
-
const user = await getUser(id); const orders = await getOrders(id);
|
|
85
|
-
// CORRECT: total = max of all
|
|
86
|
-
const [user, orders] = await Promise.all([getUser(id), getOrders(id)]);
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### 4. Database Issues [20]
|
|
42
|
+
### 4. Database Issues
|
|
90
43
|
|
|
91
44
|
Missing indexes, SELECT *, OFFSET pagination on large tables, LIKE with leading wildcard. See `references/violations.md`.
|
|
92
45
|
|
|
93
|
-
### 5. Frontend / Web Vitals
|
|
46
|
+
### 5. Frontend / Web Vitals
|
|
94
47
|
|
|
95
48
|
| Metric | Good | Poor | Measures |
|
|
96
49
|
|--------|------|------|---------|
|
|
97
|
-
| LCP
|
|
98
|
-
| INP
|
|
99
|
-
| CLS
|
|
50
|
+
| LCP | < 2.5s | > 4s | Largest element load |
|
|
51
|
+
| INP | < 200ms | > 500ms | Input responsiveness |
|
|
52
|
+
| CLS | < 0.1 | > 0.25 | Layout stability |
|
|
100
53
|
|
|
101
54
|
Unnecessary re-renders, missing virtualization, missing code splitting. See `references/violations.md`.
|
|
102
55
|
|
|
103
|
-
---
|
|
104
|
-
|
|
105
56
|
## Extended References
|
|
106
57
|
|
|
107
58
|
| Reference | Content |
|
|
108
59
|
|-----------|---------|
|
|
109
60
|
| `references/sources.md` | Full bibliography (25 sources) |
|
|
110
|
-
| `references/violations.md` | Extended violations
|
|
111
|
-
| `references/patterns.md` | Correct patterns
|
|
61
|
+
| `references/violations.md` | Extended violations |
|
|
62
|
+
| `references/patterns.md` | Correct patterns |
|
|
112
63
|
| `references/detection.md` | Grep commands, profiling, CI integration |
|
|
113
64
|
|
|
114
|
-
---
|
|
115
|
-
|
|
116
65
|
## Severity Guidelines
|
|
117
66
|
|
|
118
67
|
| Severity | Examples |
|
|
119
68
|
|----------|----------|
|
|
120
|
-
| **CRITICAL** | N+1 with unbounded data
|
|
121
|
-
| **HIGH** | Sequential async
|
|
122
|
-
| **MEDIUM** | Suboptimal algorithm on small data
|
|
123
|
-
| **LOW** | Micro-optimizations, premature optimization candidates
|
|
124
|
-
|
|
125
|
-
---
|
|
69
|
+
| **CRITICAL** | N+1 with unbounded data, memory leaks, blocking I/O in handlers |
|
|
70
|
+
| **HIGH** | Sequential async, SELECT *, unbounded caches, LCP > 4s |
|
|
71
|
+
| **MEDIUM** | Suboptimal algorithm on small data, missing memoization, INP > 200ms |
|
|
72
|
+
| **LOW** | Micro-optimizations, premature optimization candidates |
|
|
126
73
|
|
|
127
74
|
## Quick Detection
|
|
128
75
|
|
|
129
|
-
|
|
130
|
-
grep -rn "for.*await\|\.forEach.*async" --include="*.ts" # N+1
|
|
131
|
-
grep -rn "readFileSync\|writeFileSync" --include="*.ts" # Sync I/O
|
|
132
|
-
grep -rn "SELECT \*" --include="*.ts" --include="*.sql" # SELECT *
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
See `references/detection.md` for comprehensive detection patterns.
|
|
76
|
+
In the diff, search for `await` in a loop or `.forEach(async` (N+1), `readFileSync`/`writeFileSync` (sync I/O) and `SELECT *`.
|