---
name: bug-reproducer
description: Given a bug report, systematically investigate the codebase to identify root causes, write a failing test that proves the bug, and suggest a fix. Trigger when the user reports a bug, shares an error message, describes unexpected behavior, or says things like "I have a bug", "this is broken", "why is this failing", "can you find the bug", "debug this", "I'm getting an error", or "this isn't working as expected". Also trigger when the user shares a stack trace, error log, or screenshot of broken behavior.
---

# Bug Reproducer

Systematically investigate a bug report by reading code, forming hypotheses, writing a failing test that proves the bug exists, and suggesting a targeted fix. Thinks like a senior engineer debugging in production — methodical, hypothesis-driven, and focused on root cause rather than symptoms.

## Trigger Examples

- "I have a bug where [description]"
- "Why is this returning null?"
- "This endpoint is throwing a 500 error"
- "Can you debug this? [code/error]"
- "Users are seeing [unexpected behavior]"
- Sharing a stack trace or error message

## Inputs

- **Bug report** (required) — one or more of:
  - Description of unexpected behavior
  - Error message or stack trace
  - Steps to reproduce
  - Expected vs actual behavior
  - Screenshot of broken UI
- **Codebase access** (optional but recommended) — files, directories, or repo to investigate
- **Environment context** (optional) — which environment (dev/staging/prod), browser, OS, versions
- **Severity assessment** (optional) — how urgent: blocking users, data corruption, cosmetic, etc.

---

## Workflow

### Step 1: Understand the Bug Report

Before touching code, build a mental model of the bug:

1. **What is the expected behavior?** What should happen?
2. **What is the actual behavior?** What happens instead?
3. **What are the reproduction steps?** Can this be reliably triggered?
4. **What changed recently?** Did this ever work? What's different now?
5. **What's the blast radius?** How many users/flows are affected?

If the report is incomplete, ask targeted questions — but ask the minimum needed to start investigating, not an exhaustive list. You can learn more as you dig in.

### Step 2: Investigate the Code

Read relevant code files systematically. Don't guess — trace the actual execution path.

**Investigation strategy:**

```
1. Start at the entry point
   └─ Where does the request/action enter the system?
   
2. Trace the data flow
   └─ Follow the data through each layer:
      Controller → Service → Repository → Database
      Component → Hook → API Call → Response Handler
   
3. Identify the failure point
   └─ Where does actual behavior diverge from expected?
   
4. Check the boundaries
   └─ Validation, type coercion, null checks, error handling
   
5. Look at recent changes
   └─ git log --oneline -20 -- [relevant files]
   └─ git diff HEAD~5 -- [relevant files]
```

**Common bug patterns to check:**

| Pattern | What to Look For |
|---------|-----------------|
| **Null reference** | Missing null checks, optional chaining gaps, undefined access |
| **Race condition** | Async operations without proper ordering, missing await |
| **State management** | Stale closures, missing dependency arrays, mutation of state |
| **Type coercion** | String vs number comparison, truthy/falsy misuse, JSON parsing |
| **Off-by-one** | Array bounds, pagination, date ranges, loop conditions |
| **Missing error handling** | Uncaught exceptions, swallowed errors, missing catch blocks |
| **Environment mismatch** | Missing env vars, different configs between environments |
| **Data integrity** | Missing constraints, concurrent writes, orphaned records |
| **Authorization gap** | Missing permission checks, wrong user context, leaked data |
| **Encoding issue** | UTF-8 handling, URL encoding, HTML entities, special characters |

### Step 3: Form Hypotheses

Based on the investigation, generate 1-3 ranked hypotheses:

```markdown
## Hypotheses

### Hypothesis 1 (Most Likely): [Title]
**Root cause:** [What's actually going wrong, specifically]
**Evidence:** 
- [Code reference that supports this]
- [Behavior that matches this theory]
**Explains:** [Which symptoms this accounts for]
**Doesn't explain:** [Any symptoms this leaves unexplained, if any]

### Hypothesis 2: [Title]
[Same structure]
```

### Step 4: Write a Failing Test

Write a test that:
- **Proves the bug exists** — it should FAIL with the current code
- **Describes the expected behavior** — the test name and assertions make the correct behavior clear
- **Is minimal** — tests only the buggy behavior, not unrelated functionality
- **Will pass when fixed** — the test should pass once the root cause is addressed

