# Matriz de estados de UI

Completa una fila por cada estado que pueda ocurrir. Elimina los que no
pertenezcan al dominio y añade estados de negocio específicos.

| Estado | Entrada | Qué ve | Qué se conserva | Acción | Salida | Anuncio accesible | Prueba |
|---|---|---|---|---|---|---|---|
| `idle` | Vista aún no iniciada | Contexto y CTA | Entrada local | Iniciar | `loading` | Ninguno | CTA funciona con teclado |
| `loading` | Primera petición | Estructura o indicador + objeto cargado | Contexto | Cancelar si aplica | `ready`, `empty`, `error` | Estado cortés; región busy | No muestra empty antes de resolver |
| `ready` | Datos válidos | Contenido + timestamp si importa | Datos | Operar o refrescar | `refreshing` | Resultado si fue dinámico | Tarea crítica completa |
| `refreshing` | Actualización con datos previos | Contenido anterior + actividad | Datos y posición | Seguir usando o cancelar | `ready`, `stale` | Busy + texto breve | Contenido no desaparece |
| `empty:first-use` | Cero elementos creados | Valor + primer paso | Contexto | Crear | `ready` | Heading descriptivo | CTA pertinente |
| `empty:no-results` | Filtro sin coincidencias | Query y filtros activos | Filtros | Limpiar o ajustar | `ready` | Conteo cero cortés | No se confunde con primera vez |
| `empty:completed` | Nada pendiente | Confirmación de logro | Contexto | Salir o revisar historial | `ready` | Status si cambió dinámicamente | No inventa CTA |
| `partial` | Una dependencia o lote falla | Resultados válidos + fallos localizados | Éxitos | Reparar pendientes | `ready`, `partial` | Resumen proporcional | No reinicia éxitos |
| `stale` | Falla un refresco | Datos previos + antigüedad | Datos | Reintentar | `refreshing` | Status cortés | Timestamp visible |
| `offline:no-cache` | Sin red en primera carga | Explicación | Entrada local | Reintentar | `loading` | Status una vez | No promete datos inexistentes |
| `offline:cached` | Sin red con caché | Datos + fecha | Caché | Ver o refrescar después | `refreshing` | Status una vez | Distingue caché de tiempo real |
| `offline:pending` | Escrituras locales | Datos + cambios pendientes | Cola local | Revisar | `ready`, `partial` | Cambios relevantes | Conflicto tiene salida |
| `unauthenticated` | Sesión expirada | Consecuencia + login | Borrador si existe | Iniciar sesión | Estado anterior | Alert si peligra trabajo | Regreso conserva contexto |
| `forbidden` | Rol insuficiente | Permiso requerido | Trabajo permitido | Solicitar o salir | Según dominio | Mensaje visible | No reintenta en bucle |
| `rate-limited` | Cupo agotado | Límite y fecha | Trabajo local | Ver uso | `ready` al vencer | Status | Fecha y zona horaria correctas |
| `error:retryable` | Timeout o 5xx | Tarea fallida + conservación | Entrada y datos útiles | Reintentar | `loading`, `refreshing` | Alert sólo si urgente | Reintento idempotente |
| `error:terminal` | Recurso eliminado o inválido | Explicación + salida | Lo seguro | Volver | Otra vista | Contexto nuevo | No ofrece reintento inútil |

## Preguntas obligatorias por estado

- ¿La persona entiende qué tarea o región cambió?
- ¿Puede distinguir espera, resultado, vacío, permiso y error?
- ¿Conservamos datos correctos, campos y posición?
- ¿La acción propuesta modifica la condición que impide avanzar?
- ¿La salida funciona con teclado?
- ¿El cambio se anuncia sin mover foco innecesariamente?
- ¿Color, animación o icono tienen una alternativa?
- ¿Podemos provocar el estado sin romper un servicio real?
- ¿Existe una prueba de entrada, transición y recuperación?

## Política de anuncios sugerida

| Evento | Patrón |
|---|---|
| Resultado o guardado no urgente | `role="status"` |
| Error dinámico que necesita atención inmediata | `role="alert"` |
| Región actualizándose | `aria-busy="true"` + texto visible |
| Progreso medible | `role="progressbar"` + nombre, mínimo, máximo y valor |
| Cada 1% o cada tecla | No anunciar; agrupar en hitos |
| Navegación o diálogo | Gestionar foco; no duplicar con alert innecesario |

## Definition of Done

- [ ] No existen combinaciones imposibles de booleanos.
- [ ] Carga inicial y refresco preservan comportamientos diferentes.
- [ ] Empty explica su causa y siguiente paso.
- [ ] Error identifica recuperación y datos conservados.
- [ ] Partial no destruye resultados válidos.
- [ ] Stale y offline comunican vigencia.
- [ ] Permiso y límite no parecen fallos genéricos.
- [ ] Los anuncios accesibles son suficientes, pero no repetitivos.
- [ ] Cada estado es determinista en desarrollo/testing.
- [ ] Las transiciones críticas tienen pruebas automatizadas.
