<reasoning_content>
*   Extend an existing (implied) `JobQueue` class.
    *   Add a method `process_job(job_id: str, Processor: Callable) -> bool`.
    *   Functionality:
        1.  Call `processor(data)` where `data` is retrieved from `add_job(job_id, data)`.
        2.  Retry on any exception.
        3.  Max 4 attempts (1 original + 3 retries).
        4.  Track retry counts.
        5.  Use exponential backoff (1s, 2s, 4s).
        6.  *Crucial*: Do NOT use `time.sleep()`. Instead, record the delays as data (presumably in the stored dictionary or a separate tracking structure).
        7.  Return `True` on success, `False` on failure after 4 attempts.
        8.  Standard library only.
        9.  Only Python code, no explanations.

    *   `jobs`: A dictionary to store `{job_id: data}`.
    *   `retries`: A dictionary to store `{job_id: count}`.
    *   `backoffs`: A dictionary to store `{job_id: [list_of_delays]}` or just update the `data` dict. The prompt says "record the delays as data". I'll assume this means adding a key to the job's data dictionary.

    ```python
    from typing import Callable, Dict, Any

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}

        def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
            self.jobs[job_id] = data

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]]]) -> bool:
            if job_id not in self.jobs:
                return False

            data = self.jobs[job_id]
            # We need to track attempts.
            # Let's assume we need to track 'attempts' and 'delays' in the data dict.
            if 'attempts' not in data:
                data['attempts'] = 0
            if 'delays' not in data:
                data['delays'] = []

            max_attempts = 4
            # Delays: 1s, 2s, 4s. These are for the 1st, 2nd, 3rd retries.
            # Attempt 1: Fail -> Delay 1s -> Attempt 2
            # Attempt 2: Fail -> Delay 2s -> Attempt 3
            # Attempt 3: Fail -> Delay 4s -> Attempt 4
            # Attempt 4: Fail -> Done.

            for attempt in range(max_attempts):
                data['attempts'] = attempt + 1
                try:
                    processor(data)
                    return True
                except Exception:
                    if attempt < max_attempts - 1:
                        # Calculate delay: 2^attempt
                        # Attempt 0 (1st time) fails -> delay 2^0 = 1
                        # Attempt 1 (2nd time) fails -> delay 2^1 = 2
                        # Attempt 2 (3rd time) fails -> delay 2^2 = 4
                        delay = 2 ** attempt
                        data['delays'].append(delay)
                    else:
                        # Final attempt failed
                        pass

            return False
    ```

    *   "Record the delays as data". Should I add a key? Yes.
    *   "Do NOT actually sleep".
    *   Retry count per job.

    Refining the Logic:
    The prompt says "Track the retry count per job". I should probably keep a separate `_retry_counts` dict or put it inside the job data. Putting it in the job data is cleaner for "recording as data".

    Wait, let's look at the requirements again:
    1. Call `processor(data)` where `data` is the dict passed to `add_job`.
    2. On exception, retry. Max 4 attempts.
    3. Track retry count.
    4. Exponential backoff (1, 2, 4).
    5. Record delays as data.

    Implementation structure:
    ```python
    from typing import Callable, Dict, Any

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}

        def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
            self.jobs[job_id] = data

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]]]) -> bool:
            if job_id not in self.jobs:
                return False

            job_data = self.jobs[job_id]

            # Ensure keys exist
            if "retry_count" not in job_data:
                job_data["retry_count"] = 0
            if "delays" not in job_data:
                job_data["delays"] = []

            for attempt in range(4):
                try:
                    processor(job_data)
                    return True
                except Exception:
                    # If this was the last attempt, break and return False
                    if attempt == 3:
                        break

                    # Record retry count
                    job_data["retry_count"] += 1
                    # Calculate delay: 1, 2, 4
                    delay = 2 ** attempt
                    job_data["delays"].append(delay)

            return False
    ```

    Wait, Attempt 1 (index 0) fails. `retry_count` becomes 1. `delay` becomes $2^0=1$.
    Attempt 2 (index 1) fails. `retry_count` becomes 2. `delay` becomes $2^1=2$.
    Attempt 3 (index 2) fails. `retry_count` becomes 3. `delay` becomes $2^2=4$.
    Attempt 4 (index 3) fails. Loop ends.

    This matches the requirement "Make up to 4 total attempts (initial + 3 retries)".

    One detail: "Track the retry count per job". Does this mean a separate dictionary?
    Actually, the prompt says "record the delays as data". If I record delays as data, it makes sense to record the retry count as data too.

    Let's refine the `retry_count`.
    Initial attempt: count 0.
    Fail 1: count 1, delay 1.
    Fail 2: count 2, delay 2.
    Fail 3: count 3, delay 4.
    Fail 4: stop.

    Actually, if I increment `retry_count` *before* the next attempt, that works.

    Revised code:
    ```python
    from typing import Callable, Dict, Any

1    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}

        def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
            self.jobs[job_id] = data

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]]]) -> bool:
            if job_id not in self.jobs:
                return False

            data = self.jobs[job_id]
            if "retry_count" not in data:
                data["retry_count"] = 0
            if "delays" not in data:
                data["delays"] = []

            for i in range(4):
                try:
                    processor(data)
                    return True
                except Exception:
                    if i < 3:
                        data["retry_count"] += 1
                        delay = 2 ** i
                        data["delays"].append(delay)
                    else:
                        break
            return False
    ```

    Wait, the prompt says: "Track the retry count per job. Use exponential backoff (delays of 1s, 2s, 4s)".
    If the first call fails, that is attempt 1. Then we retry.
    Attempt 2.
    Attempt 3.
    Attempt 4.

    Retry count tracking:
    Attempt 1 fails -> retry_count = 1.
    Attempt 2 fails -> retry_count = 2.
    Attempt 3 fails -> retry_count = 3.
    Attempt 4 fails -> stop.

    The list of delays should be `[1, 2, 4]`.

    Double check requirements:
    1. Call `processor(data)`. Yes.
    2. On any exception, retry. Max 4 attempts. Yes.
    3. Track retry count per job. Yes.
    4. Exponential backoff (1, 2, 4). Yes.
    5. Do NOT actually sleep. Yes.
    6. Return True/False. Yes.

    One small detail: Should `retry_count` be initialized in `add_job` or `process_job`?
    The instructions say "Extend...". Usually, it's better to check if it exists in `process_job` to avoid modifying `add_job`.

    Final check on indices:
    Loop `i` from 0 to 3.
    i=0: call processor. Fail? `i < 3` is true. `retry_count`=1, `delays`=[1].
    i=1: call processor. Fail? `i < 3` is true. `retry_count`=2, `delays`=[1, 2].
    i=2: call processor. Fail? `i < 3` is true. `retry_count`=3, `delays`=[1, 2, 4].
    i=3: call processor. Fail? `i < 3` is false. Break. Return False.

    Perfect.

    One edge case: If `process_job` is called twice for the same `job_id`, the `retry_count` and `delays` will persist. Is that desired? Usually, yes, because the `data` is the state of the job.

    Wait, "Track the retry count per job". Does it mean a global map?
    "Record the delays as data".
    If I record delays as data, it's strongly implied that the retry count is also part of the data or tracked similarly.

    Actually, I'll just put `retry_count` in the data dict.

    ```python
    from typing import Callable, Dict, Any

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}

        def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
            self.jobs[job_id] = data

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]]]) -> bool:
            if job_id not in self.jobs:
                return False

            data = self.jobs[job_id]
            
            if "retry_count" not in data:
                data["retry_count"] = 0
            if "delays" not in data:
                data["delays"] = []

            for attempt_idx in range(4):
                try:
                    processor(data)
                    return True
                except Exception:
                    if attempt_idx < 3:
                        data["retry_count"] += 1
                        delay = 2 ** attempt_idx
                        data["delays"].append(delay))
                    else:
                        break
            return False
    ```
    Wait, "Record the delays as data". If I just append to a list, that's recording it.

    One more thing: "Track the retry count per job". If I use a separate dict `self._retry_counts`, it's safer. But "Record the delays as data" suggests the `data` dict is the primary source of truth. I'll put both in `data`.

    Wait, I'll stick to the prompt's wording.
    "Track the retry count per job." -> Could be a class attribute.
    "Record the delays as data." -> Must be in the data dict.

    Let's look at the `data` dict content. `data` is what was passed to `add_job(job_id, data)`.
    If I modify `data`, I am modifying the object in `self.jobs[job_id]`. This is standard for such patterns.

    Let's use a simple approach.

    ```python
    from typing import Callable, Dict, Any

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}

        def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
            self.jobs[job_id] = data

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]]]) -> bool:
            if job_id not in self.jobs:
                return False
            
            job_data = self.jobs[job_id]
            
            if "retry_count" not in job_data:
                job_data["retry_count"] = 0
            if "delays" not in job_data:
                job_data["delays"] = []
            
            for i in range(4):
                try:
                    processor(job_data)
                    return True
                except Exception:
                    if i < 3:
                        job_data["retry_count"] += 1
                        delay = 2 ** i
                        job_data["delays"].append(delay)
                    else:
                        break
            return False
    ```

    Wait, `2 ** i` for `i` in `0, 1, 2` gives `1, 2, 4`. This matches the prompt exactly.

    Final code structure.
</reasoning_content>

<content>
```python
from typing import Callable, Dict, Any

class JobQueue:
    def __init__(self):
        self.jobs: Dict[str, Dict[str, Any]] = {}

    def add_job(self, job_id: str, data: Dict[str, Any]) -> None:
        self.jobs[job_id] = data

    def process_job(self, job_id: str, Processor: Callable[[Dict[str, Any]]]) -> bool:
        if job_id not in self.jobs:
            return False

        data = self.jobs[job_id]
        
        if "retry_count" not in data:
            data["retry_count"] = 0
        if "delays" not in data:
            data["delays"] = []

        for attempt in range(4):
            try:
                Processor(data)
                return True
            except Exception:
                if attempt < 3:
                    data["retry_count"] += 1
                    delay = 2 ** attempt
                    data["delays"].append(delay)
                else:
                    break
                    
        return False
```
</content>