### Task 5 (Quick win): Branch/worktree slug uniqueness via task_id

**Root cause (verified):** `make_branch_name` (`slug.py:43`) and `create_worktree`/`create_feature_branch` (`branching.py:95,125`) accept `task_id` but never fold it into the name — the branch is `{prefix}/{cat}-{desc}` and the worktree dir is keyed on `slug` alone (`branching.py:147`). Two same-category tasks with colliding truncated descriptions share one branch **and one worktree** (two agents in one tree, or a force-remove under a live agent). `cleanup.py:_build_slug_to_task_map` (`cleanup.py:437`) also silently overwrites on collision.

**Files:**
- Modify: `claw_forge/git/slug.py` (`make_branch_name` gains an optional `task_id`)
- Modify call sites: `claw_forge/orchestrator/task_handler.py:750`, `claw_forge/git/cleanup.py:437`
- Test: `tests/git/test_slug_uniqueness.py` (create)

**Interfaces:**
- Produces: `make_branch_name(description, category, plugin_name="feat", *, prefix="feat", max_len=55, task_id: str | None = None)` — when `task_id` is given, append `-{task_id[:6]}` to the slug (inside `max_len` budget). Backward compatible: `task_id=None` reproduces today's output.

- [ ] **Step 1: Write the failing test**

```python
# tests/git/test_slug_uniqueness.py
from claw_forge.git.slug import make_branch_name


def test_task_id_disambiguates_colliding_descriptions():
    a = make_branch_name("Add user login", "auth", task_id="abc123def")
    b = make_branch_name("Add user login flow variant", "auth", task_id="zzz999yyy")
    assert a != b
    assert a.endswith("-abc123")
    assert b.endswith("-zzz999")


def test_no_task_id_is_backward_compatible():
    assert make_branch_name("Add JWT authentication", "auth") == "feat/auth-jwt-authentication"
```

- [ ] **Step 2: Run test to verify it fails**

Run: `uv run pytest tests/git/test_slug_uniqueness.py -v`
Expected: FAIL — `TypeError: unexpected keyword argument 'task_id'`.

- [ ] **Step 3: Add the `task_id` suffix**

In `claw_forge/git/slug.py`, extend `make_branch_name`:

```python
def make_branch_name(
    description: str | None,
    category: str | None,
    plugin_name: str = "feat",
    *,
    prefix: str = "feat",
    max_len: int = 55,
    task_id: str | None = None,
) -> str:
    cat_raw = category or plugin_name or "feat"
    cat_slug = _NON_ALNUM.sub("-", cat_raw.lower()).strip("-")[:15]

    suffix = f"-{task_id[:6]}" if task_id else ""
    desc_budget = max(10, max_len - len(cat_slug) - 1 - len(suffix))
    desc_slug = make_slug(description, max_len=desc_budget) if description else ""

    if desc_slug:
        return f"{prefix}/{cat_slug}-{desc_slug}{suffix}"
    return f"{prefix}/{cat_slug}{suffix}"
```

- [ ] **Step 4: Thread `task_id` through the call sites**

`task_handler.py:750` — add `task_id=task_node.id` to the `_make_branch_name(...)` call (the `.removeprefix(...)` on the result is unaffected).
`cleanup.py:437` — the replay must match, so add `task_id=<task's id column>` there too; read `cleanup.py:430-440` for the row variable name and pass its id. (If cleanup replays over tasks whose id is available in the same dict, use it; otherwise this is where the silent-overwrite map should key on the new unique slug.)

- [ ] **Step 5: Run the tests to verify they pass**

Run: `uv run pytest tests/git/test_slug_uniqueness.py tests/git/ -q`
Expected: PASS. If any existing branching/cleanup test asserted the old non-unique slug, update it.

- [ ] **Step 6: Lint + commit**

Run: `uv run ruff check claw_forge/ tests/`
```bash
git add claw_forge/git/slug.py claw_forge/orchestrator/task_handler.py claw_forge/git/cleanup.py tests/git/test_slug_uniqueness.py
git commit -m "fix(git): fold task_id into branch/worktree slug to prevent collisions"
```

---

