Módulo 8: Capstone The Andes Cargo Reliability Package

2. Repaso de arquitectura: la máquina de confiabilidad completa

Descripción

Antes de introducir cualquier dato nuevo, esta lección hace algo que ninguna lección anterior de esta guía tuvo motivo de hacer: mirar andes-cargo-infra/ completo, de una sola vez, como lo haría alguien que nunca vio los siete módulos anteriores y tiene que entender, en minutos, qué construye cada archivo y cómo se conecta con los demás. Es un repaso, no una lección nueva —cada pieza que aparece aquí ya está construida, ya está verificada, y ya tiene su propia lección de origen citada—.

Conexión con el módulo

Esta lección verifica el inventario completo con un comando real, no con una lista escrita de memoria: find andes-cargo-infra -type f | sort sobre el repositorio que construiste a lo largo de los Módulos 1 a 7 debería devolver, exactamente, los archivos que esta lección nombra. La lección 3 introduce el único archivo genuinamente nuevo de todo el módulo sobre esta misma estructura, sin modificar ninguno de los que ya existen.


Paso 1 — El inventario completo, verificado

find andes-cargo-infra -type f \
  \( -name "*.md" -o -name "*.py" -o -name "*.tf" -o -name "*.yml" -o -name "*.json" \) \
  | sort

Qué esperar (literal — la estructura la construiste tú, archivo por archivo, en los Módulos 1 a 7; este comando solo la confirma):

andes-cargo-infra/ALERTING-POLICY.md
andes-cargo-infra/INCIDENT-RESPONSE-PLAN.md
andes-cargo-infra/RELIABILITY-CHARTER.md
andes-cargo-infra/RELIABILITY-POSTMORTEM-PACKAGE.md
andes-cargo-infra/SLO.md
andes-cargo-infra/incidents/2026-02-26-claude-code-destroy/POSTMORTEM.md
andes-cargo-infra/incidents/2026-02-26-claude-code-destroy/TIMELINE.md
andes-cargo-infra/observability.tf
andes-cargo-infra/observability/alert_rules.yml
andes-cargo-infra/observability/alert_webhook_receiver.py
andes-cargo-infra/observability/alertmanager.yml
andes-cargo-infra/observability/burn_rate_exporter.py
andes-cargo-infra/observability/docker-compose.yml
andes-cargo-infra/observability/instrument_manifest_flow.py
andes-cargo-infra/observability/manifest-log-events.json
andes-cargo-infra/observability/prometheus.yml
andes-cargo-infra/observability/upload_manifest_batch.py
andes-cargo-infra/oncall/schedule.py
andes-cargo-infra/runbooks/manifest-processor-error-rate.md
andes-cargo-infra/scripts/burn_rate_evaluator.py
andes-cargo-infra/scripts/error_budget_calculator.py

Veintiún archivos, ninguno de negocio —nada de main.tf, nada del propio process-shipment-manifest, nada del bucket ni de Shipments—. Cada uno de estos veintiún archivos es, exclusivamente, la capa de confiabilidad que esta guía agregó encima de lo que las seis guías hermanas ya construyeron: cinco documentos de portafolio, dos scripts de matemática de SRE, un directorio de observabilidad con nueve piezas, un archivo de Terraform, un generador de guardia, un runbook, y dos documentos del incidente ya operado.


