> **MIGRATED:** SSOT now lives in `better-toolkits/toolkits/assurance-toolkit/skills/sre-alerting-incident-management/` + `references/liveness/protocol.md` y `references/governance/protocol.md`. This copy is a shim.
Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
SSkills DirectorySkills Directory
Is that skill safe to install?
Are you the author of Alerting Incident Management?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/chimeranext-alerting-incident-management)
> **MIGRATED:** SSOT now lives in `better-toolkits/toolkits/assurance-toolkit/skills/sre-alerting-incident-management/` + `references/liveness/protocol.md` y `references/governance/protocol.md`. This copy is a shim.
# 🚨 Skill: Alerting & Incident Management
## 📋 Metadata
| Atributo | Valor |
|----------|-------|
| **ID** | `sre-alerting-incident-management` |
| **Nivel** | 🔴 Avanzado |
| **Versión** | 1.0.0 |
| **Keywords** | `alerting`, `incident-management`, `pagerduty`, `opsgenie`, `oncall`, `runbooks`, `monitoring-as-code`, `gcp`, `opentofu`, `terraform-import`, `alert-policy` |
| **Referencia** | [Google SRE - On-Call](https://sre.google/workbook/on-call/), [PagerDuty](https://www.pagerduty.com/) |
## 🔑 Keywords para Invocación
- `alerting`
- `incident-management`
- `pagerduty`
- `opsgenie`
- `oncall`
- `runbooks`
- `incident-response`
- `monitoring-as-code`
- `alert-policy`
- `opentofu`
- `@skill:alerting`
### Ejemplos de Prompts
```
Implementa alerting con PagerDuty y runbooks
```
```
Configura incident management y on-call rotation
```
```
Configura runbooks y on-call rotation
```
```
@skill:alerting - Sistema completo de alertas e incidentes
```
```
Adoptar en OpenTofu las alert policies que se crearon a mano en la consola de GCP
```
```
¿Cómo pruebo que esta alerta puede ponerse en rojo?
```
## 📖 Descripción
Alerting efectivo y gestión de incidentes es crítico para mantener servicios confiables. Este skill cubre diseño de alertas efectivas, on-call rotations, runbooks, e incident response workflows.
### ✅ Cuándo Usar Este Skill
- Servicios en producción
- Equipos on-call
- SLAs críticos
- Sistemas distribuidos
- Incidentes frecuentes
- Compliance requirements
### ❌ Cuándo NO Usar Este Skill
- Desarrollo local solo
- Servicios no críticos sin SLA
- Equipos sin capacidad on-call
## 🏗️ Arquitectura de Alerting
```
┌──────────────┐
│ Prometheus │
│ (Metrics) │
└──────┬───────┘
│
│ Alert Rules
│
┌──────▼───────┐
│ Alertmanager │
└──────┬───────┘
│
├──────────┬──────────┬──────────┐
│ │ │ │
┌──────▼───┐ ┌───▼────┐ ┌───▼────┐ ┌──▼─────┐
│ PagerDuty│ │ Slack │ │ Email │ │ Webhook│
└──────────┘ └────────┘ └────────┘ └────────┘
│
│
┌──────▼──────────────┐
│ On-Call Engineer │
│ (Incident Response) │
└─────────────────────┘
```
## 💻 Implementación
### 1. Alertmanager Configuration
```yaml
# alertmanager/alertmanager.yml
global:
resolve_timeout: 5m
slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'default'
routes:
# Critical alerts → PagerDuty immediately
- match:
severity: critical
receiver: 'pagerduty-critical'
continue: true
# Warning alerts → Slack only
- match:
severity: warning
receiver: 'slack-warnings'
repeat_interval: 24h
# Service-specific routes
- match:
service: payment-service
receiver: 'payment-team'
group_wait: 5s
inhibit_rules:
# Inhibit warning if critical is firing
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'cluster', 'service']
receivers:
- name: 'default'
slack_configs:
- channel: '#alerts'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty-critical'
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
description: '{{ .GroupLabels.alertname }}: {{ .GroupLabels.service }}'
severity: 'critical'
client: 'Prometheus'
client_url: 'http://prometheus:9090'
- name: 'slack-warnings'
slack_configs:
- channel: '#alerts-warnings'
title: 'Warning: {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'payment-team'
pagerduty_configs:
- service_key: 'PAYMENT_TEAM_KEY'
description: 'Payment Service Alert'
slack_configs:
- channel: '#payment-team'
```
### 2. Alert Rules (Prometheus)
```yaml
# prometheus/alerts/service-alerts.yml
groups:
- name: service_alerts
interval: 30s
rules:
# Error Budget Exhaustion
- alert: ErrorBudgetExhaustion
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
) > 0.001
and
(
sum_over_time(
(
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
)[28d:]
) > 0.001
)
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: "Error budget exhausted for {{ $labels.service }}"
description: |
Service {{ $labels.service }} has exceeded error budget threshold.
Current error rate: {{ $value | humanizePercentage }}
Runbook: https://runbooks.example.com/error-budget
# High Latency
- alert: HighLatencyP99
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 1.0
for: 10m
labels:
severity: warning
annotations:
summary: "High P99 latency in {{ $labels.service }}"
description: "P99 latency is {{ $value }}s (threshold: 1s)"
runbook: https://runbooks.example.com/high-latency
# Service Down
- alert: ServiceDown
expr: up{job=~"app-.*"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Service {{ $labels.job }} is down"
description: "Service has been unreachable for more than 2 minutes"
runbook: https://runbooks.example.com/service-down
# High Memory Usage
- alert: HighMemoryUsage
expr: |
(
container_memory_usage_bytes{pod=~".+"}
/
container_spec_memory_limit_bytes{pod=~".+"}
) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage in {{ $labels.pod }}"
description: "Memory usage is {{ $value | humanizePercentage }}"
runbook: https://runbooks.example.com/high-memory
# Disk Space
- alert: DiskSpaceLow
expr: |
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Low disk space on {{ $labels.instance }}"
description: "Only {{ $value | humanizePercentage }} disk space remaining"
# CPU Throttling
- alert: CPUThrottling
expr: |
rate(container_cpu_cfs_throttled_seconds_total[5m]) > 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "CPU throttling detected in {{ $labels.pod }}"
description: "Container is being CPU throttled"
# Connection Pool Exhaustion
- alert: ConnectionPoolExhaustion
expr: |
(
db_connections_active{service=~".+"}
/
db_connections_max{service=~".+"}
) > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "Connection pool near exhaustion in {{ $labels.service }}"
description: "{{ $value | humanizePercentage }} of connections in use"
```
### 3. Runbook Template
```markdown
# Runbook: High Error Rate
## Alert Name
`HighErrorRate`
## Severity
Critical
## Description
Service error rate exceeds threshold (5% for 5 minutes)
## Symptoms
- High HTTP 5xx response rate
- User complaints
- Error logs increasing
## Immediate Actions
1. **Acknowledge Alert**
- Acknowledge in PagerDuty/OpsGenie
- Notify team in Slack
2. **Check Service Health**
```bash
kubectl get pods -l app=service-name
kubectl logs -l app=service-name --tail=100
```
3. **Check Metrics**
- Grafana dashboard: `/d/service-overview`
- Error rate graph
- Latency graphs
4. **Identify Root Cause**
- Check recent deployments
- Review error logs
- Check dependencies (DB, APIs)
## Resolution Steps
### If caused by code deployment:
```bash
# Rollback deployment
kubectl rollout undo deployment/service-name
```
### If caused by resource exhaustion:
```bash
# Scale up
kubectl scale deployment/service-name --replicas=5
```
### If caused by dependency failure:
1. Check dependency service status
2. Implement circuit breaker
3. Enable fallback mechanisms
## Post-Incident
- Document in incident log
- Update runbook if needed
## Escalation
- If not resolved in 15 min → Escalate to senior engineer
- If not resolved in 30 min → Escalate to engineering manager
- If service completely down → Escalate to CTO
```
### 4. On-Call Rotation (PagerDuty)
```yaml
# pagerduty/escalation-policies.yml
escalation_policies:
- name: "Primary On-Call"
description: "Primary escalation for production services"
num_loops: 3
escalation_rules:
- escalation_delay_in_minutes: 0
targets:
- type: "user"
id: "PXXXXXXXX" # Primary on-call
- escalation_delay_in_minutes: 15
targets:
- type: "user"
id: "PYYYYYYYY" # Secondary on-call
- escalation_delay_in_minutes: 30
targets:
- type: "schedule"
id: "PZZZZZZZZ" # Manager on-call
- name: "Critical Alerts Only"
escalation_rules:
- escalation_delay_in_minutes: 0
targets:
- type: "user_reference"
id: "PXXXXXXXX"
- escalation_delay_in_minutes: 10
targets:
- type: "escalation_policy_reference"
id: "EPXXXXXXX" # Manager escalation
schedules:
- name: "Primary On-Call Schedule"
time_zone: "America/New_York"
layers:
- name: "Layer 1"
start: "2024-01-01T00:00:00"
rotation_virtual_start: "2024-01-01T00:00:00"
rotation_turn_length_seconds: 604800 # 1 week
users:
- user_id: "PXXXXXXXX"
- user_id: "PYYYYYYYY"
- user_id: "PZZZZZZZZ"
restrictions:
- type: "daily_restriction"
start_time_of_day: "09:00:00"
duration_seconds: 32400 # 9 hours
```
### 5. Incident Response Workflow
```python
# incident_response/workflow.py
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional
from enum import Enum
class IncidentSeverity(Enum):
SEV1 = "critical" # Service down
SEV2 = "high" # Major degradation
SEV3 = "medium" # Minor issues
SEV4 = "low" # Informational
@dataclass
class Incident:
id: str
title: str
severity: IncidentSeverity
status: str # open, investigating, mitigated, resolved
created_at: datetime
resolved_at: Optional[datetime]
assigned_to: str
affected_services: List[str]
description: str
root_cause: Optional[str] = None
resolution: Optional[str] = None
class IncidentResponseWorkflow:
def __init__(self):
self.incidents = []
def create_incident(
self,
title: str,
severity: IncidentSeverity,
affected_services: List[str],
description: str
) -> Incident:
incident = Incident(
id=f"INC-{datetime.now().strftime('%Y%m%d-%H%M%S')}",
title=title,
severity=severity,
status="open",
created_at=datetime.now(),
resolved_at=None,
assigned_to=self._assign_oncall(),
affected_services=affected_services,
description=description
)
self.incidents.append(incident)
self._notify_team(incident)
self._create_incident_channel(incident)
return incident
def _assign_oncall(self) -> str:
# Logic to assign to current on-call engineer
return "engineer@example.com"
def _notify_team(self, incident: Incident):
# Send notifications via PagerDuty, Slack, etc.
pass
def _create_incident_channel(self, incident: Incident):
# Create dedicated Slack channel for incident
channel_name = f"incident-{incident.id.lower()}"
# Create channel logic
pass
def update_status(self, incident_id: str, status: str, notes: str):
incident = self._find_incident(incident_id)
if incident:
incident.status = status
if status == "resolved":
incident.resolved_at = datetime.now()
def _find_incident(self, incident_id: str) -> Optional[Incident]:
return next((i for i in self.incidents if i.id == incident_id), None)
```
### 6. Alert Fatigue Prevention
```yaml
# alertmanager/alert-fatigue-prevention.yml
# Strategies to prevent alert fatigue
# 1. Alert Grouping
route:
group_by: ['alertname', 'service']
group_wait: 10s # Wait before sending initial notification
group_interval: 5m # Wait before sending updated notification
repeat_interval: 12h # Minimum time between notifications
# 2. Alert Inhibition
inhibit_rules:
# Don't alert on warning if critical is firing
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['service']
# Don't alert on individual instance if all instances are down
- source_match:
alertname: 'AllInstancesDown'
target_match_re:
alertname: '.*InstanceDown'
# 3. Alert Suppression (Silence Rules)
# Use Alertmanager UI or API to create silences for known issues
# 4. Threshold Tuning
# Use error budgets and SLOs to set meaningful thresholds
# Example: Alert only when error budget is at risk
# 5. Alert Classification
# Only page on actionable alerts
# Use different channels for different severities
```
### 7. Alerting como código en GCP — y el discriminador que decide si se pudre
> **Todo lo de arriba sigue vigente.** Alertmanager, PagerDuty y los runbooks siguen siendo
> el camino sobre Prometheus/Kubernetes. Esta sección cubre el caso GCP + OpenTofu, donde
> las alertas viven en `google_monitoring_alert_policy` en vez de en reglas de Prometheus, y
> agrega la pregunta que ninguna de las dos configuraciones contesta sola: **¿esta alerta
> puede ponerse en rojo?**
#### 7.1 La regla que gobierna todo lo demás
> **Ningún control cuenta como desplegado hasta que se lo vio ponerse en rojo a propósito.**
No es una postura, es lo que la evidencia obliga. *Del registro
`openspec/changes/2026-08-02-observability-liveness-axis/design.md` en
`DojoCodingLabs/dojo-os @ origin/develop 18d4f7da3`, **no re-medido acá**:* tres alertas de
un servicio real se ejercitaron una vez y llevaban meses en silencio sin que nadie lo
notara.
| control | cómo se lo pone en rojo a propósito |
|---|---|
| sink de heartbeats | apagar la URL y confirmar que el check **falla**, no que sale vacío |
| liveness de un bucket | congelar el productor 48 h y confirmar que la alerta llega |
| synthetic monitor | romper un paso del flujo y **cronometrar** cuánto tarda en avisar |
La tercera columna importa: el tiempo de detección se **mide**, no se estima.
#### 7.2 Cableado y mudo: el modo de falla que un dashboard no muestra
Verificado en `dojo-infra-alerts @ origin/main 2304b6e`: el servicio expone ocho rutas
HTTP, todas funcionando, y su README documenta siete de ellas como disparadas por un
*"Cloud Scheduler tick"*.
**`cloudscheduler.googleapis.com` no estaba habilitada** — *medido contra GCP el
2026-08-02 por el registro citado arriba y **no re-corrido en este pase***. Los endpoints
existían, respondían, y **nada los disparaba**. Cuatro canales de Slack estaban cableados a
ese servicio y recibían cero.
El barrido original tuvo el cuidado de no sobre-afirmar, y conviene copiarlo: lo demostrado
fue *"cero requests en los últimos 30 días"*, **no** *"nunca corrió"*.
**Qué mirar, en este orden, antes de confiar en un canal de alertas:**
1. ¿La API que dispara el control está habilitada? (`gcloud services list --enabled`)
2. ¿Hay requests reales en la ventana? Cero requests es un hallazgo, no un blanco.
3. ¿El canal recibió algo alguna vez, y de este control en particular?
4. ¿Alguien vio este control en rojo, a propósito, con fecha?
#### 7.3 El caso más fino: la alerta que fabrica la apariencia de dueño
*Tomado del mismo registro y no re-medido en este pase:* **95 alertas** enrutadas a un
canal llevaban la nota `Routed to #alerts-sentry so Doji can triage`, y el agente nombrado
**no publicó ni una vez** en esa ventana. La nota le decía a todo humano que leyera el
canal que el ítem ya estaba atendido.
**Una alerta que nombra a un dueño no prueba que ese dueño exista.** Es la misma familia que
`resolve` en el camino de observabilidad: *nada puede nombrar lo que no existe*, y un
destinatario inventado es peor que ninguno porque suprime el reflejo de mirar.
#### 7.4 Monitoring as code: dos posiciones que parecen contradecirse
La industria sostiene las dos, y **las dos tienen razón sobre cosas distintas**:
| | qué llama "monitoring as code" | por qué se pudre, o por qué no |
|---|---|---|
| **IBM** | escribir a mano collectors, tracing, dashboards y reglas de alerta | es un **segundo artefacto** que nadie corre hasta que falla, y deriva del sistema que describe |
| **Checkly** | desplegar como monitor un spec E2E que ya existe | **no hay segundo artefacto**: CI ya lo corre en cada PR, así que se mantiene solo |
> **El discriminador es si el código de monitoreo es un segundo artefacto o el mismo.**
Por eso reusar los specs E2E ya existentes como synthetic monitors es seguro, y escribir
probes a mano por servicio no lo sería. La regla operativa: **si ya existe un programa que
contesta la pregunta, se corre; no se escribe el segundo.**
Y el propio checklist de autoevaluación de IBM incluye *"How many performance or
availability incidents are we **missing** per month or quarter?"* — hace la pregunta de
liveness y su producto no la contesta.
> *Las citas de IBM y Checkly están tomadas del plan de sesión `plan-observability-layer`;
> **no se re-consultaron las páginas originales en este pase**.*
#### 7.5 Adoptar alertas hechas a mano: el `import` block, no `tofu import`
Este es el paso que más se saltea y el que hace **activamente daño** si falta.
**Re-medido para este documento** sobre `DojoCodingLabs/dojo-infra-gitops`:
```bash
### ref: origin/main @ d6e59f0 | delta: none
git grep -lE 'google_monitoring|monitoring_alert_policy|uptime_check' origin/main -- tofu/
# → cero filas (exit 1)
git grep -ohE '^resource "([a-z_]+)"' origin/main -- tofu/ | sort | uniq -c | sort -rn
# → 18 declaraciones: compute, IAM, secrets, artifact registry. Ninguna de monitoring.
```
**Cero recursos `google_monitoring_*` en todo el árbol de OpenTofu.** Cada uptime check,
cada política de alerta y los dos canales de notificación se habían creado a mano en la
consola de GCP. El costo no fue hipotético: **cuatro de los seis checks
llevaban la string literal `--display-name=` dentro de su nombre visible** —la huella de un
script pasando el flag por una capa extra de comillas— y nadie lo notó durante meses,
**porque no había diff que leer**.
**Y declarar los recursos sin importarlos duplica el tablero, en silencio:**
```hcl
# tofu/monitoring-imports.tf — dojo-infra-gitops PR #27
#
# SIN ESTE ARCHIVO EL CAMBIO ES ACTIVAMENTE DAÑINO. `monitoring.tf` declara recursos que
# YA EXISTEN; sin un `import` que ate cada declaración al objeto vivo, `apply` crea un
# SEGUNDO conjunto al lado del de la consola: doce uptime checks donde van seis, cada par
# sondeando el mismo host, y dos políticas de alerta por incidente. Nada da error. El
# tablero simplemente se duplica, y el duplicado que nadie declaró es el que conserva el
# camino viejo y equivocado.
import {
provider = google.monitoring
to = google_monitoring_uptime_check_config.marketing_site_prod
id = "projects/<proj>/uptimeCheckConfigs/display-name-production-...-RTCiHItDixI"
}
```
**Bloques `import` en vez de invocaciones `tofu import`, a propósito:** la atadura queda
revisable en el diff y re-corrible por cualquiera, en vez de vivir en el historial de shell
de quien fue primero.
**Tres trampas concretas del provider de GCP.** *Las tres están documentadas en el cuerpo
de `dojo-infra-gitops` PR #27, que sí se leyó (`gh pr diff 27`); los planes que las
revelaron **no se re-corrieron acá**:*
- **`provider` Y `project`, en cada recurso y en cada `import`.** Un primer intento usó solo
`project =` sin alias, razonando que un alias es para credenciales distintas. `tofu plan`
lo refutó: el provider **no lee `project` de un ID de import calificado**, así que los
doce recursos entraron al state como el proyecto equivocado — y `project` es ForceNew. El
plan volvió `12 to import, 14 to add, 0 to change, 16 to destroy`: una "adopción" que
borra todo lo que adopta.
- **El ID de un uptime check es inmutable y se deriva slugificando el nombre al crearlo.**
Renombrar el check no lo limpia; solo recrearlo, y recrearlo tira el historial de uptime y
huerfaniza su política de alerta. El ID feo se queda; **lo que se arregla es el nombre que
un humano lee a las 03:00**.
- **Un canal `webhook_tokenauth` guarda su endpoint en `labels.url`, y para un webhook de
Slack esa URL ES la credencial.** El provider ofrece `sensitive_labels` para
`auth_token` / `password` / `service_key` y **no** para `url`, así que declarar el canal
como recurso significa commitear un bearer vivo. Se **leen** por display name en vez de
declararse: la búsqueda es exacta, no necesita secreto, y las políticas igual pueden
referenciarlos.
#### 7.6 Un veredicto de alerta también tiene tres estados
`success` contesta hoy dos preguntas distintas: *"verifiqué y estaba bien"* y *"no miré"*.
Nada aguas abajo las distingue.
| verdicto | significa |
|---|---|
| `pass` | se verificó y está bien |
| `fail` | se verificó y está mal |
| `unverifiable` | **no se pudo determinar** — nunca es sinónimo de ninguno de los otros dos |
El tercero se escribe **con la palabra completa**, nunca con un símbolo: un vocabulario de
tilde-o-cruz es lo que colapsa tres estados en dos en la cabeza de quien lee, y la terminal
es donde ese colapso pasa primero.
```js
// scripts/receipt.mjs — dojo-os PR #4309. Tres códigos de salida distintos.
assert.equal(exitCodeFor(PASS), 0);
assert.equal(exitCodeFor(FAIL), 1);
assert.equal(exitCodeFor(UNVERIFIABLE), 2);
// El punto entero: quien testea `code === 0` no debe poder leer "no pude saber" como "bien".
assert.notEqual(exitCodeFor(UNVERIFIABLE), exitCodeFor(PASS));
// Y no al revés tampoco: reportar una falla que no observamos es como una alerta se gana
// la reputación que termina en que alguien la desactiva.
assert.notEqual(exitCodeFor(UNVERIFIABLE), exitCodeFor(FAIL));
```
## 🎯 Mejores Prácticas
### 1. Alert Design
✅ **DO:**
- Alert on symptoms, not causes
- Make alerts actionable
- Include runbook links
- Use appropriate severity levels
- Test alerts regularly
❌ **DON'T:**
- Alert on every metric
- Create alerts that require investigation to understand
- Alert on things you can't fix
- Duplicate alerts across systems
### 2. On-Call
✅ **DO:**
- Maintain clear rotation schedules
- Provide context in handoffs
- Limit on-call duration (max 1 week)
- Compensate on-call time
- Track on-call load
❌ **DON'T:**
- Have people on-call 24/7
- Make on-call mandatory without compensation
- Skip handoffs between rotations
### 3. Incident Response
✅ **DO:**
- Follow runbooks
- Communicate frequently
- Document decisions
- Implement action items
❌ **DON'T:**
- Skip incident documentation
- Point fingers
- Ignore post-mortem action items
## 🚨 Troubleshooting
### Too Many Alerts
1. Review alert rules
2. Increase thresholds where appropriate
3. Implement better grouping
4. Use alert inhibition
### Alerts Not Firing
1. Check Prometheus query syntax
2. Verify alert rule evaluation
3. Check Alertmanager configuration
4. Verify notification channel configs
### On-Call Burnout
1. Review alert volume
2. Reduce non-actionable alerts
3. Improve runbooks
4. Rotate more frequently
## 📚 Recursos Adicionales
- [PagerDuty Incident Response](https://response.pagerduty.com/)
- [Google SRE - On-Call Handbook](https://sre.google/workbook/on-call/)
- [Incident Response Guide](https://response.pagerduty.com/)
---
**Versión:** 1.0.0
**Última actualización:** Diciembre 2025
**Total líneas:** 1,100+