Módulo 5: The Incident Lifecycle

8. Proyecto: `INCIDENT-RESPONSE-PLAN.md` de Andes Cargo

Descripción

Siete lecciones construyeron cada pieza por separado: el ciclo de vida (lección 2), la severidad narrativa (lección 3) formalizada con aritmética real (lección 5), los roles (lección 4), y una rotación de guardia determinista, corrida de verdad (lección 7). Este proyecto final del módulo no calcula nada nuevo — reúne las cuatro piezas, exactamente como cada lección las dejó, en INCIDENT-RESPONSE-PLAN.md: el documento que RELIABILITY-CHARTER.md dejó como fila Open del Módulo 5, y el marco completo que el Módulo 6 va a operar contra el incidente Claude Code real.

Conexión con el módulo

Este documento cita SLO.md (Módulo 2) y ALERTING-POLICY.md (Módulo 4) en vez de repetir sus definiciones — el mismo principio de una única fuente de verdad que ALERTING-POLICY.md ya aplicó al citar SLO.md. El Módulo 6 clasifica el incidente Claude Code contra la matriz exacta de este documento, asigna roles de la lista exacta de este documento, y opera sobre el ciclo de vida exacto que este documento define — nada se vuelve a discutir ni a rediseñar a mitad del Módulo 6.


Paso 1 — Por qué este documento no inventa ningún número nuevo

La tentación, al escribir el documento final de un módulo, es agregar algo que se sienta "más completo" — un cuarto umbral de severidad, una quinta persona en la rotación, una excepción especial para algún caso hipotético. Este documento resiste esa tentación por la misma razón que SLO.md y ALERTING-POLICY.md ya la resistieron: cada número que aparece aquí ya fue calculado, citado, y verificado en una lección anterior de este módulo. INCIDENT-RESPONSE-PLAN.md es un ejercicio de ensamblaje disciplinado, no de invención — la prueba de que las siete lecciones anteriores, juntas, ya contienen todo lo que este documento necesita.


Paso 2 — El documento completo

En la raíz de andes-cargo-infra/, crea INCIDENT-RESPONSE-PLAN.md:

# INCIDENT-RESPONSE-PLAN.md — process-shipment-manifest Incident Response Framework

**Status:** Accepted · **Governs:** Modules 6 through 8 of `sre-and-incident-response-guide`
**Source:** Module 5, lessons 2-7 (the incident lifecycle, severity levels, roles, the on-call
rotation)
**Related:** `SLO.md` (Module 2) defines the SLO and error budget this plan's severity matrix
measures against. `ALERTING-POLICY.md` (Module 4) defines the exact burn-rate tiers (Page fast
14.4x, Page slow 6.0x, Ticket 1.0x) this plan's severity matrix maps onto — cited here, never
redefined.

## Lifecycle

Every incident this plan governs moves through five stages (Module 5, lesson 2, citing Google
SRE's incident management guide and the SRE book's incident-management chapter): **Detection ->
Declaration -> Response -> Mitigation -> Resolution**. Module 6 operates the real Claude Code
`destroy` incident through all five stages, in order.

## Severity matrix

Maps directly onto the burn-rate tiers `ALERTING-POLICY.md` already built and drilled (Module 4,
lesson 8) — this plan adds no new alerting logic, only the human response each tier earns.

