🛡️ sandbox-labs GitHub ↗

CM-06 · Asesoría crediticia#

En una frase, para cualquiera: dos créditos con la misma cuota mensual pueden costar el doble uno que otro. La diferencia está en cosas que no aparecen en el anuncio.

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

Perfiles, ofertas y tasas simulados. Sin datos personales reales. No es una autorización regulatoria ni asesoría financiera real.

Por qué se realiza este caso#

El crédito se vende por la cuota, y la cuota es el peor indicador posible: se puede bajar alargando el plazo, y alargar el plazo casi siempre encarece el total.

Lo que se compara habitualmenteLo que decide el costo real
La cuota mensualEl costo total a lo largo de la vida del crédito
La tasa anunciadaLa tasa efectiva con seguros y comisiones incluidos
El plazoCuánto se paga de intereses por alargarlo
Si la tasa es variable y qué pasa si sube
Si la capacidad de pago aguanta un mal año

Y hay un conflicto que rara vez se declara: quien recomienda suele cobrar del que presta, y no siempre lo mismo por cada producto.

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

Recomendar obliga a explicar y a declarar de qué se vive. La recomendación tiene que venir con el costo total, con el escenario adverso, y con quién paga a quien recomienda. Sin esos tres datos, una recomendación es publicidad.

Casos de uso reales#

Cómo funcionará#

flowchart LR
  P["👤 Perfil financiero<br/>ingresos · obligaciones"] --> C["🧮 Capacidad de pago"]
  O["🏦 Ofertas simuladas"] --> E["⚖️ Comparación por<br/>COSTO TOTAL"]
  C --> E
  E --> S["📈 Escenarios de tasa<br/>y de ingreso adverso"]
  S --> R["📄 Recomendación explicable"]
  R --> D["📢 Declaración de<br/>conflictos comerciales"]
flowchart TB
  A["Oferta"] --> B["Costo total = capital + intereses + seguros + comisiones"]
  B --> C{"¿La cuota cabe en la<br/>capacidad de pago?"}
  C -- no --> C1["🚫 Descartada: no es apta"]
  C -- sí --> D{"¿Aguanta un escenario<br/>de tasa +3 puntos?"}
  D -- no --> D1["📣 Apta con advertencia"]
  D -- sí --> E["✅ Comparable"]

Esquemas#

{
  "profile": {
    "monthlyIncome": { "minorUnits": 900000, "currency": "CLP" },
    "monthlyObligations": { "minorUnits": 300000, "currency": "CLP" },
    "stabilityMonths": 24
  },
  "offers": [
    { "id": "of-1", "principal": 5000000, "annualRate": 0.18, "months": 36, "insurance": 45000, "fees": 30000, "rateType": "fixed" }
  ]
}
{
  "ranked": [
    { "offer": "of-1", "monthlyPayment": 180500, "totalCost": 6498000, "effectiveRate": 0.213, "affordable": true }
  ],
  "stress": [{ "offer": "of-1", "scenario": "tasa +3pp", "monthlyPayment": 189200, "stillAffordable": true }],
  "recommendation": "of-1",
  "why": "menor costo total entre las ofertas que caben en la capacidad de pago y resisten el escenario adverso",
  "commercialConflicts": [{ "offer": "of-1", "disclosure": "el comparador recibe comisión del emisor" }],
  "notFinancialAdvice": true
}

asesoría financiera real.

Software necesario#

ComponentePara qué
Rust 1.75+Cálculo de costo total, capacidad de pago y escenarios
Node.js 20+ / pnpm 9+Formulario y comparación visual (opcional)

Sin jaula ni Linux. Aritmética con enteros en unidades mínimas: los intereses con coma flotante producen diferencias de céntimos que, acumuladas, no cuadran.

Instalación#

cargo build --release

Procesos que se crearán#

sandboxctl markets credit --profile perfil.json --offers ofertas.json
  │
  └─ un proceso determinista, sin red
      └─ mismos datos → misma recomendación, siempre

Tiempo de carga estimado#

OperaciónCoste esperado
Comparar 20 ofertas con escenarios< 10 ms
Generar la explicación< 5 ms

Qué hace falta para construirlo#

  1. Cálculo de costo total y tasa efectiva con seguros y comisiones.
  2. Capacidad de pago con margen y estabilidad de ingresos.
  3. Escenarios de tasa y de caída de ingreso.
  4. Explicación obligatoria y declaración de conflictos.
  5. Perfiles sintéticos: nunca datos personales reales.

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
La oferta con la cuota más baja no es la recomendadaAlargar el plazo baja la cuota y sube el costo totalEs el punto del caso. La explicación dice el costo total de cada una, que es la comparación honesta
Ninguna oferta sale affordableLa capacidad de pago no daNo relajar el margen para que salga alguna: el resultado correcto es «ninguna de estas ofertas cabe»
El escenario de tasa adversa tumba la recomendaciónTasa variableSe marca como apta con advertencia, no se oculta. Quien decide tiene que ver el escenario malo
Los totales no cuadran por céntimosIntereses con coma flotanteAritmética con enteros en unidades mínimas. Un céntimo por cuota son varios euros a lo largo del crédito
Alguien toma la salida como asesoría realMalentendido gravenotFinancialAdvice: true es obligatorio en el esquema. Este simulador no emite asesoría financiera

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

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 credit

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-07 · robo-advisor · CM-20 · gobierno de modelos