* test(#1961): add failing-first bug-taxonomy routing contract tests Epic #1957 Phase 2B. Source-text-is-the-product contract tests (3 taxonomy classes, explicit class->technique routing table, Bohrbug->repro+SBFL+bisect, Heisenbug->record-replay/stability+SKIP-SBFL, Concurrency->atomicity/order/ deadlock checklist, bug_class in DEBUG Current Focus, supersede-not-append) plus a routing-table specification object pinning the documented decisions (SBFL forbidden on Heisenbug is the load-bearing 1B/2B seam). Failing-first: reference, Phase 1.75, and routing-table reframe do not yet exist. * feat(#1961): add bug-taxonomy classification + strategy routing to gsd-debugger Epic #1957 Phase 2B (reliability-critical). Adds Phase 1.75: classify the failure as Bohrbug / Heisenbug-Mandelbug / Concurrency, then route the investigation technique via an explicit class->technique table (Kernighan: no opaque heuristic). Bohrbug -> reproduction + SBFL (Phase 1.25) + git bisect; Heisenbug/Mandelbug -> record-replay (rr) + stability-stress + statistical sampling, with SBFL explicitly SKIPPED (a flaky spectrum poisons the Ochiai ranking — the load-bearing 1B/2B seam); Concurrency -> the atomicity/order/deadlock checklist first. Reframes (supersedes, not appends — Zawinski) the flat 'Technique Selection by situation' table into a class-routed table; the 11 techniques remain as routed targets. bug_class recorded in Current Focus (DEBUG template); common-bug- patterns catalog cross-referenced to the taxonomy. Full rules extracted to gsd-core/references/debugger-bug-taxonomy.md. INVENTORY + manifest + agent-size baseline + install-parity goldens + AGENTS.md updated. * fix(#1961): address orthogonal review (phase-name drift, General lane, revoke framing, row-scoped tests, bounding) - HIGH: reference said 'Phase 1B' (epic shorthand); corrected to the deployed 'Phase 1.25' (matches the agent + SBFL reference). - HIGH: 6 of 11 techniques (Rubber duck, Delta, Working backwards, Differential, Comment-out, Follow-the-indirection) were orphaned by the situation-table reframe. Added a 'General (any class, situation-cued)' lane to BOTH the reference routing table and the agent's Technique Selection table that re-homes them — supersede-not-append now holds. - MEDIUM: the SBFL-skip is structurally retroactive (Phase 1.25 runs before Phase 1.75 classification), so reframed the table column from 'Do NOT use' to 'Revoke if already run' + an explicit 'retroactive revocation, not proactive skip' note stating the ordering honestly. - MEDIUM: contract tests are now row-scoped (parse the table by class, assert per-row) instead of presence-only; added a guard that the previously- orphaned techniques now have a General-lane route. - LOW: pinned the canonical bug_class value form (lowercase-kebab: bohrbug|heisenbug-mandelbug|concurrency; prose may use title-case). - NIT: added a 'Bound the Heisenbug-chase runs' note (rr/stability/sampling timeouts) per the unbounded-subprocess gauntlet. * chore(#1961): backfill changeset pr number (PR #2407)
6.3 KiB
6.3 KiB
Common Bug Patterns
Checklist of frequent bug patterns to scan before forming hypotheses. Ordered by frequency. Check these FIRST — they cover ~80% of bugs across all technology stacks.
Null / Undefined Access
- Null property access — accessing property on
nullorundefined, missing null check or optional chaining - Missing return value — function returns
undefinedinstead of expected value, missingreturnstatement or wrong branch - Destructuring null — array/object destructuring on
null/undefined, API returned error shape instead of data - Undefaulted optional — optional parameter used without default, caller omitted argument
Off-by-One / Boundary
- Wrong loop bound — loop starts at 1 instead of 0, or ends at
lengthinstead oflength - 1 - Fence-post error — "N items need N-1 separators" miscounted
- Inclusive vs exclusive — range boundary
<vs<=, slice/substring end index - Empty collection —
.length === 0falls through to logic assuming items exist
Async / Timing
- Missing await — async function called without
await, gets Promise object instead of resolved value - Race condition — two async operations read/write same state without coordination
- Stale closure — callback captures old variable value, not current one
- Initialization order — event handler fires before setup complete
- Leaked timer — timeout/interval not cleaned up, fires after component/context destroyed
State Management
- Shared mutation — object/array modified in place affects other consumers
- Stale render — state updated but UI not re-rendered, missing reactive trigger or wrong reference
- Stale handler state — closure captures state at bind time, not current value
- Dual source of truth — same data stored in two places, one gets out of sync
- Invalid transition — state machine allows transition missing guard condition
Import / Module
- Circular dependency — module A imports B, B imports A, one gets
undefined - Export mismatch — default vs named export,
import Xvsimport { X } - Wrong extension —
.jsvs.cjsvs.mjs,.tsvs.tsx - Path case sensitivity — works on Windows/macOS, fails on Linux
- Missing extension — ESM requires explicit file extensions in imports
Type / Coercion
- String vs number compare —
"5" > "10"istrue(lexicographic),5 > 10isfalse - Implicit coercion —
==instead of===, truthy/falsy surprises (0,"",[]) - Numeric precision —
0.1 + 0.2 !== 0.3, large integers lose precision - Falsy valid value — value is
0or""which is valid but falsy
Environment / Config
- Missing env var — environment variable missing or wrong value in dev vs prod vs CI
- Hardcoded path — works on one machine, fails on another
- Port conflict — port already in use, previous process still running
- Permission denied — different user/group in deployment
- Missing dependency — not in package.json or not installed
Data Shape / API Contract
- Changed response shape — backend updated, frontend expects old format
- Wrong container type — array where object expected or vice versa,
datavsdata.resultsvsdata[0] - Missing required field — required field omitted in payload, backend returns validation error
- Date format mismatch — ISO string vs timestamp vs locale string
- Encoding mismatch — UTF-8 vs Latin-1, URL encoding, HTML entities
Regex / String
- Sticky lastIndex — regex
gflag with.test()then.exec(),lastIndexnot reset between calls - Missing escape —
.matches any char,$is special, backslash needs doubling - Greedy overmatch —
.*eats through delimiters, need.*? - Wrong quote type — string interpolation needs backticks for template literals
Error Handling
- Swallowed error — empty
catch {}or logs but doesn't rethrow/handle - Wrong error type — catches base
Errorwhen specific type needed - Error in handler — cleanup code throws, masking original error
- Unhandled rejection — missing
.catch()or try/catch aroundawait
Scope / Closure
- Variable shadowing — inner scope declares same name, hides outer variable
- Loop variable capture — all closures share same
var i, useletor bind - Lost this binding — callback loses context, need
.bind()or arrow function - Scope confusion —
varhoisted to function,let/constblock-scoped
How to Use This Checklist
- Before forming any hypothesis, scan the relevant categories based on the symptom
- Match symptom to pattern — if the bug involves "undefined is not an object", check Null/Undefined first
- Each checked pattern is a hypothesis candidate — verify or eliminate with evidence
- If no pattern matches, proceed to open-ended investigation
Pattern categories → bug taxonomy (Phase 1.75)
The categories here feed bug-class classification (see debugger-bug-taxonomy.md):
| Pattern category | Typical bug_class |
|---|---|
| Null / Undefined, Off-by-One, State, Import, Type, Regex, Error Handling, Scope | Bohrbug (deterministic) |
| Async / Timing (intermittent, leaked timer, init order) | Heisenbug / Concurrency |
| Environment / Config (works-here-not-there) | Heisenbug / Mandelbug (or config-as-root-cause) |
| Data Shape / API Contract | Bohrbug (or Mandelbug if volume-dependent) |
The taxonomy routes the investigation technique (SBFL + bisect for Bohrbugs; record-replay/stability for Heisenbugs; atomicity/order/deadlock checklist for Concurrency).
Symptom-to-Category Quick Map
| Symptom | Check First |
|---|---|
| "Cannot read property of undefined/null" | Null/Undefined Access |
| "X is not a function" | Import/Module, Type/Coercion |
| Works sometimes, fails sometimes | Async/Timing, State Management |
| Works locally, fails in CI/prod | Environment/Config |
| Wrong data displayed | Data Shape, State Management |
| Off by one item / missing last item | Off-by-One/Boundary |
| "Unexpected token" / parse error | Data Shape, Type/Coercion |
| Memory leak / growing resource usage | Async/Timing (cleanup), Scope/Closure |
| Infinite loop / max call stack | State Management, Async/Timing |