brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
adversarial-reviewAdversarially hunt for correctness bugs and regressions in a change set. Use when reviewing a diff before finalizing, during a cleanup pass, or when asked to find bugs, pressure-test, or stress-test recently modified code. Triggers on "find bugs", "what could break", "review for correctness", "did I break anything", "hunt regressions", "adversarial review",…
Independent GitHub snapshot · Automated classification · Original documentation governs
Assume the change is wrong until a concrete input proves it right. Hunt correctness bugs the change introduced — not style, not security. One finding you can trigger beats ten you cannot.
Review the change, not the codebase.
git diff. Every finding ties to a changed line.simplify. Comment intent → code-comments. Type design → parse-dont-validate. Security → security-review. Framework idioms → typescript / no-use-effect / macos-swift-desktop.This is read-only. Propose fixes; do not apply them, and do not touch code outside the change.
| Bug class | The tell |
|---|---|
| Null / optional | A value from an API, map lookup, regex match, or DB row is dereferenced without a guard |
| Boundary / off-by-one | Index math, slice bounds, < vs <=, empty or single-element input |
| Swallowed error | Empty catch, catch-log-continue, ignored error/Result return, un-awaited rejection |
| Happy-path gap | Works on the demo input; empty / zero / negative / huge / missing-field / dependency-down untested |
| Race / ordering | Shared mutable state, check-then-act, an await between a read and its write |
| State mutation / aliasing | Mutates a passed-in object, array, or default arg the caller still holds |
| Async / await | A promise used as its value, a forgotten await, async inside forEach, sequential-vs-parallel slip |
| Type coercion | == vs ===, truthy 0 / "" / [], implicit string↔number, NaN |
| Result-type loss | A generic closure or callback silently produces Void/unit, an optional, or a wider type than the caller expects |
| Type-erasure boundary | A value flows through Any, unknown, catch-all overloads, dynamic JSON, IPC, persistence, or plugin APIs before its shape is checked |
| Resource leak | Acquire (file, socket, lock, listener, subscription) with no release on every path — especially the error path |
| Inverted logic | Flipped boolean, wrong operator, bad default, De Morgan slip — plausible, but takes the wrong branch |
| Contract mismatch | Signature / units / nullability / return shape changed but not all callers; or a call with wrong or hallucinated args |
| Partial change | One branch updated but not its twin; a flag without the gated code; a migration without its reader; leftover TODO |
Weight the hunt: fresh, often agent-written code skews to happy-path gaps, missing null and edge guards, swallowed errors, mismatched or hallucinated APIs, and half-finished refactors. Look there first.
At every generic closure, callback, actor hop, transaction, lock helper, retry wrapper, or task body whose result is consumed:
Void context, a multi-statement ordinary closure with no explicit return can infer Void even when its final expression produces a value. A concrete expected result usually turns the omission into a compiler error instead.Any, catch-all overloads, and dynamic serializers can turn a compile-time mistake into a runtime failure.Do not apply ordinary closure-return rules to result builders or intentionally side-effect-only closures. Prefer a concrete expected type at serialization, IPC, persistence, and plugin boundaries so accidental widening fails compilation.
For each changed function:
The gate that keeps findings high-signal:
Before surfacing anything, attack your own findings. For each, try to prove it false: re-read the trigger path, confirm the guard you assumed was missing really is missing, confirm the input really reaches the line. Drop anything you cannot defend.
This pass is what separates real findings from plausible noise. Do not skip it.
For each surviving finding:
If the change holds up under attack, say so plainly. Finding nothing is a valid, honest result — do not invent bugs to look thorough.