```python
# Example for Python/FastAPI
import pytest
from httpx import AsyncClient

class TestUserSearch:
    """Regression test for BUG: user search returns 500 
    when query contains special characters."""
    
    @pytest.mark.asyncio
    async def test_search_with_special_characters(
        self, client: AsyncClient, sample_users
    ):
        """Search should handle special characters gracefully,
        not throw an unhandled exception."""
        # This currently fails with a 500 error
        response = await client.get(
            "/api/v1/users/search",
            params={"q": "O'Brien"}
        )
        
        # Should return 200 with filtered results, 
        # not 500 from unescaped SQL
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data["users"], list)
```

```typescript
// Example for TypeScript/React
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SearchResults } from './SearchResults';

describe('SearchResults - BUG: empty state not shown after clearing results', () => {
  it('should show empty state when search returns no results after having results', async () => {
    // This currently fails — the previous results stay visible
    render(<SearchResults />);
    
    const input = screen.getByRole('searchbox');
    
    // First search returns results
    await userEvent.type(input, 'existing-user');
    await waitFor(() => {
      expect(screen.getByText('existing-user@example.com')).toBeInTheDocument();
    });
    
    // Second search returns nothing
    await userEvent.clear(input);
    await userEvent.type(input, 'zzz-no-match-zzz');
    
    await waitFor(() => {
      // BUG: This assertion fails — stale results still visible
      expect(screen.getByText('No results found')).toBeInTheDocument();
      expect(screen.queryByText('existing-user@example.com')).not.toBeInTheDocument();
    });
  });
});
```

### Step 5: Suggest the Fix

Provide a targeted fix that addresses the root cause:

```markdown
## Suggested Fix

### Root Cause
[One-sentence explanation of why the bug happens]

### Fix
**File:** `path/to/file.ts` 
**Lines:** 42-58

**Before:**
```[lang]
[current buggy code]
```

**After:**
```[lang]
[fixed code with comments explaining the change]
```

### Why This Fixes It
[Explanation of how the fix addresses the root cause]

### What to Verify
- [ ] The failing test now passes
- [ ] Existing tests still pass (no regressions)
- [ ] [Specific manual check related to the bug]
- [ ] [Edge case to verify]

### Side Effects
[Any potential impact of this fix on other functionality.
"None expected" is a valid answer if true.]
```

### Step 6: Deliver the Full Report

```markdown
# Bug Investigation: [Brief Title]

## Bug Report Summary
- **Reported behavior:** [what's broken]
- **Expected behavior:** [what should happen]
- **Severity:** [Critical/High/Medium/Low]
- **Affected area:** [component/endpoint/feature]

## Investigation

### Files Examined
- `path/to/file1.ts` — [what was checked, what was found]
- `path/to/file2.py` — [what was checked, what was found]

### Root Cause
[Clear, specific explanation]

### Failing Test
[Test code as shown in Step 4]

### Suggested Fix
[Fix as shown in Step 5]

## Prevention
[How to prevent similar bugs in the future:
 linting rules, type safety improvements, 
 test coverage gaps to fill, etc.]
```

---

## Output Format

- Display the investigation summary, root cause, and fix in chat
- Write the failing test to a file in `/mnt/user-data/outputs/`
- If the fix involves multiple files, write a patch or diff file

---

## Notes for Claude

- **Read the code, don't guess.** Trace the actual execution path. Many bugs are in the code you didn't read, not the code you assumed you understood.
- **The test is the proof.** A hypothesis without a failing test is just a guess. The test makes the investigation concrete and verifiable.
- **Root cause, not symptoms.** "Add a null check" might fix the crash, but the root cause might be that the data should never be null in the first place. Dig deeper.
- **One bug at a time.** If investigation reveals multiple issues, report them separately. Fixing multiple bugs in one change makes review harder and rollback risky.
- **Check the tests that exist.** Before writing a new test, check if there's an existing test that should have caught this. If so, understand why it didn't — the test might be wrong, not just missing.
- **Git history is evidence.** `git log` and `git blame` on relevant files can reveal when the bug was introduced and what change caused it.
- **Be honest about confidence.** If you can't reproduce with certainty, say "I believe the root cause is X based on code analysis, but I'd verify by [specific step]."
- **Prevention > detection.** After fixing the bug, suggest how to prevent the same class of bug from recurring — better types, a linting rule, a pre-commit check, etc.
