---
name: sre-patrones
description: >
  Patrones SRE: definición de SLO/SLI, cálculo de error budgets, diseño de
  alertas accionables, runbooks de incidentes y post-mortems blameless.
  Cargar cuando se definan objetivos de confiabilidad, se diseñen alertas
  que minimicen ruido, se escriba un runbook, se conduzca un post-mortem
  o se planifique la estrategia de on-call.
version: "1.0.0"
herramientasPermitidas: [Read, Bash]
evolvable: true  # default para skill estandar
exclusiones:
  - "No cargar para instrumentación de código con Prometheus, OpenTelemetry o logging estructurado — para instrumentación cargar `monitoring-alertas`."
  - "No cargar para configuración de dashboards Grafana o reglas de alerting en YAML — para dashboards y alert rules cargar `monitoring-alertas`."
  - "No cargar para análisis de vulnerabilidades de seguridad o threat modeling — para modelado de amenazas cargar `threat-model-lite`."
  - "No cargar para diseño de arquitectura de microservicios resilientes (circuit breakers, bulkheads) — para patrones de resiliencia de arquitectura cargar el skill de arquitectura correspondiente al stack."
---
# Patrones SRE — Guía de Confiabilidad

## Cuándo NO cargar

- La tarea es instrumentar código con Prometheus u OpenTelemetry: cargar `monitoring-alertas`.
- La tarea es configurar dashboards Grafana o alert rules en YAML: cargar `monitoring-alertas`.
- La tarea es threat modeling o análisis de vulnerabilidades: cargar `threat-model-lite`.
- La tarea es diseñar circuit breakers o bulkheads en código: usar el skill del stack correspondiente.

## 1. Jerarquía de confiabilidad

La confiabilidad de un sistema se expresa en tres capas anidadas:

```
SLA (Service Level Agreement)  — Contrato con el cliente (ej: 99.9% uptime)
  └─ SLO (Service Level Objective) — Objetivo interno (ej: 99.95% — margen sobre SLA)
       └─ SLI (Service Level Indicator) — Métrica real (ej: % requests exitosos en 28 días)
            └─ Error Budget — Cuánto podemos fallar: 100% - SLO = presupuesto de error
```

Regla clave: el SLO **siempre** debe ser más estricto que el SLA. La diferencia
es el margen de seguridad antes de violar el contrato con el cliente.

---

## 2. Definición de SLI por tipo de servicio

Los SLIs deben ser medibles con queries reales, no con afirmaciones vagas.

```yaml
# SLIs para API HTTP
slis:
  disponibilidad:
    formula: "successful_requests / total_requests * 100"
    ventana: "28 días rolling"
    umbral_bueno: "response_code < 500 AND latency < 1000ms"
    query_prometheus: |
      sum(rate(http_requests_total{code!~"5.."}[28d]))
      / sum(rate(http_requests_total[28d])) * 100

  latencia:
    formula: "p99 de latencia de response"
    ventana: "1 hora rolling"
    umbral_bueno: "p99 < 500ms"
    query_prometheus: |
      histogram_quantile(0.99,
        sum(rate(http_request_duration_seconds_bucket[1h])) by (le)
      )

  saturacion:
    formula: "uso_cpu_promedio últimas 4 horas"
    umbral_alerta: "> 80%"
    umbral_critico: "> 95%"
    query_prometheus: |
      100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[4h])) * 100)

# SLIs para pipeline de datos
slis_pipeline:
  frescura:
    formula: "time_since_last_successful_run"
    umbral_bueno: "< 1 hora"
    query_prometheus: |
      time() - pipeline_last_success_timestamp_seconds

  completitud:
    formula: "registros_procesados / registros_esperados"
    umbral_bueno: "> 99%"
    query_prometheus: |
      pipeline_records_processed_total
      / pipeline_records_expected_total * 100
```

---

## 3. Error budget y política de burn rate

### Cálculo de error budget