Paso 2 — La cadena completa, de la medición a la operación

   LA MAQUINA DE CONFIABILIDAD DE ANDES CARGO -- SIETE MODULOS, UNA CADENA

   ┌─────────────────────────────────────────────────────────────────────┐
   │  M2 -- QUE MEDIR                                                     │
   │  SLO.md: SLI = eventos buenos / eventos validos de                   │
   │  process-shipment-manifest. SLO = 99.9% mensual.                     │
   │  scripts/error_budget_calculator.py: la formula, ejecutable.         │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │ el SLI necesita datos reales
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M3 -- DE DONDE SALE EL DATO REAL                                    │
   │  observability/upload_manifest_batch.py sube manifiestos via S3      │
   │  (el trigger real, nunca lambda invoke) -> CloudWatch Invocations/   │
   │  Errors -> logs reales (jq) -> trazas reales (Jaeger, OTel)          │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │ el dato real alimenta la alerta
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M4 -- CUANDO SUENA LA ALARMA                                        │
   │  ALERTING-POLICY.md: burn rate, no umbral estatico. Tres motores:    │
   │  scripts/burn_rate_evaluator.py (prototipo Python) + Prometheus/     │
   │  Alertmanager (observability/alert_rules.yml, burn_rate_exporter.py) │
   │  + CloudWatch (observability.tf, metric math real)                  │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │ la alerta dispara -> alguien responde
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M5 -- QUIEN RESPONDE, CON QUE REGLAS                                │
   │  INCIDENT-RESPONSE-PLAN.md: ciclo de vida de 5 etapas, matriz de     │
   │  severidad atada a los umbrales de burn rate de M4, tres roles       │
   │  (IC/OL/CL), oncall/schedule.py -- rotacion determinista real        │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │ el marco ya existe -> se opera contra un caso
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M6 -- EL INCIDENTE OPERADO (caso 1: Claude Code destroy)            │
   │  incidents/2026-02-26-claude-code-destroy/TIMELINE.md: las 5 etapas  │
   │  corridas contra hechos reales verificados, SEV1 por criterio        │
   │  independiente de perdida de datos (sin burn rate medible)           │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │ el incidente termina -> se aprende, sin culpa
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M7 -- CIERRE SIN CULPA + LA HERRAMIENTA PARA LA PROXIMA VEZ         │
   │  incidents/.../POSTMORTEM.md: 4 causas raiz, ninguna una persona.    │
   │  runbooks/manifest-processor-error-rate.md: el primer runbook real   │
   │  -- lo que alguien de guardia sigue la PROXIMA vez que suene esto    │
   └─────────────────────────────┬─────────────────────────────────────┘
                                  │
                                  ▼
   ┌─────────────────────────────────────────────────────────────────────┐
   │  M8 -- ESTE MODULO: LA MISMA CADENA, SIN CAMBIOS, CONTRA UN CASO     │
   │  NUEVO (caso 2: incidente sintetico determinista, leccion 3)         │
   └─────────────────────────────────────────────────────────────────────┘

Fíjate en la propiedad central de este diagrama: cada flecha apunta hacia adelante exactamente una vez. SLO.md no depende de INCIDENT-RESPONSE-PLAN.md; INCIDENT-RESPONSE-PLAN.md sí depende de ALERTING-POLICY.md (cita sus umbrales de burn rate sin repetirlos); TIMELINE.md depende de INCIDENT-RESPONSE-PLAN.md (aplica su ciclo de vida sin redefinirlo); POSTMORTEM.md depende de TIMELINE.md (cita sus hechos sin repetirlos). Es la misma disciplina de una única fuente de verdad que cada proyecto de esta guía ya aplicó por separado — vista aquí, por primera vez, como una cadena completa de siete eslabones.


Paso 3 — Los tres motores de alerta, lado a lado, otra vez

La lección 8 del Módulo 4 ya probó esto una vez, con un simulacro forzado sobre dos escenarios fijos (bad_week, normal). Vale la pena recordarlo antes de introducir un tercer escenario en la lección 3 de este módulo:

MotorDónde viveCobertura de ventanasCosto operativo
scripts/burn_rate_evaluator.pyMódulo 4, lección 3Multi-ventana, las 3 severidades completasNinguno — Python puro
Prometheus + Alertmanagerobservability/alert_rules.ymlMulti-ventana real, vía and ignoring(window)Docker, un exportador que mantener
CloudWatch Alarmobservability.tfUna sola ventana (limitación real, declarada)Ninguno — nativo de AWS, sin exportador

Los tres implementan la misma fórmula (burn_rate = tasa_de_error_observada / tasa_de_error_permitida, con tasa_de_error_permitida = 0.001 de SLO.md), con sintaxis y cobertura distintas. La lección 4 de este módulo va a correr los tres, otra vez, contra un tercer escenario que ninguno de los tres vio antes.


Paso 4 — Qué es negocio y qué es confiabilidad, en el mismo repositorio

