Skip to content

Commit b74fd05

Browse files
authored
Optimize daily code review agent with focused detection playbook (#128)
1 parent c49ab25 commit b74fd05

1 file changed

Lines changed: 144 additions & 1 deletion

File tree

.github/agents/daily-code-review.agent.md

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ If a finding is even partially covered by an existing issue or PR, skip it entir
6060

6161
## Step 2: Code Analysis
6262

63-
Scan the **entire repository** looking for these categories (in priority order):
63+
Scan the **entire repository** looking for these categories (in priority order).
64+
Use the **Detection Playbook** (Appendix) for concrete patterns and thresholds.
6465

6566
### Category A: Bugs (Highest Priority)
6667
- Incorrect error handling (swallowed errors, missing try/catch, wrong error types)
@@ -198,3 +199,145 @@ A successful run means:
198199
- Zero overlap with existing work
199200
- All tests pass
200201
- A human reviewer can understand and approve within 5 minutes
202+
203+
---
204+
205+
# Appendix: Detection Playbook
206+
207+
Consolidated reference for Step 2 code analysis. All patterns are scoped to this
208+
TypeScript/Node.js codebase (ES2022 target, CommonJS output).
209+
210+
**How to use:** When scanning files in Step 2, check each file against the relevant
211+
sections below. These are detection heuristics — only flag issues that meet the
212+
confidence threshold from Step 3.
213+
214+
---
215+
216+
## A. Complexity Thresholds
217+
218+
Flag any function/file exceeding these limits:
219+
220+
| Metric | Warning | Error | Fix |
221+
|---|---|---|---|
222+
| Function length | >30 lines | >50 lines | Extract method |
223+
| Nesting depth | >2 levels | >3 levels | Guard clauses / extract |
224+
| Parameter count | >3 | >5 | Parameter object or options bag |
225+
| File length | >300 lines | >500 lines | Split by responsibility |
226+
| Cyclomatic complexity | >5 branches | >10 branches | Decompose conditional / lookup table |
227+
228+
**Cognitive complexity red flags:**
229+
- Nested ternaries: `a ? b ? c : d : e`
230+
- Boolean soup: `a && b || c && !d` (missing parens)
231+
- Multiple return points inside nested blocks
232+
233+
---
234+
235+
## B. Bug Patterns (Category A)
236+
237+
### Error Handling
238+
- **Empty catch blocks:** `catch (e) {}` — silently swallows errors
239+
- **Missing error cause when wrapping:** When rethrowing or wrapping an existing error, preserve it via `throw new Error(msg, { cause: err })` instead of dropping the original error.
240+
- **Broad catch:** Giant try/catch wrapping entire functions instead of targeting fallible ops
241+
- **Error type check by name:** `e.constructor.name === 'TypeError'` instead of `instanceof`
242+
243+
### Async/Promise Issues
244+
- **Missing `await`:** Calling async function without `await` — result is discarded
245+
- **Unhandled rejection:** Promise chain without `.catch()` or surrounding try/catch
246+
- **Sequential independent awaits:** `await a(); await b()` when they could be `Promise.all([a(), b()])`
247+
- **Unnecessary async:** `async function f() { return val; }` — the `async` adds overhead for no reason
248+
249+
### Resource Leaks
250+
- **Unclosed gRPC streams:** Streams opened but not closed in error paths
251+
- **Dangling timers:** `setTimeout`/`setInterval` without cleanup on teardown
252+
- **Event listener leaks:** `.on()` without corresponding `.off()` or `.removeListener()`
253+
254+
### Repo-Specific (Durable Task SDK)
255+
- **Non-determinism in orchestrators:** `Date.now()`, `Math.random()`, `crypto.randomUUID()`, or direct I/O in orchestrator code
256+
- **Replay event mismatch:** The executor's switch statement silently drops unmatched events — verify all cases are handled
257+
- **Timer-to-retry linkage:** Retry tasks create timers with different IDs; verify maps connecting them are maintained
258+
- **Generator lifecycle:** Check for unguarded `generator.next()` when `done` might be true
259+
- **Composite task constructor:** Already-complete children trigger `onChildCompleted()` during construction — callers must handle immediate completion
260+
- **Entity state mutation:** Verify lazy JSON deserialization handles null/undefined state correctly
261+
262+
---
263+
264+
## C. Dead Code Patterns (Category C)
265+
266+
### What to Look For
267+
- **Unused imports:** Import bindings never referenced in the file
268+
- **Unused variables:** `const`/`let` declared but never read
269+
- **Unreachable code:** Statements after `return`, `throw`, `break`, `continue`, or `process.exit()`
270+
- **Commented-out code:** 3+ consecutive lines of commented code-like patterns — should be removed (use version control)
271+
- **Unused private functions:** Functions not exported and not called within the module
272+
- **Dead parameters:** Function parameters never referenced in the body (check interface contracts first)
273+
- **Always-true/false conditions:** `if (true)`, literal tautologies
274+
- **Stale TODOs:** `TODO`/`FIXME`/`HACK` comments in code unchanged for months
275+
276+
### False Positive Guards
277+
- Variables used in string interpolation or destructuring
278+
- Parameters required by interface contracts (gRPC callbacks, event handlers)
279+
- Re-exports through barrel `index.ts` files
280+
281+
### Prioritization
282+
| Category | Impact | Action |
283+
|---|---|---|
284+
| Empty catch blocks | **High** | Review — likely hiding errors |
285+
| Unreachable code | Medium | Remove — may indicate bugs |
286+
| Unused variables | Medium | Remove — may indicate logic errors |
287+
| Unused functions | Medium | Confirm no dynamic/reflection usage first |
288+
| Unused imports | Low | Remove — zero risk |
289+
| Commented-out code | Low | Remove |
290+
| Dead parameters | Low | Check interface contracts first |
291+
292+
---
293+
294+
## D. TypeScript Modernization Patterns (Category C)
295+
296+
Only flag these when the improvement is clear and low-risk. These are **not** the
297+
primary mission — prioritize bugs and missing tests.
298+
299+
### High Value (flag these)
300+
| Verbose Pattern | Modern Alternative |
301+
|---|---|
302+
| `x && x.y && x.y.z` | `x?.y?.z` (optional chaining) |
303+
| `x !== null && x !== undefined ? x : def` | `x ?? def` (nullish coalescing) |
304+
| Manual `for` loop building/filtering array | `.map()` / `.filter()` / `.find()` / `.reduce()` |
305+
| `.then().then().catch()` chains | `async`/`await` with try/catch |
306+
| `Object.assign({}, a, b)` | `{ ...a, ...b }` (spread) |
307+
| `JSON.parse(JSON.stringify(obj))` on JSON-serializable data | `structuredClone(obj)` — note: `structuredClone` throws on non-serializable values (e.g. functions, symbols); only substitute when data is known to be JSON-serializable |
308+
| `obj.hasOwnProperty(k)` | `Object.hasOwn(obj, k)` |
309+
| `arr[arr.length - 1]` | `arr.at(-1)` |
310+
| `for (k in obj)` (includes prototype keys) | `for (const k of Object.keys(obj))` |
311+
| `throw new Error(msg)` losing cause | `throw new Error(msg, { cause: origErr })` |
312+
313+
### Medium Value (flag only if clearly better)
314+
| Verbose Pattern | Modern Alternative |
315+
|---|---|
316+
| `const x = obj.x; const y = obj.y;` | `const { x, y } = obj` (destructuring) |
317+
| String concatenation `'Hello ' + name` | Template literal `` `Hello ${name}` `` |
318+
| `function(x) { return x * 2; }` | `x => x * 2` (arrow) |
319+
| `{ x: x, y: y }` | `{ x, y }` (shorthand property) |
320+
| Implicit `any` on public API | Add explicit type annotations |
321+
322+
### Do NOT Flag (out of scope for this repo)
323+
- CommonJS `require()` → ESM `import` (repo intentionally uses CommonJS)
324+
- React/Next.js patterns (not in this codebase)
325+
- ES2024+ features (`Object.groupBy`, `Set.intersection`, `Promise.withResolvers`) — repo targets ES2022
326+
- Private field naming (`this._secret` vs `#secret`); repo uses `_underscorePrefixed` per `.github/copilot-instructions.md`
327+
328+
---
329+
330+
## E. Refactoring Strategies
331+
332+
When a fix requires restructuring, use the simplest applicable strategy:
333+
334+
1. **Guard clauses** — Flatten nested if/else by returning early for edge cases
335+
2. **Extract method** — Pull 30+ line blocks with a clear purpose into named functions
336+
3. **Replace loop with pipeline**`for` + `if` + `push``.filter().map()`
337+
4. **Decompose conditional** — Extract complex boolean expressions into well-named variables
338+
5. **Consolidate duplicates** — If every branch of a conditional has the same code, move it outside
339+
6. **Extract constant** — Replace magic numbers/strings with named constants
340+
7. **Introduce parameter object** — When 4+ related params travel together
341+
342+
**Key principle:** Only refactor code that you're already fixing for a bug or test gap.
343+
Don't open PRs for refactoring alone — it must accompany a concrete fix.

0 commit comments

Comments
 (0)