Here's the refactored package structure with clean separation of concerns, proper imports, and a polished public API.

### `queue/core.py`
*Responsibility: Job data model and basic FIFO queue operations*
```python
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Optional
from uuid import uuid4
from collections import deque
from datetime import datetime

@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str = field(default_factory=lambda: str(uuid4()))
    payload: Any = None
    priority: int = 0
    status: str = "pending"
    created_at: datetime = field(default_factory=datetime.now)
    attempts: int = 0

class JobQueue:
    """Basic FIFO job queue implementation."""
    def __init__(self) -> None:
        self._queue: deque[Job] = deque()

    def enqueue(self, job: Job) -> None:
        job.status = "queued"
        self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        if not self._queue:
            return None
        job = self._queue.popleft()
        job.status = "processing"
        return job

    def is_empty(self) -> bool:
        return len(self._queue) == 0

    def size(self) -> int:
        return len(self._queue)
```

### `queue/priority.py`
*Responsibility: Priority-based scheduling*
```python
import heapq
from typing import Optional
from .core import Job

class PriorityQueue:
    """Priority-based job queue implementation."""
    def __init__(self) -> None:
        self._heap: list[tuple[int, int, Job]] = []
        self._counter = 0  # Ensures stable sorting for equal priorities

    def enqueue(self, job: Job) -> None:
        job.status = "queued"
        # Lower priority value = higher priority
        heapq.heappush(self._heap, (job.priority, self._counter, job))
        self._counter += 1

    def dequeue(self) -> Optional[Job]:
        if not self._heap:
            return None
        _, _, job = heapq.heappop(self._heap)
        job.status = "processing"
        return job

    def is_empty(self) -> bool:
        return len(self._heap) == 0

    def size(self) -> int:
        return len(self._heap)
```

### `queue/retry.py`
*Responsibility: Execution wrapper with exponential backoff*
```python
import time
from typing import Callable, Any
from .core import Job

def process_with_retry(
    job: Job,
    func: Callable[..., Any],
    max_retries: int = 3,
    base_delay: float = 1.0
) -> Any:
    """
    Execute a job's function with exponential backoff retry logic.
    
    Args:
        job: The Job instance to process
        func: Callable that accepts the job payload
        max_retries: Maximum number of retry attempts
        base_delay: Initial delay in seconds before first retry
        
    Returns:
        Result of the successful function execution
        
    Raises:
        Exception: The last exception raised if all retries fail
    """
    last_exception: Optional[Exception] = None

    for attempt in range(max_retries + 1):
        job.attempts = attempt + 1
        try:
            result = func(job.payload)
            job.status = "completed"
            return result
        except Exception as e:
            last_exception = e
            job.status = "retrying" if attempt < max_retries else "failed"
            if attempt < max_retries:
                delay = base_delay * (2 ** attempt)
                time.sleep(delay)

    raise last_exception  # type: ignore[misc]
```

### `queue/__init__.py`
*Responsibility: Clean public API & package initialization*
```python
from .core import Job, JobQueue
from .priority import PriorityQueue
from .retry import process_with_retry

__all__ = [
    "Job",
    "JobQueue",
    "PriorityQueue",
    "process_with_retry",
]
```

### Key Design Decisions:
1. **Relative Imports**: `priority.py` and `retry.py` use `.core` imports, which is the Pythonic standard for intra-package dependencies.
2. **Consistent Interface**: `JobQueue` and `PriorityQueue` share identical method signatures (`enqueue`, `dequeue`, `is_empty`, `size`), making them interchangeable via dependency injection.
3. **Stable Priority Sorting**: `PriorityQueue` uses a `_counter` tie-breaker to guarantee FIFO order for jobs with equal priority (prevents `heapq` from comparing `Job` objects).
4. **State Tracking**: `Job.status` and `Job.attempts` are updated automatically by the queue and retry logic, providing observable lifecycle state.
5. **Public API**: `__init__.py` explicitly defines `__all__` to control what's exposed when users do `from queue import *` or IDE auto-completion.

> 💡 **Note**: `queue` shadows Python's standard library `queue` module. For production use, consider naming the package `jobqueue` or `taskqueue` to avoid import conflicts. The structure remains identical regardless of the directory name.