Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Entwicklung · SKILL.md

adversarial-review

adversarial-review

Adversarially 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

Skill-Dokumentation

GitHub

name: adversarial-review description: >- Adversarially 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", or "pressure-test this change".

Adversarial Review

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.

Stance

  • Default to distrust. The diff is guilty until a named input clears it.
  • No credit for good intent, partial fixes, or "probably fine."
  • Happy-path-only is a defect. If code only works on the example input, that is the finding.
  • A specific attack angle ("what input makes this throw?") finds bugs. "Review this code" produces polite nothing.

Scope

Review the change, not the codebase.

  • Read the supplied frozen review target. If none was supplied, use git diff. Every finding ties to a changed line.
  • Trace the blast radius: for each changed signature, return shape, nullability, or unit, read its callers. A rename or a newly-nullable return breaks stale callers the diff never shows — the regression pure-diff review structurally misses.
  • Hand off, do not duplicate. Style → 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.

What to hunt

Bug classThe tell
Null / optionalA value from an API, map lookup, regex match, or DB row is dereferenced without a guard
Boundary / off-by-oneIndex math, slice bounds, < vs <=, empty or single-element input
Swallowed errorEmpty catch, catch-log-continue, ignored error/Result return, un-awaited rejection
Happy-path gapWorks on the demo input; empty / zero / negative / huge / missing-field / dependency-down untested
Race / orderingShared mutable state, check-then-act, an await between a read and its write
State mutation / aliasingMutates a passed-in object, array, or default arg the caller still holds
Async / awaitA 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 lossA generic closure or callback silently produces Void/unit, an optional, or a wider type than the caller expects
Type-erasure boundaryA value flows through Any, unknown, catch-all overloads, dynamic JSON, IPC, persistence, or plugin APIs before its shape is checked
Resource leakAcquire (file, socket, lock, listener, subscription) with no release on every path — especially the error path
Inverted logicFlipped boolean, wrong operator, bad default, De Morgan slip — plausible, but takes the wrong branch
Contract mismatchSignature / units / nullability / return shape changed but not all callers; or a call with wrong or hallucinated args
Partial changeOne 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.

Trace result flow before type erasure

At every generic closure, callback, actor hop, transaction, lock helper, retry wrapper, or task body whose result is consumed:

  1. State the concrete result type the caller expects.
  2. Verify every value-producing path actually returns that type. In Swift, when a generic closure result is inferred from its body without a concrete non-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.
  3. Follow the result through overload resolution and type erasure. Any, catch-all overloads, and dynamic serializers can turn a compile-time mistake into a runtime failure.
  4. If the API has side effects, verify the side effect and returned success/error response separately. "The mutation happened" does not prove the protocol response succeeded.

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.

Technique

For each changed function:

  1. State its contract in one line before reading the body — inputs, output, side effects. Then check the body actually delivers it.
  2. Assume every variable can be null and every external call can fail. Find the first line that does not survive that assumption.
  3. Construct one concrete failing input and trace it line by line to the suspect spot. Verify it actually reaches that line — not a plausible neighbor.
  4. Ask "if I deleted this change, what breaks?" — tests whether it is necessary and what it regresses.
  5. For every added regression test, ask whether restoring the defect makes that test fail. A helper-level test that bypasses the changed production boundary is not regression coverage.

Report only what you can trigger

The gate that keeps findings high-signal:

  • Name the input or path that triggers the bug. Cannot name it → do not report it.
  • Do not speculate about breakage you cannot trace to a specific code path.
  • Read the surrounding context first — callers, guards, sanitizers. A line that looks unsafe alone is often safe in context.
  • Tag each finding with severity and a confidence: high / medium / low.
  • Exception: high-impact bugs (data loss, corruption, crash on common input) — report even at lower confidence, and state what is uncertain.
  • Prefer one strong finding over five weak ones. Do not pad.

Self-verification

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.

Output

For each surviving finding:

  • Location — file and line in the diff
  • The bug — one sentence
  • The trigger — the concrete input or sequence that makes it fail
  • Severity + confidence
  • Suggested fix — propose, do not apply

If the change holds up under attack, say so plainly. Finding nothing is a valid, honest result — do not invent bugs to look thorough.

Gespeicherte Skills