/correctness-traps
Use when writing or reviewing error handling, floating-point math, concurrent code, remote calls, singletons/globals, hot-path data structures, or high-volume log statements
$ npx -y skills add oribarilan/97 --skill correctness-traps --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/correctness-traps
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing or reviewing error handling, floating-point math, concurrent code, remote calls, singletons/globals, hot-path data structures, or high-volume log statements
SKILL.md
correctness-traps.SKILL.mdname: correctness-traps
description: Use when writing or reviewing error handling, floating-point math, concurrent code, remote calls, singletons/globals, hot-path data structures, or high-volume log statements
Error and Correctness Traps
Overview
Common bugs grouped by domain: floats that won't compare equal, retries that hammer a downed service, singletons that wreck testability, and others. **When you write code in one of these domains, stop and run the matching checks before you commit.**
This is a **rigid** skill. Jump to the sub-section that matches what you're writing and run that sub-section's checks.
These checks matter most when code will reach real users in production. In MVPs, prototypes, internal dev tools, and one-off scripts where the architecture is still in flux, prefer the simplest thing that works.
When to invoke
Invoke when you're about to:
- Add or change error-handling around a call that can fail
- Compare, sum, or accumulate floating-point numbers
- Write concurrent, parallel, or threaded code, or share mutable state between threads
- Call a remote process, web service, database, or another machine
- Introduce a singleton or any globally-shared mutable state
- Choose a data structure or algorithm on a path that runs often or on large inputs
- Add or change log statements that may fire at high volume
- Review code that handles errors, floats, concurrency, remote calls, singletons, or hot-path data structures
Non-triggers — do NOT invoke for
- Renaming a local variable inside one function
- Adding a docstring to an existing function
- Fixing a typo in a comment
- Formatting-only changes handled by a formatter
- Adjusting a config value in a config file with no logic change
- Skimming code for context without producing findings or edits
- An early-stage MVP or prototype where the architecture is still in flux
- An internal dev tool, debugging endpoint, or one-off script
- Throwaway code expected to be replaced before reaching users
If the change touches one of these domains even slightly, **invoke anyway** — the per-domain check is short and the bugs are not.
Checks by domain
Errors (97/21, 97/26, 97/29)
1. **Distinguish business exceptions from technical ones.** A *technical* exception means the system can't proceed — bad arguments, broken DB connection, programming error. Let it bubble to a top-level handler that puts the system in a safe state (rollback, log, alert, friendly user message); the caller can't fix it. A *business* exception is part of the contract — withdrawing from an empty account, booking an unavailable slot — and is an alternative return path the caller is expected to handle. Give them separate types or hierarchies; mixing them blurs the contract. *(Bergh Johnsson, 97/21.)* 2. **Never write the empty `catch`.** `try { ... } catch (...) {}` silently swallows everything. Same for ignoring return codes (`printf`'s return value, `write()`'s short-write count) and pretending `errno` doesn't exist. Example: a service-call wrapper swallows every exception and returns `null`, so every downstream caller has to invent their own theory of what `null` means. Expose erroneous conditions in your interfaces; if handling errors feels onerous, the interface is wrong. *(Goodliffe, 97/26.)* 3. **Don't rely on unexplained magic.** If your change depends on behavior nobody can explain (build picks a DLL by load order, deployment reads an undocumented env var, a job runs because of a side effect in a config file), surface it in your summary to the user before shipping — don't bury the dependency. *(Griffiths, 97/29.)*
Numerics (97/33)
4. **Never compare floats with `==`.** `0.1 + 0.2 != 0.3` in IEEE 754 — the canonical demonstration. Compare with a tolerance appropriate to the magnitude of the values involved (≈ ε|x|, where ε is machine epsilon — ~1e-7 for `float`, ~1e-16 for `double`). 5. **Watch for catastrophic cancellation.** Subtracting nearly-equal floats promotes roundoff to the most significant digits. Example: solving `x² - 100000x + 1 = 0` directly via the quadratic formula gives a wildly wrong small root because `-b + sqrt(b² - 4)` cancels; compute one root and derive the other from `r1 * r2 = c/a`. Same shape of error appears in any series with alternating signs of similar magnitude. 6. **Don't use float for money.** Use a fixed-point or decimal type. Floats are for scientific calculation where you accept ε-level error; financial code does not accept it. *(Allison, 97/33.)*
Concurrency & IPC (97/41, 97/57)
7. **Default to message passing over shared mutable state.** When you reach for a lock around shared data, ask first whether the data could be owned by one process/actor that others message. CSP-style designs (Erlang, Go channels, actor frameworks in mainstream languages) sidestep most race / deadlock / livelock bugs by construction. Reserve shared-memory + locks for cases you have measured and understood. *(Winder, 97/57.)* 8. **Count IPCs per user stimulus, not lines of code.** Each remote call is non-trivial latency; sequential calls add. Example: ORM lazy-loading produces 1,000 sequential 10ms DB calls for one page render — minimum 10s response time before any rendering work. Ratios in the thousands appear routinely in slow apps. Apply parsimony (one round-trip carrying the right data), parallelism (overall latency = longest call, not sum), or caching. *(Stafford, 97/41.)* 9. **Retry with backoff and a cap, never in a tight loop.** Example: `while (!call()) call();` against a downed service hammers it the moment it comes back. Exponential backoff, jitter, and a max-retries ceiling are the minimum; idempotency on the server side is what makes retry safe at all.
Limits & Performance (97/46, 97/89)
10. **Know the complexity of the data structure you picked.** Linked list vs. hash vs. balanced tree on a million items is the difference between snappy and unusable. Pick by access pattern (lookup-heav
Read more
name: correctness-traps description: Use when writing or reviewing error handling, floating-point math, concurrent code, remote calls, singletons/globals, hot-path data structures, or high-volume log statements
Error and Correctness Traps
Overview
Common bugs grouped by domain: floats that won't compare equal, retries that hammer a downed service, singletons that wreck testability, and others. **When you write code in one of these domains, stop and run the matching checks before you commit.**
This is a **rigid** skill. Jump to the sub-section that matches what you're writing and run that sub-section's checks.
These checks matter most when code will reach real users in production. In MVPs, prototypes, internal dev tools, and one-off scripts where the architecture is still in flux, prefer the simplest thing that works.
When to invoke
Invoke when you're about to:
- Add or change error-handling around a call that can fail
- Compare, sum, or accumulate floating-point numbers
- Write concurrent, parallel, or threaded code, or share mutable state between threads
- Call a remote process, web service, database, or another machine
- Introduce a singleton or any globally-shared mutable state
- Choose a data structure or algorithm on a path that runs often or on large inputs
- Add or change log statements that may fire at high volume
- Review code that handles errors, floats, concurrency, remote calls, singletons, or hot-path data structures
Non-triggers — do NOT invoke for
- Renaming a local variable inside one function
- Adding a docstring to an existing function
- Fixing a typo in a comment
- Formatting-only changes handled by a formatter
- Adjusting a config value in a config file with no logic change
- Skimming code for context without producing findings or edits
- An early-stage MVP or prototype where the architecture is still in flux
- An internal dev tool, debugging endpoint, or one-off script
- Throwaway code expected to be replaced before reaching users
If the change touches one of these domains even slightly, **invoke anyway** — the per-domain check is short and the bugs are not.
Checks by domain
Errors (97/21, 97/26, 97/29)
1. **Distinguish business exceptions from technical ones.** A *technical* exception means the system can't proceed — bad arguments, broken DB connection, programming error. Let it bubble to a top-level handler that puts the system in a safe state (rollback, log, alert, friendly user message); the caller can't fix it. A *business* exception is part of the contract — withdrawing from an empty account, booking an unavailable slot — and is an alternative return path the caller is expected to handle. Give them separate types or hierarchies; mixing them blurs the contract. *(Bergh Johnsson, 97/21.)* 2. **Never write the empty `catch`.** `try { ... } catch (...) {}` silently swallows everything. Same for ignoring return codes (`printf`'s return value, `write()`'s short-write count) and pretending `errno` doesn't exist. Example: a service-call wrapper swallows every exception and returns `null`, so every downstream caller has to invent their own theory of what `null` means. Expose erroneous conditions in your interfaces; if handling errors feels onerous, the interface is wrong. *(Goodliffe, 97/26.)* 3. **Don't rely on unexplained magic.** If your change depends on behavior nobody can explain (build picks a DLL by load order, deployment reads an undocumented env var, a job runs because of a side effect in a config file), surface it in your summary to the user before shipping — don't bury the dependency. *(Griffiths, 97/29.)*
Numerics (97/33)
4. **Never compare floats with `==`.** `0.1 + 0.2 != 0.3` in IEEE 754 — the canonical demonstration. Compare with a tolerance appropriate to the magnitude of the values involved (≈ ε|x|, where ε is machine epsilon — ~1e-7 for `float`, ~1e-16 for `double`). 5. **Watch for catastrophic cancellation.** Subtracting nearly-equal floats promotes roundoff to the most significant digits. Example: solving `x² - 100000x + 1 = 0` directly via the quadratic formula gives a wildly wrong small root because `-b + sqrt(b² - 4)` cancels; compute one root and derive the other from `r1 * r2 = c/a`. Same shape of error appears in any series with alternating signs of similar magnitude. 6. **Don't use float for money.** Use a fixed-point or decimal type. Floats are for scientific calculation where you accept ε-level error; financial code does not accept it. *(Allison, 97/33.)*
Concurrency & IPC (97/41, 97/57)
7. **Default to message passing over shared mutable state.** When you reach for a lock around shared data, ask first whether the data could be owned by one process/actor that others message. CSP-style designs (Erlang, Go channels, actor frameworks in mainstream languages) sidestep most race / deadlock / livelock bugs by construction. Reserve shared-memory + locks for cases you have measured and understood. *(Winder, 97/57.)* 8. **Count IPCs per user stimulus, not lines of code.** Each remote call is non-trivial latency; sequential calls add. Example: ORM lazy-loading produces 1,000 sequential 10ms DB calls for one page render — minimum 10s response time before any rendering work. Ratios in the thousands appear routinely in slow apps. Apply parsimony (one round-trip carrying the right data), parallelism (overall latency = longest call, not sum), or caching. *(Stafford, 97/41.)* 9. **Retry with backoff and a cap, never in a tight loop.** Example: `while (!call()) call();` against a downed service hammers it the moment it comes back. Exponential backoff, jitter, and a max-retries ceiling are the minimum; idempotency on the server side is what makes retry safe at all.
Limits & Performance (97/46, 97/89)
10. **Know the complexity of the data structure you picked.** Linked list vs. hash vs. balanced tree on a million items is the difference between snappy and unusable. Pick by access pattern (lookup-heav
Showing the first part of this file.
Agent skills distilled from the hard-won lessons of world-renowned programmers, in the spirit of "97 Things Every Programmer Should Know"
Repo: oribarilan/97
Other skills on 97.
- /api-design
Use when designing or reviewing a public API, exported function signature, module boundary, exported type/interface, or any contract other code depends on
Open skill - /before-you-refactor
Use when considering, evaluating, or performing a refactor, restructure, cross-file rename, or cleanup
Open skill - /build-deploy-and-tooling
Use when writing, reviewing, or changing build scripts, CI workflows, deploy pipelines, repo setup, or evaluating a new tool/dependency
Open skill - /clean-code
Use when writing or reviewing functions, classes, naming, or non-trivial logic (≥3 lines)
Open skill - /domain-modeling
Use when introducing, reviewing, or renaming a top-level type, table, or domain concept; or choosing where state lives (in-memory vs persistent)
Open skill - /observability
Use when writing or reviewing request handlers, RPCs, or background jobs for production; adding tracing, metrics, or structured-log calls; or making diagnosability decisions
Open skill