```python
def calcular_error_budget(slo_porcentaje: float, ventana_dias: int = 28) -> dict:
    """Calcula el error budget para un SLO dado."""
    uptime_permitido = 1 - (slo_porcentaje / 100)
    minutos_totales = ventana_dias * 24 * 60
    minutos_downtime = minutos_totales * uptime_permitido

    return {
        "slo": f"{slo_porcentaje}%",
        "ventana": f"{ventana_dias} días",
        "downtime_permitido_min": round(minutos_downtime, 1),
        "downtime_permitido_horas": round(minutos_downtime / 60, 2),
        "requests_fallidos_permitidos": f"{uptime_permitido * 100:.3f}% del total",
    }

# Ejemplos comunes:
# 99.0%  → 403.2 min / 6.72 h por mes
# 99.5%  → 201.6 min / 3.36 h por mes
# 99.9%  → 43.8 min / 0.73 h por mes
# 99.95% → 21.9 min / 0.37 h por mes
# 99.99% → 4.38 min por mes
```

### Política de consumo de error budget

| Estado del budget | Acción |
|-------------------|--------|
| > 50% disponible | Operación normal, todos los deploys habilitados |
| 20%–50% disponible | Solo deploys con feature flag y rollback en < 5 min |
| < 20% disponible | Solo hotfixes críticos, congelar deploys regulares |
| 0% agotado | Modo emergencia: post-mortem obligatorio, solo incidente activo |

La regla del 20% aplica al porcentaje **restante** en la ventana actual de 28
días. No se calcula sobre el budget anual acumulado.

---

## 4. Alertas accionables (no ruidosas)

Las alertas basadas en burn rate son superiores a los thresholds estáticos
porque detectan tanto incidentes rápidos como degradaciones lentas.

```yaml
# Alerta de burn rate alto — P1, requiere atención en 1 hora
# Lógica: consumimos el budget 14x más rápido de lo sostenible
- alert: ErrorBudgetBurnRateAlto
  expr: |
    (
      sum(rate(http_requests_total{code=~"5.."}[1h])) /
      sum(rate(http_requests_total[1h]))
    ) > (14 * (1 - 0.999))
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "Error budget consumiéndose 14x más rápido — revisar en 1 hora"
    runbook: "https://wiki/runbooks/error-budget-burn"
    accion: "Ver logs de errores 5xx en los últimos 30 minutos"

# Alerta de burn rate moderado — P2, investigar en el día
# Lógica: consumimos el budget 6x más rápido, se agotará en ~5 días
- alert: ErrorBudgetBurnRateModerado
  expr: |
    (
      sum(rate(http_requests_total{code=~"5.."}[6h])) /
      sum(rate(http_requests_total[6h]))
    ) > (6 * (1 - 0.999))
  for: 30m
  labels:
    severity: warning
  annotations:
    summary: "Error budget consumiéndose 6x más rápido — investigar hoy"
    runbook: "https://wiki/runbooks/error-budget-burn"
    accion: "Revisar tendencia de errores en el dashboard de SLO"

# Alerta de budget bajo — recordatorio de política
- alert: ErrorBudgetBajo
  expr: |
    (error_budget_remaining_ratio) < 0.20
  for: 0m
  labels:
    severity: warning
  annotations:
    summary: "Error budget < 20% — activar política de deploys conservadores"
    runbook: "https://wiki/runbooks/error-budget-policy"
```

### Tabla de multiplicadores de burn rate

| Severidad | Multiplicador | Se agota en | `for` recomendado |
|-----------|--------------|-------------|-------------------|
| Critical (P1) | 14.4x | ~2 días | 5m |
| Warning (P2) | 6x | ~5 días | 30m |
| Info (P3) | 3x | ~9 días | 1h |

---

## 5. Runbook template

