🛡️ sandbox-labs GitHub ↗

CM-14 · Resiliencia operacional#

En una frase, para cualquiera: los sistemas se caen. La diferencia entre un susto y un desastre es si alguien había ensayado qué hacer, y si el sistema sabe pararse solo antes de hacer daño.

Estado real: 🟠 prototype — hay código y escenarios que se ejecutan, sin verificación en un entorno real · Módulo: crates/sandbox-markets/src/cases/resilience.rs

Incidentes, sistemas y datos simulados. No es una autorización regulatoria.

Por qué se realiza este caso#

En un sistema financiero, seguir funcionando mal es peor que detenerse. Un motor de órdenes con precios erróneos ejecuta operaciones reales a precios que no existen, y deshacerlas después es caro, lento y a veces imposible.

IncidentePor qué es peligroso seguir
Base de datos caídaSe opera sobre un estado que no se puede persistir
Mensajes duplicadosLa misma orden se ejecuta dos veces
Latencia altaSe opera con precios de hace medio minuto
Motor de órdenes desconectadoNadie sabe qué se ejecutó y qué no
Precios erróneosSe ejecuta a precios inventados
Custodio indisponibleSe prometen entregas que no se pueden cumplir
Credenciales comprometidasCada segundo cuenta
Despliegue defectuosoEl fallo se multiplica por el volumen

La idea que enseña, y que ningún otro caso enseña#

Detenerse a tiempo es una función del sistema. El kill switch no es un botón de emergencia para humanos: es un control con condiciones definidas de antemano —qué lo dispara, qué se detiene, qué sigue funcionando— y que se ensaya.

Y junto a él, la degradación controlada: cuando algo falla, el sistema no elige entre «todo» y «nada», sino que apaga por partes en un orden decidido antes.

Casos de uso reales#

Cómo funcionará#

flowchart LR
  I["⚡ Incidente inyectado"] --> D["👁️ Detección"]
  D --> K{"🛑 ¿Se cumplen las<br/>condiciones del kill switch?"}
  K -- sí --> S["🔴 Detener lo afectado"]
  K -- no --> G["🟡 Degradación controlada"]
  S & G --> R["🔧 Recuperación"]
  R --> RP["⏪ Replay de<br/>lo que quedó a medias"]
  RP --> RC["🔍 Reconciliación"]
  RC --> CO["📣 Comunicación"]
  CO --> PM["📚 Post mortem"]
flowchart TB
  A["Incidente"] --> B{"¿Afecta a la<br/>integridad de los datos?"}
  B -- sí --> C["🛑 KILL SWITCH inmediato"]
  B -- no --> D{"¿Afecta a la<br/>calidad de la ejecución?"}
  D -- sí --> E["🟡 Suspender solo lo afectado"]
  D -- no --> F["🟢 Seguir, con alerta"]
  C & E --> G["⏱️ Medir: tiempo hasta detectar<br/>y tiempo hasta detener"]

Esos dos tiempos —detectar y detener— son las métricas del caso. Todo lo demás se deriva de ellas.

Esquemas#

{
  "incident": {
    "kind": "stale-prices",
    "injectedAt": 1200,
    "affects": ["order-engine"],
    "severity": "alta"
  }
}
{
  "response": {
    "detectedAtMs": 340,
    "killSwitchTriggeredAtMs": 380,
    "stopped": ["nuevas órdenes en ACME-SIM"],
    "keptRunning": ["consulta de saldos", "cancelaciones"],
    "replayed": 128,
    "reconciliationFindings": [],
    "dataIntegrityPreserved": true
  }
}

durante un incidente. Impedir cancelar mientras el mercado se mueve es atrapar a los clientes en sus posiciones.

Software necesario#

ComponentePara qué
Rust 1.75+Inyección de incidentes, kill switch y replay
Node.js 20+ / pnpm 9+Panel de estado durante el incidente (recomendado)

Sin jaula ni Linux: los incidentes se inyectan en un sistema simulado, no se provocan fallos reales en el equipo.

Instalación#

cargo build --release

Procesos que se crearán#

sandboxctl markets resilience --incident precios-obsoletos --seed 7
  │
  └─ un proceso determinista, sin red
      ├─ reloj simulado con inyección en un instante exacto
      ├─ registro append-only para poder hacer replay
      └─ conciliación posterior contra CM-03

La semilla y el reloj simulado hacen que el mismo incidente se reproduzca igual, que es lo que permite comparar respuestas entre versiones del sistema.

Tiempo de carga estimado#

OperaciónCoste esperado
Un escenario de incidente completo< 1 s
Replay de 100 000 eventossegundos
Conciliación posteriormilisegundos

Qué hace falta para construirlo#

  1. Inyección de los ocho incidentes listados, en instantes exactos.
  2. Kill switch con condiciones declarativas y ensayables.
  3. Degradación controlada por partes, con orden definido.
  4. Replay desde el registro append-only.
  5. Conciliación posterior contra CM-03.
  6. Post mortem generado con la línea de tiempo y las dos métricas.

Si algo falla#

El caso ya tiene código y escenarios que se ejecutan. Lo que sigue son sus fallos con la causa y la salida:

SituaciónCausaCómo se resuelve
El kill switch no se disparaLas condiciones estaban mal definidasSe declaran de antemano y se ensayan con incidentes inyectados. Un kill switch que nunca se ha probado no se sabe si funciona
Se detiene todo cuando bastaba con degradarRespuesta desproporcionadaSe apaga por partes, en un orden decidido antes. keptRunning importa tanto como stopped
Las cancelaciones se bloquean durante el incidenteError de diseño frecuenteLas cancelaciones siguen vivas siempre: impedir cancelar mientras el mercado se mueve atrapa a los clientes en sus posiciones
El replay duplica operacionesFalta idempotenciaEl libro es idempotente por operación. Repetir un evento del registro no lo aplica dos veces
El mismo incidente da resultados distintosFalta la semilla o el reloj simuladoCon semilla y reloj simulado el incidente se reproduce igual, que es lo que permite comparar la respuesta entre versiones

Los fallos que afectan a cualquier caso —la compilación, el catálogo, la evidencia— están resueltos uno a uno en Cuando algo falla.

Esta familia no necesita aislamiento del sistema: no ejecuta código ajeno, sino reglas de negocio deterministas. Por eso casi ningún fallo suyo viene del entorno, y casi todos vienen de los datos.

Cómo se comprueba#

cargo run -p sandboxctl -- markets check --case CM-14

Ejecuta los escenarios de este caso y compara cada uno con lo que declara de antemano que debe salir. Corre en cada commit: si el caso deja de detectar lo que dice detectar, la integración continua se pone roja.

cargo test -p sandbox-markets resilience

Los invariantes del módulo, incluidos los que ningún escenario de arriba cubre.

Sigue en prototype, no en functional. Los escenarios se ejecutan y pasan, pero el caso no emite evidencia firmada por ejecución ni se ha usado contra datos que no sean los suyos. La regla completa está en el ROADMAP.

Ver también: Catálogo completo · CM-10 · liquidación · CM-16 · datos de mercado