Testland
Browse all skills & agents

dr-drill-runner

The full DR-drill discipline for one service: author the runbook (per-tier RTO + RPO), pre-drill checklist (data sync state, alert silencing, customer comms), drill workflow (announce, fail-over, verify, fail-back) with timestamps, the supervised run protocol (refuse without declared RTO/RPO or against production, RTO/RPO monitoring cadence, abort-on-breach), and an auditor-ready post-drill report. Backup-integrity verification (SHA-256 + signature, restore spot checks, cross-region replication, retention, key recovery) and restore-time / RTO measurement (TTF segments, PITR latency, parallel-restore tuning, trend tracking) are worked in references. Per Google Cloud DR planning guide; covers cold / warm / hot standby tier-specific patterns. Use when a scheduled or post-incident failover drill for one service is being planned, executed, or written up, or when a new tier-1 service ships without a drill defined.

Install with skills.sh (any agent)

npx skills add testland/qa --skill dr-drill-runner
View source

dr-drill-runner

Per the Google Cloud DR planning guide (opens in new window), DR planning requires "end-to-end recovery design addressing backup, restoration, and cleanup procedures." Drills test that the procedure works AND that the team can run it. Both surface different failures.

When to use

  • Quarterly DR drill (mandatory in compliance-heavy industries: banking, healthcare, defense).
  • After a region-failover incident: rerun the drill with the lessons learned.
  • New service onboarding: every new tier-1 service ships with its drill defined.

Step 1 - Define RTO + RPO per service tier

Per the Google Cloud DR planning guide (opens in new window):

MetricDefinition
RTOMaximum acceptable length of time the application can be offline
RPOMaximum acceptable data loss (time window)
TierExample RTOExample RPOPattern
1 (revenue-critical)< 15 min< 1 minHot standby (active-active)
2 (customer-impacting)< 4 hr< 1 hrWarm standby
3 (internal)< 24 hr< 24 hrCold (rebuild from backup)

Document per service in a service catalog; drills enforce the contract.

Step 2 - DR-pattern tier per service

Per the Google Cloud DR planning guide (opens in new window):

  • Cold: Minimal preparation; recovery requires external intervention and extended downtime.
  • Warm: Basic readiness with resources available; recovery stops normal ops temporarily.
  • Hot: Continuous operation with built-in redundancy; minimal interruption.

Drill expectations differ:

  • Cold: Test bring-up from backup (restore-time tests - references/restore-time.md).
  • Warm: Test failover automation + warm-up time.
  • Hot: Test traffic redirection + sticky-session impact.

Step 3 - Pre-drill checklist

## Pre-Drill Checklist - `<service>` `<date>`

- [ ] Drill window scheduled (low-traffic; aligned with
      customer-comm window)
- [ ] Drill scope decided (region, single service, full app)
- [ ] Replication lag confirmed within RPO at T-30 min
- [ ] Monitoring alerts SILENCED for expected failure indicators
      (alert routing redirected to drill channel)
- [ ] On-call notified (avoid duplicate paging during drill)
- [ ] Customer comms sent if customer-impacting drill
- [ ] Rollback path documented (what triggers abort?)
- [ ] Drill commander assigned (owns go/no-go calls)
- [ ] Postmortem time scheduled (within 48hr of drill end)

Skipping the pre-drill = drills become incidents.

Step 4 - Drill workflow

## Drill Workflow

### T-0: Announce
- Post in #drill-channel; confirm all participants ready.
- Drill commander gives "GO" - record T-0 timestamp.

### T+0..N: Fail-over
- Execute the runbook step-by-step (everyone follows the doc; no
  improvisation).
- Capture timestamp of each step.

### Verify
- Run the verification suite (smoke + customer-impact + data integrity).
- Compare actual vs expected RTO; if RTO breached, decide:
  abort + rollback, or continue + capture learning.

### Fail-back
- If hot/warm: redirect traffic back to primary.
- If cold: tear down DR environment + restore primary.
- Verify primary is healthy before claiming drill complete.

### Cleanup
- Re-enable alerts (Step 3).
- Send "all clear" customer comms.
- Reconcile any drill-introduced data divergence.

Step 5 - Post-drill report

