t1_off_by_one_slice_BEGIN
**Line 2:** `items[len(items) - n - 1:]` returns the last `n + 1` items, not `n` (off-by-one).

**Fix:**
```python
return items[-n:] if n > 0 else []
```
The `n > 0` guard is required because `items[-0:]` returns the full list.
t1_off_by_one_slice_END
t2_mutable_default_dict_BEGIN
**Line 1:** Mutable default argument — `history={}` is created once at definition time and shared across all calls that omit `history`, leaking visit counts between callers.

**Fix:**
```python
def greet(name, history=None):
    if history is None:
        history = {}
    ...
```
t2_mutable_default_dict_END
t3_command_injection_BEGIN
**Line 4:** Shell command injection — `directory` from a web form interpolated into a `shell=True` string lets attackers run arbitrary commands (e.g. `; rm -rf ~`).

**Fix:** Drop `shell=True` and pass argv as a list:
```python
subprocess.run(["ls", directory], capture_output=True, text=True)
```
Better: skip the subprocess entirely with `os.listdir(directory)`, after validating the path stays within an allowed root.
t3_command_injection_END
t4_forgotten_await_BEGIN
**Line 3:** `httpx.AsyncClient().get(...)` returns a coroutine that is never awaited, so `response` is a coroutine and `.json()` raises `AttributeError`. The client is also never closed (resource leak).

**Fix:**
```python
async def fetch_user(user_id):
    async with httpx.AsyncClient() as client:
        response = await client.get(f"/users/{user_id}")
        return response.json()
```
t4_forgotten_await_END
t5_dict_iter_mutation_BEGIN
**Line 2-4:** Mutating `d` while iterating raises `RuntimeError: dictionary changed size during iteration`.

**Fix:** Iterate a snapshot of the keys, or rebuild:
```python
return {k: v for k, v in d.items() if v >= 0}
```
t5_dict_iter_mutation_END
t6_clean_code_BEGIN
No bugs. The bounds are validated, `max(lo, min(value, hi))` is the standard clamp idiom, and types are annotated. Ship it.
t6_clean_code_END
c1_factorial_BEGIN
**Line 3:** `range(n)` starts at 0, so `result *= 0` on the first iteration makes `factorial(n)` always return 0 for `n >= 1`.

**Fix:**
```python
for i in range(1, n + 1):
    result *= i
```
Also consider raising `ValueError` on negative `n` (currently silently returns 1).
c1_factorial_END
c2_counter_race_BEGIN
**Line 6:** `self.count += 1` is not atomic — load/add/store can interleave under threading, losing increments.

**Fix:**
```python
import threading

class Counter:
    def __init__(self):
        self.count = 0
        self._lock = threading.Lock()

    def increment(self):
        with self._lock:
            self.count += 1
```
c2_counter_race_END
c3_sql_injection_BEGIN
**Line 1:** SQL injection — string concatenation lets an attacker inject arbitrary SQL (e.g. `'; DROP TABLE users; --`).

**Fix — parameterize:**
```python
cursor.execute("SELECT * FROM users WHERE name = ?", (user_input,))
```
(`%s` for psycopg2/MySQLdb.) Never build SQL with `+`, f-strings, or `.format` on untrusted input.
c3_sql_injection_END
c4_file_leak_BEGIN
**Line 2:** File handle is never closed — leaks the descriptor (and on Windows, holds a file lock until GC).

**Fix:**
```python
def process_file(path):
    with open(path, encoding="utf-8") as f:
        return f.read()
```
Specify `encoding=` explicitly to avoid platform-default surprises.
c4_file_leak_END
c5_n_plus_1_BEGIN
**Line 3:** Two issues — N+1 query (one SELECT per user) and SQL injection via f-string interpolation of `u.id`.

**Fix:** One parameterized query plus in-memory grouping:
```python
ids = [u.id for u in users]
rows = db.query("SELECT * FROM posts WHERE user_id IN %s", (tuple(ids),))
by_user = {}
for r in rows:
    by_user.setdefault(r.user_id, []).append(r)
return [{"user": u, "posts": by_user.get(u.id, [])} for u in users]
```
c5_n_plus_1_END
c6_ordered_check_BEGIN
**Lines 2-4:** Two bugs — (1) `assert` is stripped by `python -O`, so validation silently disappears in production; (2) `order['total']` is read before checking that the key exists, raising `KeyError` instead of a clean validation error.

**Fix:**
```python
def validate_order(order: dict) -> None:
    for field in ("customer_id", "total", "items"):
        if field not in order:
            raise ValueError(f"missing field: {field}")
    if order["total"] <= 0:
        raise ValueError("total must be positive")
    if not order["items"]:
        raise ValueError("items must not be empty")
```
c6_ordered_check_END
c7_concat_loop_BEGIN
**Line 3:** Repeated `+=` on a string is O(n^2) in the general case (CPython has a fragile in-place optimization, but PyPy/Jython do not).

**Fix:**
```python
return '\n'.join(lines) + '\n'
```
Preserves the trailing newline; drop the `+ '\n'` if it isn't intentional.
c7_concat_loop_END
c8_mutable_default_BEGIN
**Line 1:** Mutable default `log: list = []` is shared across calls — events accumulate across unrelated callers.

**Fix:**
```python
def add_event(event: str, log: list | None = None) -> list:
    if log is None:
        log = []
    log.append(event)
    return log
```
c8_mutable_default_END
c9_late_binding_BEGIN
**Line 4:** Late-binding closure — every lambda captures the same `v`, which holds the final loop value when the callbacks run. All three print `3`.

**Fix — bind via default argument:**
```python
callbacks.append(lambda v=v: print(v))
```
Or `functools.partial(print, v)`.
c9_late_binding_END
c10_clean_code_BEGIN
No bugs. Correctly computes a sum-mod-256 checksum over the bytes.

Optional: `return sum(data) % 256` is equivalent, shorter, and faster (the loop runs in C). Naming nit: "checksum" is generic — document which algorithm if interop matters.
c10_clean_code_END