```markdown
# Runbook: [Nombre del Incidente/Alerta]

## Cuando activar
- Alerta: [nombre exacto de la alerta en Prometheus/Datadog]
- Severidad: [P1/P2/P3]
- SLO afectado: [disponibilidad/latencia/etc]

## Diagnóstico rápido (primeros 5 minutos)
1. `kubectl get pods -n produccion` — ¿hay pods en CrashLoopBackOff?
2. Revisar dashboard: [URL del dashboard]
3. Últimos deploys: `kubectl rollout history deployment/mi-api`

## Acciones de mitigación
### Si hay pods fallando:
```bash
kubectl rollout undo deployment/mi-api
kubectl rollout status deployment/mi-api
```

### Si es problema de base de datos:
1. Verificar conexiones activas: [query SQL]
2. Revisar slow queries: [URL de logs]

## Escalación
- P1 (SLO breach): escalar a Tech Lead inmediatamente
- P2 (burn rate alto): escalar si no se resuelve en 30 min
- Contacto de escalación: [nombre] — [medio]

## Post-mortem
- Abrir ticket en [sistema] con template de post-mortem
- Conducir revisión en las 48 horas siguientes
```

---

## 6. Post-mortem blameless

```markdown
# Post-mortem: [Título del Incidente]
**Fecha**: [fecha]  **Duración**: [N horas M minutos]  **Severidad**: P[N]

## Impacto
- Usuarios afectados: [N usuarios / % del total]
- SLO consumido: [X% del error budget mensual]
- Ingresos en riesgo: [estimado si aplica]

## Causa raíz
[Descripción técnica objetiva — SIN mencionar nombres de personas.
Ejemplo correcto: "el proceso de deploy no tenía validación de health check
antes de enrutar tráfico al nuevo pod."
Ejemplo incorrecto: "Juan olvidó activar el health check."]

## Timeline
| Hora | Evento |
|------|--------|
| 14:32 | Primera alerta disparada |
| 14:38 | Ingeniero de guardia detecta el incidente |
| 15:10 | Causa raíz identificada |
| 15:25 | Mitigación aplicada, SLO recuperado |
| 16:00 | Servicio estable, incidente cerrado |

## Qué funcionó bien
- Las alertas dispararon dentro del SLO de detección
- El runbook tenía la solución correcta documentada

## Qué no funcionó
- El deploy no tenía feature flag para rollback rápido
- No había alerta de degradación antes del incidente completo

## Acciones correctivas
| Acción | Responsable | Fecha límite | Prioridad |
|--------|-------------|--------------|-----------|
| Agregar feature flag a todos los deploys del módulo de pago | [equipo] | [fecha] | P1 |
| Mejorar el runbook con el nuevo comando de diagnóstico | [equipo] | [fecha] | P2 |
| Agregar alerta de latencia p95 como señal temprana | [equipo] | [fecha] | P2 |
```

---

## 7. MUST DO / MUST NOT DO

### MUST DO

- Alertas basadas en SLO burn rate, no en thresholds estáticos de CPU/memoria.
- Escribir el runbook **antes** de configurar la alerta. Si no hay acción documentada, la alerta genera ruido sin valor.
- Conducir post-mortems blameless dentro de 48 horas del cierre del incidente.
- Aplicar la política de error budget: no deploy cuando budget < 20% del período.
- Usar ventana rolling de 28 días para SLOs — evita el "reset" de inicio de mes.
- Definir el SLO siempre más estricto que el SLA para tener margen de seguridad.
- Tener primario y secundario de on-call para cada servicio crítico.

### MUST NOT DO

- NUNCA culpar a personas en post-mortems — ni directa ni implícitamente.
- NUNCA poner el SLA igual o más alto que el SLO interno.
- NUNCA configurar una alerta sin su runbook correspondiente.
- NUNCA ignorar cuando el error budget spend supera el 50% en la primera semana del período.
- NUNCA hacer chaos engineering sin tener el SLO baseline medido y el budget > 50%.
- NUNCA usar latencia promedio en alertas — usar p99. El promedio oculta percentiles altos.
- NUNCA dejar acciones correctivas de post-mortem sin responsable y fecha límite.

---

## 8. Tabla de referencias

| Tema | Archivo |
|------|---------|
| Chaos engineering: steady state, herramientas, safety | [recursos/chaos-engineering.md](recursos/chaos-engineering.md) |
| On-call: rotación, escalación, fatiga de alertas | [recursos/oncall-design.md](recursos/oncall-design.md) |
| Alertas Prometheus con runbook completo | `Skill("monitoring-alertas")` |
| Implementación de métricas en código | Invocar `Agent(subagent_type="observabilidad-swl")` — es agente, no skill |