## Drill Report - `<service>` `<date>`

**Drill objective:** Verify warm standby fails over within RTO 4hr.

**Timeline:**
- T-30 min: Replication lag verified (52s - within RPO 1hr) ✓
- T-0: Announced, on-call silenced
- T+12m: Failover initiated
- T+47m: Standby took traffic
- T+1h22m: Verified service healthy on standby
- T+2h11m: Failback to primary
- T+3h05m: Drill complete

**RTO observed:** 1h22m (target: 4hr) ✓

**Issues found:**
1. CRITICAL: DNS TTL was 24hr in standby DNS records; users
   couldn't reach service for 23min after failover. Fix: lower
   TTL to 60s in standby zone before next drill.
2. MAJOR: Secret-manager copy step was undocumented; commander
   improvised. Fix: add Step 3.4 to runbook.
3. MINOR: One alert wasn't silenced in advance; on-call was paged.

**Action items (with owners + dates):**
- DNS TTL fix → @platform-team - 2026-05-20
- Runbook Step 3.4 → @sre - 2026-05-13
- Alert routing audit → @sre - 2026-05-13

**Next drill:** 2026-08-06 (quarterly cadence).

Step 6 - Cold-tier-specific drill pattern

Cold drills = bring up from backup. Verifies:

Step 7 - Hot-tier-specific drill pattern

Hot drills = redirect traffic between active replicas. Verifies:

  • Health check propagation (load balancer detects standby is healthy).
  • Sticky-session handling (do connections drain or break?).
  • Cache warmup not required (or warmup time is within RTO).
  • Cross-region replication lag stays within RPO during the drill.

Step 8 - Cadence

TierCadence
1Monthly (game-day style)
2Quarterly
3Annually

Per the Google Cloud DR planning guide (opens in new window): "test it regularly, noting any issues." Without cadence, runbooks rot.

Run protocol (executing the drill end to end)

Nobody delegates failover execution; a human drill commander runs the five stages below against this protocol. This is the rehearsed DR path - for injecting unrehearsed failures see the chaos-drill-protocol skill in this plugin.

Refuse to start when:

  • No declared RTO + RPO. Per the Google Cloud DR planning guide (opens in new window), RTO is "the maximum acceptable length of time that your application can be offline" and RPO bounds acceptable data loss - without them there is no pass/fail criterion.
  • The DR environment identifier matches prod / production.
  • Any CRITICAL pre-drill item fails (backup integrity, key recovery, alert silencing) - halt and emit the blocking checklist instead of proceeding.

Stage 1 - pre-drill. Run the Step 3 checklist. Verify backup SHA-256 integrity, replication lag within RPO at T-30 min, and encryption-key recoverability in the DR region per references/backup-verification.md. Verify DR-environment configuration drift is within bounds - per the AWS DR testing whitepaper (opens in new window), "Manage configuration drift at the DR Region. Ensure that your infrastructure, data, and configuration are as needed at the DR Region."

Stage 2 - failover. Record T-0; execute the Step 4 runbook step by step, capturing a timestamp per step. Per the AWS DR testing whitepaper (opens in new window), "Our experience has shown that the only error recovery that works is the path you test frequently" - a runbook step that requires improvisation is logged as a MAJOR finding immediately, never silently adapted.

Stage 3 - RTO/RPO monitor. While failover is active, sample on a fixed interval (60 s is a workable default): replication lag at the DR side, smoke-suite pass rate, and data-row spot checks. Measure time-to-functional for the Restore + Verification segments per references/restore-time.md and compare against the per-segment RTO budget. If observed TTF exceeds the RTO - abort the failover, record the breach metrics, and skip directly to the report. Record the peak RPO gap (replication lag at fail-over time); flag if it exceeds the declared RPO.

Stage 4 - fail-back. Per Step 4: redirect traffic back (warm/hot) or tear down + restore primary (cold), re-enable silenced alerts, send the all clear, verify primary health before recording fail-back complete, reconcile drill-introduced data divergence.

Stage 5 - report. Emit the Step 5 post-drill report, including the observed TTF, total RTO, and peak RPO gap versus their declared targets. Schedule the postmortem within 48 hours; every finding gets an owner + due date before the drill closes.

