Plantilla de Postmortem de Incidentes
Una plantilla de postmortem sin culpables para documentar incidentes: cronología, impacto, causa raíz, factores contribuyentes y acciones con responsables.
Resumen
Un postmortem es el registro escrito de un incidente: qué pasó, por qué pasó, cómo se resolvió y qué va a cambiar para que no se repita. Bien hecho, es sin culpables: el análisis va contra causas sistémicas, no contra errores individuales. Esta plantilla da a cada incidente la misma estructura, así los postmortems se mantienen consistentes y accionables entre equipos.
Cuándo Usarla
- Después de cualquier incidente P0 o P1 (obligatorio en un plazo de 48 horas)
- Tras incidentes P2 recurrentes (la tercera ocurrencia dispara el postmortem)
- Después de near-miss que podrían haber causado un impacto serio
- Tras incidentes de seguridad o filtraciones de datos
- Para requisitos de cumplimiento y auditoría
Antes de Empezar
- El incidente está completamente resuelto y los sistemas son estables.
- Ya recopilaste una cronología de eventos — ver la plantilla de cronología de incidentes.
- Están disponibles los participantes clave: respondedores, ingenieros involucrados y al menos un observador.
- El liderazgo apoya un proceso sin culpables.
- Ya se decidió si el postmortem es solo interno o de cara al cliente.
Plantilla
# Postmortem de Incidente: `<ID del incidente>`
## Resumen del Incidente
| Campo | Valor |
|-------|-------|
| ID del incidente | INC-2026-07-05-001 |
| Título | Caída del servicio de pagos en hora punta de checkout |
| Severidad | P0 |
| Estado | Resuelto |
| Fecha | 2026-07-05 |
| Hora de inicio | 14:32 UTC |
| Hora de detección | 14:35 UTC (3 min en detectarse) |
| Hora de mitigación | 14:52 UTC (20 min en mitigarse) |
| Hora de resolución | 15:48 UTC (76 min en total) |
| Incident Commander | <Nombre> |
| Autor del postmortem | <Nombre> |
| Revisores | <Tech Lead>, <SRE Lead> |
| Servicios afectados | Servicio de Pagos, Servicio de Checkout |
| Usuarios afectados | ~12.000 usuarios activos |
| Impacto en ingresos | ~$45.000 en pedidos perdidos |
## Resumen del Impacto
### Impacto de cara al usuario
| Impacto | Duración | Usuarios afectados |
|---------|----------|--------------------|
| La página de checkout devolvió errores 500 | 20 minutos (14:32-14:52) | ~12.000 |
| Falló el procesamiento de pagos | 20 minutos | ~3.500 intentos de checkout |
| Emails de confirmación de pedido retrasados | 76 minutos | ~1.200 pedidos en cola |
| Procesamiento de reembolsos retrasado | 76 minutos | ~50 reembolsos pendientes |
### Impacto de negocio
| Métrica | Normal | Durante el incidente | Impacto |
|---------|--------|----------------------|---------|
| Pedidos por minuto | 180 | 0 (durante 20 min) | 3.600 pedidos perdidos |
| Ingresos por minuto | $2.250 | $0 (durante 20 min) | $45.000 de ingresos perdidos |
| Tickets de soporte | 5/hora | 85/hora | 80 tickets extra |
| Reclamaciones | 2/hora | 45/hora | 43 reclamaciones extra |
| Impacto en NPS | — | -8 puntos (estimado) | Encuesta en 1 semana |
### Impacto en SLO
| SLO | Objetivo | Actual (30d) | Antes del incidente | Después del incidente | Presupuesto consumido |
|-----|----------|--------------|---------------------|------------------------|------------------------|
| Disponibilidad | 99.9% | 99.85% | 99.92% | 99.85% | 70% del presupuesto mensual |
| Latencia p95 | < 500ms | 680ms | 420ms | 680ms | N/A (SLO aparte) |
## Cronología
| Hora (UTC) | Evento | Fuente |
|------------|--------|--------|
| 14:30 | Sale el despliegue v2.5.0, con la nueva integración del proveedor de pagos | Pipeline CI/CD |
| 14:32 | La tasa de errores salta de 0.1% a 45% en `/api/v1/payments` | Alerta de Prometheus |
| 14:35 | Salta la alerta de PagerDuty: `HighErrorRate-PaymentService` | Alertmanager |
| 14:36 | El ingeniero de guardia reconoce la alerta | PagerDuty |
| 14:38 | Revisa el dashboard de Grafana y ve errores 500 en el endpoint de pagos | Grafana |
| 14:40 | Revisa los logs y ve `TypeError: Cannot read property 'id' of undefined` en el servicio de pagos | Kibana |
| 14:42 | Identifica el nuevo despliegue como causa probable y mira el canal `#deployments` | Slack |
| 14:44 | Confirma que v2.5.0 salió a las 14:30, 2 minutos antes de empezar los errores | Logs de CI/CD |
| 14:46 | Escala a la guardia secundaria para apoyar el rollback | PagerDuty |
| 14:48 | Se decide volver a v2.4.1 | Canal del incidente |
| 14:50 | Empieza el rollback: `kubectl rollout undo deployment/payment` | Terminal |
| 14:52 | Rollback completo; la tasa de errores baja a 0.1% | Grafana |
| 14:55 | La tasa de errores se mantiene normal 3 minutos seguidos | Grafana |
| 15:00 | El incidente baja de P0 a P1 y se vigilan efectos residuales | Canal del incidente |
| 15:15 | Empieza a procesarse la cola de emails de confirmación: 1.200 emails pendientes | Servicio de email |
| 15:30 | Cola de emails vaciada; todas las confirmaciones enviadas | Servicio de email |
| 15:48 | Todos los reembolsos pendientes procesados; incidente resuelto por completo | Servicio de pagos |
| 16:00 | El incidente se declara resuelto en PagerDuty | PagerDuty |
| 16:30 | Se agenda el postmortem para el 2026-07-06 a las 10:00 UTC | Calendario |
## Análisis de Causa Raíz
### Qué pasó
El despliegue v2.5.0 introdujo una nueva integración con el proveedor de pagos. El nuevo código asumía que la API del proveedor siempre devolvería un campo `transaction.id` en la respuesta. Sin embargo, para ciertos tipos de tarjeta (Amex, Discover), el proveedor devuelve el ID de transacción en un objeto anidado: `transaction.metadata.transaction_id`. El código accedía a `transaction.id` directamente, que era `undefined` para esos tipos de tarjeta, provocando un `TypeError` que tumbaba el handler de la petición.
### Por qué pasó
| Factor | Detalle |
|--------|---------|
| Cobertura de tests insuficiente | Los tests de integración usaban respuestas mockeadas que siempre incluían `transaction.id`. Ningún test cubría el formato de respuesta anidado. |
| Sin contract testing | La documentación de la API del proveedor no se verificó contra respuestas reales. Ningún contract test validaba el esquema de la respuesta. |
| Falta de programación defensiva | El código no validaba la estructura de la respuesta antes de acceder a campos anidados. Sin comprobación de null en `transaction.id`. |
| Canary deployment insuficiente | El despliegue fue directo al 100% del tráfico. Sin canary ni rollout gradual configurado. |
| Sin feature flag | La nueva integración no estaba detrás de un feature flag. No se podía desactivar sin un rollback. |
### Análisis de los Cinco Porqués
1. **¿Por qué el servicio de pagos devolvía errores 500?**
El código lanzaba un `TypeError` al acceder a `transaction.id` sobre undefined.
2. **¿Por qué era `transaction.id` undefined?**
El proveedor de pagos devuelve los IDs de transacción en `transaction.metadata.transaction_id` para tarjetas Amex y Discover, no en `transaction.id`.
3. **¿Por qué los tests no lo detectaron?**
Los tests de integración usaban respuestas mockeadas que siempre incluían `transaction.id`. Ningún test usaba el formato real de respuesta para tarjetas que no fueran Visa/Mastercard.
4. **¿Por qué no se verificó el formato real de la respuesta?**
No había contract testing entre el servicio de pagos y el proveedor. El equipo confió en la documentación de la API, que estaba desactualizada.
5. **¿Por qué el despliegue afectó a todos los usuarios a la vez?**
No había canary deployment ni rollout gradual configurados. El despliegue fue al 100% del tráfico de una vez.
### Factores contribuyentes
| Factor | Impacto | Categoría |
|--------|---------|-----------|
| Despliegue en hora punta (14:30 UTC) | Maximizó el impacto sobre usuarios | Proceso |
| Sin congelación de despliegues en horario punta | Permitió un deploy arriesgado con tráfico alto | Política |
| Umbral de alerta demasiado alto (5% de errores) | 3 minutos de retraso en la detección | Monitorización |
| Sin chequeo sintético del flujo de pagos | Sin detección proactiva antes de que los usuarios vieran errores | Monitorización |
| Cola de emails sin mecanismo de backpressure | Confirmaciones de pedido retrasadas 76 minutos | Arquitectura |
| Un único proveedor de pagos | Sin fallback cuando la integración se rompió | Arquitectura |
## Qué salió bien
- [x] La alerta saltó a los 3 minutos del inicio de los errores
- [x] El ingeniero de guardia la reconoció en menos de 1 minuto
- [x] La causa raíz se identificó en 10 minutos
- [x] La decisión de rollback se tomó en 16 minutos
- [x] El rollback se completó en 20 minutos
- [x] La comunicación en el canal del incidente fue clara y puntual
- [x] Sin corrupción de datos: todos los pedidos quedaron guardados en la base de datos
## Qué salió mal
- [x] El despliegue fue al 100% del tráfico sin canary
- [x] Los tests no cubrían los formatos de respuesta de tarjetas no Visa/Mastercard
- [x] Sin contract testing con el proveedor de pagos
- [x] Sin feature flag para desactivar la integración sin rollback
- [x] La cola de emails no tenía backpressure: 1.200 emails retrasados
- [x] El umbral de alerta al 5% supuso 3 minutos de errores antes de alertar
## Dónde tuvimos suerte
- [x] El rollback fue rápido porque la versión anterior seguía disponible
- [x] El error era consistente y fácil de reproducir: el diagnóstico fue directo
- [x] No se perdieron datos: los pedidos se guardaron en la base de datos antes del fallo
- [x] El proveedor de pagos no estaba caído: solo nuestra integración estaba rota
## Acciones pendientes
| # | Acción | Tipo | Responsable | Prioridad | Fecha límite | Estado |
|---|--------|------|-------------|-----------|--------------|--------|
| 1 | Añadir contract tests para las respuestas de la API del proveedor | Prevenir | Equipo de backend | Alta | 2026-07-12 | Abierta |
| 2 | Añadir casos de test para tarjetas Amex, Discover y otras | Prevenir | Equipo de backend | Alta | 2026-07-10 | Abierta |
| 3 | Implementar canary deployment para el servicio de pagos | Prevenir | Equipo de plataforma | Alta | 2026-07-19 | Abierta |
| 4 | Añadir feature flag para la nueva integración de pagos | Prevenir | Equipo de backend | Media | 2026-07-15 | Abierta |
| 5 | Bajar el umbral de alerta de tasa de errores de 5% a 2% | Mejorar | Equipo de SRE | Media | 2026-07-08 | Abierta |
| 6 | Añadir chequeo sintético del flujo de pagos (cada 1 min) | Mejorar | Equipo de SRE | Media | 2026-07-12 | Abierta |
| 7 | Implementar backpressure en la cola de emails | Mejorar | Equipo de plataforma | Baja | 2026-07-26 | Abierta |
| 8 | Añadir política de congelación de despliegues en hora punta (9-18 UTC) | Proceso | Eng Manager | Media | 2026-07-10 | Abierta |
| 9 | Actualizar el runbook con el procedimiento de canary deployment | Proceso | Equipo de SRE | Baja | 2026-07-19 | Abierta |
| 10 | Evaluar un proveedor de pagos secundario como fallback | Arquitectura | Equipo de backend | Baja | 2026-08-05 | Abierta |
### Categorías de acciones
| Categoría | Descripción | Cantidad |
|-----------|-------------|----------|
| Prevenir | Evitar que este problema concreto se repita | 4 |
| Mejorar | Mejorar detección, respuesta o mitigación | 3 |
| Proceso | Mejorar procesos o políticas | 2 |
| Arquitectura | Cambios de arquitectura para reducir el blast radius | 1 |
## Lecciones aprendidas
### Lecciones técnicas
1. **Las respuestas mockeadas tienen que coincidir con el comportamiento real de la API**: los tests con mocks dieron una confianza falsa. Los contract tests contra la API real habrían pillado el desajuste del esquema.
2. **Los canary deployments pillan bugs de integración**: un canary al 5% habría afectado a ~600 usuarios en lugar de 12.000.
3. **Los feature flags permiten rollback instantáneo**: un flag habría desactivado la integración en segundos, sin desplegar un rollback.
4. **Los chequeos sintéticos detectan problemas antes que los usuarios**: un sintético golpeando el flujo de pagos cada minuto lo habría detectado antes que los usuarios reales.
### Lecciones de proceso
1. **El momento del despliegue importa**: desplegar en hora punta maximiza el impacto. Una congelación en horario punta es un cambio de política sencillo.
2. **Los umbrales de alerta hay que afinarlos**: un umbral del 5% de errores es demasiado alto para un servicio crítico. El 2% habría alertado 2 minutos antes.
3. **El backpressure evita fallos en cascada**: la cola de emails se atascó porque no tenía backpressure, lo que alargó el incidente más allá de la recuperación del servicio.
## Apéndice
### Logs de error (extracto)
```
2026-07-05T14:32:01.234Z ERROR [payment-service] TypeError: Cannot read properties of undefined (reading 'id')
at processPaymentResponse (payment.js:142)
at handlePayment (payment.js:87)
at async processCheckout (checkout.js:34)
at async <anonymous> (server.js:156)
transactionId: undefined
cardType: "amex"
requestId: "req-abc123"
```
### Configuración de la alerta
```yaml
- alert: HighErrorRate-PaymentService
expr: |
rate(http_requests_total{service="payment",status=~"5.."}[5m])
/
rate(http_requests_total{service="payment"}[5m]) > 0.05
for: 5m
labels:
severity: critical
```
### Detalles del despliegue
| Campo | Valor |
|-------|-------|
| Versión desplegada | v2.5.0 |
| Versión anterior | v2.4.1 |
| Método de despliegue | kubectl apply (rollout al 100%) |
| Hora del despliegue | 14:30 UTC |
| Cambios | Nueva integración de proveedor de pagos (Stripe → Adyen) |
| PR | #1234 |
| Revisado por | 2 revisores |
| Estado de CI | Todos los checks en verde |
Explicación
Un postmortem sin culpables va contra causas sistémicas, no contra acciones individuales. Nadie despliega código con intención de romper producción: el sistema dejó que un cambio arriesgado llegara a todos los usuarios sin las pruebas adecuadas. El trabajo del postmortem es nombrar los cambios sistémicos que lo habrían impedido.
La cronología es el registro factual, construida solo con fuentes objetivas: logs de PagerDuty, registros de CI/CD, mensajes de chat, datos de monitorización. Las interpretaciones subjetivas no tienen sitio ahí.
Los cinco porqués excavan más allá de los síntomas. Sigue preguntando hasta aterrizar en una causa sistémica que, arreglada, habría evitado el incidente por completo.
Las acciones pendientes son la parte que más importa. Cada una necesita responsable, prioridad y fecha límite. Antes de escribir un postmortem nuevo, revisa las acciones abiertas de los anteriores: las acciones recurrentes son la señal de un problema de seguimiento.
Segundo Ejemplo Real: Cambio de Configuración Sin Deploy
No todos los incidentes empiezan con código nuevo. Postmortem condensado de un cambio en la rotación del secreto JWT:
- Qué pasó: el 15% de los intentos de login en la UE falló durante 30 minutos después de que un cambio de configuración acortara el intervalo de rotación del secreto JWT de 24h a 1h, invalidando las sesiones activas.
- Cronología: la CPU de la base de datos subió a las 10:42, PagerDuty disparó a las 10:55, SEV-1 declarado a las 11:00, cambio de config identificado a las 11:03, rollback completo a las 11:08, resuelto a las 11:25 UTC.
- Cinco porqués: la validación de tokens falló → el secreto rotó antes de que expiraran los tokens existentes → el cambio de config pasó los tests → los tests nunca cubrían el comportamiento de rotación → ninguna alerta disparó antes del impacto → los umbrales de latencia estaban demasiado altos. La causa raíz es el proceso de revisión ausente para cambios de configuración, no el cambio en sí.
- Acciones pendientes: añadir un test de rotación de secreto (P0), reajustar los umbrales de alerta de latencia (P1), exigir revisión de seguridad en cambios de config (P1).
La misma forma que el ejemplo de pagos — disparador, cadena de porqués, arreglo sistémico — pero el disparador es operativo, no un bug en código nuevo.
Cómo Llevar la Reunión de Postmortem
Asigna un facilitador que no haya sido respondedor del incidente: aporta perspectiva fresca y puede empujar más allá del “todos sabemos qué pasó”. Empieza con la cronología para que el grupo se ponga de acuerdo en los hechos antes de interpretarlos, y después trabaja los cinco porqués en voz alta. Fomenta preguntas, no acusaciones, limita la sesión a 60 minutos y documenta en un archivo compartido en tiempo real para que nada se reconstruya de memoria. Asigna acciones pendientes con responsables y fechas límite antes de que termine la reunión, y comparte el borrador con todos los equipos de ingeniería en un plazo de 48 horas.
Invita también a observadores, no solo a respondedores: la gente que no estuvo en el calor del incidente detecta patrones que los respondedores suelen pasar por alto.
Variantes
| Contexto | Enfoque | Notas |
|---|---|---|
| Incidente de seguridad | Añade CVE, vector de ataque y detalles de exposición de datos | Sigue el plan de IR de seguridad |
| Pérdida de datos | Añade pasos de recuperación y verificación de backups | Incluye chequeos de integridad |
| Caída de un tercero | Añade la cronología de comunicación con el proveedor | Incluye el timeline de su status page |
| Near-miss | Salta la sección de impacto y céntrate en prevención | Sin impacto de usuario que documentar |
| Incidente multi-servicio | Añade el mapa de dependencias entre servicios | Muestra la ruta de la cascada |
| Degradación de rendimiento (no caída) | Añade percentiles de latencia, caída de throughput y efectos en cascada | La degradación es más difícil de acotar que el downtime |
| Incidente recurrente | Compara con postmortems anteriores y analiza por qué las acciones previas no lo evitaron | Los patrones importan más que los eventos individuales |
Lo Que Funciona
- Escribe el postmortem en un plazo de 48 horas; los detalles se desvanecen rápido.
- Mantenlo sin culpables: sistemas, no personas.
- Construye la cronología solo con fuentes objetivas (PagerDuty, CI/CD, monitorización).
- Asigna a cada acción un responsable y una fecha límite, porque las acciones sin dueño no se hacen.
- Revisa primero las acciones anteriores; las recurrentes delatan un problema de seguimiento.
- Comparte los postmortems ampliamente para que otros equipos aprendan de tus incidentes.
- Mide el porcentaje de acciones completadas; un postmortem sin acciones hechas es teatro.
- Publica las acciones pendientes en la misma semana: el valor de un postmortem decae con la demora.
- Revisa postmortems antiguos cada trimestre para detectar temas recurrentes y brechas sistémicas.
Errores Comunes
- Culpar a personas: “el ingeniero debería haber probado más” no es una causa raíz.
- Acciones vagas como “mejorar los tests” no llevan a nada sin detalles ni responsables.
- Sin seguimiento: un postmortem sin accountability es esfuerzo desperdiciado.
- Escribirlo demasiado tarde, cuando la memoria se ha difuminado y la cronología se vuelve imprecisa.
- Arreglar solo la prevención, cuando una mejor detección y mitigación cuentan igual.
- Saltarse el “qué salió bien”, que es cómo se refuerzan las buenas respuestas.
- Mantener los postmortems privados en vez de dejar que otros equipos aprendan de ellos.
Ver También
- Repositorio companion: la plantilla rellenable y el ejemplo de caída de pagos completado como archivos markdown independientes.
- Blameless Postmortems: Learning from Incidents Without Blame: la guía complementaria sobre cómo llevar el proceso de postmortem.
- Google SRE — Postmortem Culture: el capítulo original sobre postmortems sin culpables del SRE book.
- Atlassian Incident Handbook: playbooks de incidentes y postmortems de un equipo que los practica a escala.
Preguntas frecuentes
¿Cuándo deberíamos escribir un postmortem?
Para todos los incidentes P0 y P1, en un plazo de 48 horas desde la resolución. Para los P2, escribe uno si el problema es recurrente (tercera ocurrencia). Para near-misses, escríbelo si el impacto potencial habría sido P0 o P1.
¿Qué largo debería ser un postmortem?
Lo bastante largo para capturar toda la información relevante y lo bastante corto para que la gente lo lea. Normalmente entre 2 y 4 páginas. La cronología y las acciones pendientes son las secciones más importantes; mantén la narrativa concisa.
¿Quién debería escribir el postmortem?
El incident commander o alguien que participó desde la detección hasta la resolución. El autor no debería ser quien causó el incidente (si aplica), para reducir el sesgo, pero sí necesita conocimiento de primera mano de lo que pasó.
¿Qué hace que un postmortem sea sin culpables?
Centrarse en causas sistémicas: tests que faltan, monitorización insuficiente, huecos en los procesos. Nunca nombres a personas como causas. En vez de "John desplegó sin probar", escribe "el proceso de despliegue no exigía tests de integración para cambios de API". El sistema permitió que el error llegara a producción.
¿Cómo nos aseguramos de que las acciones se hagan?
Asigna responsables y fechas límite. Revísalas en la reunión semanal de ingeniería y mide el porcentaje de completadas. Si las acciones se acumulan vencidas, escala al management. Las acciones sin completar de postmortems anteriores se revisan antes de empezar uno nuevo.
¿Y si alguien claramente cometió un error?
Pregunta por qué el error fue posible: ¿la documentación era confusa, la herramienta engañosa, la persona estaba sobrecargada o faltaba una salvaguarda? Sin culpables no significa sin consecuencias: significa arreglar el sistema en lugar de castigar a la persona.
¿Los postmortems deberían ser públicos?
Los postmortems internos deberían ser visibles para todos los equipos de ingeniería. Los de cara al cliente deberían sanitizarse y publicarse en la página de estado o el blog. La transparencia genera confianza, pero deja fuera los detalles sensibles: un mapa de infraestructura también le sirve a un atacante.
¿Quién debería aprobar el postmortem antes de publicarlo?
Revísalo con el incident commander para la precisión de los hechos, los respondedores clave para la precisión técnica y el líder del equipo para las acciones pendientes. Los postmortems de SEV-1 van al CTO o VP de ingeniería; los incidentes de seguridad necesitan aprobación de legal y compliance antes de cualquier versión externa.
¿Cómo medimos la efectividad de los postmortems?
Mide el porcentaje de acciones completadas dentro del plazo (objetivo: más del 80%), el tiempo medio en completarlas, el número de incidentes recurrentes por la misma causa y el tiempo entre el incidente y la publicación (objetivo: menos de 72 horas). Revisa las cifras cada trimestre: si las acciones se siguen aplazando, hay que ajustar el proceso, no escribir más postmortems.
Recursos Relacionados
Plantilla de Runbook de Alertas
Un runbook estandarizado para responder alertas: triage, diagnosis, mitigation, resolution y post-incident steps con escalation paths.
DocPlantilla de Línea de Tiempo de Incidentes
Una plantilla para reconstruir la secuencia exacta de eventos durante investigaciones de incidentes para identificar brechas de detección y retrasos en la respuesta.
DocPlantilla de Evaluación de Madurez de Observabilidad
Una plantilla para evaluar la madurez de logging, métricas y tracing entre equipos con puntuación, análisis de brechas y hoja de ruta de mejora.
GuideLogging Estructurado: logs JSON, correlation IDs, agregación
Dominá structured logging con JSON format, correlation IDs, log levels y aggregation. Cubre Python structlog, Node.js pino, Java SLF4J, stacks ELK y Loki.
DocPlantilla de Comunicacion de Incidentes
Una plantilla para notificar a stakeholders durante interrupciones de produccion con mensajes pre-redactados para cada nivel de severidad y tipo de audiencia.
DocPlantilla de Plan de Respuesta a Incidentes
Una plantilla para respuesta a incidentes cubriendo clasificación de severidad, roles, detección, contención, erradicación, recuperación y revisión post-incidente.