Here's the complete refactored package structure with production-ready implementations that maintain clear separation of concerns and proper module boundaries.

### `queue/__init__.py`
```python
"""Public API for the job queue package."""
from .core import Job, JobQueue

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

### `queue/core.py`
```python
"""Core data structures and basic FIFO queue operations."""
from dataclasses import dataclass, field
from typing import Any, Optional
import time


@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str
    payload: Any
    status: str = "pending"
    created_at: float = field(default_factory=time.time)
    attempts: int = 0


class JobQueue:
    """Basic FIFO job queue."""
    
    def __init__(self):
        self._queue: list[Job] = []

    def add(self, job: Job) -> None:
        """Add a job to the end of the queue."""
        self._queue.append(job)

    def get(self) -> Optional[Job]:
        """Remove and return the next job, or None if empty."""
        if not self._queue:
            return None
        return self._queue.pop(0)

    def is_empty(self) -> bool:
        """Check if the queue is empty."""
        return len(self._queue) == 0

    def size(self) -> int:
        """Return the number of jobs in the queue."""
        return len(self._queue)
```

### `queue/priority.py`
```python
"""Priority queue implementation using a min-heap."""
import heapq
from typing import Optional
from .core import Job


class PriorityQueue:
    """Job queue that processes lower priority numbers first."""
    
    def __init__(self):
        self._heap: list[tuple[int, int, Job]] = []
        self._counter: int = 0  # Tie-breaker for equal priorities

    def add(self, job: Job, priority: int = 0) -> None:
        """Add a job with a given priority level.
        
        Args:
            job: The job to enqueue.
            priority: Priority level (lower = higher priority).
        """
        heapq.heappush(self._heap, (priority, self._counter, job))
        self._counter += 1

    def get(self) -> Optional[Job]:
        """Remove and return the highest priority job, or None if empty."""
        if not self._heap:
            return None
        _, _, job = heapq.heappop(self._heap)
        return job

    def is_empty(self) -> bool:
        """Check if the queue is empty."""
        return len(self._heap) == 0

    def size(self) -> int:
        """Return the number of jobs in the queue."""
        return len(self._heap)
```

### `queue/retry.py`
```python
"""Retry logic with exponential backoff and jitter."""
import time
import random
from typing import Any, Callable, Optional
from .core import Job


def process_with_retry(
    job: Job,
    func: Callable[[Job], Any],
    max_retries: int = 3,
    base_delay: float = 1.0,
    max_delay: float = 60.0,
    jitter: bool = True
) -> Any:
    """Execute a job with exponential backoff retry logic.
    
    Args:
        job: The job to process.
        func: Callable that accepts a Job and returns a result.
        max_retries: Maximum number of retry attempts.
        base_delay: Initial delay in seconds.
        max_delay: Maximum delay cap in seconds.
        jitter: Whether to add random jitter to prevent thundering herd.
        
    Returns:
        The result of the successful function call.
        
    Raises:
        The last exception encountered if all retries are exhausted.
    """
    last_exception: Optional[Exception] = None
    
    for attempt in range(max_retries + 1):
        job.attempts = attempt + 1
        try:
            result = func(job)
            job.status = "completed"
            return result
        except Exception as e:
            last_exception = e
            job.status = "failed"
            
            if attempt < max_retries:
                # Exponential backoff: base_delay * 2^attempt
                delay = min(base_delay * (2 ** attempt), max_delay)
                if jitter:
                    delay *= random.uniform(0.5, 1.5)
                time.sleep(delay)
                
    job.status = "permanently_failed"
    if last_exception is not None:
        raise last_exception
```

### Key Design Decisions:
1. **Single Responsibility**: Each module handles exactly one concern: `core` (data + basic queue), `priority` (ordering), `retry` (fault tolerance)
2. **Clean Imports**: Relative imports (`from .core import ...`) prevent circular dependencies and work correctly when installed as a package
3. **Type Safety**: Full type hints with `Optional`, `Callable`, and `list` syntax for modern Python compatibility
4. **Stable Priority Queue**: Uses a monotonic counter to preserve insertion order for jobs with equal priority
5. **Production-Ready Retry**: Includes jitter to prevent retry storms, delay capping, and proper exception propagation
6. **Explicit Public API**: `__init__.py` uses `__all__` to clearly define what consumers get when they `import queue`

To use: `pip install -e .` in the parent directory, then `from queue import Job, JobQueue` in your application code.