Anti-patterns

Anti-patternWhy it failsFix
Skip pre-drill checklistDrill becomes incidentStep 3 mandatory
One person knows the runbookBus-factor 1; drill panics when they're outRotate drill commander
Skip post-drill reportLessons lost; same issues recurStep 5 mandatory + 48hr deadline
Test failover only; skip failbackFailback is the actual prod path; bugs hideStep 4 covers both
Lower RTO target after a missed drillGoalpost movingHold the line + invest in fixes

Limitations

  • DR drills don't replace chaos engineering (this plugin's chaos skills) - they test rehearsed paths; chaos tests unrehearsed ones.
  • Cloud-managed services may have built-in regional failover that bypasses your runbook; document boundaries.
  • Some compliance regimes (FFIEC for banks) prescribe specific drill frequencies + scopes - verify per regulation.

References

Backup verification harness

View source (opens in new window)

Backup verification harness

Deep dive for dr-drill-runner - the backup-integrity half of DR readiness. "An untested backup is not a backup." Consult when a service's backups have never been restore-tested, when the backup tool is being swapped, or when an audit needs proof that backups are integrity-checked and restorable.

Backups silently fail in many ways - wrong encryption key, missing volume, corrupted file, expired credential. Per the Google Cloud DR planning guide (opens in new window), DR success requires "end-to-end recovery design addressing backup, restoration, and cleanup procedures." This skill authors the verification harness.

When to use

  • Building DR readiness for a new service.
  • Backup-tool migration (Restic → Borg, AWS Backup → Veeam) - verify the new tool works on real data.
  • Compliance audit: prove backups are tested + integrity-checked.

Step 1 - Catalog backup types

## Backup Catalog - `<service>`

| Type | Source | Frequency | Retention | Tool |
|---|---|---|---|---|
| Full DB dump | postgres prod | Daily 02:00 UTC | 30 days | pg_dump + S3 |
| Logical schema | postgres prod | Hourly | 24 hours | logical replication slot |
| File store | S3 prod bucket | Continuous | 90 days | S3 versioning + cross-region |
| Audit log | append-only S3 | Continuous | 7 years | S3 + Glacier |
| Secrets / KMS keys | Vault prod | Daily | 7 days | Vault snapshot + encrypted S3 |

Each row needs its own verification step (Step 3).

Step 2 - Integrity checks at backup time

#!/usr/bin/env bash
set -e

BACKUP_FILE="postgres-prod-$(date +%Y%m%d).sql.gz"
BACKUP_PATH="/backups/$BACKUP_FILE"

# Take backup
pg_dump -h prod-db -U replica db_name | gzip > "$BACKUP_PATH"

# Generate SHA-256 + sign
sha256sum "$BACKUP_PATH" > "$BACKUP_PATH.sha256"
gpg --detach-sign --armor "$BACKUP_PATH"

# Upload to backup destination
aws s3 cp "$BACKUP_PATH" "s3://backup/postgres/$BACKUP_FILE"
aws s3 cp "$BACKUP_PATH.sha256" "s3://backup/postgres/$BACKUP_FILE.sha256"
aws s3 cp "$BACKUP_PATH.asc" "s3://backup/postgres/$BACKUP_FILE.asc"

# Tag with metadata
aws s3api put-object-tagging \
  --bucket backup --key "postgres/$BACKUP_FILE" \
  --tagging 'TagSet=[{Key=integrity_verified,Value=true},{Key=created,Value='$(date -Iseconds)'}]'

Tests assert:

  • SHA matches at upload.
  • Signature verifies with the correct key.
  • Tag present.

Step 3 - Restore-to-test-env spot check

A restore that has never been done is not a backup. Schedule:

# CI cron: weekly random sample
- cron: "0 4 * * 1"  # Monday 04:00 UTC
  job:
    - name: Pick random backup
      run: |
        DAYS=(1 7 14 30)
        DAYS_AGO=${DAYS[$RANDOM % ${#DAYS[@]}]}
        BACKUP=$(date -d "$DAYS_AGO days ago" +%Y%m%d)
        echo "BACKUP=postgres-prod-$BACKUP.sql.gz" >> $GITHUB_ENV

    - name: Verify integrity
      run: |
        aws s3 cp s3://backup/postgres/$BACKUP.sha256 .
        aws s3 cp s3://backup/postgres/$BACKUP .
        sha256sum -c "$BACKUP.sha256"

    - name: Restore to test DB
      run: |
        gunzip "$BACKUP"
        psql -h test-db -U test -f "${BACKUP%.gz}" db_test

    - name: Spot check
      run: |
        psql -h test-db -U test db_test -c "SELECT COUNT(*) FROM orders WHERE created_at > NOW() - INTERVAL '1 day'"
        # Verify count > 0 (or whatever invariant fits)

Step 4 - Partial-restore test

Real DR scenarios often need single-table or single-object restore (not full DB):

# Single-table extract + restore
pg_restore --table=orders --data-only \
  -h test-db -U test -d db_test \
  postgres-prod-backup.dump

Test: extract one table; assert rowcount + checksum match the production-time snapshot.

For S3 single-object:

aws s3 cp \
  s3://backup-versioned/object-key \
  --version-id "VERSION_ID_AT_DESIRED_TIME" \
  ./restored-object

Step 5 - Cross-region replication test

def test_backup_replicated_to_dr_region():
    # Take a backup in primary region
    backup_path_primary = take_backup_to(region="us-east-1")

    # Wait for replication SLA
    deadline = time.time() + 300  # 5 min SLA
    while time.time() < deadline:
        if exists_in(region="us-west-2", path=backup_path_primary):
            return
        time.sleep(10)

    pytest.fail("Cross-region replication exceeded 5min SLA")

Per the Google Cloud DR planning guide (opens in new window): "Security synchronization" also matters - DR region must have the same KMS keys / IAM / secrets, not just the data.

Step 6 - Retention-policy verification

def test_old_backups_purged_per_retention_policy():
    # 30-day retention; 100-day-old backup should not exist
    target = (datetime.utcnow() - timedelta(days=100)).strftime("%Y%m%d")
    obj_key = f"postgres/postgres-prod-{target}.sql.gz"

    response = s3.head_object(Bucket="backup", Key=obj_key)
    # Should 404
    pytest.fail(f"Backup {obj_key} still exists past 30-day retention")

Wrap in a try/except - actual missing object = pass.

def test_recent_backups_present():
    # Last 30 days should have at least one daily backup each
    for d in range(30):
        date = (datetime.utcnow() - timedelta(days=d)).strftime("%Y%m%d")
        key = f"postgres/postgres-prod-{date}.sql.gz"
        s3.head_object(Bucket="backup", Key=key)  # raises if missing

Step 7 - Encryption verification

For encrypted backups, verify both:

  • The backup is encrypted at rest (S3 SSE-KMS / GCP CMEK / Azure CMK).
  • The encryption key is recoverable in DR (key escrow + cross-region replication of the key).
def test_backup_encrypted_with_correct_key():
    obj = s3.head_object(Bucket="backup", Key=key)
    assert obj["ServerSideEncryption"] == "aws:kms"
    assert obj["SSEKMSKeyId"] == EXPECTED_KMS_KEY_ARN

Step 8 - Customer-induced backup test (compliance)

Some regulations (HIPAA, SOC 2) require demonstrated ability to restore on demand. Author the workflow:

## Customer-Induced Backup Restore Test

1. Customer requests demo restore via support ticket.
2. SRE picks a random recent backup; restores to clean isolated env.
3. Customer verifies their data via read-only SQL or UI.
4. Cleanup: tear down env, sanitize logs.
5. Document: ticket + timestamps + verification artifacts → audit log.

Anti-patterns

Anti-patternWhy it failsFix
Verify backup file exists; not contentsCorrupt files passSHA + restore (Steps 2-3)
Test restore once, never againBit rot, key rotation, schema drift surface laterWeekly cadence (Step 3)
Skip partial-restore testReal DR usually wants partial; full restore takes too longStep 4
Skip key recoveryBackup encrypted with key not in DR region; uselessStep 7
Trust replication "succeeded" statusAsync replication can claim success then failStep 5 explicit verification

Limitations

  • Backup verification doesn't test the restore-time SLA - see restore-time.md (opens in new window) for that.
  • Some legal regimes prescribe per-restore audit records; this reference covers the test pattern, not the legal compliance.
  • Cloud-managed backup services (AWS Backup, Veeam Cloud) handle some steps; verify the boundary clearly.

References

Restore-time SLA tests

View source (opens in new window)

Restore-time SLA tests

Deep dive for dr-drill-runner - the RTO-measurement half of DR readiness. Bound time-to-functional (TTF) at or under the documented RTO; flag silent regressions when restore time grows over months. Consult when a service documents an RTO nobody has actually timed, when the backup has grown by an order of magnitude, or right after a backup-tool change.

Per the Google Cloud DR planning guide (opens in new window), RTO is "the maximum acceptable length of time that your application can be offline." Restore-time tests measure the actual time-to-functional (TTF) for each backup type and gate it on the RTO budget.

When to use

  • DR readiness: validate stated RTO for a tier-1 service is achievable.
  • Capacity-planning: backup grew from 100 GB to 1 TB; restore time no longer fits the RTO window.
  • After backup-tool change: did the new tool restore at the same speed?

Step 1 - Define TTF segments

Time-to-functional = sum of:

SegmentDefinition
DetectionTime from incident to "something's wrong"
DecisionTime from detection to "initiate DR"
ProvisioningTime to spin up DR environment (IaC apply)
RestoreTime to apply the latest backup
VerificationTime to run smoke tests + accept traffic
CutoverDNS / load balancer switch + propagation

Each segment has its own SLA. The aggregate is the RTO.

This skill focuses on Restore + Verification segments.

Step 2 - Baseline: timed restore

import subprocess, time
import pytest

@pytest.mark.benchmark
def test_postgres_restore_time_under_rto():
    # Setup: clean target DB
    subprocess.run(["psql", "-h", "test-db", "-c", "DROP DATABASE IF EXISTS db_test"])
    subprocess.run(["psql", "-h", "test-db", "-c", "CREATE DATABASE db_test"])

    backup = "postgres-prod-latest.sql.gz"

    start = time.time()
    subprocess.run(
        ["bash", "-c", f"gunzip -c {backup} | psql -h test-db -d db_test"],
        check=True,
    )
    elapsed = time.time() - start

    RTO_BUDGET_SECONDS = 4 * 3600  # 4 hours
    # The 0.5 split (restore gets half the RTO, the rest goes to provision +
    # verify + cutover) is a planning choice, NOT a standard. Set the fraction
    # from your own per-segment RTO budget (Step 1).
    RESTORE_SEGMENT_FRACTION = 0.5
    budget = RTO_BUDGET_SECONDS * RESTORE_SEGMENT_FRACTION
    assert elapsed < budget, f"Restore took {elapsed:.0f}s; budget {budget:.0f}s"

Run weekly in CI; track trend.

Step 3 - Parallel-restore optimization

Many backup tools support parallelization. Test:

# pg_restore parallel
pg_restore -j 8 -d db_test backup.dump  # 8 parallel workers

# WAL-E / pgbackrest parallel restore
pgbackrest --stanza=prod --process-max=8 restore
def test_parallel_restore_faster_than_serial():
    serial = run_restore(parallel_jobs=1)
    parallel = run_restore(parallel_jobs=8)

    speedup = serial / parallel
    # 3.0x is an illustrative target; real speedup depends on I/O saturation,
    # CPU count, and backup format. Set the expected ratio from your own
    # measured serial-vs-parallel baseline rather than this placeholder.
    assert speedup > 3.0, f"Parallel restore only {speedup:.1f}x faster"

Find the sweet spot (often 4-8 jobs); past that, contention diminishes returns.

Step 4 - Point-in-time-recovery (PITR) latency

PITR = restore the database to an arbitrary point in the past (within retention). Restore time + WAL replay time:

PITR recovers a pre-existing base backup forward to a target time by replaying archived WAL. It needs two things that must already exist before the restore: a base backup taken earlier and retained, and a continuous WAL archive covering the window up to the target. Do NOT call pg_basebackup at restore time: a backup taken "now" captures the present, leaving nothing earlier to recover to. Per the PostgreSQL PITR docs (opens in new window):

def test_pitr_to_5min_ago_under_30min():
    target_time = datetime.utcnow() - timedelta(minutes=5)

    # 1. Lay down the PRE-EXISTING base backup into a clean data dir
    #    (untar the retained base backup; do not take a fresh one here).
    restore_retained_base_backup(dest="/restore")

    # 2. PG12+ recovery config: restore_command pulls archived WAL,
    #    recovery_target_time is the stop point, and recovery.signal triggers
    #    targeted recovery (recovery.conf was removed in PG12).
    write_conf("/restore/postgresql.auto.conf", {
        "restore_command": "cp /wal_archive/%f %p",
        "recovery_target_time": f"'{target_time.isoformat()}'",
        "recovery_target_action": "promote",
    })
    Path("/restore/recovery.signal").touch()

    # 3. Time the restore + WAL replay: this is the real PITR latency.
    start = time.time()
    subprocess.run(["pg_ctl", "start", "-D", "/restore", "-w"], check=True)
    wait_for_recovery_complete(timeout=1800)
    elapsed = time.time() - start

    # 1800s is illustrative; set the budget from your service's RTO segment SLA.
    assert elapsed < 1800, f"PITR took {elapsed:.0f}s; budget 30min"

PITR latency = base restore + WAL replay. Tests both segments.

Step 5 - Object-store partial restore

For S3 / GCS / Azure Blob restores, time the partial restore (not whole-bucket):

def test_partial_object_restore_under_5_min():
    keys_to_restore = sample_500_keys_from_inventory()

    start = time.time()
    for key in keys_to_restore:
        s3.copy_object(
            Bucket="restore-target",
            Key=key,
            CopySource={"Bucket": "backup-versioned", "Key": key, "VersionId": ...},
        )
    elapsed = time.time() - start

    assert elapsed < 300, f"500-object restore took {elapsed:.0f}s"

The 500-object count and the 300s budget are illustrative; size both from your own per-account object inventory and restore SLA.

Step 6 - Track restore-time trend

Backup grows over time → restore time grows. Track:

def emit_restore_time_metric(elapsed_seconds, backup_size_bytes):
    metrics_client.gauge("dr.restore_time_seconds", elapsed_seconds)
    metrics_client.gauge("dr.backup_size_bytes", backup_size_bytes)
    metrics_client.gauge("dr.restore_throughput_bytes_per_sec",
                          backup_size_bytes / elapsed_seconds)

Alert when restore time grows beyond a threshold you choose (e.g. 20% over 90 days; tune to your data-growth profile). Sustained growth indicates a need for backup compaction, more parallelism, or RTO renegotiation.

Step 7 - Verification time

Restore success ≠ functional. Verification adds time:

def test_post_restore_smoke_under_5_min():
    do_restore()

    start = time.time()
    run_smoke_suite("dr-environment")
    elapsed = time.time() - start

    assert elapsed < 300, f"Smoke tests took {elapsed:.0f}s; budget 5min"

Smoke suite scope: critical paths only. Full regression is too slow for the RTO window.

Step 8 - Cold-start vs warm-cache

After restore, applications hit cold caches → first requests slow. Test that the cold-start latency is within service SLA:

def test_cold_start_latency_within_sla():
    # Restore complete; app started; first requests
    latencies = []
    for _ in range(100):
        start = time.time()
        requests.get("https://dr-env.svc/api/products")
        latencies.append(time.time() - start)

    p99_cold = sorted(latencies)[99]
    # 2.0s is a placeholder; set the cold-start bound from your service's SLO.
    assert p99_cold < 2.0, f"Cold-start p99 {p99_cold:.2f}s exceeds 2s SLA"

Cache-warm step may be needed in DR runbook (loading common queries before declaring "functional").

Anti-patterns

Anti-patternWhy it failsFix
Test on yesterday's backup, claim "RTO met"Real DR uses minutes-old backupWeekly cadence with realistic data freshness
Skip parallel test; use single threadAggregate RTO + budget breached at scaleStep 3 sweet-spot tuning
Skip verification timeRestore "complete"; users still 5xxStep 7 must be timed
No trend trackingSilent regression months inStep 6 metric + alert
RTO unit on DB only, ignore appApp may take longer than DBStep 8 cold-start

Limitations

  • Real RTO depends on the worst path through the dependency graph; this skill measures one segment at a time.
  • Some cloud-managed restores (RDS snapshot, Aurora restore) have fixed per-cloud SLA - verify documentation, not just test.
  • Compression-heavy backups optimize for storage, not restore speed; tradeoffs are real.

References

Related skills

chaos-drill-protocol

Run protocol and run workflow for a chaos experiment that has already been designed: the four pre-flight gates (non-production target, measured healthy baseline, live observability, a rollback that has actually been exercised), how to pick a conservative blast-radius bound, the sampling cadence and abort criteria fixed in writing before injection, the per-runner inject and abort commands (Chaos Mesh / Litmus / Gremlin / Toxiproxy), the refuse-to-start rules (no blast-radius bound, production context, degraded baseline, offline observability, unexercised rollback), and the recovery-validation step with its tolerance and timeout. Owns execution safety only, not experiment design: the steady-state hypothesis, the fault to inject, and the experiment file come from chaos-experiment-author. Use when an experiment definition exists and a fault is about to be injected into a running system, and the go/no-go gates, abort thresholds, and recovery check still need to be agreed and written down before the fault starts.

chaos-experiment-author

Build-an-X workflow for a chaos experiment per the Principles of Chaos Engineering - defines steady-state hypothesis, picks the variables (real-world events: network latency, node failure, region outage), sets the blast radius (which percentage / namespace / user cohort), automates execution, and emits the verdict (steady-state held / didn't hold). Includes the five-check pre-flight validation of the steady-state hypothesis (measurable, baselined, SLI-backed tolerance, defined measurement window, metric moves under the fault) with hard-reject rules, and routes the tool choice: Chaos Mesh has its own standalone skill, while LitmusChaos and Gremlin setup live in this skill's references. Use to scope and pre-flight-validate a chaos experiment before running it via Chaos Mesh / Litmus / Gremlin / Toxiproxy.

chaos-mesh

Configures Chaos Mesh for Kubernetes-native chaos engineering - picks fault types (PodChaos, NetworkChaos, StressChaos, IOChaos, TimeChaos, DNSChaos, KernelChaos, HTTPChaos), targets via label selectors, controls blast radius via namespace whitelists + selector filters, schedules via CronJobs, observes via dashboard. Distinct from Litmus by architecture (Chaos Mesh has its own dashboard + workflow orchestration; Litmus uses ChaosCenter UI). Use when the target system runs on Kubernetes and fault experiments should be declared as CRDs in the cluster alongside the workloads they target.

error-budget-tests

Build error-budget gate tests - SLO + error-budget calculation per Google SRE workbook ("difference between target uptime and actual uptime"); burn-rate alerting; monthly-budget exhaustion test; freeze-trigger when budget consumed. Per sre.google embracing-risk reference. Includes the incident-metrics reference for MTTR / MTBF / MTTD / MTTA - per-incident record schema, calculation formulae, exclusion rules, dashboards-as-code, and target-vs-actual alerting. Use when an SLO and error budget are written down but nothing verifies that burn-rate alerts fire or that the release freeze engages when the budget runs out, or when MTTR / MTBF dashboards report numbers nobody can reproduce.

failure-injection-test-author

Orchestrates WireMock fault stubs (HTTP-level fault: 500s, malformed JSON, slow responses) with Toxiproxy (TCP-level: latency, packet loss, reset) into a single resilience test scenario - the test starts both, applies fault per scenario, runs the SUT against the impaired endpoints, verifies the SUT's resilience patterns. Use when one test must reproduce a combined network + HTTP failure - a cross-layer failure mode from an incident postmortem that neither pure HTTP fault stubs nor pure TCP chaos can cover alone, because most real failures span both layers.

toxiproxy-chaos

Configures Toxiproxy for TCP-level fault injection - runs as a sidecar / proxy between client and upstream, applies toxics (latency, bandwidth, slow_close, timeout, slicer, limit_data, reset_peer) via control API. Focused on the proxy itself rather than an API-level chaos runner, including non-test usage (chaos in dev environments, integration tests, pre-prod simulation). Use when the team needs TCP-precise fault injection in development / integration environments without K8s or commercial tooling.