Un detalle que vale la pena dejar explícito antes de seguir: andes-cargo-infra/ no es exclusivamente de esta guía. Contiene el bucket andes-cargo-shipment-docs, la tabla Shipments, el Lambda process-shipment-manifest, los roles IAM, el pipeline de .github/workflows/, el security gate de conftest/Trivy/cosign, y el cost gate de Infracost — todo heredado íntegro de las seis guías hermanas, sin un solo recurso reescrito. Esta guía nunca tocó ese código. Los veintiún archivos del Paso 1 son, exclusivamente, la capa que se agrega encima: mide qué tan bien funciona lo que ya existe, y qué hacer cuando no funciona bien. Ningún archivo de esta lista modifica el comportamiento de process-shipment-manifest — todos lo observan, lo alertan, o documentan la respuesta cuando algo con él sale mal.

   DOS CAPAS, UN REPOSITORIO

   CAPA DE NEGOCIO (6 guias hermanas)        CAPA DE CONFIABILIDAD (esta guia)
   ────────────────────────────────           ─────────────────────────────────
   main.tf, S3, Shipments, Lambda,             SLO.md, ALERTING-POLICY.md,
   IAM, .github/workflows/,                    INCIDENT-RESPONSE-PLAN.md,
   conftest, cosign, Infracost                 observability/, oncall/,
                                                incidents/, runbooks/
        │                                              │
        ▼                                              ▼
   "¿El sistema hace lo que                    "¿Sabemos si el sistema sigue
    debe hacer?"                                haciendolo bien, y que hacemos
                                                 si deja de hacerlo?"

Errores comunes

Tratar esta lección como si necesitara reconstruir el contenido de las siete piezas heredadas, en vez de solo citarlas (repetido del mismo error de ensamblaje disciplinado que cada proyecto de esta guía ya evitó). Qué pasa: alguien, al escribir su propio resumen de esta lección, copia párrafos completos de SLO.md o INCIDENT-RESPONSE-PLAN.md, en vez de referenciarlos por ruta. Cómo detectarlo: si tu versión de esta lección duplica contenido textual de un documento ya escrito en un módulo anterior. Cómo corregirlo: esta lección es, deliberadamente, un mapa — cada casilla del diagrama del Paso 2 apunta a un archivo y a una lección de origen; el trabajo de esta lección es mostrar cómo se conectan, no repetir lo que cada uno ya dice por su cuenta.

Confundir "la máquina completa" con "todos los archivos de andes-cargo-infra/", incluyendo los de negocio heredados de las seis guías hermanas (de perder la frontera del Paso 4). Qué pasa: alguien, al describir esta guía en una entrevista, incluye el Lambda, el bucket o el pipeline de CI/CD como si esta guía los hubiera construido. Cómo detectarlo: si tu inventario de "lo que esta guía construyó" incluye algún archivo que no aparece en la lista de veintiuno del Paso 1. Cómo corregirlo: la frontera del Paso 4 es exacta — esta guía agrega la capa de confiabilidad, nunca toca ni reescribe la capa de negocio. Un entrevistador que pregunte "¿construiste el Lambda?" merece un "no, lo heredé de aws-serverless-and-containers-guide — lo que construí es cómo se mide y se opera cuando algo le sale mal", no una atribución incorrecta.

Asumir que el orden de las flechas del diagrama del Paso 2 es solo una forma bonita de presentarlo, sin ninguna consecuencia real si se lee en otro orden (de subestimar por qué la dirección importa). Qué pasa: alguien intenta explicar INCIDENT-RESPONSE-PLAN.md sin haber entendido primero ALERTING-POLICY.md, y termina sin poder justificar de dónde salen los umbrales exactos de su matriz de severidad. Cómo detectarlo: si, al explicar cualquier pieza de la cadena, tienes que "adivinar" un número en vez de señalar de qué pieza anterior viene. Cómo corregirlo: el orden del diagrama es una dependencia real, no una preferencia de presentación — cada eslabón cita al anterior porque literalmente lo necesita para justificarse (la matriz de severidad no tendría ningún umbral que citar sin ALERTING-POLICY.md; ALERTING-POLICY.md no tendría ningún umbral que evaluar sin SLO.md). Entender la cadena en orden es entender por qué cada documento existe, no solo qué dice.


Ejercicios

Ejercicio 1 — Sin mirar el Paso 1, escribe de memoria los cinco documentos de portafolio (.md, en la raíz de andes-cargo-infra/, sin contar los que viven dentro de incidents/ o runbooks/) que esta guía construyó hasta el Módulo 7. Verifica tu respuesta contra el Paso 1.

Ver solución

