🛡️ sandbox-labs GitHub ↗

CM-13 · Salida ordenada#

En una frase, para cualquiera: cerrar una empresa que maneja dinero ajeno no es apagar los servidores. Es devolver cada peso a su dueño, y poder demostrar que se devolvió.

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/wind_down.rs

Clientes, fondos y activos simulados. No es una autorización regulatoria.

Por qué se realiza este caso#

El cierre es el momento donde se comprueba si todo lo anterior era verdad. Si los activos estaban bien segregados, devolverlos es un procedimiento. Si estaban mezclados, es una liquidación concursal.

Por eso CM-00 pide el plan de salida al entrar: quien no sabe explicar cómo devolvería el dinero probablemente no ha separado bien de quién es.

Lo que sale mal cuando no hay plan:

FalloConsecuencia
Se siguen aceptando clientes mientras se cierraMás gente afectada
Quedan órdenes pendientes sin cancelarObligaciones nuevas después de decidir cerrar
Se devuelve por orden de llegadaLos primeros cobran todo, los últimos nada
No se exportan los historialesLos clientes pierden la prueba de lo que tenían
Las integraciones siguen vivasTerceros siguen operando contra un sistema que ya no atiende

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

Cerrar es un procedimiento con orden obligatorio. No se pueden hacer los pasos en cualquier secuencia: primero se detiene la entrada, después se cancela lo pendiente, después se liquida, y solo entonces se devuelve. Saltarse el orden crea obligaciones nuevas mientras se intenta cumplir las viejas.

Casos de uso reales#

funciona.

Cómo funcionará#

flowchart TB
  A["1️⃣ Detener altas<br/>de clientes"] --> B["2️⃣ Detener nuevas órdenes"]
  B --> C["3️⃣ Cancelar pendientes"]
  C --> D["4️⃣ Liquidar posiciones abiertas"]
  D --> E["5️⃣ Devolver fondos"]
  E --> F["6️⃣ Transferir activos<br/>a otro custodio"]
  F --> G["7️⃣ Exportar historiales<br/>a cada cliente"]
  G --> H["8️⃣ Notificar"]
  H --> I["9️⃣ Cerrar integraciones"]
  I --> J["🔟 Reporte final firmado"]
flowchart LR
  S["Estado del cierre"] --> C{"¿Queda algo<br/>por devolver?"}
  C -- sí --> D["🚫 El cierre NO ha terminado"]
  C -- no --> E{"¿El libro cuadra?<br/>CM-03"}
  E -- no --> F["🚨 Faltante: no se puede cerrar"]
  E -- sí --> G["✅ Cierre completo y demostrable"]

Esquemas#

{
  "windDown": {
    "startedAt": "2026-08-07T00:00:00Z",
    "steps": [
      { "step": "stop-onboarding", "status": "done" },
      { "step": "stop-new-orders", "status": "done" },
      { "step": "cancel-pending", "status": "done", "cancelled": 412 },
      { "step": "liquidate", "status": "in-progress" }
    ]
  }
}
{
  "finalReport": {
    "clientsRepaid": 1840,
    "clientsPending": 0,
    "assetsTransferred": [{ "instrument": "ACME-SIM", "units": 90000, "toCustodian": "custodio-sim-2" }],
    "ledgerBalanced": true,
    "reconciliationFindings": [],
    "historiesExported": true,
    "signature": "base64…"
  }
}

de cierre completo. Cualquier otra combinación significa que el cierre no ha terminado, por mucho que los servidores estén apagados.

Software necesario#

ComponentePara qué
Rust 1.75+Máquina de estados del cierre y reporte final firmado
Node.js 20+ / pnpm 9+Panel del progreso del cierre (recomendado)

Sin jaula ni Linux. Se apoya en CM-03 —ya construido— para comprobar que el libro cuadra al final.

Instalación#

cargo build --release

Procesos que se crearán#

sandboxctl markets wind-down --scenario cierre-con-faltante
  │
  └─ un proceso determinista, sin red
      ├─ máquina de estados con orden OBLIGATORIO
      ├─ conciliación CM-03 al final
      └─ reporte final firmado

Tiempo de carga estimado#

OperaciónCoste esperado
Ejecutar el cierre completo de una cartera simulada< 1 s
Conciliación finalmilisegundos
Reporte final firmado< 10 ms

Qué hace falta para construirlo#

  1. Máquina de estados con el orden de los pasos como restricción, no como

sugerencia.

  1. Devolución con regla de reparto explícita, no por orden de llegada.
  2. Transferencia a otro custodio simulado.
  3. Exportación de historiales por cliente.
  4. Reporte final firmado con conciliación incluida.
  5. Escenario de cierre con faltante: qué se hace cuando no alcanza.

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 cierre termina y quedan clientes sin cobrarclientsPending > 0El cierre no ha terminado, por mucho que los servidores estén apagados. La definición de cierre completo son dos campos: clientsPending: 0 y reconciliationFindings: []
Aparece un faltante al conciliarNo había tanto como decían los librosEs el escenario que hay que ensayar antes de necesitarlo. Se reparte con la regla publicada, nunca por orden de llegada
Se ejecutan los pasos en otro ordenEl orden es una restricción, no una sugerenciaLa máquina de estados lo impide: cancelar pendientes antes de detener nuevas órdenes crea obligaciones mientras intentas cumplir las viejas
Los clientes no reciben su historialFalta la exportaciónSin historial, el cliente pierde la prueba de lo que tenía. Es un paso obligatorio del cierre, no un extra
Nadie había probado el plan de cierreLo habitualPor eso CM-00 lo exige al entrar: un plan sin ensayar es un documento, no un plan

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-13

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 wind_down

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-00 · entrada · CM-03 · custodia