ANEXO 20
Reglas de negocio FARO
Este anexo corresponde a la Fase 6 — Inteligencia, etapa “Reglas de negocio”. Es la capa donde FARO Connect convierte KPIs, señales, objetivos, umbrales y relaciones entre datos en condiciones lógicas que permiten activar alertas, tensiones, diagnósticos, recomendaciones, acciones, responsables, escalamiento y FARO Score.
1. Objetivo del anexo
El objetivo del Anexo 20 — Reglas de negocio FARO es definir bajo qué condiciones FARO debe interpretar que algo requiere atención.
La pregunta central es:
¿Qué condición debe cumplirse para que FARO diga: “esto importa”?
Ejemplo simple:
Si margen bruto < 20%
y descuento promedio > 10%
entonces activar alerta de margen crítico
y evaluar tensión de crecimiento no rentable.
Sin reglas de negocio, FARO tendría datos, KPIs y señales, pero no sabría cuándo actuar.
2. Tesis del Anexo 20
La tesis es:
Las reglas de negocio son el puente entre medir y dirigir.
Hasta ahora FARO tiene:
Datos
→ KPIs
→ Objetivos
→ Umbrales
→ Señales
Pero falta definir:
Si pasa esto
+ en este contexto
+ con esta severidad
+ y esta confianza
→ entonces hacer esto.
Eso es una regla de negocio.
Ejemplo:
Dato:
Descuento promedio 12%.
KPI:
Descuento promedio.
Señal:
Descuento alto.
Regla:
Si descuento > 10% y margen < 22%, generar alerta.
Alerta:
Margen deteriorado por descuento.
Tensión:
Crecimiento no rentable.
Acción:
Auditar descuentos mayores al 8%.
Responsable:
Gerente Comercial.
3. Qué es una regla de negocio FARO
Una regla de negocio FARO es una condición lógica que evalúa datos y define una consecuencia.
Estructura básica:
SI condición
ENTONCES consecuencia
Pero en FARO debe ser más completa:
SI condición de negocio
Y calidad de dato suficiente
Y contexto aplicable
ENTONCES activar señal / alerta / tensión / acción / escalamiento / score
Ejemplo:
{
"rule_code": "RULE_MARGIN_DISCOUNT_001",
"name": "Margen bajo con descuento alto",
"condition": {
"gross_margin_rate": "< 0.22",
"discount_rate": "> 0.10"
},
"then": {
"alert": "margen_critico_con_descuento_alto",
"tension": "crecimiento_no_rentable",
"responsible": "Gerente Comercial",
"suggested_action": "auditar_descuentos_altos"
}
}
4. Diferencia entre señal, regla, alerta y tensión
| Concepto | Qué hace | Ejemplo |
|---|---|---|
| Señal | Detecta movimiento relevante. | Margen cayó 7 puntos. |
| Regla | Evalúa si ese movimiento cumple una condición. | Si margen < 22% y descuento > 10%. |
| Alerta | Avisa formalmente un riesgo. | Margen crítico por descuento alto. |
| Tensión | Interpreta contradicción entre variables. | Ventas suben, margen baja y cobranza empeora. |
| Acción | Define qué hacer. | Auditar descuentos mayores al 8%. |
La regla es el “cerebro lógico” que decide cuándo una señal pasa a ser algo accionable.
5. Tipos de reglas FARO
FARO debería manejar varias familias de reglas.
| Tipo de regla | Qué evalúa | Ejemplo |
|---|---|---|
| Reglas de validación | Si el dato sirve o no. | Venta sin producto se rechaza. |
| Reglas de calidad | Si el dato es confiable. | Costo faltante en 20% de ventas. |
| Reglas de KPI | Si un indicador está fuera de rango. | Margen < 20%. |
| Reglas de señal | Si una variación es relevante. | Margen cae más de 5 puntos. |
| Reglas de alerta | Si debe emitirse un aviso. | Stock bajo mínimo. |
| Reglas de tensión | Si varias señales forman contradicción. | Ventas suben + margen baja + cobranza empeora. |
| Reglas de acción | Qué acción sugerir. | Auditar descuentos altos. |
| Reglas de responsable | A quién asignar. | Stock crítico → Responsable de Stock. |
| Reglas de escalamiento | Cuándo subir de nivel. | Acción crítica vencida 48 hs. |
| Reglas de score | Cómo impacta FARO Score. | Tensión crítica abierta resta puntos. |
| Reglas por industria | Adaptación sectorial. | RevPAR bajo en hotelería. |
| Reglas de aprendizaje | Ajuste por resultados históricos. | Recalibrar umbral si acción no funciona. |
6. Biblioteca inicial de reglas FARO
Una base seria debería tener:
150 a 300 reglas iniciales
Escalable a:
1.000+ reglas
Distribución sugerida:
| Familia | Cantidad inicial | Escalable |
|---|---|---|
| Validación de datos | 30-60 | 200+ |
| Calidad de datos | 20-40 | 150+ |
| KPIs y umbrales | 40-80 | 300+ |
| Alertas | 30-60 | 250+ |
| Tensiones | 30-80 | 300+ |
| Acciones | 30-60 | 300+ |
| Responsables / RACI | 20-40 | 150+ |
| Escalamiento | 20-40 | 100+ |
| FARO Score | 20-40 | 150+ |
| Industria específica | 50-150 | 500+ |
No conviene arrancar con 1.000 reglas activas. Conviene arrancar con pocas, críticas y bien probadas. Una regla mal hecha escala errores con una eficiencia admirable. Y eso no es precisamente virtud.
7. Estructura estándar de una regla FARO
Cada regla debería tener una ficha formal.
{
"rule_code": "RULE_COMMERCIAL_001",
"name": "Descuento alto con margen bajo",
"description": "Detecta operaciones comerciales donde el descuento aplicado erosiona el margen bruto.",
"module": "Comercial",
"area": "Comercial",
"industry_scope": ["construction_supplies", "retail", "manufacturing"],
"inputs": [
"gross_margin_rate",
"discount_rate",
"net_sales"
],
"condition": {
"all": [
{ "field": "gross_margin_rate", "operator": "<", "value": 0.22 },
{ "field": "discount_rate", "operator": ">", "value": 0.10 }
]
},
"confidence_min": 0.75,
"severity": "alta",
"then": {
"alert": "margin_discount_alert",
"possible_tension": "crecimiento_no_rentable",
"suggested_action": "auditar_descuentos_altos",
"responsible_role": "Gerente Comercial",
"approver_role": "Dirección"
},
"score_impact": {
"module": "Comercial",
"points": -4
},
"active": true,
"version": "1.0"
}
8. Campos obligatorios por regla
| Campo | Para qué sirve |
|---|---|
| rule_code | Identificador único. |
| name | Nombre claro. |
| description | Qué detecta. |
| module | Módulo FARO donde aplica. |
| area | Área responsable. |
| industry_scope | Industrias donde aplica. |
| inputs | Variables necesarias. |
| condition | Condición lógica. |
| confidence_min | Confianza mínima requerida. |
| severity | Severidad base. |
| then | Consecuencia de la regla. |
| responsible_role | Responsable sugerido. |
| score_impact | Impacto en FARO Score. |
| version | Versión de la regla. |
| active | Si está activa o no. |
9. Operadores lógicos
FARO debe soportar operadores básicos y avanzados.
| Operador | Uso | Ejemplo |
|---|---|---|
> |
Mayor que | margen > 25% |
< |
Menor que | margen < 20% |
>= |
Mayor o igual | cumplimiento >= 90% |
<= |
Menor o igual | descuento <= 6% |
== |
Igual | estado == vencida |
!= |
Distinto | estado != cerrado |
between |
Entre valores | margen entre 20% y 25% |
in |
Está dentro de lista | área in comercial, finanzas |
not_in |
No está en lista | estado no en cerrado |
and |
Todas las condiciones | margen bajo y descuento alto |
or |
Alguna condición | stock bajo o cobertura insuficiente |
not |
Negación | no tiene responsable |
trend_down |
Tendencia negativa | margen baja 3 períodos |
trend_up |
Tendencia positiva | mora sube 4 semanas |
change_gt |
Variación mayor a | ventas suben más de 15% |
exists |
Existe dato | cliente existe |
missing |
Falta dato | costo faltante |
10. Reglas de validación de datos
Estas reglas determinan si un dato puede ingresar o no al flujo.
10.1 Venta sin campos mínimos
def regla_validar_venta(venta):
errores = []
campos_obligatorios = [
"fecha",
"cliente_id",
"producto_id",
"cantidad",
"precio_final",
"vendedor_id",
"sucursal_id"
]
for campo in campos_obligatorios:
if not venta.get(campo):
errores.append(f"{campo}_faltante")
if venta.get("cantidad", 0) <= 0:
errores.append("cantidad_invalida")
if venta.get("precio_final", 0) <= 0:
errores.append("precio_invalido")
return {
"valid": len(errores) == 0,
"errors": errores
}
10.2 Acción sin responsable
def regla_accion_sin_responsable(accion):
if not accion.get("responsable_id"):
return {
"rule": "ACTION_WITHOUT_OWNER",
"status": "blocked",
"message": "La acción no puede avanzar sin responsable asignado."
}
return None
11. Reglas de calidad de datos
Estas reglas no siempre bloquean, pero reducen confianza.
11.1 Costo faltante
def regla_costo_faltante(registros_sin_costo, registros_totales):
if registros_totales == 0:
return None
ratio = registros_sin_costo / registros_totales
if ratio > 0.15:
return {
"rule": "COST_MISSING_HIGH",
"severity": "alta",
"impact": "margen_no_confiable",
"requires_validation": True
}
return None
11.2 Stock desactualizado
from datetime import datetime
def regla_stock_desactualizado(fecha_actualizacion, dias_maximos=2):
dias = (datetime.now().date() - fecha_actualizacion).days
if dias > dias_maximos:
return {
"rule": "STOCK_OUTDATED",
"severity": "alta",
"message": "El stock está desactualizado y no debería activar decisiones críticas."
}
return None
12. Reglas comerciales
12.1 Descuento alto con margen bajo
def regla_descuento_alto_margen_bajo(margen, descuento):
if margen < 0.22 and descuento > 0.10:
return {
"alerta": "margen_critico_con_descuento_alto",
"tension_posible": "crecimiento_no_rentable",
"responsable": "Gerente Comercial",
"accion": "auditar_descuentos_altos",
"severidad": "alta"
}
return None
12.2 Ventas suben, margen baja
def regla_crecimiento_no_rentable_basico(ventas_var, margen_var):
if ventas_var > 0.15 and margen_var < -0.05:
return {
"senal": "crecimiento_riesgoso",
"tension_posible": "crecimiento_no_rentable",
"accion": "analizar_descuentos_costos_y_mix",
"severidad": "alta"
}
return None
12.3 Comisión desalineada
def regla_comision_desalineada(comision_var, margen_var, cobranza_var):
condiciones = [
comision_var > 0,
margen_var < 0,
cobranza_var > 0
]
if sum(condiciones) >= 2:
return {
"tension": "comision_desalineada",
"responsable": "Comercial / RRHH",
"consultados": ["Finanzas"],
"accion": "redisenar_formula_comision",
"severidad": "alta"
}
return None
13. Reglas financieras
13.1 Caja débil con ventas altas
def regla_caja_debil_con_ventas_altas(ventas_var, caja_var, dias_cobranza_var):
if ventas_var > 0.10 and caja_var < 0 and dias_cobranza_var > 7:
return {
"tension": "caja_debil_con_ventas_altas",
"responsable": "Finanzas",
"consultados": ["Comercial"],
"accion": "priorizar_cobranza_clientes_grandes",
"severidad": "alta"
}
return None
13.2 Gasto crece más que ventas
def regla_gasto_desalineado(ventas_var, gastos_var):
if gastos_var > ventas_var and gastos_var > 0.10:
return {
"alerta": "gastos_crecen_mas_que_ventas",
"tension": "estructura_sobredimensionada",
"responsable": "Finanzas",
"accion": "revisar_gastos_por_area",
"severidad": "media_alta"
}
return None
13.3 Cliente grande moroso
def regla_cliente_grande_moroso(concentracion_cliente, dias_mora, margen_cliente):
if concentracion_cliente > 0.15 and dias_mora > 30 and margen_cliente < 0.20:
return {
"tension": "cliente_grande_riesgoso",
"responsable": "Finanzas",
"consultados": ["Comercial"],
"accion": "condicionar_credito_o_exigir_pago_parcial",
"severidad": "alta"
}
return None
14. Reglas de stock
14.1 Stock crítico
def regla_stock_critico(stock_actual, stock_minimo):
if stock_actual < stock_minimo:
return {
"alerta": "stock_bajo_minimo",
"tension_posible": "stock_critico_comercial",
"responsable": "Stock",
"consultados": ["Compras", "Comercial"],
"accion": "activar_reposicion",
"severidad": "alta"
}
return None
14.2 Cobertura menor al plazo proveedor
def regla_cobertura_menor_plazo(stock_actual, venta_promedio_diaria, plazo_proveedor):
if venta_promedio_diaria == 0:
return None
dias_cobertura = stock_actual / venta_promedio_diaria
if dias_cobertura < plazo_proveedor:
return {
"alerta": "cobertura_insuficiente",
"tension": "stock_critico_comercial",
"responsable": "Compras",
"consultados": ["Stock", "Comercial"],
"accion": "comprar_o_buscar_proveedor_alternativo",
"dias_cobertura": dias_cobertura,
"severidad": "alta"
}
return None
14.3 Stock mal compuesto
def regla_stock_mal_compuesto(stock_total_var, rotacion_var, quiebres_productos_clave, stock_inmovilizado_var):
condiciones = [
stock_total_var > 0.10,
rotacion_var < -0.10,
quiebres_productos_clave > 0,
stock_inmovilizado_var > 0.15
]
if sum(condiciones) >= 3:
return {
"tension": "stock_mal_compuesto",
"responsable": "Stock",
"consultados": ["Compras", "Comercial", "Finanzas"],
"accion": "revisar_mix_stock_y_bloquear_compras_lentas",
"severidad": "alta"
}
return None
15. Reglas de compras y proveedores
15.1 Proveedor crítico
def regla_proveedor_critico(cumplimiento, dependencia, plazo_var):
if cumplimiento < 0.75 and dependencia > 0.40:
return {
"tension": "proveedor_critico",
"responsable": "Compras",
"consultados": ["Stock", "Finanzas"],
"accion": "buscar_proveedor_alternativo",
"severidad": "alta"
}
if plazo_var > 0.25 and dependencia > 0.50:
return {
"alerta": "plazo_proveedor_en_deterioro",
"tension_posible": "proveedor_critico",
"accion": "renegociar_plazo_o_abrir_alternativa",
"severidad": "media_alta"
}
return None
15.2 Compras reactivas
def regla_compras_reactivas(compras_urgentes_ratio, variacion_precio_compra):
if compras_urgentes_ratio > 0.20 and variacion_precio_compra > 0.10:
return {
"tension": "compras_reactivas",
"responsable": "Compras",
"consultados": ["Stock", "Finanzas"],
"accion": "crear_plan_reposicion_por_rotacion",
"severidad": "media_alta"
}
return None
16. Reglas de RRHH
16.1 Costo laboral desalineado
def regla_costo_laboral_desalineado(costo_laboral_var, ventas_var, productividad_var):
if costo_laboral_var > ventas_var and productividad_var <= 0:
return {
"tension": "costo_laboral_desalineado",
"responsable": "RRHH",
"consultados": ["Finanzas", "Dirección"],
"accion": "revisar_dotacion_y_productividad",
"severidad": "media_alta"
}
return None
16.2 Ausentismo operativo
def regla_ausentismo_operativo(ausentismo, demoras_operativas_var):
if ausentismo > 0.08 and demoras_operativas_var > 0:
return {
"tension": "ausentismo_operativo",
"responsable": "RRHH",
"consultados": ["Operaciones"],
"accion": "revisar_cobertura_operativa_y_plan_de_reemplazos",
"severidad": "media"
}
return None
17. Reglas de operaciones y workflow
17.1 Acción crítica vencida
def regla_accion_critica_vencida(accion):
if accion["prioridad"] == "critica" and accion["estado"] != "cerrada" and accion["dias_vencida"] >= 1:
return {
"alerta": "accion_critica_vencida",
"responsable": accion["responsable"],
"escalar_a": "Gerencia General",
"accion": "exigir_cierre_o_reasignar",
"severidad": "critica"
}
return None
17.2 Dirección sin ejecución
def regla_direccion_sin_ejecucion(decisiones, acciones_creadas, acciones_vencidas, reincidencias):
if decisiones == 0:
return None
ratio_acciones = acciones_creadas / decisiones
ratio_vencidas = acciones_vencidas / acciones_creadas if acciones_creadas else 0
condiciones = [
ratio_acciones < 0.70,
ratio_vencidas > 0.20,
reincidencias > 2
]
if sum(condiciones) >= 2:
return {
"tension": "direccion_sin_ejecucion",
"responsable": "Gerencia General",
"accion": "activar_workflow_obligatorio_y_escalamiento",
"severidad": "alta"
}
return None
18. Reglas de alertas FARO
Una regla puede emitir una alerta cuando el evento necesita visibilidad.
Ejemplo de alerta simple
def generar_alerta(rule_result):
if not rule_result:
return None
return {
"alert_code": rule_result.get("alerta") or rule_result.get("tension"),
"severity": rule_result.get("severidad", "media"),
"responsible": rule_result.get("responsable"),
"suggested_action": rule_result.get("accion"),
"status": "open"
}
Ejemplo de regla con confianza mínima
def evaluar_regla_con_confianza(condicion_cumplida, confianza, confianza_minima=0.75):
if condicion_cumplida and confianza >= confianza_minima:
return "activar_alerta"
if condicion_cumplida and confianza < confianza_minima:
return "observar_requiere_validacion"
return "sin_accion"
Esto es clave: FARO no debe gritar con datos flojos.
19. Reglas de tensiones
Las tensiones nacen de varias señales o reglas activas.
19.1 Crecimiento no rentable
def regla_tension_crecimiento_no_rentable(ctx):
condiciones = [
ctx["ventas_var"] > 0.15,
ctx["margen_var"] < -0.05,
ctx["descuento_var"] > 0.04,
ctx["dias_cobranza_var"] > 7,
ctx["comision_var"] > 0
]
if sum(condiciones) >= 3:
return {
"tension": "crecimiento_no_rentable",
"areas": ["Comercial", "Finanzas", "Stock", "RRHH"],
"severidad": "alta",
"responsable": "Gerente Comercial",
"consultados": ["Finanzas", "Stock", "RRHH"],
"acciones": [
"auditar_descuentos_altos",
"revisar_cobranza_clientes_grandes",
"revisar_formula_comision"
]
}
return None
19.2 Cliente grande riesgoso
def regla_tension_cliente_grande_riesgoso(ctx):
condiciones = [
ctx["concentracion_cliente"] > 0.15,
ctx["dias_mora"] > 30,
ctx["margen_cliente"] < 0.20,
ctx["deuda_vencida"] > 0
]
if sum(condiciones) >= 3:
return {
"tension": "cliente_grande_riesgoso",
"responsable": "Finanzas",
"consultados": ["Comercial"],
"accion": "revisar_limite_credito_y_condiciones",
"severidad": "alta"
}
return None
20. Reglas de asignación de responsables
FARO debe asignar responsables según RACI.
Ejemplo
def asignar_responsable_por_tipo_evento(tipo_evento):
mapa = {
"margen_critico": {
"R": "Gerente Comercial",
"A": "Dirección",
"C": ["Finanzas", "Compras"],
"I": ["Administración"]
},
"stock_critico": {
"R": "Responsable de Stock",
"A": "Dirección",
"C": ["Compras", "Comercial"],
"I": ["Sucursal"]
},
"cobranza_lenta": {
"R": "Finanzas",
"A": "Dirección",
"C": ["Comercial"],
"I": ["Administración"]
},
"accion_vencida": {
"R": "Responsable asignado",
"A": "Gerencia General",
"C": ["Área involucrada"],
"I": ["Dirección"]
}
}
return mapa.get(tipo_evento)
Regla sana:
Una alerta sin responsable es ruido con diseño premium.
21. Reglas de escalamiento
FARO debe escalar cuando una acción no se resuelve.
Escalamiento por vencimiento
def regla_escalamiento_accion(accion):
if accion["estado"] == "cerrada":
return None
if accion["prioridad"] == "critica" and accion["dias_vencida"] >= 1:
return {
"escalar_a": "Gerencia General",
"motivo": "acción crítica vencida",
"severidad": "critica"
}
if accion["prioridad"] == "alta" and accion["dias_vencida"] >= 3:
return {
"escalar_a": "Dirección",
"motivo": "acción alta vencida más de 3 días",
"severidad": "alta"
}
if accion["dias_vencida"] >= 7:
return {
"escalar_a": "Responsable superior",
"motivo": "acción vencida recurrente",
"severidad": "media"
}
return None
22. Reglas de FARO Score
Las reglas también modifican el Score.
Ejemplo simple
def impacto_score_por_evento(evento):
impactos = {
"margen_critico": -5,
"stock_critico": -4,
"cobranza_roja": -5,
"accion_critica_vencida": -6,
"crecimiento_no_rentable": -8,
"calidad_datos_baja": -3,
"accion_cerrada_en_fecha": 2,
"margen_recuperado": 4
}
return impactos.get(evento, 0)
Regla con severidad
def impacto_score_por_severidad(severidad):
if severidad == "critica":
return -8
if severidad == "alta":
return -5
if severidad == "media":
return -2
if severidad == "baja":
return -1
return 0
23. Reglas por industria
23.1 Construcción / insumos
Canje mal evaluado
def regla_canje_mal_evaluado(valor_materiales, valor_activo_recibido, liquidez_activo, margen_estimado):
condiciones = [
valor_activo_recibido < valor_materiales,
liquidez_activo < 0.50,
margen_estimado < 0.20
]
if sum(condiciones) >= 2:
return {
"tension": "canje_mal_evaluado",
"responsable": "Dirección / Finanzas",
"consultados": ["Comercial", "Legal"],
"accion": "evaluar_canje_con_modelo_financiero",
"severidad": "alta"
}
return None
Referido sin trazabilidad
def regla_referido_sin_trazabilidad(comision_referido, margen_operacion, referido_identificado):
if comision_referido > 0 and not referido_identificado:
return {
"alerta": "referido_sin_trazabilidad",
"responsable": "Comercial",
"accion": "regularizar_identificacion_y_condicion_del_referido",
"severidad": "media_alta"
}
if margen_operacion > 0 and (comision_referido / margen_operacion) > 0.25:
return {
"tension": "referido_erosiona_margen",
"accion": "revisar_politica_de_referidos",
"severidad": "alta"
}
return None
23.2 Retail
def regla_promocion_destructiva(ventas_var, margen_var, promo_activa):
if promo_activa and ventas_var > 0.10 and margen_var < -0.08:
return {
"tension": "promocion_destructiva",
"responsable": "Comercial / Marketing",
"accion": "revisar_promocion_por_categoria_y_margen",
"severidad": "alta"
}
return None
23.3 Logística
def regla_ruta_no_rentable(costo_km, costo_km_objetivo, margen_cliente):
if costo_km > costo_km_objetivo * 1.10 and margen_cliente < 0.12:
return {
"tension": "ruta_no_rentable",
"responsable": "Operaciones",
"consultados": ["Finanzas"],
"accion": "redisenar_ruta_o_renegociar_tarifa",
"severidad": "alta"
}
return None
23.4 Hotelería
def regla_ocupacion_alta_tarifa_baja(ocupacion, adr, adr_objetivo):
if ocupacion > 0.85 and adr < adr_objetivo * 0.90:
return {
"tension": "ocupacion_alta_tarifa_baja",
"responsable": "Revenue Management",
"accion": "recalibrar_tarifas_y_canales",
"severidad": "media_alta"
}
return None
24. Motor de reglas FARO
El motor de reglas debe evaluar condiciones y devolver consecuencias.
Flujo:
Datos / KPIs / Señales
→ seleccionar reglas aplicables
→ validar calidad mínima
→ evaluar condiciones
→ calcular severidad
→ calcular confianza
→ generar alerta / tensión / acción
→ asignar responsable
→ impactar score
→ registrar trazabilidad
Código conceptual:
def motor_reglas(contexto, reglas):
resultados = []
for regla in reglas:
if not regla.get("active", True):
continue
if contexto.get("confidence", 1) < regla.get("confidence_min", 0):
resultados.append({
"rule_code": regla["rule_code"],
"status": "observed_low_confidence"
})
continue
if evaluar_condicion(regla["condition"], contexto):
resultados.append({
"rule_code": regla["rule_code"],
"status": "triggered",
"then": regla["then"],
"severity": regla.get("severity"),
"score_impact": regla.get("score_impact")
})
return resultados
25. Evaluador simple de condiciones
Ejemplo básico:
def comparar(valor, operador, esperado):
if operador == ">":
return valor > esperado
if operador == "<":
return valor < esperado
if operador == ">=":
return valor >= esperado
if operador == "<=":
return valor <= esperado
if operador == "==":
return valor == esperado
if operador == "!=":
return valor != esperado
return False
def evaluar_condicion(condicion, contexto):
if "all" in condicion:
return all(
comparar(
contexto.get(c["field"]),
c["operator"],
c["value"]
)
for c in condicion["all"]
)
if "any" in condicion:
return any(
comparar(
contexto.get(c["field"]),
c["operator"],
c["value"]
)
for c in condicion["any"]
)
return False
26. Tabla SQL de reglas
CREATE TABLE business_rules (
rule_code TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
module TEXT,
area_id TEXT,
industry_scope JSONB,
inputs JSONB,
condition JSONB NOT NULL,
confidence_min NUMERIC DEFAULT 0.70,
severity TEXT,
then_action JSONB,
score_impact JSONB,
responsible_role TEXT,
approver_role TEXT,
active BOOLEAN DEFAULT true,
version TEXT DEFAULT '1.0',
created_by TEXT,
approved_by TEXT,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now()
);
27. Tabla SQL de ejecución de reglas
CREATE TABLE rule_executions (
execution_id TEXT PRIMARY KEY,
rule_code TEXT NOT NULL,
company_id TEXT,
branch_id TEXT,
area_id TEXT,
input_snapshot JSONB,
result JSONB,
status TEXT,
severity TEXT,
confidence NUMERIC,
triggered_at TIMESTAMP DEFAULT now()
);
Esto permite auditar:
qué regla se ejecutó,
con qué datos,
qué resultado dio,
qué alerta generó,
qué acción disparó,
qué score impactó.
28. Versionado de reglas
Las reglas cambian. FARO debe versionarlas.
Ejemplo:
Regla margen v1:
margen < 20%
Regla margen v2:
margen < 22% y descuento > 10%
Regla margen v3:
margen depende de industria y familia de producto.
Tabla sugerida:
CREATE TABLE business_rule_versions (
version_id TEXT PRIMARY KEY,
rule_code TEXT NOT NULL,
version TEXT NOT NULL,
previous_definition JSONB,
new_definition JSONB,
changed_by TEXT,
approved_by TEXT,
change_reason TEXT,
active_from DATE,
created_at TIMESTAMP DEFAULT now()
);
Regla sana:
Una regla crítica no se cambia sin motivo, aprobador y fecha de vigencia.
29. Gobernanza de reglas
| Tipo de regla | Responsable | Aprobador |
|---|---|---|
| Validación de datos | Sistemas / Data Owner | Dirección / Data Governance |
| Calidad de datos | Sistemas / Data Owner | Dirección |
| Comercial | Gerente Comercial | Dirección |
| Finanzas | Finanzas | Dirección |
| Stock | Stock / Compras | Dirección |
| RRHH | RRHH | Dirección |
| Workflow | Gerencia General | Dirección |
| FARO Score | Dirección | Directorio |
| Industria | Consultoría / Dirección | Dirección / Cliente |
30. Estados de una regla
| Estado | Significado |
|---|---|
| Draft | Regla en diseño. |
| Testing | Regla en prueba. |
| Active | Regla activa. |
| Observed | Regla observa, pero no dispara acción automática. |
| Suspended | Regla pausada. |
| Deprecated | Regla reemplazada. |
| Archived | Regla histórica. |
31. Reglas en modo observación
Al principio, muchas reglas deberían correr en modo observación.
Ejemplo:
La regla detecta margen bajo,
pero todavía no genera acción automática.
Primero se valida si la detección es correcta.
Esto evita automatizar errores.
Recomendación:
Fase inicial:
reglas críticas en observación durante 2 a 4 semanas.
Luego:
activar alertas y acciones cuando se confirme que funcionan.
32. Reglas y confianza
Una misma regla puede tener distintos resultados según confianza.
| Condición | Resultado |
|---|---|
| Regla cumplida + confianza alta | Activar alerta / acción. |
| Regla cumplida + confianza media | Activar alerta con observación. |
| Regla cumplida + confianza baja | Pedir validación. |
| Regla no cumplida | No actuar. |
Ejemplo:
def decidir_salida_regla(regla_cumplida, confianza):
if not regla_cumplida:
return "sin_accion"
if confianza >= 0.85:
return "activar_accion"
if confianza >= 0.70:
return "activar_alerta_con_observacion"
if confianza >= 0.50:
return "pedir_validacion"
return "no_usar_para_decision"
33. Reglas y acciones automáticas
No todas las reglas deben generar acciones automáticas.
| Tipo de evento | Acción automática |
|---|---|
| Dato inválido | Sí, bloquear o observar. |
| Tarea vencida | Sí, notificar o escalar. |
| Stock bajo mínimo | Sí, crear acción de revisión. |
| Margen bajo | Mejor sugerir, no ejecutar automáticamente. |
| Cliente moroso | Sugerir bloqueo, requiere aprobación. |
| Cambio de comisión | Nunca automático sin Dirección. |
| Canje | Nunca automático sin análisis directivo. |
| Despido / sanción RRHH | Nunca automático. Solo señal / recomendación. |
Regla conservadora:
FARO puede sugerir muchas decisiones, pero no debe ejecutar decisiones sensibles sin aprobación humana.
34. Ejemplo completo: regla comercial
Contexto
{
"ventas_var": 0.18,
"margen_actual": 0.21,
"margen_anterior": 0.28,
"descuento_actual": 0.12,
"dias_cobranza_var": 10,
"confidence": 0.84
}
Regla
Si ventas suben más de 15%
y margen cae más de 5 puntos
y descuento supera 10%
entonces detectar crecimiento no rentable.
Resultado FARO
{
"tension": "crecimiento_no_rentable",
"severity": "alta",
"confidence": 0.84,
"responsible": "Gerente Comercial",
"consulted": ["Finanzas", "Stock", "RRHH"],
"suggested_actions": [
"auditar_descuentos_altos",
"revisar_comisiones",
"priorizar_cobranza_clientes_grandes"
],
"score_impact": -8
}
35. Ejemplo completo: regla de stock
Contexto
{
"product_id": "PROD_001",
"stock_actual": 180,
"stock_minimo": 150,
"venta_promedio_diaria": 45,
"plazo_proveedor": 7,
"confidence": 0.90
}
Regla
Si días de cobertura < plazo proveedor,
aunque stock actual sea mayor al mínimo,
activar señal temprana de stock crítico futuro.
Resultado
{
"signal": "stock_critico_futuro",
"dias_cobertura": 4,
"plazo_proveedor": 7,
"alert": "cobertura_insuficiente",
"responsible": "Compras",
"consulted": ["Stock", "Comercial"],
"suggested_action": "anticipar_reposicion",
"severity": "alta"
}
36. Ejemplo completo: regla de dirección
Contexto
{
"decisiones_tomadas": 20,
"acciones_creadas": 12,
"acciones_vencidas": 6,
"problemas_reincidentes": 4,
"confidence": 0.88
}
Resultado FARO
{
"tension": "direccion_sin_ejecucion",
"severity": "alta",
"responsible": "Gerencia General",
"suggested_action": "activar_workflow_obligatorio",
"score_impact": -7
}
37. Herramientas posibles
| Necesidad | Herramientas |
|---|---|
| Motor de reglas propio | Python, Node.js, TypeScript |
| Reglas JSON | JSON Rules Engine, json-logic |
| Backend | FastAPI, NestJS, Django |
| Base de reglas | PostgreSQL JSONB |
| Orquestación | Celery, Temporal, Airflow, Prefect |
| Testing de reglas | Pytest, unit tests, fixtures |
| Auditoría | rule_executions, logs, data lineage |
| Versionado | Git + tablas de versiones |
| Reglas complejas | Drools, Durable Rules, motores expertos |
| IA explicativa | OpenAI API + plantillas FARO + RAG |
| Simulación | Python, Pandas, Monte Carlo, escenarios |
38. Testing de reglas
Cada regla debe probarse con casos.
Ejemplo test simple
def test_descuento_alto_margen_bajo():
resultado = regla_descuento_alto_margen_bajo(
margen=0.18,
descuento=0.12
)
assert resultado is not None
assert resultado["alerta"] == "margen_critico_con_descuento_alto"
assert resultado["severidad"] == "alta"
Test negativo
def test_no_dispara_si_margen_sano():
resultado = regla_descuento_alto_margen_bajo(
margen=0.30,
descuento=0.12
)
assert resultado is None
Sin testing, las reglas son opiniones con sintaxis.
39. Riesgos si no existe esta capa
| Riesgo | Consecuencia |
|---|---|
| KPIs sin acción | El sistema informa, pero no dirige. |
| Alertas arbitrarias | El usuario no entiende por qué se activan. |
| Tensiones débiles | No hay lógica que las sostenga. |
| Recomendaciones genéricas | FARO dice obviedades. |
| Score inexplicable | No se sabe qué lo afecta. |
| Automatización peligrosa | Se toman decisiones con reglas mal definidas. |
| Baja confianza técnica | Un socio técnico puede cuestionar la arquitectura. |
| Difícil escalar | Cada cliente requiere lógica manual. |
40. Output final del Anexo 20
Al finalizar este anexo, FARO debe tener definido:
1. Biblioteca inicial de reglas de negocio.
2. Tipos de reglas FARO.
3. Reglas de validación de datos.
4. Reglas de calidad de datos.
5. Reglas por KPI.
6. Reglas por señal.
7. Reglas de alerta.
8. Reglas de tensión.
9. Reglas de acción.
10. Reglas de responsable / RACI.
11. Reglas de escalamiento.
12. Reglas de FARO Score.
13. Reglas por industria.
14. Motor de reglas.
15. Estructura JSON de reglas.
16. Modelo SQL de reglas.
17. Tabla de ejecución de reglas.
18. Versionado de reglas.
19. Testing de reglas.
20. Gobernanza y aprobadores.
21. Modo observación.
22. Reglas automáticas vs reglas con aprobación humana.
23. Relación regla → alerta.
24. Relación regla → tensión.
25. Relación regla → acción.
26. Relación regla → score.
41. Conexión con otros anexos
| Próximo anexo | Qué recibe desde Anexo 20 |
|---|---|
| Anexo 17 — Biblioteca de KPIs | KPIs usados como inputs de reglas. |
| Anexo 18 — Objetivos y umbrales | Condiciones para definir estados. |
| Anexo 19 — Señales FARO | Señales que alimentan reglas. |
| Anexo 21 — Alertas FARO | Reglas que disparan alertas. |
| Anexo 22 — Biblioteca de tensiones | Combinaciones de reglas y señales. |
| Anexo 23 — Diagnóstico ejecutivo | Interpretación de reglas activadas. |
| Anexo 24 — Confianza del diagnóstico | Confianza mínima para actuar. |
| Anexo 25 — Priorización ejecutiva | Severidad y prioridad según reglas. |
| Anexo 26 — Recomendaciones FARO | Recomendaciones derivadas de reglas. |
| Anexo 29 — Biblioteca de acciones | Acciones sugeridas por regla. |
| Anexo 31 — Workflow y escalamiento | Reglas que asignan, vencen y escalan acciones. |
| Anexo 35 — FARO Score | Penalizaciones y mejoras por reglas activadas. |
| Anexo 37 — Recalibración | Ajuste de reglas según resultados reales. |
Las reglas de negocio FARO son la capa lógica que convierte KPIs y señales en decisiones accionables. Definen cuándo un dato importa, cuándo se activa una alerta, cuándo nace una tensión, qué acción se sugiere, quién responde, cuándo se escala y cómo impacta en el FARO Score.