skills/debugging/semantic-bug-detector/SKILL.md
Detects logical and semantic bugs by understanding program intent — catches issues that syntax-only tools miss. Use when static analysis has already run and found nothing, when the user reports incorrect behavior but no crash, or when reviewing algorithmic code for correctness.
npx skillsauth add santosomar/general-secure-coding-agent-skills semantic-bug-detectorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Find bugs where the code is syntactically fine and type-correct but does the wrong thing. → static-bug-detector catches provable errors; this skill catches violated intent.
You cannot find a semantic bug without a model of intent. For each function, establish intent from (in order of reliability):
sort should sort; retry(n) should try at most n+1 times)binarySearch, you know what invariants it should hold)If you have none of these, you are not detecting bugs — you are generating hypotheses.
| Smell | What it looks like | Why it's suspicious |
| ------------------------------- | ------------------------------------------------------------ | --------------------------------------------------------------- |
| Copy-paste-mutate asymmetry | Two near-identical blocks differ in one token | The one token was supposed to change in both — or neither |
| Condition-action mismatch | if x > limit: ... x — the condition checks one variable, the body mutates another | The variable in the condition is probably the one the author meant to modify |
| Loop variable ignored | for x in items: but body never uses x | Either the loop is a repeat n times — or author meant to use x |
| Inverted boundary | Sorted-collection logic that uses < where the surrounding comparisons use <= (or vice versa) | Boundary consistency is algorithmic; inconsistency is usually a bug |
| Mutation during iteration | Modifying the collection being iterated | Skipped elements / ConcurrentModificationException — correct use is rare |
| State set, never read | Field written in 3 places, read in 0 | Either dead state — or the read is the bug (someone forgot to check it) |
| Integer division in float ctx | a / b where a, b are ints but result feeds a float op | Python 2 habits, C integer division — silent truncation |
| Exception changes control flow silently | try: ...; except: pass followed by code that assumes try succeeded | The swallow masks the failure; the following code operates on garbage |
Unlike static bugs, semantic findings are hypotheses until confirmed. Rank by how cheaply they can be confirmed:
needs-review, don't assert_ naming convention would apply. for _ in range(n) is intentional; for item in items with no item reference is suspicious.[a, b) legitimately mix <= and <.Code:
def apply_discounts(cart, coupons):
total = sum(item.price for item in cart)
for coupon in coupons:
if coupon.type == "percent":
total -= total * coupon.value / 100
elif coupon.type == "fixed":
total -= total * coupon.value / 100 # line 7
return max(total, 0)
Detection: Copy-paste-mutate asymmetry. Lines 5 and 7 are identical, but the branch conditions differ. The fixed branch should subtract coupon.value, not total * coupon.value / 100.
Confirmation: Write a test — cart total 100, one fixed coupon value 10 → expect 90, get 90. Wait — it passes? Re-check: 100 - 100 * 10 / 100 = 90. The bug is masked at total=100. Try total=50: expect 40, get 45. Confirmed.
Finding:
pricing.py:7 COPY_PASTE_ASYMMETRY confidence=high (confirmed by test)
Fixed-coupon branch applies percent formula. At total=50, fixed coupon of
$10 discounts $5 instead of $10.
Fix: `total -= coupon.value`
Confirming test:
cart(total=50), fixed_coupon(10) → assert total == 40
state set, never read in a hot loop might be cache prefetching. mutation during iteration might be a carefully designed in-place algorithm. Lower confidence for anything marked // PERF.normalize() means fifteen different things.<file>:<line> <SMELL_NAME> confidence=<hypothesis|confirmed>
<what the code does vs. what intent suggests it should do>
<confirming evidence or test, or "needs manual review">
<proposed fix if confident>
development
Extracts human-readable pseudocode from a verified formal artifact (Dafny, Lean, TLA+) while preserving the verified properties as annotations, so the proof-carrying logic can be reimplemented in a production language. Use when porting verified code to an unverified target, when documenting what a formal spec actually does, or when handing a verified algorithm to an implementer.
development
Translates natural-language or pseudocode descriptions of concurrent and distributed systems into TLA+ specifications ready for the TLC model checker. Identifies state variables, actions, type invariants, safety properties, and liveness properties from the description. Use when formalizing a protocol, when the user describes a distributed algorithm to verify, when designing a consensus or locking scheme, or when starting formal verification of a concurrent system.
testing
Reduces a TLA+ model so TLC can actually check it — shrinks constants, adds state constraints, abstracts data, or applies symmetry — when the state space is too large to enumerate. Use when TLC runs out of memory, when checking takes hours, or when a spec works at N=2 and you need confidence at larger scale.
development
TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.