sequant 2.7.0 → 2.8.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +9 -1
- package/dist/bin/cli.d.ts +1 -1
- package/dist/bin/cli.js +10 -1
- package/dist/bin/preflight.d.ts +21 -0
- package/dist/bin/preflight.js +45 -0
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/force-push.md +34 -0
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +24 -7
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +29 -0
- package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +100 -2
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +24 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/anti-pattern-detection.md +285 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/call-site-review.md +202 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/quality-gates.md +287 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/test-quality-checklist.md +272 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/testing-requirements.md +40 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +95 -11
- package/dist/marketplace/external_plugins/sequant/skills/references/shared/framework-gotchas.md +186 -0
- package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +661 -0
- package/dist/marketplace/external_plugins/sequant/skills/test/references/browser-testing-patterns.md +423 -0
- package/dist/marketplace/external_plugins/sequant/skills/upstream/SKILL.md +419 -0
- package/dist/src/lib/errors.d.ts +85 -0
- package/dist/src/lib/errors.js +111 -0
- package/dist/src/lib/version-check.d.ts +19 -0
- package/dist/src/lib/version-check.js +44 -0
- package/dist/src/lib/workflow/batch-executor.js +61 -6
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +17 -0
- package/dist/src/lib/workflow/drivers/claude-code.d.ts +22 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +111 -7
- package/dist/src/lib/workflow/log-writer.d.ts +1 -1
- package/dist/src/lib/workflow/phase-executor.d.ts +18 -0
- package/dist/src/lib/workflow/phase-executor.js +76 -14
- package/dist/src/lib/workflow/run-log-schema.d.ts +3 -0
- package/dist/src/lib/workflow/run-log-schema.js +7 -0
- package/dist/src/lib/workflow/state-manager.d.ts +1 -0
- package/dist/src/lib/workflow/state-manager.js +6 -0
- package/dist/src/lib/workflow/state-schema.d.ts +3 -0
- package/dist/src/lib/workflow/state-schema.js +7 -0
- package/dist/src/lib/workflow/types.d.ts +17 -0
- package/dist/src/ui/tui/theme.d.ts +18 -4
- package/dist/src/ui/tui/theme.js +18 -4
- package/package.json +4 -3
- package/templates/skills/_shared/references/force-push.md +34 -0
- package/templates/skills/assess/SKILL.md +24 -7
- package/templates/skills/exec/SKILL.md +29 -0
- package/templates/skills/loop/SKILL.md +100 -2
- package/templates/skills/qa/SKILL.md +24 -0
- package/templates/skills/qa/references/anti-pattern-detection.md +285 -0
- package/templates/skills/qa/references/call-site-review.md +202 -0
- package/templates/skills/qa/references/quality-gates.md +287 -0
- package/templates/skills/qa/references/test-quality-checklist.md +272 -0
- package/templates/skills/qa/references/testing-requirements.md +40 -0
- package/templates/skills/qa/scripts/quality-checks.sh +95 -11
- package/templates/skills/references/shared/framework-gotchas.md +186 -0
- package/templates/skills/release/SKILL.md +661 -0
- package/templates/skills/test/references/browser-testing-patterns.md +423 -0
- package/templates/skills/upstream/SKILL.md +419 -0
package/dist/marketplace/external_plugins/sequant/skills/qa/references/anti-pattern-detection.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Anti-Pattern Detection
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Lightweight pattern-matching sanity checks to catch issues that experts would flag immediately. These checks complement code review by automating detection of common mistakes.
|
|
6
|
+
|
|
7
|
+
## Part 1: New Dependency Audit
|
|
8
|
+
|
|
9
|
+
### When to Run
|
|
10
|
+
|
|
11
|
+
Run dependency audit when `package.json` is modified:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Check if package.json was modified
|
|
15
|
+
pkg_modified=$(git diff main...HEAD --name-only | grep -E "^package\.json$" | head -1)
|
|
16
|
+
if [[ -n "$pkg_modified" ]]; then
|
|
17
|
+
echo "package.json modified - running dependency audit"
|
|
18
|
+
fi
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Detecting New Dependencies
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Get new dependencies (added in this branch)
|
|
25
|
+
git diff main...HEAD -- package.json | grep '^\+.*":' | grep -v '^\+\+\+' | sed 's/.*"\([^"]*\)".*/\1/' | grep -v -E '^(@types/|version|name|description|scripts|devDependencies|dependencies|peerDependencies)$'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Audit Criteria
|
|
29
|
+
|
|
30
|
+
| Flag | Threshold | Detection Method | Risk Level |
|
|
31
|
+
|------|-----------|------------------|------------|
|
|
32
|
+
| Low downloads | <1,000/week | `npm view <pkg> --json \| jq '.downloads'` | ⚠️ Medium |
|
|
33
|
+
| Stale | No updates 12+ months | `npm view <pkg> time.modified` | ⚠️ Medium |
|
|
34
|
+
| License risk | UNLICENSED, GPL in MIT project | `npm view <pkg> license` | ❌ High |
|
|
35
|
+
| Size concern | >100kb for utility | `npm view <pkg> dist.unpackedSize` | ⚠️ Low |
|
|
36
|
+
| Security advisory | Known vulnerabilities | `npm audit --json` | ❌ High |
|
|
37
|
+
|
|
38
|
+
### Audit Commands
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Get package metadata (run for each new dependency)
|
|
42
|
+
pkg="<package-name>"
|
|
43
|
+
|
|
44
|
+
# Weekly downloads (requires npm API)
|
|
45
|
+
downloads=$(curl -s "https://api.npmjs.org/downloads/point/last-week/$pkg" | jq '.downloads // 0')
|
|
46
|
+
|
|
47
|
+
# Last update date
|
|
48
|
+
last_update=$(npm view "$pkg" time.modified 2>/dev/null)
|
|
49
|
+
|
|
50
|
+
# License
|
|
51
|
+
license=$(npm view "$pkg" license 2>/dev/null)
|
|
52
|
+
|
|
53
|
+
# Unpacked size (in bytes)
|
|
54
|
+
size=$(npm view "$pkg" dist.unpackedSize 2>/dev/null)
|
|
55
|
+
|
|
56
|
+
# Security check (all dependencies)
|
|
57
|
+
npm audit --json 2>/dev/null | jq '.vulnerabilities | length'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Output Format
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
### Dependency Audit
|
|
64
|
+
|
|
65
|
+
| Package | Downloads/wk | Last Update | License | Size | Flags |
|
|
66
|
+
|---------|--------------|-------------|---------|------|-------|
|
|
67
|
+
| foo-pkg | 500 | 2023-01-15 | MIT | 45kb | ⚠️ Low downloads, ⚠️ Stale |
|
|
68
|
+
| bar-lib | 50,000 | 2024-12-01 | Apache-2.0 | 120kb | ⚠️ Size |
|
|
69
|
+
|
|
70
|
+
**Security Audit:** 0 vulnerabilities found
|
|
71
|
+
|
|
72
|
+
**Flagged Dependencies:**
|
|
73
|
+
1. `foo-pkg` - Low downloads (<1,000/week) and stale (12+ months)
|
|
74
|
+
- **Risk:** Unmaintained packages may have unpatched vulnerabilities
|
|
75
|
+
- **Suggestion:** Consider alternative with active maintenance or vendor the code
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Verdict Impact
|
|
79
|
+
|
|
80
|
+
| Finding | Verdict Impact |
|
|
81
|
+
|---------|----------------|
|
|
82
|
+
| Low downloads only | Note in QA, no verdict change |
|
|
83
|
+
| Stale only | Note in QA, no verdict change |
|
|
84
|
+
| Security vulnerability (moderate+) | `AC_NOT_MET` (blocker) |
|
|
85
|
+
| License incompatibility | `AC_NOT_MET` (blocker) |
|
|
86
|
+
| Multiple flags on same package | `AC_MET_BUT_NOT_A_PLUS` |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Part 2: Code Pattern Checks
|
|
91
|
+
|
|
92
|
+
### Anti-Pattern Detection Matrix
|
|
93
|
+
|
|
94
|
+
| Category | Pattern | Detection | Suggestion | Risk |
|
|
95
|
+
|----------|---------|-----------|------------|------|
|
|
96
|
+
| **Performance** | N+1 query (`await` in loop) | `for.*await\|\.forEach.*await` | Use batch query or `Promise.all` | ⚠️ Medium |
|
|
97
|
+
| **Performance** | Unbounded loop | `while.*true\|for.*;;` without break limit | Add iteration limit | ⚠️ Medium |
|
|
98
|
+
| **Performance** | Sync file ops in async context | `fs\.readFileSync\|fs\.writeFileSync` | Use async fs methods | ⚠️ Low |
|
|
99
|
+
| **Error Handling** | Empty catch block | `catch.*\{\s*\}` | Log or rethrow | ⚠️ Medium |
|
|
100
|
+
| **Error Handling** | Swallowed error | `catch.*\{\s*//` | Handle or rethrow | ⚠️ Medium |
|
|
101
|
+
| **Error Handling** | Unhandled promise | `\.then\(.*\)[^.]` without `.catch` | Add `.catch()` or use try/catch | ⚠️ Medium |
|
|
102
|
+
| **Security** | Hardcoded secret | `(api[_-]?key\|secret\|password)\s*[:=]\s*['"][^'"]+['"]` | Use env variable | ❌ High |
|
|
103
|
+
| **Security** | SQL concatenation | `\+.*SELECT\|SELECT.*\+\|'.*\$\{.*\}.*SELECT` | Use parameterized query | ❌ High |
|
|
104
|
+
| **Security** | eval usage | `eval\(` | Remove eval, use safe alternative | ❌ High |
|
|
105
|
+
| **Security** | Server binds all interfaces | `.listen(port)` without explicit host | Bind to `127.0.0.1` for local-only servers | ❌ High |
|
|
106
|
+
| **Memory** | Uncleared interval | `setInterval\(` without corresponding `clearInterval` | Clear in cleanup | ⚠️ Medium |
|
|
107
|
+
| **Memory** | Uncleared timeout | `setTimeout\(` in component without cleanup | Clear in useEffect cleanup | ⚠️ Low |
|
|
108
|
+
| **A11y** | Image without alt | `<img[^>]*(?!alt=)[^>]*>` | Add descriptive alt | ⚠️ Low |
|
|
109
|
+
| **A11y** | Click handler without keyboard | `onClick=\{` without `onKeyDown` | Add keyboard handler | ⚠️ Low |
|
|
110
|
+
|
|
111
|
+
### Detection Commands
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Run on changed files only
|
|
115
|
+
changed_files=$(git diff main...HEAD --name-only | grep -E '\.(ts|tsx|js|jsx)$')
|
|
116
|
+
|
|
117
|
+
# N+1 query pattern (await in loop)
|
|
118
|
+
grep -n -E 'for\s*\([^)]*\)\s*\{[^}]*await|\.forEach\([^)]*async' $changed_files 2>/dev/null
|
|
119
|
+
|
|
120
|
+
# Empty catch block
|
|
121
|
+
grep -n -E 'catch\s*\([^)]*\)\s*\{\s*\}' $changed_files 2>/dev/null
|
|
122
|
+
|
|
123
|
+
# Hardcoded secrets (case insensitive)
|
|
124
|
+
grep -ni -E '(api[_-]?key|secret|password|token)\s*[:=]\s*['"'"'"][^'"'"'"]+['"'"'"]' $changed_files 2>/dev/null | grep -v -E '(\.env|example|test|mock|placeholder)'
|
|
125
|
+
|
|
126
|
+
# SQL concatenation
|
|
127
|
+
grep -n -E "(\+\s*['\"].*SELECT|SELECT.*['\"].*\+|\`.*\$\{.*\}.*SELECT)" $changed_files 2>/dev/null
|
|
128
|
+
|
|
129
|
+
# Server binding to all interfaces (0.0.0.0)
|
|
130
|
+
grep -n -E '\.listen\(\s*(port|[0-9]+)\s*[,)]' $changed_files 2>/dev/null | grep -v -E '127\.0\.0\.1|localhost'
|
|
131
|
+
|
|
132
|
+
# Uncleared intervals (check for setInterval without corresponding clear)
|
|
133
|
+
for f in $changed_files; do
|
|
134
|
+
intervals=$(grep -c 'setInterval(' "$f" 2>/dev/null || echo 0)
|
|
135
|
+
clears=$(grep -c 'clearInterval(' "$f" 2>/dev/null || echo 0)
|
|
136
|
+
if [[ $intervals -gt $clears ]]; then
|
|
137
|
+
echo "$f: $intervals setInterval calls, only $clears clearInterval calls"
|
|
138
|
+
fi
|
|
139
|
+
done
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Output Format
|
|
143
|
+
|
|
144
|
+
```markdown
|
|
145
|
+
### Code Pattern Analysis
|
|
146
|
+
|
|
147
|
+
| File:Line | Category | Pattern | Suggestion |
|
|
148
|
+
|-----------|----------|---------|------------|
|
|
149
|
+
| `src/api/users.ts:45` | Performance | N+1 query | Use `Promise.all` for batch fetching |
|
|
150
|
+
| `src/utils/config.ts:12` | Error Handling | Empty catch | Log error or rethrow |
|
|
151
|
+
| `src/components/List.tsx:89` | Memory | Uncleared interval | Add `clearInterval` in cleanup |
|
|
152
|
+
|
|
153
|
+
**Critical Issues:** 0
|
|
154
|
+
**Warnings:** 3
|
|
155
|
+
|
|
156
|
+
**Details:**
|
|
157
|
+
|
|
158
|
+
1. **N+1 Query** at `src/api/users.ts:45`
|
|
159
|
+
```typescript
|
|
160
|
+
// Current (N+1)
|
|
161
|
+
for (const id of userIds) {
|
|
162
|
+
await fetchUser(id); // Makes N requests
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Suggested
|
|
166
|
+
await Promise.all(userIds.map(id => fetchUser(id)));
|
|
167
|
+
// Or use batch endpoint
|
|
168
|
+
await fetchUsers(userIds);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
2. **Empty Catch** at `src/utils/config.ts:12`
|
|
172
|
+
```typescript
|
|
173
|
+
// Current
|
|
174
|
+
try { ... } catch (e) { }
|
|
175
|
+
|
|
176
|
+
// Suggested
|
|
177
|
+
try { ... } catch (e) {
|
|
178
|
+
console.error('Config load failed:', e);
|
|
179
|
+
// or rethrow: throw e;
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Verdict Impact
|
|
185
|
+
|
|
186
|
+
| Finding | Verdict Impact |
|
|
187
|
+
|---------|----------------|
|
|
188
|
+
| Performance warnings | Note in QA, no verdict change |
|
|
189
|
+
| Empty catch blocks | `AC_MET_BUT_NOT_A_PLUS` |
|
|
190
|
+
| Security issues (secrets, SQL injection) | `AC_NOT_MET` (blocker) |
|
|
191
|
+
| Uncleared intervals/timeouts | `AC_MET_BUT_NOT_A_PLUS` |
|
|
192
|
+
| A11y issues | Note in QA, no verdict change |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Part 3: Integration with QA Workflow
|
|
197
|
+
|
|
198
|
+
### When to Run
|
|
199
|
+
|
|
200
|
+
1. **Dependency Audit:** Only when `package.json` is modified
|
|
201
|
+
2. **Code Pattern Checks:** Always run on changed `.ts/.tsx/.js/.jsx` files
|
|
202
|
+
|
|
203
|
+
### Execution Order
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
1. Standard quality checks (type safety, deleted tests, scope)
|
|
207
|
+
2. Dependency audit (if package.json modified)
|
|
208
|
+
3. Code pattern checks
|
|
209
|
+
4. Test quality review (if test files modified)
|
|
210
|
+
5. Execution evidence (if scripts/CLI modified)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Combined Output Section
|
|
214
|
+
|
|
215
|
+
```markdown
|
|
216
|
+
### Anti-Pattern Detection
|
|
217
|
+
|
|
218
|
+
#### Dependency Audit
|
|
219
|
+
[Include if package.json modified, otherwise: "N/A - No dependency changes"]
|
|
220
|
+
|
|
221
|
+
#### Code Patterns
|
|
222
|
+
[Always include for code changes]
|
|
223
|
+
|
|
224
|
+
**Summary:**
|
|
225
|
+
- Dependencies flagged: X
|
|
226
|
+
- Code patterns flagged: Y
|
|
227
|
+
- Critical issues: Z (blockers)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Appendix: Full Detection Script
|
|
233
|
+
|
|
234
|
+
For automation, this script can be run to check all patterns:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
#!/bin/bash
|
|
238
|
+
# anti-pattern-check.sh
|
|
239
|
+
|
|
240
|
+
set -e
|
|
241
|
+
|
|
242
|
+
echo "=== Anti-Pattern Detection ==="
|
|
243
|
+
|
|
244
|
+
# Get changed files
|
|
245
|
+
CHANGED_TS=$(git diff main...HEAD --name-only | grep -E '\.(ts|tsx|js|jsx)$' || true)
|
|
246
|
+
PKG_CHANGED=$(git diff main...HEAD --name-only | grep -E '^package\.json$' || true)
|
|
247
|
+
|
|
248
|
+
# 1. Dependency Audit
|
|
249
|
+
if [[ -n "$PKG_CHANGED" ]]; then
|
|
250
|
+
echo ""
|
|
251
|
+
echo "## Dependency Audit"
|
|
252
|
+
# Get new deps
|
|
253
|
+
NEW_DEPS=$(git diff main...HEAD -- package.json | grep '^\+.*":' | grep -v '^\+\+\+' | sed 's/.*"\([^"]*\)".*/\1/' | grep -v -E '^(@types/|version|name|description|scripts|devDependencies|dependencies|peerDependencies|engines|repository|author|license|bugs|homepage|main|module|types)$' || true)
|
|
254
|
+
|
|
255
|
+
if [[ -n "$NEW_DEPS" ]]; then
|
|
256
|
+
echo "New dependencies detected:"
|
|
257
|
+
for dep in $NEW_DEPS; do
|
|
258
|
+
echo " - $dep"
|
|
259
|
+
done
|
|
260
|
+
else
|
|
261
|
+
echo "No new dependencies added"
|
|
262
|
+
fi
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
# 2. Code Pattern Checks
|
|
266
|
+
if [[ -n "$CHANGED_TS" ]]; then
|
|
267
|
+
echo ""
|
|
268
|
+
echo "## Code Pattern Checks"
|
|
269
|
+
|
|
270
|
+
echo ""
|
|
271
|
+
echo "### N+1 Queries (await in loop):"
|
|
272
|
+
grep -n -E 'for\s*\([^)]*\)\s*\{[^}]*await|\.forEach\([^)]*async' $CHANGED_TS 2>/dev/null || echo " None found"
|
|
273
|
+
|
|
274
|
+
echo ""
|
|
275
|
+
echo "### Empty Catch Blocks:"
|
|
276
|
+
grep -n -E 'catch\s*\([^)]*\)\s*\{\s*\}' $CHANGED_TS 2>/dev/null || echo " None found"
|
|
277
|
+
|
|
278
|
+
echo ""
|
|
279
|
+
echo "### Potential Hardcoded Secrets:"
|
|
280
|
+
grep -ni -E '(api[_-]?key|secret|password|token)\s*[:=]\s*['"'"'"][^'"'"'"]+['"'"'"]' $CHANGED_TS 2>/dev/null | grep -v -E '(\.env|example|test|mock|placeholder|process\.env)' || echo " None found"
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
echo ""
|
|
284
|
+
echo "=== End Anti-Pattern Detection ==="
|
|
285
|
+
```
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Call-Site Review Checklist
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
When new exported functions are added, QA must review not just the function itself but **where** and **how** it's called. A function can be perfectly implemented but called incorrectly at the call site.
|
|
6
|
+
|
|
7
|
+
**Origin:** Issue #295 — `rebaseBeforePR()` had thorough unit tests but was called for every issue in a chain loop when the AC specified "only the final branch."
|
|
8
|
+
|
|
9
|
+
## When to Apply
|
|
10
|
+
|
|
11
|
+
This review is **triggered** when new exported functions are detected in the diff:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Detect new exported functions (added lines only)
|
|
15
|
+
# Catches: export function foo, export async function foo,
|
|
16
|
+
# export const foo = () =>, export const foo = async () =>
|
|
17
|
+
git diff main...HEAD | grep -E '^\+export (async )?function \w+' | sed 's/^+//'
|
|
18
|
+
git diff main...HEAD | grep -E '^\+export const \w+ = (async )?\(' | sed 's/^+//'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Review Steps
|
|
22
|
+
|
|
23
|
+
### Step 1: Call-Site Inventory
|
|
24
|
+
|
|
25
|
+
For each new exported function, find where it's called using the Grep tool:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Find call sites for a function (exclude test files)
|
|
29
|
+
Grep(pattern="functionName\\(", glob="*.{ts,tsx}", output_mode="content")
|
|
30
|
+
# Then exclude results from .test. files and __tests__ directories
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Step 2: Condition Audit
|
|
34
|
+
|
|
35
|
+
For each call site, identify:
|
|
36
|
+
|
|
37
|
+
1. **What conditions gate the call?**
|
|
38
|
+
- `if` statements, `&&` guards, ternaries
|
|
39
|
+
- Mode flags, feature flags, environment checks
|
|
40
|
+
|
|
41
|
+
2. **Is it in a loop?**
|
|
42
|
+
- `for`, `while`, `forEach`, `.map()`, `.filter()`, etc.
|
|
43
|
+
- If yes: Should it run for every iteration or only specific ones?
|
|
44
|
+
|
|
45
|
+
3. **Is it in an async context?**
|
|
46
|
+
- Is `await` used appropriately?
|
|
47
|
+
- Could it cause race conditions?
|
|
48
|
+
|
|
49
|
+
4. **Error handling at call site?**
|
|
50
|
+
- Is the call wrapped in try/catch?
|
|
51
|
+
- What happens if the function throws?
|
|
52
|
+
|
|
53
|
+
**AC Constraint Matching:**
|
|
54
|
+
|
|
55
|
+
Compare call-site conditions against AC constraints:
|
|
56
|
+
|
|
57
|
+
| AC Constraint | Call Site Check |
|
|
58
|
+
|---------------|-----------------|
|
|
59
|
+
| "Only for X" | Is there a guard: `if (X)` before the call? |
|
|
60
|
+
| "When Y happens" | Is the call triggered by the Y event/condition? |
|
|
61
|
+
| "Not in Z mode" | Is there a guard: `if (!Z)` or similar? |
|
|
62
|
+
| "Final item only" | If in loop, is there an index check or break? |
|
|
63
|
+
|
|
64
|
+
### Step 3: Loop Awareness
|
|
65
|
+
|
|
66
|
+
When a function is called inside a loop, answer:
|
|
67
|
+
|
|
68
|
+
1. **Iteration scope:**
|
|
69
|
+
- Should it run for ALL iterations? → OK
|
|
70
|
+
- Should it run for FIRST/LAST only? → Check for index guard
|
|
71
|
+
- Should it run for SOME iterations? → Check for condition filter
|
|
72
|
+
|
|
73
|
+
2. **Common patterns to verify:**
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// LAST only - should have index check
|
|
77
|
+
for (let i = 0; i < items.length; i++) {
|
|
78
|
+
if (i === items.length - 1) {
|
|
79
|
+
newFunction(); // ✅ Guarded for last
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// FIRST only - should have index check
|
|
84
|
+
items.forEach((item, index) => {
|
|
85
|
+
if (index === 0) {
|
|
86
|
+
newFunction(); // ✅ Guarded for first
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// CONDITIONAL - should have filter
|
|
91
|
+
for (const item of items) {
|
|
92
|
+
if (item.shouldProcess) {
|
|
93
|
+
newFunction(item); // ✅ Conditionally called
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. **Red flags:**
|
|
99
|
+
- Function called unconditionally in loop when AC says "only once"
|
|
100
|
+
- No break/return after the call when AC implies single execution
|
|
101
|
+
- Missing mode/flag guard when AC specifies conditions
|
|
102
|
+
|
|
103
|
+
### Step 4: Mode Sensitivity
|
|
104
|
+
|
|
105
|
+
If the function behaves differently based on mode flags:
|
|
106
|
+
|
|
107
|
+
1. **Identify mode parameters:**
|
|
108
|
+
- Does the function accept `options` or `config`?
|
|
109
|
+
- Are there mode-specific code paths inside?
|
|
110
|
+
|
|
111
|
+
2. **Verify at call site:**
|
|
112
|
+
- Is the mode passed correctly?
|
|
113
|
+
- Does the caller's context match the mode expected?
|
|
114
|
+
|
|
115
|
+
## Output Format
|
|
116
|
+
|
|
117
|
+
```markdown
|
|
118
|
+
### Call-Site Review
|
|
119
|
+
|
|
120
|
+
**New exported functions detected:** N
|
|
121
|
+
|
|
122
|
+
| Function | Call Sites | Loop? | Conditions | AC Match |
|
|
123
|
+
|----------|-----------|-------|------------|----------|
|
|
124
|
+
| `newFunction()` | `file.ts:123` | No | `if (condition)` | ✅ Matches AC-2 |
|
|
125
|
+
| `anotherFunc()` | `run.ts:456` | Yes (forEach) | None | ⚠️ Missing guard (AC-3 says "final only") |
|
|
126
|
+
| `thirdFunc()` | Not called | - | - | ⚠️ Unused export |
|
|
127
|
+
|
|
128
|
+
**Findings:**
|
|
129
|
+
- `anotherFunc()` is called in a loop without iteration guard. AC-3 specifies "only for the final item."
|
|
130
|
+
|
|
131
|
+
**Recommendations:**
|
|
132
|
+
1. Add index check: `if (index === items.length - 1)` before calling `anotherFunc()`
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Verdict Impact
|
|
136
|
+
|
|
137
|
+
| Finding | Verdict Impact |
|
|
138
|
+
|---------|----------------|
|
|
139
|
+
| All call sites match AC | No impact |
|
|
140
|
+
| Call site missing AC-required guard | `AC_NOT_MET` |
|
|
141
|
+
| Function not called anywhere | `AC_MET_BUT_NOT_A_PLUS` (dead export) |
|
|
142
|
+
| Call site in loop, AC unclear about iteration | `NEEDS_VERIFICATION` |
|
|
143
|
+
|
|
144
|
+
## Examples
|
|
145
|
+
|
|
146
|
+
### Example 1: Missing Chain Mode Guard (Issue #295)
|
|
147
|
+
|
|
148
|
+
**AC:** "Rebase only the final branch in a chain"
|
|
149
|
+
|
|
150
|
+
**Detection:**
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
Grep(pattern="rebaseBeforePR\\(", glob="*.ts", output_mode="content")
|
|
154
|
+
# Output: src/run.ts:2977: await rebaseBeforePR(worktreePath)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Analysis:**
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Found in loop over all chain issues
|
|
161
|
+
for (const result of chainResults) {
|
|
162
|
+
if (result.success && result.worktreePath) {
|
|
163
|
+
await rebaseBeforePR(result.worktreePath); // ⚠️ Called for ALL
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Finding:** No guard for "final only" — function called for every issue in chain.
|
|
169
|
+
|
|
170
|
+
**Fix:** Add final-issue check:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
for (let i = 0; i < chainResults.length; i++) {
|
|
174
|
+
const result = chainResults[i];
|
|
175
|
+
const isFinal = i === chainResults.length - 1;
|
|
176
|
+
if (result.success && result.worktreePath && isFinal) {
|
|
177
|
+
await rebaseBeforePR(result.worktreePath); // ✅ Only final
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Example 2: Correct Guard Present
|
|
183
|
+
|
|
184
|
+
**AC:** "Send notification only when status is 'complete'"
|
|
185
|
+
|
|
186
|
+
**Detection:**
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
Grep(pattern="sendNotification\\(", glob="*.ts", output_mode="content")
|
|
190
|
+
# Output: src/handlers.ts:89: sendNotification(user.email, message)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Analysis:**
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Found with proper guard
|
|
197
|
+
if (task.status === 'complete') {
|
|
198
|
+
sendNotification(user.email, message); // ✅ Guarded
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Finding:** Call site condition matches AC constraint. No issues.
|