Código inmutable
Una vez asignado, TNS-001 = Crecimiento no rentable nunca se reutiliza para otra tensión. Reutilizar códigos rompe el histórico, los reportes y los tests.
Verdad oficial de TNS-001 a TNS-030 que rige reglas YAML, motor evaluador, UI, demo, tests y reportes. Coexiste con la biblioteca extendida de 300 tensiones (v2) con mapeo bidireccional.
Este catálogo establece 30 tensiones canónicas (TNS-001 a TNS-030) que son la fuente única de verdad para todo el MVP de FARO Connect. Si un código TNS no está acá, no debería existir en ningún módulo del sistema.
FARO maneja dos namespaces de tensiones que coexisten intencionalmente:
TNS-001..TNS-030 que rigen el motor evaluador, las reglas YAML, la UI de la bandeja, la demo en Empresa Demo Cuyo S.A., los tests de integración y los reportes ejecutivos del primer release.La decisión ejecutiva detrás de esta separación: el MVP necesita un set finito, estable y testeado; la biblioteca v2 necesita libertad para crecer sin romper producción. Mezclar ambos namespaces es la receta clásica para que el catálogo se contradiga consigo mismo a los seis meses.
Desde el momento en que este documento queda aprobado, aplica la regla dura: ningún módulo (SQL, YAML, motor, UI, tests, reportes, demo) puede usar un tension_code que no esté listado acá. El parser de reglas YAML rechaza códigos desconocidos con UNKNOWN_TENSION_CODE. El motor evaluador enriquece toda tensión disparada con los metadatos de faro.tension_definitions. La UI no permite nombres hardcodeados.
Lo que parece un detalle técnico es gobierno de producto: cuando FARO diga TNS-001, todos los módulos entienden “Crecimiento no rentable”, con la misma severidad base, el mismo responsable por defecto y la misma dimensión Score afectada. Sin catálogo canónico, el sistema crece torcido y después no se arregla con diseño premium; se arregla con bisturí.
Antes de tocar cualquier código TNS-NNN, leer estas reglas. Romperlas no se nota en el commit; se nota seis meses después cuando dos módulos interpretan el mismo código distinto.
Una vez asignado, TNS-001 = Crecimiento no rentable nunca se reutiliza para otra tensión. Reutilizar códigos rompe el histórico, los reportes y los tests.
Si una tensión deja de usarse, pasa a status = archived. Borrar tensiones rompe las referencias en datos históricos y rule_evaluations.
Si cambia la lógica de disparo o el impacto Score, se incrementa version. El tension_code base se mantiene. UNIQUE (tension_code, version).
Alerta = “Descuento alto”. Tensión = “Crecimiento no rentable”. FARO no se llena de alertitas; FARO lee el negocio. Si no es diagnóstico, no entra.
Si recommended_actions está vacío, la tensión no entra al catálogo MVP. Sin acción no hay cierre operativo posible.
Si evidence_required está vacío, no hay cierre confiable. FARO no premia relatos; premia evidencia documentada.
Aunque sea poco, toda tensión tiene score_impact_min/max ambos negativos. Tensiones que no impactan Score son ruido, no señal.
YAML, parser, motor, UI, tests y reportes consumen faro.tension_definitions. Prohibido nombres hardcodeados en código de aplicación.
Toda tensión del MVP cumple este contrato. Es lo que define faro.tension_definitions en SQL y lo que el motor evaluador puede esperar al enriquecer una tensión disparada.
| Campo | Tipo | Descripción | Ejemplo (TNS-001) |
|---|---|---|---|
tension_code | text · unique | Código canónico inmutable. Formato TNS-NNN. | TNS-001 |
name | text | Nombre canónico ejecutivo de la tensión. | Crecimiento no rentable |
short_name | text · null | Nombre corto para tablas densas y UI compacta. | Crecimiento no rentable |
area_code | text | Área funcional principal (commercial, finance, stock, etc.). | commercial |
module_code | text | Módulo FARO específico dentro del área. | sales_margin |
business_question | text | Pregunta ejecutiva que la tensión responde. | ¿Estamos vendiendo más pero ganando menos? |
description | text | Qué detecta técnicamente (1-2 líneas). | Crecimiento de ventas + caída de margen + aumento de descuentos. |
executive_diagnosis | text | Lectura ejecutiva al estilo FARO (qué significa para dirección). | La empresa crece en volumen pero sacrifica rentabilidad. |
trigger_logic | text | Lógica base de disparo en lenguaje natural. | Ventas netas suben + margen bruto cae + descuento sube. |
required_kpis | text[] | KPIs necesarios para que la regla pueda evaluarse. | KPI-SAL-001 KPI-SAL-002 KPI-SAL-003 |
recommended_actions | text[] | Acciones sugeridas por defecto al dispararse. | ACT-COM-001 ACT-COM-002 ACT-COM-003 |
evidence_required | text[] | Evidencia mínima para validar cierre. | EVD-007 EVD-012 |
default_severity | enum | Severidad base. Valores: low, medium, high, critical. | high |
severity_logic | text · null | Cómo escala severidad según condiciones específicas. | Alta por defecto; crítica si margen cae bajo umbral. |
default_owner_role | text | Rol responsable por defecto. | commercial_manager |
approver_role | text · null | Rol aprobador por defecto. | general_manager |
score_dimension | text | Dimensión del FARO Score afectada. | commercial_health |
score_impact_min / max | numeric | Rango de impacto en Score (siempre negativos). | -12 a -8 |
mvp_priority | enum | Prioridad MVP: P1 (demo), P2 (segunda capa), P3 (backlog). | P1 |
demo_relevance | boolean | Si debe aparecer en la demo de Empresa Demo Cuyo S.A. | true |
La tabla muestra los 17 campos lógicos del contrato. La DDL real (sección 7) agrega industry_scope, module_scope, status, version, metadata, timestamps y UUID — todos operativos, no semánticos.
Una ficha por tensión con código, severidad base, área, owner por defecto, KPIs requeridos, acciones recomendadas, evidencia y rango de impacto Score. Las marcadas DEMO son las que aparecen en la demo de Empresa Demo Cuyo S.A.
Detecta crecimiento de ventas acompañado por caída de margen y aumento de descuentos.
La empresa crece en volumen, pero sacrifica rentabilidad. No es crecimiento sano; es crecimiento comprado con margen.
KPI-SAL-001KPI-SAL-002KPI-SAL-003ACT-COM-001ACT-COM-002ACT-COM-003EVD-007EVD-012Detecta descuentos superiores a la política comercial aprobada.
El sistema detecta venta con descuento excesivo. La venta puede verse bien arriba, pero abajo erosiona margen.
KPI-SAL-003KPI-SAL-006ACT-COM-001ACT-COM-003EVD-007EVD-012Detecta vendedores con alto volumen, descuento elevado y margen inferior al objetivo.
El vendedor cumple volumen, pero no necesariamente cumple negocio. La comisión debe premiar rentabilidad, no solo facturación.
KPI-SAL-004KPI-SAL-005KPI-SAL-006ACT-COM-004ACT-COM-002ACT-COM-003EVD-010EVD-012Detecta crecimiento comercial acompañado de deterioro en cobranza.
La venta no es caja hasta que se cobra. Si la cobranza se estira, el crecimiento puede estar financiando al cliente.
KPI-SAL-001KPI-FIN-001KPI-FIN-002ACT-FIN-001ACT-FIN-002ACT-FIN-003EVD-011EVD-006EVD-012Detecta clientes con deuda vencida relevante y días de mora superiores al umbral.
No todos los clientes vencidos pesan igual. FARO prioriza los que combinan atraso, monto y riesgo.
KPI-FIN-003KPI-FIN-004ACT-FIN-001ACT-FIN-002EVD-011EVD-006Detecta productos de alta rotación con cobertura insuficiente.
La empresa puede tener ventas, pero si no tiene producto, pierde margen, cliente y reputación. Tres por uno, pero malo.
KPI-STK-001KPI-STK-003ACT-STK-001ACT-STK-002EVD-005EVD-002Detecta inventario con alto valor y baja o nula rotación.
Stock quieto es caja quieta. Y caja quieta, en empresa en crecimiento, suele ser problema disfrazado de activo.
KPI-STK-002KPI-STK-004ACT-STK-003ACT-COM-001EVD-010EVD-012Detecta compras urgentes recurrentes por falta de planificación de reposición.
Comprar a las corridas casi siempre sale más caro. FARO detecta si la reposición dejó de ser proceso y pasó a ser bombero.
KPI-STK-001KPI-PUR-001ACT-STK-001ACT-PUR-001EVD-005EVD-010Detecta acciones abiertas con fecha vencida.
Una empresa no mejora por detectar problemas; mejora por cerrar acciones. Lo demás es reunión con PowerPoint.
KPI-ACT-001ACT-OPS-001ACT-DIR-001EVD-004EVD-012Detecta acciones cerradas o avanzadas sin evidencia suficiente.
Sin evidencia no hay cierre. Hay relato. FARO no debería premiar relatos.
KPI-ACT-002ACT-OPS-002ACT-DIR-001EVD-004EVD-012Detecta concentración excesiva de ventas en pocos clientes.
Vender mucho a pocos puede parecer eficiencia. También puede ser dependencia. FARO debe distinguirlo.
KPI-SAL-007KPI-CUS-001ACT-COM-004ACT-DIR-001EVD-010EVD-012Detecta caída del ticket promedio aunque la venta total se mantenga estable.
La facturación puede estar estable, pero con más esfuerzo y menor eficiencia comercial.
KPI-SAL-001KPI-SAL-008ACT-COM-001ACT-COM-004EVD-010Detecta caída relevante de ventas en una sucursal con peso comercial.
No alcanza mirar la venta total. Una sucursal puede estar cayendo mientras otra maquilla el promedio.
KPI-SAL-009ACT-COM-004ACT-DIR-001EVD-010Detecta familias de producto con margen por debajo del objetivo.
El margen promedio puede ocultar familias rotas. FARO debe abrir la caja negra del mix.
KPI-SAL-010ACT-COM-001ACT-PUR-001EVD-010EVD-012Detecta crecimiento de ventas explicado principalmente por aumento de descuentos.
No todo crecimiento es buena noticia. Si la demanda aparece solo cuando se descuenta, el negocio no está creciendo: está cediendo margen.
KPI-SAL-001KPI-SAL-003KPI-SAL-011ACT-COM-001ACT-COM-003EVD-007Detecta clientes cuya deuda o exposición supera el límite de crédito.
El crédito sin control es venta que puede transformarse en problema financiero.
KPI-FIN-005KPI-FIN-006ACT-FIN-002ACT-FIN-001EVD-011EVD-012Detecta concentración excesiva de gestión de cobranza en pocos responsables.
La cobranza no debe depender de héroes. Los héroes se cansan, se van o se enferman. El sistema debe sostener el proceso.
KPI-FIN-007ACT-FIN-003EVD-010Detecta facturación relevante con porcentaje de cobranza insuficiente.
Facturar no es cobrar. Repetimos porque parece obvio, pero las empresas se funden igual por olvidarlo.
KPI-SAL-001KPI-FIN-008ACT-FIN-001ACT-FIN-003EVD-011Detecta insuficiencia de caja proyectada frente a compromisos.
Si la caja proyectada no alcanza, todo lo demás se vuelve secundario. La caja manda. Feo, antiguo y cierto.
KPI-FIN-009KPI-FIN-010ACT-FIN-003ACT-DIR-001EVD-010EVD-012Detecta crecimiento de mora sin acciones registradas de cobranza.
El problema no es solo que la mora suba. El problema serio es que suba y no haya gestión documentada.
KPI-FIN-002KPI-ACT-003ACT-FIN-001ACT-OPS-002EVD-011Detecta quiebres de stock asociados a demanda o ventas perdidas estimadas.
El faltante de stock no solo es operativo: es venta perdida. Y la venta perdida no aparece en el ERP si nadie la registra.
KPI-STK-005KPI-SAL-012ACT-STK-001ACT-STK-002EVD-005Detecta aumento de costo de compra sin ajuste comercial suficiente.
Si el costo sube y el precio no responde, el margen paga la fiesta.
KPI-PUR-002KPI-SAL-002ACT-PUR-001ACT-COM-001EVD-010EVD-012Detecta proveedores estratégicos con demoras repetidas que impactan stock.
Un proveedor que falla seguido no es “un proveedor complicado”; es un riesgo de negocio.
KPI-PUR-003KPI-STK-001ACT-PUR-001ACT-DIR-001EVD-010Detecta stock elevado junto con deuda relevante a proveedores.
Tener stock no es malo. Tener stock que no rota mientras se debe a proveedores, sí.
KPI-STK-002KPI-PUR-004ACT-STK-003ACT-DIR-001EVD-010EVD-012Detecta reposiciones en productos con rotación insuficiente.
Comprar más de lo que no rota no es abastecimiento; es acumulación con factura.
KPI-PUR-005KPI-STK-004ACT-PUR-001ACT-STK-003EVD-010Detecta ausencia de reportes, KPIs o visibilidad ejecutiva semanal.
Una empresa sin visibilidad semanal dirige mirando por el espejo retrovisor. A veces funciona. Hasta que deja de funcionar.
KPI-DQ-001KPI-REP-001ACT-DQ-001ACT-DIR-001EVD-010EVD-012Detecta fuentes de datos críticas atrasadas o no actualizadas.
Si la fuente no llega, el diagnóstico puede quedar viejo. Y dato viejo con estética moderna sigue siendo dato viejo.
KPI-DQ-002ACT-DQ-001EVD-002EVD-004Detecta KPIs críticos con confianza de dato menor al umbral.
No todo KPI merece el mismo nivel de confianza. FARO debe decir no solo qué mide, sino cuánto cree en lo que mide.
KPI-DQ-003ACT-DQ-001EVD-002EVD-004Detecta acciones o tensiones críticas sin responsable asignado.
Problema crítico sin responsable es problema que no existe para nadie. Hasta que explota.
KPI-ACT-004ACT-OPS-001ACT-DIR-001EVD-004Detecta tensiones críticas repetidas en períodos consecutivos o recurrentes.
Una tensión crítica una vez puede ser gestión. Dos veces puede ser descuido. Tres veces ya es sistema roto.
KPI-TNS-001ACT-DIR-001ACT-OPS-002EVD-010EVD-012Las 30 tensiones no se activan todas el día uno. Se escalonan por prioridad para que la demo sea sólida sin abrir frentes operativos imposibles de sostener.
Las 15 tensiones marcadas con mvp_priority = 'P1' en el seed SQL-004. Catorce de ellas tienen demo_relevance = true y se muestran en Empresa Demo Cuyo S.A. (TNS-008 entra al motor pero queda fuera de la demo inicial).
Las 13 tensiones marcadas con mvp_priority = 'P2'. Entran después del primer release, cuando el cliente ya tiene rutina sobre las P1. Útiles operativamente pero no obligatorias para la demo.
Las 2 tensiones marcadas con mvp_priority = 'P3'. Existen en catálogo pero no se activan por defecto en el primer release; se prenden cuando el cliente las pide o cuando la madurez operativa las hace relevantes.
Nota. Los conteos coinciden literalmente con el seed SQL-004 V026 (15 P1 + 13 P2 + 2 P3 = 30). El set de demo (14 tensiones) se controla por demo_relevance, no por mvp_priority: la única P1 fuera de la demo es TNS-008 (Reposición reactiva).
Densidad alta, lectura rápida. Útil para vista directiva, control de cobertura y validación contra reglas YAML.
| Código | Tensión | Área | Severidad | Owner | Score dimensión | Impacto | Prio | Demo |
|---|---|---|---|---|---|---|---|---|
TNS-001 | Crecimiento no rentable | Comercial | High | commercial_manager | commercial_health | -12 a -8 | P1 | Sí |
TNS-002 | Descuento fuera de política | Comercial | High | commercial_manager | margin_health | -9 a -5 | P1 | Sí |
TNS-003 | Vendedor erosiona margen | Comercial | High | commercial_manager | commercial_execution | -10 a -6 | P1 | Sí |
TNS-004 | Venta sin conversión a caja | Finanzas | High | finance_manager | cash_health | -12 a -7 | P1 | Sí |
TNS-005 | Mora crítica por cliente | Finanzas | High | finance_manager | cash_risk | -10 a -6 | P1 | Sí |
TNS-006 | Stock crítico alta rotación | Stock | High | stock_manager | stock_health | -10 a -6 | P1 | Sí |
TNS-007 | Stock inmovilizado | Stock | Medium | stock_manager | stock_cash_health | -8 a -4 | P1 | Sí |
TNS-008 | Reposición reactiva | Compras | High | purchasing_manager | stock_execution | -9 a -5 | P1 | No |
TNS-009 | Acciones vencidas | Dirección | Medium | general_manager | execution_health | -10 a -4 | P1 | Sí |
TNS-010 | Acciones sin evidencia | Dirección | High | general_manager | execution_trust | -10 a -5 | P1 | Sí |
TNS-011 | Ventas concentradas | Comercial | High | commercial_manager | commercial_risk | -8 a -4 | P2 | No |
TNS-012 | Ticket promedio cae | Comercial | Medium | commercial_manager | commercial_health | -6 a -3 | P2 | No |
TNS-013 | Caída ventas sucursal | Comercial | High | commercial_manager | branch_commercial_health | -9 a -5 | P2 | No |
TNS-014 | Margen bajo por familia | Comercial | High | commercial_manager | margin_health | -9 a -5 | P2 | No |
TNS-015 | Venta crece por descuento | Comercial | High | commercial_manager | commercial_margin_health | -10 a -6 | P2 | No |
TNS-016 | Cliente supera crédito | Finanzas | Critical | finance_manager | credit_risk | -12 a -7 | P2 | No |
TNS-017 | Cobranza concentrada | Finanzas | Medium | finance_manager | cash_execution | -6 a -3 | P3 | No |
TNS-018 | Facturación alta cobranza parcial | Finanzas | High | finance_manager | cash_health | -10 a -6 | P2 | No |
TNS-019 | Caja proyectada insuficiente | Finanzas | Critical | finance_manager | cash_risk | -14 a -8 | P2 | No |
TNS-020 | Mora sin gestión | Finanzas | High | finance_manager | cash_execution | -10 a -6 | P2 | No |
TNS-021 | Quiebre con ventas perdidas | Stock | High | stock_manager | stock_commercial_health | -10 a -6 | P2 | No |
TNS-022 | Costo sube, margen no ajusta | Compras | High | purchasing_manager | margin_purchasing_health | -11 a -6 | P2 | No |
TNS-023 | Proveedor crítico demora | Compras | High | purchasing_manager | supplier_stock_risk | -9 a -5 | P2 | No |
TNS-024 | Stock alto con deuda proveedores | Finanzas/Stock | High | general_manager | cash_stock_health | -10 a -6 | P2 | No |
TNS-025 | Reposición sin rotación | Compras | Medium | purchasing_manager | stock_purchasing_health | -7 a -4 | P3 | No |
TNS-026 | Sin visibilidad semanal | Dirección | High | general_manager | direction_data_health | -9 a -5 | P1 | Sí |
TNS-027 | Fuente crítica atrasada | Datos | High | data_owner | data_quality | -8 a -4 | P1 | Sí |
TNS-028 | Baja confianza KPI | Datos | High | data_owner | data_trust | -10 a -5 | P1 | Sí |
TNS-029 | Responsable no asignado | Dirección | Critical | general_manager | governance_execution | -10 a -6 | P1 | Sí |
TNS-030 | Tensión crítica reincidente | Dirección | Critical | general_manager | learning_execution | -15 a -8 | P1 | Sí |
Migración V025__create_tension_definitions.sql. PostgreSQL 15+. Define la tabla canónica, sus constraints e índices. El seed (V026) carga sobre esta estructura.
-- ============================================================ -- FARO-SQL-004 · V025__create_tension_definitions.sql -- Catálogo canónico de tensiones FARO MVP -- ============================================================ CREATE TABLE IF NOT EXISTS faro.tension_definitions ( tension_definition_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), tension_code text NOT NULL, name text NOT NULL, short_name text NULL, area_code text NOT NULL, module_code text NOT NULL, business_question text NOT NULL, description text NOT NULL, executive_diagnosis text NOT NULL, trigger_logic text NOT NULL, required_kpis text[] NOT NULL DEFAULT ARRAY[]::text[], recommended_actions text[] NOT NULL DEFAULT ARRAY[]::text[], evidence_required text[] NOT NULL DEFAULT ARRAY[]::text[], default_severity text NOT NULL CHECK ( default_severity IN ('low', 'medium', 'high', 'critical') ), severity_logic text NULL, default_owner_role text NOT NULL, approver_role text NULL, score_dimension text NOT NULL, score_impact_min numeric(9,4) NOT NULL, score_impact_max numeric(9,4) NOT NULL, mvp_priority text NOT NULL CHECK ( mvp_priority IN ('P1', 'P2', 'P3') ), demo_relevance boolean NOT NULL DEFAULT false, industry_scope text[] NOT NULL DEFAULT ARRAY['all']::text[], module_scope text[] NOT NULL DEFAULT ARRAY[]::text[], status text NOT NULL DEFAULT 'active' CHECK ( status IN ('active', 'inactive', 'archived') ), version integer NOT NULL DEFAULT 1, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT uq_tension_definitions_code_version UNIQUE (tension_code, version) ); -- Un solo activo por código (más flexible que UNIQUE compuesto) CREATE UNIQUE INDEX IF NOT EXISTS uq_tension_definitions_one_active_per_code ON faro.tension_definitions (tension_code) WHERE status = 'active'; -- Índices de búsqueda y filtrado CREATE INDEX IF NOT EXISTS idx_tension_definitions_code ON faro.tension_definitions (tension_code); CREATE INDEX IF NOT EXISTS idx_tension_definitions_area ON faro.tension_definitions (area_code); CREATE INDEX IF NOT EXISTS idx_tension_definitions_module ON faro.tension_definitions (module_code); CREATE INDEX IF NOT EXISTS idx_tension_definitions_priority ON faro.tension_definitions (mvp_priority); CREATE INDEX IF NOT EXISTS idx_tension_definitions_demo ON faro.tension_definitions (demo_relevance); CREATE INDEX IF NOT EXISTS idx_tension_definitions_status ON faro.tension_definitions (status); -- GIN para búsqueda en arrays CREATE INDEX IF NOT EXISTS idx_tension_definitions_required_kpis ON faro.tension_definitions USING gin (required_kpis); CREATE INDEX IF NOT EXISTS idx_tension_definitions_actions ON faro.tension_definitions USING gin (recommended_actions); CREATE INDEX IF NOT EXISTS idx_tension_definitions_evidence ON faro.tension_definitions USING gin (evidence_required); COMMENT ON TABLE faro.tension_definitions IS 'Catálogo canónico de tensiones FARO. Define los códigos TNS oficiales usados por reglas, motor, UI, tests y reportes.';
Decisión técnica: se reemplaza la constraint UNIQUE (tension_code, status) propuesta inicialmente por un UNIQUE INDEX parcial filtrado por status = 'active'. Permite múltiples versiones archivadas con el mismo código sin romper la regla de “un solo activo por código”.
Migración V026__seed_tension_definitions_mvp.sql. Carga TNS-001 a TNS-030 con ON CONFLICT (tension_code, version) DO UPDATE para re-ejecución segura.
-- ============================================================ -- FARO-SQL-004 · V026__seed_tension_definitions_mvp.sql -- Seed Catálogo Canónico de Tensiones MVP FARO -- Version: v1.0 -- ============================================================ BEGIN; INSERT INTO faro.tension_definitions ( tension_code, name, short_name, area_code, module_code, business_question, description, executive_diagnosis, trigger_logic, required_kpis, recommended_actions, evidence_required, default_severity, severity_logic, default_owner_role, approver_role, score_dimension, score_impact_min, score_impact_max, mvp_priority, demo_relevance, industry_scope, module_scope, status, version, metadata ) VALUES -- ============================================================ -- TNS-001 -- ============================================================ ( 'TNS-001', 'Crecimiento no rentable', 'Crecimiento no rentable', 'commercial', 'sales_margin', '¿Estamos vendiendo más pero ganando menos?', 'Detecta crecimiento de ventas acompañado por caída de margen y aumento de descuentos.', 'La empresa crece en volumen, pero sacrifica rentabilidad. No es crecimiento sano; es crecimiento comprado con margen.', 'Ventas netas suben + margen bruto cae + descuento promedio sube.', ARRAY['KPI-SAL-001','KPI-SAL-002','KPI-SAL-003'], ARRAY['ACT-COM-001','ACT-COM-002','ACT-COM-003'], ARRAY['EVD-007','EVD-012'], 'high', 'Alta por defecto; crítica si margen cae debajo del umbral y descuento supera política.', 'commercial_manager', 'general_manager', 'commercial_health', -12, -8, 'P1', true, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','margin','discounts'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-002 -- ============================================================ ( 'TNS-002', 'Descuento fuera de política', 'Descuento fuera de política', 'commercial', 'discounts', '¿Se están otorgando descuentos por encima de lo permitido?', 'Detecta descuentos superiores a la política comercial aprobada.', 'El sistema detecta venta con descuento excesivo. La venta puede verse bien arriba, pero abajo erosiona margen.', 'Descuento promedio o descuento por operación supera umbral autorizado.', ARRAY['KPI-SAL-003','KPI-SAL-006'], ARRAY['ACT-COM-001','ACT-COM-003'], ARRAY['EVD-007','EVD-012'], 'high', 'Alta; crítica si el descuento supera fuertemente el umbral o afecta productos críticos.', 'commercial_manager', 'general_manager', 'margin_health', -9, -5, 'P1', true, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','discounts'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-003 -- ============================================================ ( 'TNS-003', 'Vendedor erosiona margen', 'Vendedor erosiona margen', 'commercial', 'salespeople', '¿Hay vendedores que venden mucho pero destruyen rentabilidad?', 'Detecta vendedores con alto volumen, descuento elevado y margen inferior al objetivo.', 'El vendedor cumple volumen, pero no necesariamente cumple negocio. La comisión debe premiar rentabilidad, no solo facturación.', 'Venta por vendedor alta + margen bajo + descuento alto.', ARRAY['KPI-SAL-004','KPI-SAL-005','KPI-SAL-006'], ARRAY['ACT-COM-004','ACT-COM-002','ACT-COM-003'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta; crítica si el vendedor concentra volumen relevante y margen muy bajo.', 'commercial_manager', 'general_manager', 'commercial_execution', -10, -6, 'P1', true, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','margin','discounts','employees'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-004 -- ============================================================ ( 'TNS-004', 'Venta sin conversión a caja', 'Venta sin caja', 'finance', 'receivables', '¿Estamos vendiendo pero no cobrando?', 'Detecta crecimiento comercial acompañado de deterioro en cobranza.', 'La venta no es caja hasta que se cobra. Si la cobranza se estira, el crecimiento puede estar financiando al cliente.', 'Ventas suben + días de cobranza suben + mora vencida sube.', ARRAY['KPI-SAL-001','KPI-FIN-001','KPI-FIN-002'], ARRAY['ACT-FIN-001','ACT-FIN-002','ACT-FIN-003'], ARRAY['EVD-011','EVD-006','EVD-012'], 'high', 'Alta; crítica si la mora crece fuerte o supera umbral de caja.', 'finance_manager', 'general_manager', 'cash_health', -12, -7, 'P1', true, ARRAY['commercial','retail','distribution','services','construction_supplies'], ARRAY['sales','receivables','finance'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-005 -- ============================================================ ( 'TNS-005', 'Mora crítica por cliente', 'Mora crítica cliente', 'finance', 'customer_risk', '¿Qué cliente está poniendo en riesgo la caja?', 'Detecta clientes con deuda vencida relevante y días de mora superiores al umbral.', 'No todos los clientes vencidos pesan igual. FARO prioriza los que combinan atraso, monto y riesgo.', 'Días vencidos altos + monto abierto vencido alto.', ARRAY['KPI-FIN-003','KPI-FIN-004'], ARRAY['ACT-FIN-001','ACT-FIN-002'], ARRAY['EVD-011','EVD-006'], 'high', 'Alta; crítica si supera monto y días críticos.', 'finance_manager', 'general_manager', 'cash_risk', -10, -6, 'P1', true, ARRAY['commercial','distribution','services','construction_supplies'], ARRAY['receivables','customers','finance'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-006 -- ============================================================ ( 'TNS-006', 'Stock crítico en productos de alta rotación', 'Stock crítico alta rotación', 'stock', 'stock_coverage', '¿Estamos por perder ventas por falta de stock?', 'Detecta productos de alta rotación con cobertura insuficiente.', 'La empresa puede tener ventas, pero si no tiene producto, pierde margen, cliente y reputación.', 'Cobertura baja + producto de alta demanda.', ARRAY['KPI-STK-001','KPI-STK-003'], ARRAY['ACT-STK-001','ACT-STK-002'], ARRAY['EVD-005','EVD-002'], 'high', 'Alta; crítica si la cobertura es menor a 3 días o hay ventas pendientes.', 'stock_manager', 'general_manager', 'stock_health', -10, -6, 'P1', true, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['stock','sales'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-007 -- ============================================================ ( 'TNS-007', 'Stock inmovilizado', 'Stock inmovilizado', 'stock', 'stock_rotation', '¿Tenemos capital dormido en mercadería que no rota?', 'Detecta inventario con alto valor y baja o nula rotación.', 'Stock quieto es caja quieta. Y caja quieta, en empresa en crecimiento, suele ser problema disfrazado de activo.', 'Valor de stock inmovilizado alto + días sin movimiento elevados.', ARRAY['KPI-STK-002','KPI-STK-004'], ARRAY['ACT-STK-003','ACT-COM-001'], ARRAY['EVD-010','EVD-012'], 'medium', 'Media; alta si el monto inmovilizado supera umbral crítico.', 'stock_manager', 'general_manager', 'stock_cash_health', -8, -4, 'P1', true, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['stock','sales','finance'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-008 -- ============================================================ ( 'TNS-008', 'Reposición reactiva', 'Reposición reactiva', 'purchasing', 'replenishment', '¿Estamos comprando tarde y por urgencia?', 'Detecta compras urgentes recurrentes por falta de planificación de reposición.', 'Comprar a las corridas casi siempre sale más caro. FARO detecta si la reposición dejó de ser proceso y pasó a ser bombero.', 'Productos críticos + compras urgentes repetidas.', ARRAY['KPI-STK-001','KPI-PUR-001'], ARRAY['ACT-STK-001','ACT-PUR-001'], ARRAY['EVD-005','EVD-010'], 'high', 'Alta; crítica si ocurre en productos estratégicos o con sobrecostos.', 'purchasing_manager', 'general_manager', 'stock_execution', -9, -5, 'P1', false, ARRAY['commercial','retail','distribution','construction_supplies','manufacturing'], ARRAY['stock','purchasing'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-009 -- ============================================================ ( 'TNS-009', 'Acciones vencidas', 'Acciones vencidas', 'direction', 'workflow', '¿Estamos perdiendo disciplina de ejecución?', 'Detecta acciones abiertas con fecha vencida.', 'Una empresa no mejora por detectar problemas; mejora por cerrar acciones. Lo demás es reunión con PowerPoint.', 'Cantidad de acciones vencidas mayor a cero.', ARRAY['KPI-ACT-001'], ARRAY['ACT-OPS-001','ACT-DIR-001'], ARRAY['EVD-004','EVD-012'], 'medium', 'Media; alta desde 3 vencidas; crítica desde 7 o si son críticas.', 'general_manager', 'director', 'execution_health', -10, -4, 'P1', true, ARRAY['all'], ARRAY['actions','workflow'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-010 -- ============================================================ ( 'TNS-010', 'Acciones sin evidencia', 'Acciones sin evidencia', 'direction', 'evidence', '¿Se están cerrando acciones sin prueba real?', 'Detecta acciones cerradas o avanzadas sin evidencia suficiente.', 'Sin evidencia no hay cierre. Hay relato. FARO no debería premiar relatos.', 'Acciones en cierre o verificación sin evidencia aprobada.', ARRAY['KPI-ACT-002'], ARRAY['ACT-OPS-002','ACT-DIR-001'], ARRAY['EVD-004','EVD-012'], 'high', 'Alta; crítica si afecta acciones críticas o reincidentes.', 'general_manager', 'director', 'execution_trust', -10, -5, 'P1', true, ARRAY['all'], ARRAY['actions','evidence','workflow'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-011 -- ============================================================ ( 'TNS-011', 'Ventas concentradas en pocos clientes', 'Ventas concentradas', 'commercial', 'customer_concentration', '¿Dependemos demasiado de pocos clientes?', 'Detecta concentración excesiva de ventas en pocos clientes.', 'Vender mucho a pocos puede parecer eficiencia. También puede ser dependencia. FARO debe distinguirlo.', 'Top clientes concentran porcentaje alto de ventas.', ARRAY['KPI-SAL-007','KPI-CUS-001'], ARRAY['ACT-COM-004','ACT-DIR-001'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta si supera 40%; crítica si supera 60%.', 'commercial_manager', 'general_manager', 'commercial_risk', -8, -4, 'P2', false, ARRAY['commercial','retail','distribution','services'], ARRAY['sales','customers','risk'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-012 -- ============================================================ ( 'TNS-012', 'Ticket promedio cae con ventas estables', 'Ticket cae', 'commercial', 'sales_mix', '¿Estamos vendiendo más operaciones de menor valor?', 'Detecta caída del ticket promedio aunque la venta total se mantenga estable.', 'La facturación puede estar estable, pero con más esfuerzo y menor eficiencia comercial.', 'Ventas estables + ticket promedio cae.', ARRAY['KPI-SAL-001','KPI-SAL-008'], ARRAY['ACT-COM-001','ACT-COM-004'], ARRAY['EVD-010'], 'medium', 'Media; alta si afecta margen o productividad comercial.', 'commercial_manager', 'general_manager', 'commercial_health', -6, -3, 'P2', false, ARRAY['commercial','retail','distribution'], ARRAY['sales','ticket','commercial_mix'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-013 -- ============================================================ ( 'TNS-013', 'Caída de ventas en sucursal relevante', 'Caída sucursal', 'commercial', 'branch_sales', '¿Qué sucursal está perdiendo ritmo?', 'Detecta caída relevante de ventas en una sucursal con peso comercial.', 'No alcanza mirar la venta total. Una sucursal puede estar cayendo mientras otra maquilla el promedio.', 'Sucursal relevante cae más que el umbral.', ARRAY['KPI-SAL-009'], ARRAY['ACT-COM-004','ACT-DIR-001'], ARRAY['EVD-010'], 'high', 'Alta si la sucursal tiene peso relevante; crítica si la caída se sostiene.', 'commercial_manager', 'general_manager', 'branch_commercial_health', -9, -5, 'P2', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','branches'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-014 -- ============================================================ ( 'TNS-014', 'Margen bajo por familia de producto', 'Margen bajo familia', 'commercial', 'product_margin', '¿Qué familia vende con margen insuficiente?', 'Detecta familias de producto con margen por debajo del objetivo.', 'El margen promedio puede ocultar familias rotas. FARO debe abrir la caja negra del mix.', 'Margen por familia menor al umbral.', ARRAY['KPI-SAL-010'], ARRAY['ACT-COM-001','ACT-PUR-001'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta; crítica si la familia representa alto volumen.', 'commercial_manager', 'general_manager', 'margin_health', -9, -5, 'P2', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','margin','products'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-015 -- ============================================================ ( 'TNS-015', 'Venta crece por descuento, no por demanda sana', 'Crecimiento por descuento', 'commercial', 'discount_driven_growth', '¿El crecimiento es real o comprado con descuentos?', 'Detecta crecimiento de ventas explicado principalmente por aumento de descuentos.', 'No todo crecimiento es buena noticia. Si la demanda aparece solo cuando se descuenta, el negocio no está creciendo: está cediendo margen.', 'Ventas suben + descuentos suben fuerte + unidades o clientes no crecen proporcionalmente.', ARRAY['KPI-SAL-001','KPI-SAL-003','KPI-SAL-011'], ARRAY['ACT-COM-001','ACT-COM-003'], ARRAY['EVD-007'], 'high', 'Alta; crítica si afecta margen y caja.', 'commercial_manager', 'general_manager', 'commercial_margin_health', -10, -6, 'P2', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['sales','discounts','demand'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-016 -- ============================================================ ( 'TNS-016', 'Cliente supera límite de crédito', 'Cliente supera crédito', 'finance', 'credit_risk', '¿Estamos vendiendo a crédito por encima del límite autorizado?', 'Detecta clientes cuya deuda o exposición supera el límite de crédito.', 'El crédito sin control es venta que puede transformarse en problema financiero.', 'Exposición actual dividida por límite de crédito mayor o igual a 100%.', ARRAY['KPI-FIN-005','KPI-FIN-006'], ARRAY['ACT-FIN-002','ACT-FIN-001'], ARRAY['EVD-011','EVD-012'], 'critical', 'Crítica por defecto si supera el límite.', 'finance_manager', 'general_manager', 'credit_risk', -12, -7, 'P2', false, ARRAY['commercial','distribution','services','construction_supplies'], ARRAY['credit','customers','receivables'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-017 -- ============================================================ ( 'TNS-017', 'Cobranza concentrada en pocos responsables', 'Cobranza concentrada', 'finance', 'collection_execution', '¿La cobranza depende demasiado de una persona o equipo?', 'Detecta concentración excesiva de gestión de cobranza en pocos responsables.', 'La cobranza no debe depender de héroes. Los héroes se cansan, se van o se enferman. El sistema debe sostener el proceso.', 'Alta proporción de cartera asignada a pocos responsables.', ARRAY['KPI-FIN-007'], ARRAY['ACT-FIN-003'], ARRAY['EVD-010'], 'medium', 'Media; alta si hay mora creciente.', 'finance_manager', 'general_manager', 'cash_execution', -6, -3, 'P3', false, ARRAY['commercial','distribution','services'], ARRAY['receivables','collections','users'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-018 -- ============================================================ ( 'TNS-018', 'Facturación alta con cobranza parcial', 'Facturación alta cobranza parcial', 'finance', 'billing_collection', '¿Estamos facturando pero cobrando parcialmente?', 'Detecta facturación relevante con porcentaje de cobranza insuficiente.', 'Facturar no es cobrar. Repetimos porque parece obvio, pero las empresas se funden igual por olvidarlo.', 'Ventas altas + ratio cobrado sobre facturado bajo.', ARRAY['KPI-SAL-001','KPI-FIN-008'], ARRAY['ACT-FIN-001','ACT-FIN-003'], ARRAY['EVD-011'], 'high', 'Alta; crítica si compromete caja proyectada.', 'finance_manager', 'general_manager', 'cash_health', -10, -6, 'P2', false, ARRAY['commercial','distribution','services','construction_supplies'], ARRAY['sales','billing','collections'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-019 -- ============================================================ ( 'TNS-019', 'Caja proyectada insuficiente', 'Caja insuficiente', 'finance', 'cash_projection', '¿La caja proyectada alcanza para las obligaciones próximas?', 'Detecta insuficiencia de caja proyectada frente a compromisos.', 'Si la caja proyectada no alcanza, todo lo demás se vuelve secundario. La caja manda. Feo, antiguo y cierto.', 'Días de caja bajos + obligaciones próximas altas.', ARRAY['KPI-FIN-009','KPI-FIN-010'], ARRAY['ACT-FIN-003','ACT-DIR-001'], ARRAY['EVD-010','EVD-012'], 'critical', 'Crítica si caja proyectada no cubre obligaciones esenciales.', 'finance_manager', 'director', 'cash_risk', -14, -8, 'P2', false, ARRAY['commercial','distribution','services','manufacturing','construction_supplies'], ARRAY['cash','finance','payments'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-020 -- ============================================================ ( 'TNS-020', 'Mora creciente sin gestión registrada', 'Mora sin gestión', 'finance', 'collection_actions', '¿La mora sube y nadie está gestionando?', 'Detecta crecimiento de mora sin acciones registradas de cobranza.', 'El problema no es solo que la mora suba. El problema serio es que suba y no haya gestión documentada.', 'Mora sube + no hay acciones o evidencias de gestión.', ARRAY['KPI-FIN-002','KPI-ACT-003'], ARRAY['ACT-FIN-001','ACT-OPS-002'], ARRAY['EVD-011'], 'high', 'Alta; crítica si involucra clientes críticos.', 'finance_manager', 'general_manager', 'cash_execution', -10, -6, 'P2', false, ARRAY['commercial','distribution','services','construction_supplies'], ARRAY['receivables','actions','evidence'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-021 -- ============================================================ ( 'TNS-021', 'Quiebre de stock con ventas perdidas', 'Quiebre con ventas perdidas', 'stock', 'lost_sales', '¿Cuánto estamos dejando de vender por no tener stock?', 'Detecta quiebres de stock asociados a demanda o ventas perdidas estimadas.', 'El faltante de stock no solo es operativo: es venta perdida. Y la venta perdida no aparece en el ERP si nadie la registra.', 'Stock cero o crítico + demanda registrada o venta perdida estimada.', ARRAY['KPI-STK-005','KPI-SAL-012'], ARRAY['ACT-STK-001','ACT-STK-002'], ARRAY['EVD-005'], 'high', 'Alta; crítica si afecta productos estratégicos.', 'stock_manager', 'general_manager', 'stock_commercial_health', -10, -6, 'P2', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['stock','sales','lost_sales'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-022 -- ============================================================ ( 'TNS-022', 'Compra con costo creciente y margen sin ajustar', 'Costo sube margen no ajusta', 'purchasing', 'cost_margin', '¿Subieron los costos y no ajustamos precios o margen?', 'Detecta aumento de costo de compra sin ajuste comercial suficiente.', 'Si el costo sube y el precio no responde, el margen paga la fiesta.', 'Costo sube + margen cae o precio no acompaña.', ARRAY['KPI-PUR-002','KPI-SAL-002'], ARRAY['ACT-PUR-001','ACT-COM-001'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta; crítica si afecta productos de alta rotación.', 'purchasing_manager', 'general_manager', 'margin_purchasing_health', -11, -6, 'P2', false, ARRAY['commercial','retail','distribution','manufacturing','construction_supplies'], ARRAY['purchasing','costs','margin'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-023 -- ============================================================ ( 'TNS-023', 'Proveedor crítico con demora recurrente', 'Proveedor crítico demora', 'purchasing', 'supplier_risk', '¿Un proveedor está generando riesgo operativo recurrente?', 'Detecta proveedores estratégicos con demoras repetidas que impactan stock.', 'Un proveedor que falla seguido no es un proveedor complicado; es un riesgo de negocio.', 'Demoras proveedor + stock crítico asociado.', ARRAY['KPI-PUR-003','KPI-STK-001'], ARRAY['ACT-PUR-001','ACT-DIR-001'], ARRAY['EVD-010'], 'high', 'Alta; crítica si afecta productos críticos o ventas perdidas.', 'purchasing_manager', 'general_manager', 'supplier_stock_risk', -9, -5, 'P2', false, ARRAY['commercial','retail','distribution','manufacturing','construction_supplies'], ARRAY['purchasing','suppliers','stock'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-024 -- ============================================================ ( 'TNS-024', 'Stock alto con deuda a proveedores', 'Stock alto deuda proveedores', 'finance', 'stock_supplier_debt', '¿Tenemos mucha mercadería y a la vez presión de proveedores?', 'Detecta stock elevado junto con deuda relevante a proveedores.', 'Tener stock no es malo. Tener stock que no rota mientras se debe a proveedores, sí.', 'Stock alto o inmovilizado + deuda o pagos vencidos a proveedores.', ARRAY['KPI-STK-002','KPI-PUR-004'], ARRAY['ACT-STK-003','ACT-DIR-001'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta; crítica si compromete abastecimiento o caja.', 'general_manager', 'director', 'cash_stock_health', -10, -6, 'P2', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['stock','suppliers','finance'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-025 -- ============================================================ ( 'TNS-025', 'Reposición sin rotación suficiente', 'Reposición sin rotación', 'purchasing', 'purchase_rotation', '¿Estamos comprando productos que no rotan?', 'Detecta reposiciones en productos con rotación insuficiente.', 'Comprar más de lo que no rota no es abastecimiento; es acumulación con factura.', 'Compra reciente + baja rotación o días sin movimiento.', ARRAY['KPI-PUR-005','KPI-STK-004'], ARRAY['ACT-PUR-001','ACT-STK-003'], ARRAY['EVD-010'], 'medium', 'Media; alta si el monto es relevante.', 'purchasing_manager', 'general_manager', 'stock_purchasing_health', -7, -4, 'P3', false, ARRAY['commercial','retail','distribution','construction_supplies'], ARRAY['purchasing','stock','rotation'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-026 -- ============================================================ ( 'TNS-026', 'Dirección sin visibilidad semanal', 'Sin visibilidad semanal', 'direction', 'executive_visibility', '¿La dirección tiene lectura semanal confiable?', 'Detecta ausencia de reportes, KPIs o visibilidad ejecutiva semanal.', 'Una empresa sin visibilidad semanal dirige mirando por el espejo retrovisor. A veces funciona. Hasta que deja de funcionar.', 'Reporte vencido o calidad de datos insuficiente.', ARRAY['KPI-DQ-001','KPI-REP-001'], ARRAY['ACT-DQ-001','ACT-DIR-001'], ARRAY['EVD-010','EVD-012'], 'high', 'Alta; crítica si coincide con tensiones críticas activas.', 'general_manager', 'director', 'direction_data_health', -9, -5, 'P1', true, ARRAY['all'], ARRAY['reports','data_quality','direction'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-027 -- ============================================================ ( 'TNS-027', 'Fuente crítica atrasada', 'Fuente atrasada', 'data', 'data_sources', '¿Una fuente crítica no está llegando a tiempo?', 'Detecta fuentes de datos críticas atrasadas o no actualizadas.', 'Si la fuente no llega, el diagnóstico puede quedar viejo. Y dato viejo con estética moderna sigue siendo dato viejo.', 'Fecha de última carga supera tolerancia.', ARRAY['KPI-DQ-002'], ARRAY['ACT-DQ-001'], ARRAY['EVD-002','EVD-004'], 'high', 'Alta; crítica si afecta KPIs de caja, ventas o stock.', 'data_owner', 'general_manager', 'data_quality', -8, -4, 'P1', true, ARRAY['all'], ARRAY['data_sources','ingestion','data_quality'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-028 -- ============================================================ ( 'TNS-028', 'Baja confianza de dato en KPI crítico', 'Baja confianza KPI', 'data', 'kpi_confidence', '¿Podemos confiar en este KPI crítico?', 'Detecta KPIs críticos con confianza de dato menor al umbral.', 'No todo KPI merece el mismo nivel de confianza. FARO debe decir no solo qué mide, sino cuánto cree en lo que mide.', 'Confidence score del KPI crítico por debajo del mínimo.', ARRAY['KPI-DQ-003'], ARRAY['ACT-DQ-001'], ARRAY['EVD-002','EVD-004'], 'high', 'Alta; crítica si el KPI afecta decisiones de caja, stock o margen.', 'data_owner', 'general_manager', 'data_trust', -10, -5, 'P1', true, ARRAY['all'], ARRAY['kpis','data_quality','confidence'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-029 -- ============================================================ ( 'TNS-029', 'Responsable no asignado en acción crítica', 'Sin responsable crítico', 'direction', 'governance', '¿Hay problemas críticos sin dueño?', 'Detecta acciones o tensiones críticas sin responsable asignado.', 'Problema crítico sin responsable es problema que no existe para nadie. Hasta que explota.', 'Acción o tensión crítica + responsible_user_id nulo.', ARRAY['KPI-ACT-004'], ARRAY['ACT-OPS-001','ACT-DIR-001'], ARRAY['EVD-004'], 'critical', 'Crítica por defecto.', 'general_manager', 'director', 'governance_execution', -10, -6, 'P1', true, ARRAY['all'], ARRAY['actions','raci','governance'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- TNS-030 -- ============================================================ ( 'TNS-030', 'Tensión crítica reincidente', 'Tensión reincidente', 'direction', 'learning', '¿Estamos repitiendo el mismo problema crítico?', 'Detecta tensiones críticas repetidas en períodos consecutivos o recurrentes.', 'Una tensión crítica una vez puede ser gestión. Dos veces puede ser descuido. Tres veces ya es sistema roto.', 'Misma tensión crítica aparece dos o más veces en ventana definida.', ARRAY['KPI-TNS-001'], ARRAY['ACT-DIR-001','ACT-OPS-002'], ARRAY['EVD-010','EVD-012'], 'critical', 'Crítica por defecto.', 'general_manager', 'director', 'learning_execution', -15, -8, 'P1', true, ARRAY['all'], ARRAY['tensions','learning','execution'], 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ) ON CONFLICT (tension_code, version) DO UPDATE SET name = EXCLUDED.name, short_name = EXCLUDED.short_name, area_code = EXCLUDED.area_code, module_code = EXCLUDED.module_code, business_question = EXCLUDED.business_question, description = EXCLUDED.description, executive_diagnosis = EXCLUDED.executive_diagnosis, trigger_logic = EXCLUDED.trigger_logic, required_kpis = EXCLUDED.required_kpis, recommended_actions = EXCLUDED.recommended_actions, evidence_required = EXCLUDED.evidence_required, default_severity = EXCLUDED.default_severity, severity_logic = EXCLUDED.severity_logic, default_owner_role = EXCLUDED.default_owner_role, approver_role = EXCLUDED.approver_role, score_dimension = EXCLUDED.score_dimension, score_impact_min = EXCLUDED.score_impact_min, score_impact_max = EXCLUDED.score_impact_max, mvp_priority = EXCLUDED.mvp_priority, demo_relevance = EXCLUDED.demo_relevance, industry_scope = EXCLUDED.industry_scope, module_scope = EXCLUDED.module_scope, status = EXCLUDED.status, metadata = EXCLUDED.metadata, updated_at = now(); COMMIT;
Verbatim del seed oficial. Las 30 entradas se presentan in extenso y sin recortes, idénticas a FARO-SQL-004 · V026__seed_tension_definitions_mvp.sql. El cierre con ON CONFLICT (tension_code, version) DO UPDATE SET ... updated_at = now() hace que la migración sea idempotente: aplicar dos veces produce el mismo estado final.
Ejecutar en orden después de aplicar V025 + V026. Cada query verifica una condición del contrato canónico. Si alguna falla, el seed no se considera aceptado.
El catálogo MVP debe tener exactamente 30 registros con status = 'active'. Ni más ni menos.
SELECT COUNT(*) AS active_tensions FROM faro.tension_definitions WHERE status = 'active';
El índice único parcial debería prevenirlo, pero esta query lo verifica explícitamente.
SELECT tension_code, COUNT(*) AS total FROM faro.tension_definitions WHERE status = 'active' GROUP BY tension_code HAVING COUNT(*) > 1;
Regla 05 del gobierno: sin acción no hay cierre operativo. El array recommended_actions no puede estar vacío.
SELECT tension_code, name FROM faro.tension_definitions WHERE status = 'active' AND cardinality(recommended_actions) = 0;
Regla 06: sin evidencia no hay cierre confiable. El array evidence_required no puede estar vacío.
SELECT tension_code, name FROM faro.tension_definitions WHERE status = 'active' AND cardinality(evidence_required) = 0;
Sin KPIs no hay regla evaluable. El array required_kpis debe tener al menos un elemento.
SELECT tension_code, name FROM faro.tension_definitions WHERE status = 'active' AND cardinality(required_kpis) = 0;
Regla 07: una tensión que no resta Score es ruido. Ambos score_impact_min y score_impact_max deben ser negativos.
SELECT tension_code, name, score_impact_min, score_impact_max FROM faro.tension_definitions WHERE status = 'active' AND (score_impact_min >= 0 OR score_impact_max >= 0);
Tensiones que deben aparecer en la demo de Empresa Demo Cuyo S.A. Lista esperada: TNS-001/002/003/004/005/006/007/009/010/026/027/028/029/030.
SELECT tension_code, name, mvp_priority, default_severity, score_dimension FROM faro.tension_definitions WHERE demo_relevance = true ORDER BY tension_code;
Cada tensión MVP del catálogo tiene una equivalencia conceptual (directa, parcial o exclusiva MVP) en biblioteca-tensiones.html. Mapeo bidireccional para que ambos namespaces convivan sin perder trazabilidad.
Convención de mapeo. Directo = 1:1 conceptual. Parcial = la v2 cubre un caso más amplio o más estrecho. MVP-only = no tiene equivalente directo en la biblioteca extendida (suele ser tensión de gobierno/datos del MVP).
| MVP | Nombre canónico MVP | Equivalente conceptual en biblioteca v2 (300) | Estado |
|---|---|---|---|
TNS-001 | Crecimiento no rentable | TNS-014 · Margen crece, pero erosiona rentabilidad sostenidaEquivalente conceptual en bloque de Margen (no replica vector descuento) | Parcial |
TNS-002 | Descuento fuera de política | TNS-005 · Costos de ventas crecen más rápido que el resultadoCostos comerciales crecen más rápido que el resultado; v2 no aísla la política de descuento | Parcial |
TNS-003 | Vendedor erosiona margen | TNS-098 · Dotación crece, pero erosiona productividad humanaTNS-008 · Dependencia excesiva dentro de pipeline comercialDotación que erosiona productividad + Dependencia excesiva en pipeline | Múltiples |
TNS-004 | Venta sin conversión a caja | TNS-036 · Ciclo económico de caja desfasado respecto a cajaCiclo económico de caja desfasado respecto a caja | Directo |
TNS-005 | Mora crítica por cliente | TNS-043 · Riesgo no controlado en cuentas por cobrarRiesgo no controlado en cuentas por cobrar | Directo |
TNS-006 | Stock crítico alta rotación | TNS-052 · Capacidad de inventario desalineada con demanda realCapacidad de inventario desalineada con demanda real | Directo |
TNS-007 | Stock inmovilizado | TNS-060 · Ciclo económico de stock desfasado respecto a cajaCiclo económico de stock desfasado respecto a caja | Directo |
TNS-008 | Reposición reactiva | TNS-071 · Recurso crítico de base de proveedores no disponible a tiempoRecurso crítico de base de proveedores no disponible a tiempo | Directo |
TNS-009 | Acciones vencidas | TNS-141 · Acciones sobre decisiones vencidas sin corrección visibleAcciones sobre decisiones vencidas sin corrección visible | Directo |
TNS-010 | Acciones sin evidencia | TNS-134 · Decisiones crece, pero erosiona gobierno con seguimientoDecisiones crecen pero erosiona gobierno con seguimiento; v2 no aísla "evidencia" | Parcial |
TNS-011 | Ventas concentradas en pocos clientes | TNS-115 · Riesgo no controlado en base de clientesRiesgo no controlado en base de clientes | Directo |
TNS-012 | Ticket promedio cae | TNS-001 · Ventas con alta actividad pero bajo resultado ejecutivoVentas con alta actividad pero bajo resultado (engloba caída de ticket) | Parcial |
TNS-013 | Caída de ventas en sucursal | TNS-159 · Sucursales fuera de ritmo contra planSucursales fuera de ritmo contra plan | Directo |
TNS-014 | Margen bajo por familia | TNS-015 · Margen fuera de ritmo contra planMargen fuera de ritmo contra plan | Directo |
TNS-015 | Venta crece por descuento | TNS-002 · Ventas crece, pero erosiona conversión rentableVentas crece, pero erosiona conversión rentable | Directo |
TNS-016 | Cliente supera crédito | TNS-043 · Riesgo no controlado en cuentas por cobrarRiesgo no controlado en cuentas por cobrar (acotado al límite de crédito) | Parcial |
TNS-017 | Cobranza concentrada | TNS-044 · Dependencia excesiva dentro de cuentas por cobrarDependencia excesiva dentro de cuentas por cobrar | Directo |
TNS-018 | Facturación alta · cobranza parcial | TNS-039 · Cartera de clientes fuera de ritmo contra planCartera de clientes fuera de ritmo contra plan (recorte facturado/cobrado) | Parcial |
TNS-019 | Caja proyectada insuficiente | TNS-031 · Riesgo no controlado en flujo de fondosRiesgo no controlado en flujo de fondos | Directo |
TNS-020 | Mora sin gestión | TNS-045 · Acciones sobre cartera de clientes vencidas sin corrección visibleAcciones sobre cartera de clientes vencidas sin corrección visible | Directo |
TNS-021 | Quiebre con ventas perdidas | TNS-058 · Promesa de servicio de stock deterioradaPromesa de servicio de stock deteriorada | Directo |
TNS-022 | Costo sube, margen no ajusta | TNS-065 · Costos de compras crecen más rápido que el resultadoCostos de compras crecen más rápido que el resultado | Directo |
TNS-023 | Proveedor crítico demora | TNS-067 · Riesgo no controlado en base de proveedoresRiesgo no controlado en base de proveedores | Directo |
TNS-024 | Stock alto con deuda proveedores | TNS-053 · Costos de stock crecen más rápido que el resultadoTNS-072 · Ciclo económico de compras desfasado respecto a cajaCostos de stock + Ciclo económico de compras (cruce stock-caja-proveedores) | Múltiples |
TNS-025 | Reposición sin rotación | TNS-066 · Datos de compras insuficientes para decidir con confianzaDatos de compras insuficientes para decidir con confianza | Parcial |
TNS-026 | Sin visibilidad semanal | TNS-138 · Datos de decisiones insuficientes para decidir con confianzaDatos de decisiones insuficientes para decidir con confianza | Parcial |
TNS-027 | Fuente crítica atrasada | TNS-279 · Datos e integraciones fuera de ritmo contra planDatos e integraciones fuera de ritmo contra plan | Parcial |
TNS-028 | Baja confianza KPI | TNS-278 · Datos e integraciones crece, pero erosiona confiabilidad del modelo ejecutivoDatos e integraciones crecen, pero erosionan confiabilidad ejecutiva | Parcial |
TNS-029 | Responsable no asignado | TNS-296 · Dependencia excesiva dentro de marco de control internoDependencia excesiva dentro de marco de control interno | Parcial |
TNS-030 | Tensión crítica reincidente | TNS-295 · Riesgo no controlado en marco de control internoRiesgo no controlado en marco de control interno (no es reincidencia) | Parcial |
Resumen del mapeo. Sobre las 30 tensiones MVP: 16 Directo · 12 Parcial · 2 Múltiples · 0 Solo MVP. Los códigos v2 que aparecen apuntan a fichas reales de biblioteca-tensiones.html; ninguna fila quedó sin equivalente conceptual porque la v2 cubre los 30 conceptos del MVP vía sus 25 áreas × 12 arquetipos (algunos parciales porque la v2 no aísla vectores muy específicos como "descuento", "evidencia" o "reincidencia").
El catálogo MVP no vive solo. Estos son los puntos donde se consume, se valida o se extiende.
300 tensiones extendidas v2 con DSL, KPIs y severidad 1-5. Mapeo bidireccional con MVP en sección 10.
1.500 cruces KPI↔TNS↔ACT validados sin huérfanos. Verifica que cada código del MVP tiene KPIs y acciones reales.
DDL completo del sistema FARO Connect. Incluye faro.tension_definitions y tablas relacionadas (tensions, actions, evidence).
Catálogo de 300 acciones con RACI y workflow. Los códigos ACT-* de cada tensión MVP resuelven contra esta biblioteca.
400 KPIs filtrables. Los required_kpis de cada tensión MVP resuelven acá.
Catálogo canónico MVP de acciones (paralelo a este pero para ACT-*). En construcción.
Catálogo canónico MVP de evidencias (paralelo a este pero para EVD-*). En construcción.
Diagnóstico ejecutivo que usa los códigos TNS canónicos como base de evaluación de empresa cliente.
Este catálogo es el primero de la trilogía. Los siguientes documentos cierran el contrato de tensión → acción → evidencia.
Este documento es la base para FARO-SQL-005 (acciones), FARO-SQL-006 (evidencias) y la migración del motor evaluador. Pasá al hub para ver el resto del pack o seguí con la biblioteca extendida de 300 tensiones.
→ Volver al hub modelos NDA