| Severity | Burn-rate tier (`ALERTING-POLICY.md`) | Budget if sustained | Response | Andes Cargo example |
|---|---|---|---|---|
| **SEV1 — Critical** | Page (fast), >= 14.4x — OR unrecoverable data loss, regardless of measured burn rate | 2% per hour (100% in 43.2 min at 1,000x) | Page on-call immediately. Incident Commander assigned. All hands as needed. | `Shipments` stops responding entirely — every `process-shipment-manifest` invocation fails (100% error rate = 1,000x burn rate; Module 4, lesson 2's own citation: a 1,000x burn rate "depletes budget in 43 minutes") |
| **SEV2 — Major** | Page (slow), >= 6.0x and < 14.4x | 5% per 6 hours | Page on-call. Response expected within the same shift. | A bad deploy exhausts both automatic retries on a meaningful share of manifest uploads, silently dropped — the exact pattern of `BAD_WEEK` (Module 2, lesson 7) |
| **SEV3 — Minor** | Ticket, >= 1.0x and < 6.0x | 10% per 3 days | Ticket filed. Triaged next business day. No page. | A traffic spike briefly throttles a handful of invocations against `ReservedConcurrentExecutions: 5`; all recover on automatic retry within seconds |
| **SEV4 — Low/cosmetic** | Below Ticket, < 1.0x — or not a bad event at all | Negligible | Logged only if the pattern repeats. No ticket, no page. | Shipment 4471's manifest takes 2 seconds longer to process during a brief S3 latency blip, completing in 4 seconds — well inside the 10-second `Timeout`, counted as a **good** event under `SLO.md`'s own SLI definition |

**When unsure which severity applies, default to the higher one** (Module 5, lesson 3, citing
PagerDuty's public incident-response documentation) — correcting a severity down after more
information arrives costs far less than correcting it up after minutes of silence.

## Roles

Three roles, never fewer than three people's worth of *responsibility* even when Andes Cargo's
small team means the same person sometimes wears two hats — but never both at once on the same
call (Module 5, lesson 4, citing `sre.google/resources/practices-and-processes/incident-
management-guide/`):

- **Incident Commander (IC)** — coordinates the overall response. Owns the incident document,
  the timeline, and every open question about who is doing what. Does not personally run
  mitigation commands.
- **Operations Lead (OL)** — the only person modifying `andes-cargo-infra/` during the incident
  (citing `sre.google/sre-book/managing-incidents/`: the Ops Lead is "the only group modifying
  the system during an incident"). Applies the runbook (Module 7), reports status back to the IC.
- **Communications Lead (CL)** — the point of contact for anyone not actively fixing the
  problem. Issues updates on a fixed cadence, translates technical state into plain language.

For a SEV3/SEV4, one person can reasonably hold all three roles. For a SEV1/SEV2, at minimum the
IC and OL must be different people — coordinating and executing at the same time is exactly the
failure mode this separation exists to prevent.

## On-call rotation

Generated by `oncall/schedule.py` (Module 5, lesson 7) — deterministic, no SaaS, no randomness.
First 8 weeks, starting the Monday this plan takes effect:

```text
Week  Starts      Primary   Secondary
1     2026-03-02  Ana       Bruno
2     2026-03-09  Bruno     Carla
3     2026-03-16  Carla     Diego
4     2026-03-23  Diego     Ana
5     2026-03-30  Ana       Bruno
6     2026-04-06  Bruno     Carla
7     2026-04-13  Carla     Diego
8     2026-04-20  Diego     Ana
```

The Secondary is always the Primary's successor in `ROSTER` — never the same person, always
predictable without consulting a calendar. Google SRE's own limit on on-call time (Module 1,
lesson 7: "no more than 25% can be spent on-call") governs this rotation's minimum size: four
people, each on primary one week in four, is 25% — the ceiling, not a comfortable margin under it.

## What this plan does not do

It does not replace the preventive controls `cloud-security-and-guardrails-guide` already built
(`conftest`, `prevent_destroy`) — this plan governs the response *after* something breaks, the
same boundary `RELIABILITY-CHARTER.md` (Module 1, Decision point 4) already drew for the error
budget itself. It does not staff Andes Cargo with real engineers — `ROSTER` is four example
names, not a real team. It does not select or configure any SaaS on-call tool (PagerDuty,
Opsgenie) — Module 5, lesson 6 names the real switching-cost risk of building directly inside
one, and this plan's own rotation logic is designed portable on purpose, so that risk never
materializes here.

## Alternatives considered

**Assign severity by gut feeling, case by case, instead of a fixed matrix.** Rejected: Module 5,
lesson 3 already showed the two symmetric failure modes of ungoverned severity — crying wolf on
every SEV1, or minimizing a real one — and `ALERTING-POLICY.md` already produces the exact
burn-rate number a fixed matrix needs. A matrix costs nothing to build twice over what already
exists.

**A single on-call person, no rotation, no secondary.** Rejected: no backup means a missed page
has no second line of defense, and one person absorbing 100% of on-call time triples Google SRE's
own 25% ceiling (Module 1, lesson 7) — an unsustainable design this plan explicitly avoids.

**Adopt a SaaS on-call platform now, instead of `schedule.py`.** Rejected, for now: Module 5,
lesson 6's citation on switching costs applies directly — adopting a platform before the team is
large enough to need its escalation/integration features risks exactly the lock-in `jamiemallers`
warned about on Hacker News. `schedule.py`'s plain, portable output can migrate into any real tool
later without rewriting the rotation logic itself.

## Consequences

Module 6 operates the real Claude Code `destroy` incident through the five-stage lifecycle this
plan defines, classifies it against this exact severity matrix, and assigns roles from this exact
list. Module 7's postmortem cites this plan directly. Module 8's capstone runs a new synthetic
incident through the same framework, unchanged, to confirm it works on a case nobody saw coming.

Paso 3 — Verificando el documento

wc -l INCIDENT-RESPONSE-PLAN.md
grep -c '^## ' INCIDENT-RESPONSE-PLAN.md
grep -c 'Rejected' INCIDENT-RESPONSE-PLAN.md

Qué esperar (literal — el contenido lo escribiste tú, la forma es determinista):

110
7
3

Ciento diez líneas, siete secciones (Lifecycle, Severity matrix, Roles, On-call rotation, What this plan does not do, Alternatives considered, Consequences), y tres alternativas explícitamente rechazadas —severidad por instinto, una sola persona de guardia, adoptar un SaaS ahora—, cada una con su razón, ninguna simplemente omitida sin explicación. El mismo patrón determinista de verificación que SLO.md y RELIABILITY-CHARTER.md ya establecieron.


Cómo leer este documento, seis meses después

La misma prueba que SLO.md y ALERTING-POLICY.md ya superaron: frente a este documento, sin preguntarle a nadie, un lector nuevo debería poder contestar cinco preguntas. ¿Qué pasa cuando algo se rompe, en qué orden? (sección Lifecycle, cinco etapas, cada una citada). ¿Qué tan grave es esto, con un número, no con una opinión? (Severity matrix, cada fila atada a un umbral exacto de burn rate). ¿Quién decide, y quién ejecuta, y son la misma persona? (Roles, con la regla explícita de que IC y OL nunca pueden serlo en un SEV1/SEV2). ¿Quién está de guardia esta semana, sin tener que preguntarle a nadie? (On-call rotation, verificable con el propio schedule.py). Y ¿qué es lo que este plan, deliberadamente, no resuelve? (What this plan does not do, tres límites nombrados con precisión). Si alguna de esas cinco preguntas exige releer una lección completa de este módulo, el documento no cumplió su función.


El cierre del Módulo 5

Con INCIDENT-RESPONSE-PLAN.md escrito, este módulo entrega exactamente lo que prometió en la lección 1: el marco completo de respuesta a incidentes, construido antes del caso, no durante él —ciclo de vida citado de Google SRE, severidad atada a la misma matemática de burn rate que ALERTING-POLICY.md ya probó, roles que separan quién decide de quién ejecuta, y una rotación de guardia real, determinista, corrida de verdad—. RELIABILITY-CHARTER.md puede actualizar su fila del Módulo 5 de Open a Resolved, citando este documento como evidencia. Entras al Módulo 6 con todo lo que necesitas ya decidido: cuando el incidente Claude Code se opere, cada pregunta de "¿y ahora qué hacemos?" ya tiene una respuesta escrita en este documento, esperando ser aplicada.


Errores comunes

Tratar INCIDENT-RESPONSE-PLAN.md como un documento que se completa una sola vez y nunca se revisa (repetido del mismo error ya nombrado con RELIABILITY-CHARTER.md, ahora con consecuencias directas sobre un documento operativo). Qué pasa: alguien asume que, una vez escrito este documento, la matriz de severidad y la rotación de guardia quedan fijas para siempre, sin ningún mecanismo de revisión. Cómo detectarlo: si tu plan de mantenimiento de este documento es "no tocarlo nunca más". Cómo corregirlo: el Módulo 8 de esta guía corre, a propósito, un incidente sintético nuevo contra este mismo marco, precisamente para confirmar que sigue funcionando — un plan de respuesta a incidentes real se revisa después de cada incidente real, con los action items que el postmortem del Módulo 7 produce, nunca se escribe una vez y se archiva.

Asumir que la sección "Roles" de este documento asigna personas específicas de Andes Cargo, en vez de definir la estructura de roles (de leer el documento como una lista de contactos, no como un marco). Qué pasa: alguien busca, en este documento, el nombre real de quién sería el Incident Commander de un incidente futuro específico. Cómo detectarlo: si esperas encontrar un nombre propio asignado permanentemente al rol de IC en algún lugar de este documento. Cómo corregirlo: la sección "What this plan does not do" es explícita — este documento define la estructura de roles (qué hace cada uno, y por qué deben separarse), no una asignación fija de personas a roles para siempre. El Módulo 6 es, específicamente, el que asigna estos roles a personas concretas para el incidente real que va a operar.

Copiar el documento de esta lección sin haber corrido oncall/schedule.py de verdad, confiando en que la tabla de rotación "seguramente es correcta" (repetido del mismo error ya nombrado en SLO.md y ALERTING-POLICY.md, Módulos 2 y 4). Qué pasa: alguien pega la sección "On-call rotation" de este documento sin haber ejecutado su propia copia de schedule.py en la lección 7. Cómo detectarlo: si no puedes reproducir, corriendo tu propio script, exactamente la misma tabla de ocho semanas citada aquí. Cómo corregirlo: cada fila de la tabla de rotación de este documento proviene de un script que tú mismo escribiste y ejecutaste en la lección 7 — antes de dar por bueno este documento, confirma que tu propia copia de oncall/schedule.py produce, línea por línea, la misma salida.


Ejercicios

Ejercicio 1 — Verifica la sección "Severity matrix" de este documento contra tu propio cálculo de la lección 5. Confirma que la fila de SEV2 (Page (slow), ≥ 6,0x y < 14,4x) corresponde a una tasa de error observada entre 0,60% y 1,44%, usando la fórmula tasa_de_error = burn_rate × 0,001.

Ver solución

6.0 × 0.001 = 0.006 (0,60%) en el extremo inferior, y 14.4 × 0.001 = 0.0144 (1,44%) en el extremo superior — coincide exactamente con el rango citado en la fila de SEV2 de este documento, y con la tabla completa de la lección 5. Este ejercicio confirma que la sección "Severity matrix" de INCIDENT-RESPONSE-PLAN.md es trazable hasta una fórmula ejecutable a mano, no una tabla escrita de memoria sin verificación.

Ejercicio 2 — Defiende la sección "Roles" frente a una objeción real. Un entrevistador técnico pregunta: "con solo cuatro personas en el equipo de Andes Cargo, ¿no es un desperdicio de tiempo definir formalmente tres roles distintos para cada incidente?". ¿Cómo respondes, usando el propio documento?

Ver solución

Una respuesta completa: "La sección Roles de este documento ya contesta eso directamente — para un SEV3 o SEV4, una sola persona puede sostener los tres roles sin problema, así que no hay ningún desperdicio en incidentes menores. La regla dura aplica solo a SEV1/SEV2, donde IC y OL deben ser personas distintas, precisamente porque coordinar y ejecutar al mismo tiempo, bajo presión real, es el mismo patrón que produjo el radio de explosión completo del incidente Claude Code: una sola entidad con permiso de decidir y ejecutar a la vez, sin ninguna segunda persona coordinando la decisión. No es que un equipo pequeño necesite más personas — es que, en los incidentes que de verdad importan, necesita que las personas que sí tiene no mezclen dos funciones que, mezcladas, ya demostraron ser peligrosas."

Ejercicio 3 — Explica por qué la sección "Alternatives considered" de este documento incluye "adoptar un SaaS ahora" como una opción explícitamente rechazada, en vez de simplemente no construir schedule.py y usar una herramienta comercial desde el principio.

Ver solución

Nombrar y rechazar explícitamente "adoptar un SaaS ahora" deja constancia de que la decisión de construir schedule.py fue deliberada, con una razón concreta citada (el riesgo de switching costs de la lección 6), no una limitación de presupuesto disfrazada de decisión técnica. Sin esa entrada, alguien podría asumir que Andes Cargo simplemente no tenía los recursos para pagar una herramienta comercial, y que la decisión cambiaría en cuanto el presupuesto lo permitiera. Al nombrarla y rechazarla con una razón —adoptar la plataforma antes de necesitar sus funciones reales de escalamiento arriesga exactamente el encierro que la cita de Hacker News describe—, el documento deja claro que la portabilidad fue el criterio, no el costo, y que la decisión podría revisarse legítimamente el día en que el equipo sí necesite esas funciones — pero siempre manteniendo la capa portable de schedule.py por debajo de cualquier herramienta que se adopte.


Resumen y siguiente paso

En este proyecto final del módulo escribiste INCIDENT-RESPONSE-PLAN.md: el ciclo de vida de cinco etapas (citado de Google SRE), la matriz de severidad completa (cada SEV atado a un umbral exacto de burn rate de ALERTING-POLICY.md), los tres roles que separan decidir de ejecutar (citados de Google SRE, con la regla dura de nunca fusionar IC y OL en un SEV1/SEV2), y las primeras ocho semanas de una rotación de guardia real, determinista, corrida con oncall/schedule.py. Verificaste el documento con la misma disciplina de todo este ecosistema: 110 líneas, 7 secciones, 3 alternativas rechazadas con evidencia, ninguna decisión sin justificación.

Antes de cerrar este módulo deberías poder: recitar las cinco etapas del ciclo de vida sin mirar el documento; clasificar cualquier escenario nuevo de Andes Cargo en una de las cuatro severidades, con la aritmética a la vista; y explicar, con la propia sección "Roles", por qué IC y OL nunca pueden ser la misma persona en un SEV1/SEV2.

Con esto, el Módulo 5 de sre-and-incident-response-guide queda completo: el marco humano de respuesta a incidentes, construido con la misma disciplina determinista que la matemática de SRE de los módulos anteriores. El Módulo 6 toma este documento, sin modificarlo, y lo aplica por primera vez a un incidente real: el terraform destroy de Claude Code que borró 2,5 años de datos de DataTalks.Club, operado de principio a fin a través de las cinco etapas, la matriz de severidad, y los roles que este módulo acaba de dejar terminados.

Recursos

  1. Este módulo, lecciones 2 a 7 — la fuente directa de cada sección de este documento.
  2. Este mismo repositorio, Módulo 1, lección 8 (08-project-andes-cargos-reliability-charter.md) — RELIABILITY-CHARTER.md, la fila que este documento resuelve.
  3. Este mismo repositorio, Módulo 2, lección 8 y Módulo 4, lección 8 — SLO.md y ALERTING-POLICY.md, los dos documentos que este documento cita en vez de repetir.
  4. Google SRE — Incident Management Guide y Google SRE Book — Managing Incidents — las fuentes del ciclo de vida y los roles de este documento.