RELIABILITY-CHARTER.md (Módulo 1), SLO.md (Módulo 2), ALERTING-POLICY.md (Módulo 4), INCIDENT-RESPONSE-PLAN.md (Módulo 5), RELIABILITY-POSTMORTEM-PACKAGE.md (Módulo 7) — cinco documentos, cada uno el proyecto final de su propio módulo, cada uno citando al anterior en vez de repetirlo. Si tu lista tuvo un documento de más o de menos, revisa contra el Paso 1: los dos documentos del incidente (TIMELINE.md, POSTMORTEM.md) viven dentro de incidents/2026-02-26-claude-code-destroy/, no en la raíz, y el runbook vive dentro de runbooks/ — ninguno de los tres cuenta como uno de los cinco "documentos de portafolio de la raíz".

Ejercicio 2 — Explica, usando el diagrama del Paso 2, por qué TIMELINE.md (Módulo 6) no podría haberse escrito antes de que INCIDENT-RESPONSE-PLAN.md (Módulo 5) existiera.

Ver solución

TIMELINE.md necesita, para tener sentido, un marco contra el cual clasificar el incidente: sin INCIDENT-RESPONSE-PLAN.md, no existiría ninguna matriz de severidad contra la cual decidir que el incidente Claude Code es SEV1, ningún conjunto de roles (IC/OL/CL) que asignar a personas concretas, y ningún ciclo de vida de cinco etapas contra el cual estructurar el documento. El Módulo 5 existe, deliberadamente, antes del Módulo 6 —la introducción del Módulo 5 ya lo dijo explícitamente: "el marco antes del caso"— precisamente para que operar el incidente real sea aplicar un marco ya terminado, no improvisar uno a medida que el incidente se analiza.

Ejercicio 3 — Un compañero argumenta que el diagrama de "dos capas" del Paso 4 es innecesario, porque "al final todo vive en el mismo repositorio de Terraform, así que la distinción no importa en la práctica". ¿Estás de acuerdo?

Ver solución

En desacuerdo. Que ambas capas vivan en el mismo repositorio no borra una diferencia real de propósito y de propiedad: la capa de negocio responde "¿el sistema hace lo que debe hacer?" y la modifican las seis guías hermanas; la capa de confiabilidad responde "¿sabemos si sigue haciéndolo bien, y qué hacer si no?" y la modifica esta guía. Esta distinción importa en la práctica de forma muy concreta: si alguien necesita cambiar el esquema de Shipments, ese cambio pertenece a aws-serverless-and-containers-guide, no a esta guía; si alguien necesita ajustar el umbral de una alarma, ese cambio pertenece aquí, no a esa guía. Sin la distinción explícita, sería fácil que alguien intente "arreglar" un problema de confiabilidad reescribiendo el Lambda, cuando el cambio correcto vive en observability.tf o en el runbook — exactamente el tipo de confusión de capas que esta lección existe para prevenir.


Resumen y siguiente paso

Esta lección confirmó, con un comando real (find), el inventario completo de los veintiún archivos que esta guía construyó en los Módulos 1 a 7, y trazó la cadena completa de siete eslabones que los conecta: qué medir (M2) → de dónde sale el dato (M3) → cuándo suena la alarma (M4) → quién responde (M5) → el incidente operado (M6) → el cierre sin culpa y la herramienta para la próxima vez (M7). Confirmaste, con el diagrama de dos capas, la frontera exacta entre lo que esta guía construyó (la capa de confiabilidad) y lo que heredó sin tocar (la capa de negocio de las seis guías hermanas).

Antes de avanzar deberías poder: recitar los siete eslabones de la cadena en orden, con el archivo exacto que representa cada uno; explicar por qué el orden de esa cadena refleja dependencias reales, no solo una forma de presentarla; y defender la frontera entre capa de negocio y capa de confiabilidad frente a alguien que la considere irrelevante.

La lección 3 introduce el primer dato genuinamente nuevo de este módulo: un incidente sintético, fijo y determinista, que va a entrar por el mismo punto de siempre —el bucket real— y va a poner a prueba, por primera vez, si esta cadena completa reacciona sin que nadie la haya preparado para este caso específico.

Recursos

  1. Este mismo repositorio, Módulos 2, 4, 5, 6 y 7 completos — la fuente de cada pieza nombrada en el diagrama del Paso 2.
  2. Este mismo repositorio, Módulo 4, lección 8 (08-project-andes-cargos-alerting-policy.md) — el precedente directo del simulacro de tres motores que el Paso 3 de esta lección resume.
  3. Google SRE Book — Table of Contents — la fuente original de la disciplina completa que esta cadena de siete eslabones implementa.