<reasoning_content>
*   Existing context: `JobQueue` class (implied, but I need to define/extend it).
    *   New method: `process_job(job_id: str, Processor: Callable) -> bool`.
    *   Requirement 1: Call `processor(data)` where `data` is from `add_job(job_id, data)`.
    *   Requirement 2: Retry on exception. Max 4 total attempts (1 initial + 3 retries).
    *   Requirement 3: Track retry count. Use exponential backoff (1s, 2s, 4s).
    *   Requirement 4: Do NOT use `time.sleep`. Record delays as data.
    *   Requirement 5: Return `True` on success, `False` if all fail.
    *   Constraint: Standard library only. No extra packages.
    *   Constraint: Write only the Python code, no explanations.

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

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Dict[str, Any]] = {}
            self.retry_counts: Dict[str, int] = {}
            self.delays: Dict[str, list] = {} # To record delays as data

        def add_job(self, job_id: str, data: Dict[str, Any]):
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0
            self.delays[job_id] = []

        def process_job(self, job_id: str, processor: Callable[[Dict[str, Any]], Any]) -> bool:
            # Implementation logic here
    ```

    *   Max attempts = 4.
    *   Retries = 3.
    *   Delays: 1, 2, 4.
    *   Loop through attempts:
        *   Try `processor(self.jobs[job_id]])`.
        *   If success, return `True`.
        *   If failure:
            *   Increment retry count.
            *   If count > 3, return `False`.
            *   Calculate delay: $2^{(retry\_count - 1)}$. Since retries are 1, 2, 3, delays are $2^0=1, 2^1=2, 2^2=4$.
            *   Record delay in `self.delays`.
    *   Need to make sure `self.jobs` is accessible.

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

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

        def add_job(self, job_id: str, data: Dict[str, Any]):
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0
            self.history[job_id] = []

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

            data = self.jobs[job_id]
            max_attempts = 4
            
            for attempt in range(max_attempts):
                try:
                    processor(data)
                    return True
                except Exception:
                    if attempt < max_attempts - 1:
                        self.retry_counts[job_id] += 1
                        # Backoff: 1, 2, 4
                        delay = 2 ** (self.retry_counts[job_id] - 1)
                        self.history[job_id].append(delay)
                    else:
                        break
            return False
    ```

    *   Wait, the prompt says "Record the delays as data". Does that mean inside the `data` dict? Or a separate list? "Record the delays as data" usually implies adding it to the job's associated metadata/data.
    *   Let's check: "Record the delays as data". `data` is the dict passed to `add_job`. So I should update `self.jobs[job_id]['delays']` or similar.
    *   Requirement 3: "Track the retry count per job".
    *   Let's refine the structure.

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

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

        def add_job(self, job_id: str, data: Dict[str, Any]):
            # Ensure 'delays' key exists in the data dict
            if 'delays' not in data:
                data['delays'] = []
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0

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

            data = self.jobs[job_id]
            
            for attempt in range(4):
                try:
                    processor(data)
                    return True
                except Exception:
                    if attempt < 3:
                        self.retry_counts[job_id] += 1
                        delay = 2 ** (self.retry_counts[job_id] - 1)
                        data['delays'].append(delay)
                    else:
                        break
            return False
    ```

    *   `process_job(job_id: str, processor: Callable) -> bool` - Done.
    *   Call `processor(data)` - Done.
    *   Retry on exception, max 4 attempts - Done.
    *   Track retry count per job - Done.
    *   Exponential backoff (1s, 2s, 4s) - Done ($2^0, 2^1, 2^2$).
    *   Do NOT actual sleep - Done.
    *   Record delays as data - Done.
    *   Return True/False - Done.
    *   Standard library only - Done.

    One detail: "Record the delays as data". I'll ensure `data` is the actual dictionary object.

    Wait, I should probably check if `job_id` exists.

    Actually, the prompt doesn't specify the structure of `JobQueue` before the addition, but it implies `add_job` exists.

    Let's write the clean version.

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

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

        def add_job(self, job_id: str, data: Dict[str, Any]):
            if 'delays' not in data:
                data['delays'] = []
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0

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

            data = self.jobs[job_id]
            
            for attempt in range(4):
                try:
                    processor(data)
                    return True
                except Exception:
                    if attempt < 3:
                        self.retry_counts[job_id] += 1
                        delay = 2 ** (self.retry_counts[job_id] - 1)
                        data['delays'].append(delay)
                    else:
                        break
            return False
    ```

    Wait, should I include `add_job`? The prompt says "Extend the JobQueue class". Usually, that means providing the class with the new method, but I should include `add_job` to make it runnable/valid.

    One tiny detail: "Retry count per job". I am doing that.
    "Exponential backoff (delays of 1s, 2s, 4s)".
    Attempt 0 (Initial) -> Fail -> Retry 1: delay 1.
    Attempt 1 (Retry 1) -> Fail -> Retry 2: delay 2.
    Attempt 2 (Retry 2) -> Fail -> Retry 3: delay 4.
    Attempt 3 (Retry 3) -> Fail -> Fail.
    Total attempts = 4.

    So:
    Attempt 0 (idx 0)
    Attempt 1 (idx 1)
    Attempt 2 (idx 2)
    Attempt 3 (idx 3)

    If idx 0 fails: retry_count becomes 1, delay $2^0 = 1$.
    If idx 1 fails: retry_count becomes 2, delay $2^1 = 2$.
    If idx 2 fails: retry_count becomes 3, delay $2^2 = 4$.
    If idx 3 fails: retry_count becomes 4 (but loop finishes).

    The logic:
    ```python
    for attempt in range(4):
        try:
            processor(data)
            return True
        except Exception:
            if attempt < 3:
                self.retry_counts[job_id] += 1
                delay = 2 ** (self.retry_counts[job_id] - 1)
                data['delays'].append(delay)
            else:
                break
    ```
    This correctly produces 3 delays (1, 2, 4) for 3 retries.

    One thing: the prompt says `processor(data)` where `data` is the dict passed to `add_job`.
    My code: `data = self.jobs[job_id]`.
    If `add_job` is called like `queue.add_job("1", {"task": "do_thing"})`, `data` is `{"task": "do_thing"}`.
    I will ensure `delays` is added to that dict.

    Double check "Write only the Python code, no explanations."

    One edge case: if `job_id` is not in `self.jobs`. I'll assume it is or handle it gracefully.

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

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

        def add_job(self, job_id: str, data: Dict[str, Any]):
            if 'delays' not in data:
                data['delays'] = []
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0

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

    Refinement: "Do NOT actually sleep — record the delays as data."
    Does this mean record the delay *before* or *after* the failure?
    Usually, you record the delay you *will* wait.
    Sequence:
    1. Try processor.
    2. Catch Exception.
    3. Calculate delay.
    4. Store delay.
    5. Loop continues to next attempt.

    Final check on requirements:
    1. Call `processor(data)` - Yes.
    2. Max 4 attempts - Yes.
    3. Track retry count - Yes.
    4. Exponential backoff - Yes.
    5. No sleep - Yes.
    6. Record delays as data - Yes.
    7. Return True/False - Yes.

    One detail: the prompt asks to "Extend the JobQueue class".
    I will provide the class.

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

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

        def add_job(self, job_id: str, data: Dict[str, Any]):
            if 'delays' not in data:
                data['delays'] = []
            self.jobs[job_id] = data
            self.retry_counts[job_id] = 0

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

    Wait, I should verify if `data` is modified in place. Since `data` is the dictionary passed to `add_job`, and dicts are mutable, `data['delays']` modification affects the original dictionary if the caller still holds a reference. However, since the `JobQueue` stores the reference, it works perfectly.

    Final Code Construction.
</reasoning_content>

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

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

    def add_job(self, job_id: str, data: Dict[str, Any]):
        if 'delays' not in data:
            data['delays'] = []
        self.jobs[job_id] = data
        self.retry_counts[job_id] = 0

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

        data = self.jobs[job_id]
        
        for attempt in range(4):
            try:
                processor(data)
                return True
            except Exception:
                if attempt < 3:
                    self.retry_counts[job_id] += 1
                    # Exponential backoff: 2^(1-1)=1, 2^(2-1)=2, 2^(3-1)=4
                    delay = 2 ** (self.retry_counts[job_id] - 1)
                    data['delays'].append(delay)
                else:
                    break
                    
        return False
```
</content>