# Tipo: Task / TaskStatus / TaskManager

Fuente conceptual: MiroFish `backend/app/models/task.py` (AGPL-3.0)
Reimplementar desde cero. No copiar codigo.

## Tipos a implementar

### 1. TaskStatus (enum/sum)

- **Dominio:** core
- **Lang:** Python
- **Algebraic:** sum
- **Definicion:**
  ```python
  class TaskStatus(str, Enum):
      PENDING = "pending"
      PROCESSING = "processing"
      COMPLETED = "completed"
      FAILED = "failed"
  ```
- **Descripcion:** Estado de una tarea de larga duracion (graph building, simulation, report generation).

### 2. Task (product)

- **Dominio:** core
- **Lang:** Python
- **Algebraic:** product
- **Definicion:**
  ```python
  @dataclass
  class Task:
      task_id: str                                # UUID
      task_type: str                              # tipo libre: "graph_build", "simulation", etc.
      status: TaskStatus
      created_at: datetime
      updated_at: datetime
      progress: int = 0                           # 0-100%
      message: str = ""                           # mensaje de estado legible
      result: dict | None = None                  # resultado al completar
      error: str | None = None                    # error al fallar
      metadata: dict = field(default_factory=dict)
      progress_detail: dict = field(default_factory=dict)  # detalles de progreso (etapa actual, items procesados, etc.)
  ```
- **Metodos:**
  - `to_dict() -> dict` — serializacion con ISO timestamps

### 3. TaskManager (singleton thread-safe)

- **Dominio:** core
- **Lang:** Python
- **Purity:** impure (estado mutable, thread-safe)
- **Descripcion:** Gestor de tareas en memoria con thread safety. Patron singleton para acceso global. Util para tracking de tareas background con polling desde frontend.
- **Signature:**
  ```python
  class TaskManager:
      def create_task(self, task_type: str, metadata: dict | None = None) -> str: ...
      def get_task(self, task_id: str) -> Task | None: ...
      def update_task(self, task_id: str, status=None, progress=None, message=None, result=None, error=None, progress_detail=None) -> None: ...
      def complete_task(self, task_id: str, result: dict) -> None: ...
      def fail_task(self, task_id: str, error: str) -> None: ...
      def list_tasks(self, task_type: str | None = None) -> list[dict]: ...
      def cleanup_old_tasks(self, max_age_hours: int = 24) -> None: ...
  ```
- **Thread safety:** `threading.Lock` protege `_tasks: dict[str, Task]`
- **Singleton:** `__new__` con double-checked locking
- **Uso:** Background thread actualiza progreso via `update_task()`, frontend poll via `get_task()`. Pattern comun en web apps con tareas async.
