# Examples — AI Bug-Fix & Draft-PR Agent

## Reproducible null-handling bug → tested fix + draft PR

A clear issue: an endpoint 500s when an optional field is missing. There's a stack trace and steps to reproduce.

**Input**

```
Issue #1423: GET /profile crashes when user has no avatar.
Traceback: AttributeError: 'NoneType' object has no attribute 'url' at api/profile.py:51
Repro: create a user without an avatar, call GET /profile -> 500.
```

**Output**

```
{
  "decision": "OPEN_PR",
  "confidence": 0.9,
  "root_cause": "api/profile.py:51 accesses user.avatar.url without checking that avatar exists; users without an avatar have avatar=None, raising AttributeError.",
  "reproduction": "Added test_profile_without_avatar which creates an avatarless user and asserts GET /profile returns 200; it fails on the original code with the reported AttributeError.",
  "patch": "--- a/api/profile.py\n+++ b/api/profile.py\n@@ -49,7 +49,7 @@\n-    avatar_url = user.avatar.url\n+    avatar_url = user.avatar.url if user.avatar else None",
  "test": "def test_profile_without_avatar(client):\n    u = make_user(avatar=None)\n    r = client.get('/profile', user=u)\n    assert r.status_code == 200\n    assert r.json()['avatar_url'] is None",
  "files_touched": ["api/profile.py", "tests/test_profile.py"],
  "risks": "Confirm clients tolerate a null avatar_url (they should; it was previously crashing).",
  "pr": { "title": "Fix 500 on /profile when user has no avatar", "body": "Guards avatar access against None and adds a regression test (fails before, passes after). Minimal change, no behavior change for users with an avatar.", "draft": true },
  "escalation": { "needed": false, "reason": "", "plan": "" }
}
```

**Note:** The textbook case: reproduce with a failing test, fix the exact line, keep the diff to one expression, and open a draft PR. The test is the proof — it fails on the old code and passes on the new, which is what makes the PR trustworthy.

## Unreproducible report → NEEDS_INFO instead of a guess

A vague report with no steps. A naive agent would invent a plausible-looking fix; this one refuses.

**Input**

```
Issue #1502: 'The dashboard is sometimes slow and sometimes wrong.' No steps, no timestamps, no account, no logs.
```

**Output**

```
{
  "decision": "NEEDS_INFO",
  "confidence": 0.2,
  "root_cause": "",
  "reproduction": "Could not reproduce: no steps, no affected account/tenant, no timeframe, and 'slow' vs 'wrong' are two different problems. Tried the default dashboard with seed data and saw correct, fast results.",
  "patch": "",
  "test": "",
  "files_touched": [],
  "risks": "Guessing here would likely produce a fix for the wrong problem and add risk without value.",
  "pr": { "title": "", "body": "", "draft": true },
  "escalation": { "needed": false, "reason": "", "plan": "Need: (1) exact steps or a screen recording, (2) an affected account/tenant id, (3) approximate timestamps, (4) whether 'wrong' means missing data or incorrect numbers. With those I can reproduce and fix." }
}
```

**Note:** This is the discipline that keeps an autonomous fixer safe: with confidence 0.2 and no reproduction, it makes zero code changes and asks four specific questions. Shipping a speculative fix for an unreproducible bug is how agents erode trust.

## Fix would touch a migration → escalate with a plan

A real, reproducible bug whose correct fix requires a schema change. The protected-path gate forces a human.

**Input**

```
Issue #1571: duplicate orders can be created on rapid double-submit. Repro confirmed. Root cause: no unique constraint on (user_id, idempotency_key); fix needs a DB migration to add it.
```

**Output**

```
{
  "decision": "ESCALATE",
  "confidence": 0.86,
  "root_cause": "services/orders.py inserts without enforcing idempotency; the real fix is a unique constraint on orders(user_id, idempotency_key), which requires a migration.",
  "reproduction": "Added a concurrency test that fires two identical submits and asserts one order; it fails today (two orders created).",
  "patch": "",
  "test": "tests/test_orders_idempotency.py (failing repro included in the PR plan)",
  "files_touched": [],
  "risks": "Adding a unique constraint can fail if duplicate rows already exist; needs a data backfill/cleanup step first.",
  "pr": { "title": "", "body": "", "draft": true },
  "escalation": { "needed": true, "reason": "Fix requires a database migration (protected path).", "plan": "1) De-dupe existing orders. 2) Add migration for UNIQUE(user_id, idempotency_key). 3) Make the insert idempotent in services/orders.py. 4) Ship the included concurrency test. I can prepare the app-code change and test now; a human should own the migration and backfill." }
}
```

**Note:** Even with high confidence in the diagnosis and a ready test, the agent stops because the correct fix touches migrations. It hands over a concrete, ordered plan and an existing failing test — maximally useful while staying inside its authority.