---

## Checklist de revisión SRE

- [ ] SLIs definidos como queries verificables (no descripciones vagas).
- [ ] SLO más estricto que el SLA en al menos 0.05%.
- [ ] Error budget calculado y documentado junto al SLO.
- [ ] Política de error budget documentada y conocida por el equipo.
- [ ] Cada alerta tiene runbook con diagnóstico y mitigación.
- [ ] Alertas basadas en burn rate, no en thresholds estáticos.
- [ ] Post-mortem redactado sin nombres de culpables.
- [ ] Acciones correctivas con responsable y fecha límite asignados.
- [ ] On-call con primario y secundario para cada servicio P1.
- [ ] Chaos engineering solo cuando budget > 50% y en staging primero.

---

## Gotchas / Errores comunes no obvios

**Un SLO de 99.9% en ventana rolling de 28 días permite 40.3 minutos de downtime, pero si el equipo usa ventana de mes calendario reinicia el contador cada 1 de mes, creando un incentivo perverso para hacer deploys riesgosos los primeros días del mes cuando el budget está lleno**: con ventana de mes calendario, un incidente de 35 minutos el día 28 consume el 87% del budget, pero el mismo incidente el día 2 consume el mismo 87% pero con 26 días para recuperarse. Causa: el mes calendario crea un "reset" artificial que desconecta el budget del riesgo real acumulado. Fix: usar siempre ventana rolling de 28 días. La ventana rolling refleja el riesgo real que los usuarios experimentan en los últimos 28 días, independientemente de cuándo empieza el mes.

**Las alertas de burn rate multiples ventanas (1h + 6h) producen falsos positivos en sistemas con carga diurna/nocturna porque el burn rate de la ventana corta (1h) dispara fuera de horario aunque el presupuesto mensual esté intacto**: un sistema con 10x más tráfico en horario laboral tiene naturalmente más errores absolutos en esas horas; si el SLI se define como "errores / total requests", el burn rate de 1h puede dispararse a las 9am sin que sea un incidente real. Causa: las alertas de burn rate asumen una tasa de requests aproximadamente uniforme; con carga variable, la misma tasa de errores genera diferentes burn rates. Fix: definir el SLI como proporción de errores (no absolutos) y verificar que el denominador (total requests) no sea cercano a cero en ventanas cortas fuera de horario, o añadir un mínimo de volumen de requests como precondición de la alerta.

**Los post-mortems blameless fallan en práctica cuando el "sistema" responsabilizado es en realidad una sola persona que tomó una decisión, creando frustración en el equipo porque todos saben quién fue pero no se puede decir**: la redacción "el deploy fue realizado sin validar el rollback" es técnicamente blameless pero todos saben que fue una persona específica. La persona en cuestión se siente expuesta pero sin poder defenderse, y el equipo siente que el proceso es hipócrita. Causa: blameless no significa ignorar la agencia humana — significa identificar los fallos del sistema que hicieron posible el error humano. Fix: reformular desde "qué fallo en el sistema que permitió que esta decisión se tomara": "no existía un checklist de deploy que incluyera verificación de rollback" o "el proceso de deploy no requería aprobación de un segundo ingeniero". La acción correctiva ataca el sistema, no la persona.

**El error budget policy de "no deploy cuando budget < 20%" bloquea hotfixes críticos de seguridad porque se aplica sin distinción al tipo de cambio**: un equipo que agotó el 85% del budget por un incidente de infraestructura no puede deployar un parche de seguridad CVE crítico porque la política lo bloquea automáticamente. Causa: la política de error budget fue diseñada para frenar deploys de features riesgosas, no hotfixes de seguridad. Fix: la política debe tener excepciones explícitas: (1) hotfixes de seguridad CVE con severidad CVSS ≥ 8 siempre se pueden deployar con aprobación del Tech Lead, (2) rollbacks de un cambio reciente que causó el budget burn siempre se permiten, (3) deploys de configuración sin cambios de código tienen presupuesto separado.
