slash-do 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/commands/do/review.md
CHANGED
|
@@ -26,7 +26,7 @@ Before dispatching agents, understand what this change set claims to do:
|
|
|
26
26
|
|
|
27
27
|
## Dispatch Review Agents
|
|
28
28
|
|
|
29
|
-
Read the three agent instruction files, then spawn **all three in parallel** using the Agent tool
|
|
29
|
+
Read the three agent instruction files, then spawn **all three in parallel** using the Agent tool with `model: "opus"`. Each agent reviews ALL changed files independently. Opus-class reasoning catches issues that require drawing on broad software engineering principles, not just pattern-matching against checklists.
|
|
30
30
|
|
|
31
31
|
<surface_scan_agent>
|
|
32
32
|
|
package/commands/do/rpr.md
CHANGED
|
@@ -39,6 +39,7 @@ Address the latest code review feedback on the current branch's pull request usi
|
|
|
39
39
|
- For larger PRs, spawn one `Agent` call (general-purpose type) per review thread (or group closely related threads on the same file into one agent)
|
|
40
40
|
- Spawn one additional `Agent` call for an **independent code quality review** of all files changed in the PR (`gh pr diff --name-only`)
|
|
41
41
|
- Launch all Agent calls **in parallel** (multiple tool calls in a single response) and wait for all to return
|
|
42
|
+
- **Model selection**: Use `model: "sonnet"` for all sub-agents — thread fixes and code quality reviews are well-scoped tasks that don't require Opus. Only escalate to `model: "opus"` if a thread involves genuinely complex architectural reasoning that Sonnet cannot resolve.
|
|
42
43
|
- Each thread-fixing agent should:
|
|
43
44
|
- Read the file and understand the context of the feedback
|
|
44
45
|
- Make the requested code changes if they are accurate and warranted
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
- Null/undefined access without guards, off-by-one errors, object spread of potentially-null values (spread of null is `{}`, silently discarding state) or non-object values (spreading a string produces indexed character keys, spreading an array produces numeric keys) — guard with a plain-object check before spreading
|
|
18
18
|
- Data from external/user sources (parsed JSON, API responses, file reads) used without structural validation — guard against parse failures, missing properties, wrong types, and null elements before accessing nested values. When parsed data is optional enrichment, isolate failures so they don't abort the main operation
|
|
19
19
|
- Type coercion edge cases — `Number('')` is `0` not empty, `0` is falsy in truthy checks, `NaN` comparisons are always false; string comparison operators (`<`, `>`, `localeCompare`) do lexicographic, not semantic, ordering (e.g., `"10" < "2"`). Use explicit type checks (`Number.isFinite()`, `!= null`) and dedicated libraries (e.g., semver for versions) instead of truthy guards or lexicographic ordering when zero/empty are valid values or semantic ordering matters. Boolean values round-tripping through text serialization (markdown metadata, query strings, form data, flat-file config) become strings — `"false"` is truthy in JavaScript, so truthiness checks on deserialized booleans silently treat explicit `false` as `true`. Use strict equality (`=== true`, `=== 'true'`) or a dedicated coercion function; ensure the same coercion is applied at every consumption site. Language type hierarchies may admit surprising subtypes through standard type-check predicates (`isinstance(x, int)` accepts `bool` in Python, `typeof NaN === 'number'` in JavaScript) — when validating numeric inputs, explicitly exclude known subtypes that would pass the check but produce wrong behavior
|
|
20
|
+
- Config/option defaults applied with `||` or falsy guards — intentional `0`, `false`, or `''` values are treated as "unset" and replaced by the default, making those valid values impossible to configure. Use `?? default` or explicit `=== undefined` checks when zero, false, or empty string are valid configuration values
|
|
21
|
+
- Functions returning different types depending on input conditions (string in one branch, object in another) — callers must branch on return type, creating implicit coupling. Prefer a consistent return shape; use typed unions only when different consumers genuinely need different handling
|
|
20
22
|
- Functions that index into arrays without guarding empty arrays; aggregate operations (`every`, `some`, `reduce`) on potentially-empty collections returning vacuously true/default values that mask misconfiguration or missing data; state/variables declared but never updated or only partially wired up
|
|
21
23
|
- Parallel arrays or tuples coupled by index position (e.g., a names array, a promises array, and a destructuring assignment that must stay aligned) — insertion or reordering in one silently misaligns all others. Use objects/maps keyed by a stable identifier instead
|
|
22
24
|
- Shared mutable references — module-level defaults passed by reference mutate across calls (use `structuredClone()`/spread); `useCallback`/`useMemo` referencing a later `const` (temporal dead zone); object spread followed by unconditional assignment that clobbers spread values
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
**API & URL safety**
|
|
26
28
|
- User-supplied or system-generated values interpolated into URL paths, shell commands, file paths, subprocess arguments, or dynamically evaluated code (eval, CDP evaluate, new Function, template strings executed in browser/page context) without encoding/escaping — use `encodeURIComponent()` for URLs, regex allowlists for execution boundaries, and `JSON.stringify()` for values embedded in evaluated code strings. Generated identifiers used as URL path segments must be safe for your router/storage (no `/`, `?`, `#`; consider allowlisting characters and/or applying `encodeURIComponent()`). Identifiers derived from human-readable names (slugs) used for namespaced resources (git branches, directories) need a unique suffix (ID, hash) to prevent collisions between entities with the same or similar names
|
|
27
29
|
- Route params passed to services without format validation; path containment checks using string prefix without path separator boundary (use `path.relative()`)
|
|
30
|
+
- Request schema fields for large string/binary payloads (base64, file content, free text) without per-field size limits — a total body-size limit alone doesn't prevent individual oversized fields from consuming excessive memory or exceeding downstream service limits. Add per-field `max(N)` constraints with clear error messages
|
|
28
31
|
- Parameterized/wildcard routes registered before specific named routes — the generic route captures requests meant for the specific endpoint (e.g., `/:id` registered before `/drafts` matches `/drafts` as `id="drafts"`). Verify route registration order or use path prefixes to disambiguate
|
|
29
32
|
- Stored or external URLs rendered as clickable links (`href`, `src`, `window.open`) without protocol validation — `javascript:`, `data:`, and `vbscript:` URLs execute in the user's browser. Allowlist `http:`/`https:` (and `mailto:` if needed) before rendering; for all other schemes, render as plain text or strip the value
|
|
30
33
|
- Server-side HTTP requests using user-configurable or externally-stored URLs without protocol allowlisting (http/https only) and host/network restrictions — the server becomes an SSRF proxy for reaching internal network services, cloud metadata endpoints, or localhost-bound APIs. Validate scheme and restrict to expected hosts or external-only ranges before any server-side fetch. Also check redirect handling: auto-following redirects (`redirect: 'follow'`) bypasses initial host validation when a public URL redirects to an internal IP. Disable auto-follow and revalidate each hop, or resolve DNS and block private/loopback/link-local ranges before connecting — public hostnames can resolve to internal IPs via DNS rebinding
|
|
@@ -54,17 +57,23 @@
|
|
|
54
57
|
- `Promise.all` without error handling — partial load with unhandled rejection. Wrap with fallback/error state. For `Promise.allSettled`, verify rejected entries are logged with rejection reasons before mapping to fallback values — silently substituting defaults makes partial failures invisible in production
|
|
55
58
|
- Sequential processing of items (loops over external operations, batch mutations) where one item throwing aborts all remaining items — wrap per-item operations in try/catch with logging so partial progress is preserved and failures are isolated
|
|
56
59
|
- Side effects during React render (setState, navigation, mutations outside useEffect)
|
|
60
|
+
- Interactive UI elements (buttons, inputs, drag-and-drop targets, keyboard shortcuts) that remain enabled while an async operation owns their related state — a second trigger while the first is in-flight produces concurrent state mutations or duplicate operations. All entry points for the same action must be disabled together while it is pending
|
|
61
|
+
- Optimistic UI messages that substitute placeholder text when the actual payload sent to the server differs — the user sees one thing, the server stores another. Use the same fallback text in both the optimistic render and the outgoing payload, or surface the actual payload text in the UI
|
|
57
62
|
|
|
58
63
|
**Error handling** _[applies when: code has try/catch, .catch, error responses, or external calls]_
|
|
59
64
|
- Service functions throwing generic `Error` for client-caused conditions — bubbles as 500 instead of 400/404. Use typed error classes with explicit status codes; ensure consistent error responses across similar endpoints — when multiple endpoints make the same access-control decision (e.g., "resource exists but caller lacks access"), they must return the same HTTP status (typically 404 to avoid leaking existence). Include expected concurrency/conditional failures (transaction cancellations, optimistic lock conflicts) — catch and translate to 409/retry rather than letting them surface as 500
|
|
60
|
-
- Swallowed errors (empty `.catch(() => {})`), handlers that replace detailed failure info with generic messages, and error/catch handlers that exit cleanly (`exit 0`, `return`) without any user-visible output — surface a notification, propagate original context, and make failures look like failures. Includes external service wrappers that return `null`/empty for all non-success responses — collapsing configuration errors (missing API key), auth failures (403), rate limits (429), and server errors (5xx) into a single "not found" return masks outages and misconfiguration as normal "no match" results. Distinguish retriable from non-retriable failures and surface infrastructure errors loudly
|
|
65
|
+
- Swallowed errors (empty `.catch(() => {})`), handlers that replace detailed failure info with generic messages, and error/catch handlers that exit cleanly (`exit 0`, `return`) without any user-visible output — surface a notification, propagate original context, and make failures look like failures. This includes cross-layer error propagation: if the server returns structured error detail (field-level validation messages, `details[]` arrays, error codes), the client should surface actionable detail rather than discarding the structure for a generic string. Includes external service wrappers that return `null`/empty for all non-success responses — collapsing configuration errors (missing API key), auth failures (403), rate limits (429), and server errors (5xx) into a single "not found" return masks outages and misconfiguration as normal "no match" results. Distinguish retriable from non-retriable failures and surface infrastructure errors loudly
|
|
66
|
+
- SSE or streaming handlers that call `end()`/`close()` on mid-stream errors without emitting an error event — the client observes a clean stream termination and treats partial content as complete. Emit a structured `event: error` block before closing so clients can detect and surface the failure
|
|
67
|
+
- SSE or event dispatchers handling named event types but ignoring the protocol's default/unnamed event — SSE streams emitting `data:` without `event:` produce type `'message'` (the SSE spec default), which a handler processing only named types silently discards. Verify the default event type is either handled or explicitly excluded
|
|
61
68
|
- Caller/callee disagreement on success/decision semantics — a function that resolves with `{ success: false }` while callers use `.catch()` for error handling means failures are treated as successes. Verify that the contract between producer and consumer is consistent: if callers branch on rejection, the function must reject on failure; if callers branch on a status field, the function must never reject. This extends beyond success/failure to any evaluation result — if a gate/check function returns `{ shouldRun: false }` on errors while the runtime treats errors as fail-open (run anyway), the API surface and runtime disagree on skip semantics. Also covers argument shape contracts — passing a wrapped object (`{ items: [...] }`) when the callee expects a bare array (or vice versa), or supplying arguments at the wrong parameter position, causes silent no-ops or partial processing; verify argument shapes match by reading the callee's signature, not assuming from naming conventions. Also check EventEmitter async handlers — `async` callbacks on `'close'`/`'error'` events create unhandled rejections because EventEmitter doesn't await handler promises; wrap in try/catch
|
|
62
69
|
- Destructive operations in retry/cleanup paths assumed to succeed without their own error handling — if cleanup fails, retry logic crashes instead of reporting the intended failure
|
|
63
70
|
- External service calls without configurable timeouts — a hung downstream service blocks the caller indefinitely
|
|
64
71
|
- Missing fallback behavior when downstream services are unavailable (see also: retry without backoff in "Sync & replication")
|
|
72
|
+
- Route handlers that call a status/health probe before delegating to the main service when the service already handles the "not configured"/"unreachable" case — the pre-probe adds a redundant upstream round-trip on every request and can fail even when the intended operation would succeed. Let the service be the authoritative source and map its structured errors to the appropriate HTTP status at the route boundary
|
|
65
73
|
|
|
66
74
|
**Resource management** _[applies when: code uses event listeners, timers, subscriptions, or useEffect]_
|
|
67
|
-
- Event listeners, socket handlers, subscriptions, timers, and useEffect side effects are cleaned up on unmount/teardown
|
|
75
|
+
- Event listeners, socket handlers, subscriptions, timers, and useEffect side effects are cleaned up on unmount/teardown. `requestAnimationFrame` handles must be cancelled on unmount — pending frames invoke DOM operations or state updates on unmounted nodes. Blob/object URLs created via `URL.createObjectURL()` must be revoked on both item removal AND component unmount. ReadableStream / fetch readers consumed in a loop need `try/finally { reader.cancel() }` — exceptions in the loop otherwise leave the stream open; the `finally` block should catch its own errors so it doesn't mask the original exception
|
|
76
|
+
- Large payloads (base64, binary buffers) stored in multiple state fields simultaneously (e.g., as both a `data` field and a `previewUrl` data URL) — each copy multiplies memory, with significant impact for large attachments. Derive one representation from the other on demand rather than storing both, and ensure cleanup on removal and unmount
|
|
68
77
|
- Deletion/destroy and state-reset functions that clean up or reset the primary resource but leave orphaned or inconsistent secondary resources (data directories, git branches, child records, temporary files, per-user flag/vote items) — trace all resources created during the entity's lifecycle and verify each is removed on delete. Also check the inverse: preservation guards that prevent cleanup under overly broad conditions (e.g., preserving a branch "in case there were commits" when the ahead count is zero) — over-conservative guards leak resources over time. For state transitions that reset aggregate values (counters, scores, flags), also clear or version the individual records that contributed to those aggregates — otherwise the aggregate and its sources disagree, and duplicate-prevention checks block legitimate re-entry. Also check cleanup operations that perform implicit state mutations (auto-merge, auto-commit, cascade writes) as part of teardown — these can introduce unreviewed changes or silently modify shared state. Verify cleanup fails safely when a prerequisite step (e.g., saving dirty state) fails rather than proceeding with data loss
|
|
69
78
|
- Initialization functions (schedulers, pollers, listeners) that don't guard against multiple calls — creates duplicate instances. Check for existing instances before reinitializing
|
|
70
79
|
- Self-rescheduling callbacks (one-shot timers, deferred job handlers) where the next cycle is registered inside the callback body — an unhandled error before the re-registration call permanently stops the schedule. Wrap the callback body in try/finally with re-registration in the finally block, or register the next cycle before executing the current one
|
|
@@ -77,6 +86,10 @@
|
|
|
77
86
|
- Data migrations that silently change runtime behavior — converting records from one type/schedule/state to another must preserve the original execution semantics (frequency, enabled state, trigger behavior). Migrating an on-demand/manual entity to a scheduled one causes unexpected automated execution; migrating a fine-grained interval to a coarser default changes frequency. Unsupported source values (cron expressions, custom intervals) must be flagged or preserved, not silently dropped to defaults
|
|
78
87
|
- Update/patch endpoints with explicit field allowlists (destructured picks, permitted-key arrays) — when the data model gains new configurable fields, the allowlist must be updated or the new fields are silently dropped on save. Trace from model definition to the update handler's field extraction to verify coverage
|
|
79
88
|
- New endpoints/schemas should match validation patterns of existing similar endpoints — field limits, required fields, types, error handling. If validation exists on one endpoint for a param, the same param on other endpoints needs the same validation. API documentation schemas (OpenAPI, JSON Schema) must be structurally complete — array types require `items` definitions, required fields must be listed, and the documented shape must match what the implementation actually returns
|
|
89
|
+
- Client-side input validation limits (max count, file size, string length, combined totals) must be consistent with — and ideally tighter than — server-side enforcement. When the client allows combinations the server rejects (e.g., 8 × 10MB files vs a 50MB JSON body limit), users hit confusing 400/413 errors. Trace all enforcement boundaries (UI, API schema, body parser, downstream service) and verify they form a coherent envelope
|
|
90
|
+
- Sample config files, README examples, and documentation that reference config keys or structure must match what the implementation actually reads. Trace example keys against the config loader — stale examples teach operators to configure values the system ignores (or vice versa)
|
|
91
|
+
- Config values whose format can be validated at initialization time (URLs, port numbers, auth schemes) but are only validated at first use — misconfiguration surfaces as a cryptic runtime error deep in the call stack. Validate format and range of security-relevant config values during initialization and surface a specific diagnostic identifying the bad field
|
|
92
|
+
- URL joining utilities that force paths absolute-from-origin discarding the base URL's pathname — `baseUrl=http://host/proxy` + `/v1/api` silently produces `http://host/v1/api` instead of `http://host/proxy/v1/api`. Verify URL construction utilities preserve pathname segments from the base URL, or document and enforce that base URLs must be origin-only
|
|
80
93
|
- Summary/aggregation endpoints that compute counts or previews via a different query path, filter set, or data source than the detail views they link to — users see inconsistent numbers between the dashboard and the destination page. Trace the computation logic in both paths and verify they apply the same filters, exclusions, and ordering guarantees (or document the intentional difference)
|
|
81
94
|
- Discovery or catalog endpoints that enumerate available capabilities (actions, supported types, valid options) for a downstream consumer must derive the enumerated set from or validate it against the consumer's actual supported set — advertising items the consumer can't handle produces runtime errors at consumption time, while omitting items the consumer supports makes them undiscoverable. If the catalog transforms identifiers (naming conventions, key formats) between producer and consumer, verify the transformation preserves the format the consumer expects
|
|
82
95
|
- When a validation/sanitization/normalization function is introduced for a field, trace ALL write paths (create, update, sync, import, raw/bulk persist) — partial application means invalid values re-enter through the unguarded path. This includes structural normalization (ID prefixes, required defaults, shape invariants) that the read/parse path depends on — a "raw" write path that skips normalization produces data that changes identity or shape on reload. Conversely, when a new code branch handles data similar to existing branches within the same function (e.g., a new data format, entity subtype, or input shape), verify it applies the same validation and coercion as its siblings — new branches that bypass established validation are the most common source of type-safety regressions
|
|
@@ -159,8 +172,12 @@
|
|
|
159
172
|
**Destructive UI operations** _[applies when: code adds delete, reset, revoke, or other destructive actions]_
|
|
160
173
|
- Destructive actions (delete, reset, revoke) in the UI without a confirmation step — compare with how similar destructive operations elsewhere in the codebase handle confirmation
|
|
161
174
|
|
|
175
|
+
**Streaming & real-time protocols** _[applies when: code implements SSE, WebSocket, ReadableStream, or event-driven APIs]_
|
|
176
|
+
- Wire protocol parsers that assume a simplified subset of the spec (e.g., `\n`-only line endings when the spec allows `\r\n`) — test against boundary representations the spec permits, not just the happy path
|
|
177
|
+
- Event handlers or effects that fire on every high-frequency event (streaming deltas, scroll, resize, keydown) without throttle, debounce, or `requestAnimationFrame` batching — causes jank and excessive re-renders
|
|
178
|
+
|
|
162
179
|
**Accessibility** _[applies when: code modifies UI components or interactive elements]_
|
|
163
|
-
- Interactive elements missing accessible names, roles, or ARIA states — including
|
|
180
|
+
- Interactive elements missing accessible names, roles, or ARIA states — including labels lost or replaced with non-descriptive placeholders in conditional/compact rendering modes. Disabled interactions should have `aria-disabled`
|
|
164
181
|
- Custom toggle/switch UI built from non-semantic elements instead of native inputs
|
|
165
182
|
- Overlay or absolutely-positioned layers with broad `pointer-events-auto` that intercept clicks/hover intended for elements beneath — use `pointer-events-none` on decorative overlays and enable events only on small interactive affordances. Conversely, `pointer-events-none` on a parent kills hover/click handlers on children — verify both directions when layering positioned elements
|
|
166
183
|
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
## Mandate
|
|
4
4
|
You review code by tracing data and control flow ACROSS files. You catch issues invisible in single-file review: mismatched contracts, broken call chains, stale state propagation, lifecycle gaps, and architectural violations.
|
|
5
5
|
|
|
6
|
+
## Approach
|
|
7
|
+
|
|
8
|
+
Apply the checklist as a prompt for attention, not an exhaustive specification. Reason from software engineering principles — correctness, consistency, resource safety, clear ownership. When you trace a data flow and something seems off (a limit that doesn't line up, a cleanup that can't run, a message that diverges from what was sent), flag it even if no checklist item names the pattern.
|
|
9
|
+
|
|
6
10
|
## Reading Strategy
|
|
7
11
|
1. Read ALL changed files to understand each module's responsibility
|
|
8
12
|
2. Trace call chains: for each new/modified function, identify callers and callees across files. Read unchanged files when needed to verify contracts
|
|
@@ -37,15 +41,20 @@ You review code by tracing data and control flow ACROSS files. You catch issues
|
|
|
37
41
|
- `Promise.all` without error handling — partial load. `Promise.allSettled` without logging rejection reasons before mapping fallbacks
|
|
38
42
|
- Sequential processing where one throw aborts remaining — wrap per-item in try/catch
|
|
39
43
|
- Side effects during React render
|
|
44
|
+
- Interactive UI elements (buttons, inputs, drag-and-drop targets, keyboard shortcuts) that remain enabled while an async operation owns their related state — a second trigger while the first is in-flight produces concurrent state mutations or duplicate operations. All entry points for the same operation must be disabled together while the operation is pending
|
|
45
|
+
- Optimistic UI messages that substitute placeholder text when the actual payload sent to the server differs — the conversation history and server-side record will show different content than what the user saw. Use the same fallback text in both the optimistic render and the outgoing payload, or surface the actual payload text
|
|
40
46
|
|
|
41
47
|
### Error Handling
|
|
42
48
|
|
|
43
49
|
- Service functions throwing generic Error for client conditions — 500 instead of 400/404. Consistent access-control responses across endpoints. Concurrency failures → 409 not 500
|
|
44
|
-
- Swallowed errors; generic messages replacing detail
|
|
50
|
+
- Swallowed errors; generic messages replacing detail — including cross-layer error propagation: if the server returns structured error details (field-level validation messages, `details[]` arrays, error codes), the client layer should surface actionable detail rather than discarding structure for a generic string. External service wrappers returning null for all failures (collapsing config errors, auth, rate limits, 5xx into "not found")
|
|
45
51
|
- Caller/callee disagreement: `{ success: false }` vs `.catch()`; gate returning `{ shouldRun: false }` on error vs fail-open runtime; argument shape mismatches (wrapped object vs bare array, wrong positional order); async EventEmitter handlers creating unhandled rejections
|
|
46
52
|
- Destructive ops in retry/cleanup paths without own error handling
|
|
47
53
|
- External service calls without configurable timeouts
|
|
48
54
|
- Missing fallback for unavailable downstream services
|
|
55
|
+
- SSE or streaming handlers that call `end()`/`close()` on mid-stream errors without emitting an error event — the client observes a clean stream termination and treats partial content as complete. Emit a structured `event: error` block before closing so clients can detect and surface the failure
|
|
56
|
+
- SSE or event dispatchers that handle named event types but ignore the protocol's default/unnamed event — SSE streams that emit `data:` without `event:` produce type `'message'` (the SSE default), which a handler processing only named types will silently discard. Verify the default event type is either handled or explicitly excluded
|
|
57
|
+
- Route handlers that call a status/health probe before delegating to the main service when the service already handles the "not configured"/"unreachable" case — the pre-probe adds an extra upstream round-trip on every request and can fail even when the intended operation would succeed. Let the service be the authoritative source of truth and map its structured errors to the appropriate HTTP status at the route boundary
|
|
49
58
|
|
|
50
59
|
### Resource Management
|
|
51
60
|
|
|
@@ -53,6 +62,10 @@ You review code by tracing data and control flow ACROSS files. You catch issues
|
|
|
53
62
|
- Delete/destroy leaving orphaned secondary resources (data dirs, branches, child records, temp files). Over-broad preservation guards preventing cleanup when nothing worth preserving (branch preserved with 0 commits ahead). Cleanup with implicit mutations (auto-merge, auto-commit) — abort on prerequisite failure
|
|
54
63
|
- Initialization functions without guard against multiple calls — creates duplicates
|
|
55
64
|
- Self-rescheduling callbacks where error before re-registration permanently stops schedule — use try/finally
|
|
65
|
+
- `requestAnimationFrame` handles not cancelled on component unmount — pending frames invoke DOM operations or state updates on unmounted nodes. Store the handle and cancel it in the `useEffect` cleanup
|
|
66
|
+
- Large payloads (base64, binary buffers) stored in multiple state fields simultaneously (e.g., as both a `data` field and a `previewUrl` data URL) — each copy multiplies memory. Derive one representation from the other on demand (use `URL.createObjectURL()` for display, revoke on removal and unmount) rather than storing both
|
|
67
|
+
- Blob/object URLs created via `URL.createObjectURL()` not revoked on both item removal AND component unmount — unmounting with pending items leaks all their URLs. Add a cleanup effect that revokes any remaining URLs on unmount
|
|
68
|
+
- ReadableStream / fetch readers consumed in a loop without `try/finally` — an exception thrown inside the loop leaves the reader and underlying stream open. Wrap the read loop in `try/finally { reader.cancel() }`. The `finally` block should catch its own errors so it doesn't mask the original exception
|
|
56
69
|
|
|
57
70
|
### Validation & Consistency
|
|
58
71
|
|
|
@@ -62,6 +75,10 @@ You review code by tracing data and control flow ACROSS files. You catch issues
|
|
|
62
75
|
- Data migrations silently changing runtime behavior — preserve execution semantics. Unsupported source values must be flagged, not defaulted
|
|
63
76
|
- Update endpoints with field allowlists not covering new model fields
|
|
64
77
|
- New endpoints not matching validation patterns of existing similar ones. API doc schemas must be structurally complete
|
|
78
|
+
- Client-side input validation limits (max count, file size, string length, combined totals) must be consistent with — and ideally tighter than — server-side enforcement. When the client allows combinations the server rejects (e.g., 8 × 10MB files vs a 50MB JSON body limit), users hit confusing 400/413 errors. Trace all enforcement boundaries (UI, API schema, body parser, downstream service) and verify they form a coherent envelope
|
|
79
|
+
- Sample config files, README examples, and documentation that reference config keys or structure must match what the implementation actually reads. Trace example keys against the config loader — stale examples teach operators to configure values the system ignores (or vice versa)
|
|
80
|
+
- Config values whose format can be validated at initialization time (URLs, port numbers, auth schemes) but are only validated at first use — misconfiguration surfaces as a cryptic runtime error deep in the call stack. Validate format and range of security-relevant config values during initialization and surface a specific diagnostic identifying the bad field
|
|
81
|
+
- URL joining utilities that force paths absolute-from-origin (stripping the base URL's pathname) — `baseUrl=http://host/proxy` + `/v1/api` silently produces `http://host/v1/api` instead of `http://host/proxy/v1/api`. Verify URL construction utilities preserve pathname segments from the base URL, or document and enforce that base URLs must be origin-only
|
|
65
82
|
- Summary/aggregation endpoints using different filters/sources than detail views they link to
|
|
66
83
|
- Discovery endpoints must validate against consumer's actual supported set. Identifier transformations between producer and consumer must preserve expected format
|
|
67
84
|
- Validation functions introduced for a field: trace ALL write paths. New branches must apply same validation as siblings
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
## Mandate
|
|
4
4
|
You review code with an adversarial mindset. Find trust boundary violations, injection vectors, data exposure, and access control gaps. Focus on security concerns that a general code reviewer would deprioritize.
|
|
5
5
|
|
|
6
|
+
## Approach
|
|
7
|
+
|
|
8
|
+
Apply the checklist as a prompt for adversarial attention, not an exhaustive specification. Reason from first principles: trace each trust boundary, ask "what happens when an attacker controls this value?", and flag issues that violate security principles even when no checklist item names the exact pattern.
|
|
9
|
+
|
|
6
10
|
## Reading Strategy
|
|
7
11
|
For each changed file:
|
|
8
12
|
1. Read the **ENTIRE file** (not just diff hunks)
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
## Mandate
|
|
4
4
|
You review code for per-file correctness: bugs, quality issues, and convention violations visible within a single file. You do NOT trace call chains or data flows across files — another agent handles cross-file analysis.
|
|
5
5
|
|
|
6
|
+
## Approach
|
|
7
|
+
|
|
8
|
+
Apply the checklist as a prompt for attention, not an exhaustive specification. Use your general software engineering judgment to identify issues that violate clear engineering principles — correctness, resource safety, user trust, simplicity — even when no checklist item names the pattern explicitly. If something looks wrong, flag it.
|
|
9
|
+
|
|
6
10
|
## Reading Strategy
|
|
7
11
|
For each changed file, read the **ENTIRE file** (not just diff hunks). New code interacting incorrectly with existing code in the same file is a common bug source. Review one file at a time.
|
|
8
12
|
|
|
@@ -27,6 +31,8 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
|
|
|
27
31
|
- Null/undefined access without guards; off-by-one errors; spread of null (is `{}`), spread of non-objects (string → indexed chars, array → numeric keys) — guard with plain-object check before spreading
|
|
28
32
|
- External/user data (parsed JSON, API responses, file reads) used without structural validation — guard parse failures, missing properties, wrong types, null elements. Optional enrichment failures should not abort the main operation
|
|
29
33
|
- Type coercion: `Number('')` is `0` not empty; `0` is falsy in truthy checks; `NaN` comparisons always false; `"10" < "2"` (lexicographic). Deserialized booleans: `"false"` is truthy — use `=== 'true'`. `isinstance(x, int)` accepts `bool` in Python; `typeof NaN === 'number'` in JS
|
|
34
|
+
- Config/option defaults applied with `||` or falsy guards — intentional `0`, `false`, or `''` values are treated as "unset" and replaced by the default. Use `?? default` or explicit `=== undefined` checks when zero, false, or empty string are valid configuration values
|
|
35
|
+
- Functions returning different types depending on input conditions (string in one branch, object in another) — callers must branch on return type; prefer a consistent return shape
|
|
30
36
|
- Indexing empty arrays; `every`/`some`/`reduce` on empty collections returning vacuously true; declared-but-never-updated state/variables
|
|
31
37
|
- Parallel arrays coupled by index position — use objects/maps keyed by stable identifier
|
|
32
38
|
- Shared mutable references: module-level defaults mutated across calls (use `structuredClone()`); `useCallback`/`useMemo` referencing later `const` (temporal dead zone); spread followed by unconditional assignment clobbering spread values
|
|
@@ -36,6 +42,7 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
|
|
|
36
42
|
- Route params passed to services without format validation; path containment using string prefix without separator boundary (use `path.relative()`)
|
|
37
43
|
- Parameterized/wildcard routes registered before specific named routes (`/:id` before `/drafts` matches `/drafts` as `id="drafts"`)
|
|
38
44
|
- Stored or external URLs rendered as clickable links without protocol validation — allowlist `http:`/`https:`
|
|
45
|
+
- Request schema fields for large string/binary payloads (base64, file content, free text) without per-field size limits — a total body-size limit alone doesn't prevent individual oversized fields from consuming excessive memory or exceeding downstream service limits; add per-field `max(N)` constraints with clear error messages
|
|
39
46
|
|
|
40
47
|
**Error handling (single-file)**
|
|
41
48
|
- Swallowed errors (empty `.catch(() => {})`); error handlers that exit cleanly (`exit 0`, `return`) without user-visible output; handlers replacing detailed failure info with generic messages
|
|
@@ -91,10 +98,13 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
|
|
|
91
98
|
- Destructive actions without confirmation step
|
|
92
99
|
|
|
93
100
|
**Accessibility** _[UI components, interactive elements]_
|
|
94
|
-
- Interactive elements missing accessible names, roles, or ARIA states
|
|
101
|
+
- Interactive elements missing accessible names, roles, or ARIA states — including labels removed or replaced with non-descriptive placeholders in conditional/compact rendering modes
|
|
95
102
|
- Custom toggles from non-semantic elements instead of native inputs
|
|
96
103
|
- Overlay layers with `pointer-events-auto` intercepting clicks beneath; `pointer-events-none` on parent killing child hover handlers
|
|
97
104
|
|
|
105
|
+
**UI performance** _[UI components with streaming, scroll, or frequent updates]_
|
|
106
|
+
- Event handlers or `useEffect` callbacks firing on every high-frequency event (streaming deltas, scroll, resize, keydown) without throttle, debounce, or `requestAnimationFrame` batching — causes jank and excessive re-renders. Batch with rAF or a time-based limiter when the handler doesn't need to run on every tick
|
|
107
|
+
|
|
98
108
|
### Always Check — Quality & Conventions
|
|
99
109
|
|
|
100
110
|
**Intent vs implementation (single-file)**
|
package/package.json
CHANGED