Evidencia ≠ comentario
Un comentario es relato. Una evidencia es prueba con metadata, archivo o aprobación. FARO los trata distinto y los pondera distinto.
Primera biblioteca oficial de evidencias FARO. Define qué prueba cierra una acción, qué confianza aporta, quién la revisa y qué metadata exige. Cierra el contrato Tensión → Acción → Evidencia para Empresa Demo Cuyo S.A. y todos los pilotos.
Este catálogo establece 12 evidencias canónicas (EVD-001 a EVD-012) que son la fuente única de verdad para validar que una acción FARO se cerró de verdad. Hasta este documento, FARO no tenía biblioteca de evidencias v2: este es el primer catálogo formal.
La cadena de gobierno FARO tenía tres piezas:
Sin evidencia, una acción cerrada es relato. Y los relatos son útiles para reuniones largas, pero malos para dirigir empresas. La regla dura es una acción FARO no se considera cerrada si no tiene evidencia válida. Este catálogo define exactamente qué cuenta como válida.
El MVP define 12 tipos canónicos que cubren todo el espectro operativo: documentos, capturas de sistema, aprobaciones, comentarios validados, órdenes emitidas, comprobantes externos, cambios de política, KPIs posteriores, cierres manuales justificados, actas, contactos con cliente/proveedor y validaciones de dirección. Cada tipo tiene un trust_level (low/medium/high/critical), un confidence_weight (peso en el cálculo de confianza de cierre) y reglas de validación específicas.
Desde el momento en que este catálogo queda aprobado, aplica la regla dura: ningún módulo (SQL, YAML, motor, UI, tests, reportes, demo) puede usar un evidence_code que no esté listado acá. El parser de reglas rechaza códigos desconocidos con UNKNOWN_EVIDENCE_CODE. El motor evaluador enriquece toda evidencia cargada con los metadatos de faro.evidence_definitions. El motor de Score usa el confidence_weight para decidir cuánto recupera una acción cerrada.
Lo que parece un detalle técnico es gobierno de producto: cuando FARO diga EVD-007, todos los módulos entienden "Cambio de política", con el mismo trust crítico, la misma metadata requerida (policy_name, approved_by, effective_from) y el mismo peso al recuperar Score. Sin catálogo canónico, FARO se llena de archivos sueltos sin criterio, y el Score termina premiando relatos en lugar de evidencia.
Antes de tocar cualquier código EVD-NNN, leer estas reglas. Definen qué cuenta como evidencia, qué no, y cómo se gestiona el ciclo de vida.
Un comentario es relato. Una evidencia es prueba con metadata, archivo o aprobación. FARO los trata distinto y los pondera distinto.
El trust_level de un tipo de evidencia se asigna una sola vez y no cambia con el contexto. Para subir confianza se cargan más evidencias, no se infla la existente.
Una vez asignado, EVD-007 = Cambio de política nunca se reutiliza para otro concepto. Reutilizar códigos rompe el histórico, los reportes y los tests.
Si un tipo deja de usarse, pasa a status = archived. Borrar evidencias rompe las referencias en datos históricos de faro.evidence.
EVD-004 (comentario validado) puede acompañar pero no cerrar acciones críticas por sí solo. Regla codificada en validation_rules.
Toda evidencia con can_close_action = true debe tener requires_review = true o ser de tipo approval / executive_validation.
El campo executive_purpose no puede estar vacío. Si no se sabe qué cierra ejecutivamente, no entra al catálogo.
YAML, parser, motor, UI, tests y reportes consumen faro.evidence_definitions. Prohibido nombres hardcodeados o evidencias sin código en producción.
Cada evidencia tiene un trust_level que indica cuánta confianza aporta al cierre. La distribución del MVP es 1 low · 4 medium · 5 high · 2 critical.
Aporta trazabilidad mínima. Sirve como respaldo blando, no cierra acciones críticas por sí sola. Peso típico: 0.7. Impacto Score: 0.5.
EVD-004 · Comentario validado
Aporta prueba documental u operativa estándar. Cierra acciones operativas con revisión. Peso típico: 0.8–1.1. Impacto Score: 0.5–1.5.
EVD-001
EVD-002
EVD-009
EVD-011
Aprobaciones, órdenes, comprobantes externos, KPIs y actas. Cierra acciones relevantes con revisión obligatoria. Peso típico: 1.2–1.5. Impacto Score: 1.5–2.5.
EVD-003
EVD-005
EVD-006
EVD-008
EVD-010
Cambios de política y validación de dirección. Son las únicas que cierran acciones críticas por sí mismas. Peso: 1.6–1.8. Impacto Score: 3.0. Retención 7 años.
EVD-007 · Cambio de política
EVD-012 · Validación de dirección
Cómo se usa el trust level. El motor de Score y la función faro.calculate_action_evidence_confidence usan el confidence_weight de cada evidencia aprobada para calcular cuánta confianza tiene el cierre de una acción. Una acción cerrada con EVD-007 + EVD-012 aprobadas tiene confianza máxima (1.6 + 1.8 = 3.4). Una cerrada solo con EVD-004 tiene confianza baja (0.7) y puede recuperar muy poco del Score perdido por la tensión asociada.
Toda evidencia del MVP cumple este contrato. Es lo que define faro.evidence_definitions en SQL y lo que el motor evaluador puede esperar al enriquecer una evidencia cargada.
| Campo | Tipo | Descripción | Ejemplo (EVD-001) |
|---|---|---|---|
evidence_code | text · unique | Código canónico inmutable. Formato EVD-NNN. | EVD-001 |
name | text | Nombre canónico ejecutivo de la evidencia. | Documento cargado |
short_name | text · null | Nombre corto para tablas densas y UI compacta. | Documento |
evidence_family | text | Familia conceptual (documentary, system_proof, approval, workflow, etc.). | documentary |
evidence_type | enum | Tipo técnico. Valores: document, screenshot, approval, comment, order, external_proof, policy_change, kpi_snapshot, manual_closure, meeting_record, contact_record, executive_validation, system_log, other. | document |
description | text | Qué representa técnicamente (1-2 líneas). | Archivo cargado como respaldo de una acción, decisión, política, análisis o entrega. |
executive_purpose | text | Para qué sirve ejecutivamente al cierre. | Permitir que el cierre de una acción quede respaldado por un documento verificable. |
allowed_submission_modes | text[] | Cómo se puede cargar (upload, manual, workflow, system, integration, system_capture). | upload manual |
allowed_file_types | text[] | Extensiones aceptadas si la evidencia es archivo. | pdf docx xlsx csv png jpg |
required_metadata_keys | text[] | Claves obligatorias que debe enviar quien la carga. | file_name submitted_by submitted_at |
can_be_user_submitted | boolean | Si la puede cargar un usuario manualmente. | true |
can_be_system_generated | boolean | Si el sistema puede generarla automáticamente. | false |
requires_review | boolean | Si requiere revisión humana para considerarse aprobada. | true |
can_close_action | boolean | Si por sí sola puede cerrar una acción (sujeto a criterio). | true |
default_reviewer_role | text · null | Rol que revisa por defecto. | general_manager |
minimum_reviewer_role | text · null | Rol mínimo que puede revisarla. | area_manager |
trust_level | enum | Nivel de confianza. Valores: low, medium, high, critical. | medium |
confidence_weight | numeric | Peso de confianza para el cálculo de cierre. | 1.0000 |
score_confidence_impact | numeric | Impacto en la dimensión de confianza del Score. | 1.0000 |
retention_policy | text | Política de retención (standard_5_years, strict_7_years). | standard_5_years |
audit_level | enum | Nivel de auditoría requerido. Valores: basic, standard, strict, critical. | standard |
validation_rules | jsonb | Reglas adicionales (tamaño máximo, hash obligatorio, etc.). | { "max_file_size_mb": 25, "requires_file_hash": true } |
La tabla muestra los 21 campos lógicos del contrato. La DDL real (sección 7) agrega related_action_families, related_tension_codes, related_action_codes, status, version, metadata, timestamps y UUID — todos operativos, no semánticos.
Una ficha por evidencia con código, nombre, trust level, capacidad de cierre, requiere revisión, peso de confianza, modos de carga, tipos de archivo, metadata requerida y reglas de validación. Datos verbatim del seed FARO-SQL-006.
Archivo cargado como respaldo de una acción, decisión, política, análisis o entrega.
Permitir que el cierre de una acción quede respaldado por un documento verificable.
file_namesubmitted_bysubmitted_at{
"max_file_size_mb": 25,
"requires_file_hash": true,
"requires_storage_uri": true
}
Captura o exportación visual de un sistema interno o externo que respalda una acción o dato.
Respaldar visualmente cambios, estados, cargas, stock, reportes, fuentes o configuraciones.
source_systemcaptured_atsubmitted_byTNS-006TNS-027TNS-028ACT-STK-001ACT-STK-002ACT-DQ-001ACT-DQ-002{
"requires_source_system": true,
"requires_capture_date": true,
"accepted_sources": ["erp", "crm", "pos", "bank", "spreadsheet", "faro", "external_system"]
}
Registro formal de aprobación realizada por responsable autorizado.
Asegurar que una decisión o cambio crítico fue aprobado por el nivel correspondiente.
approved_byapproved_atapproval_scopeACT-DIR-003{
"requires_approver_user_id": true,
"requires_role_validation": true,
"requires_timestamp": true
}
Comentario operativo o ejecutivo validado por un responsable autorizado.
Permitir trazabilidad mínima cuando la evidencia es una explicación, gestión o justificación revisada.
commentsubmitted_byvalidated_byvalidated_atTNS-009TNS-010TNS-027TNS-028TNS-029ACT-OPS-001ACT-OPS-002ACT-OPS-003ACT-DQ-001ACT-DQ-002{
"requires_comment_min_length": 20,
"requires_validator": true,
"cannot_close_critical_action_alone": true
}
Orden de compra, transferencia, reposición, despacho o instrucción operativa emitida.
Probar que una acción operativa dejó de ser intención y pasó a ejecución concreta.
order_numberorder_dateresponsible_user_idTNS-006TNS-008TNS-021ACT-STK-001ACT-STK-002{
"requires_order_number": true,
"requires_order_date": true,
"requires_related_product_or_supplier": false
}
Comprobante emitido por tercero: pago, transferencia, recibo, factura, nota, acuerdo o constancia externa.
Respaldar hechos que no dependen solo del registro interno de la empresa.
external_partydocument_datesubmitted_byTNS-004TNS-005ACT-FIN-001{
"requires_external_party": true,
"requires_document_date": true,
"requires_file_hash": true
}
Documento, registro o aprobación que acredita un cambio de política comercial, financiera, operativa o de datos.
Probar que una tensión estructural fue abordada con una regla de gobierno y no solo con una acción aislada.
policy_nameapproved_byeffective_fromTNS-001TNS-002TNS-015TNS-016ACT-COM-001ACT-COM-003ACT-PUR-003ACT-DIR-003{
"requires_policy_name": true,
"requires_approval": true,
"requires_effective_from": true,
"requires_scope": true
}
KPI posterior a la acción que permite medir si la intervención generó impacto.
Cerrar el ciclo dato → acción → resultado, midiendo si la acción funcionó.
kpi_codeperiod_startperiod_endcalculated_at{
"requires_kpi_snapshot_id": true,
"requires_comparison_period": true,
"cannot_be_manually_uploaded": true
}
Justificación formal para cerrar una acción cuando no existe evidencia documental completa.
Permitir cierres excepcionales sin romper trazabilidad, pero marcando menor confianza.
justificationsubmitted_byapproved_byreason_code{
"requires_justification_min_length": 50,
"requires_approval": true,
"cannot_close_recurrent_critical_tension_alone": true
}
Acta, minuta, reporte ejecutivo o documento de reunión donde se registra análisis, decisión o seguimiento.
Dar respaldo formal a decisiones ejecutivas, comités, revisiones y planes de acción.
meeting_dateparticipantssubmitted_byTNS-009TNS-026TNS-030ACT-COM-004ACT-COM-005ACT-FIN-003ACT-DIR-001ACT-DIR-002{
"requires_meeting_date": false,
"requires_participants": false,
"requires_summary": true
}
Registro de contacto con cliente, proveedor, referente externo o contraparte relevante.
Probar gestión activa frente a mora, proveedor crítico, negociación o reclamo.
external_partycontact_datecontact_resultsubmitted_byTNS-004TNS-005TNS-020TNS-023ACT-FIN-001ACT-FIN-006ACT-PUR-002{
"requires_external_party": true,
"requires_contact_date": true,
"requires_contact_result": true
}
Validación formal de dirección sobre una acción, política, cierre, excepción o decisión crítica.
Asegurar que decisiones de alto impacto queden aprobadas por el nivel correcto.
validated_byvalidated_atvalidation_scopeTNS-001TNS-004TNS-009TNS-010TNS-019TNS-026TNS-030ACT-COM-001ACT-COM-002ACT-FIN-005ACT-DIR-001ACT-DIR-002ACT-DIR-003{
"requires_validated_by": true,
"requires_role_validation": true,
"requires_timestamp": true,
"cannot_be_uploaded_as_file_only": true
}
Densidad alta, lectura rápida. Útil para vista directiva, control de cobertura y validación contra reglas de acciones.
| Código | Evidencia | Familia | Trust | Cierra | Revisión | Peso conf. | Impacto Score |
|---|---|---|---|---|---|---|---|
EVD-001 | Documento cargado | documentary | Medium | Sí | Sí | 1.0000 | 1.0000 |
EVD-002 | Captura de sistema | system_proof | Medium | Sí | Sí | 1.0000 | 1.0000 |
EVD-003 | Registro de aprobación | approval | High | Sí | No | 1.3000 | 1.5000 |
EVD-004 | Comentario validado | workflow | Low | No | Sí | 0.7000 | 0.5000 |
EVD-005 | Orden emitida | operational_order | High | Sí | Sí | 1.2500 | 1.5000 |
EVD-006 | Comprobante externo | external_proof | High | Sí | Sí | 1.4000 | 2.0000 |
EVD-007 | Cambio de política | policy | Critical | Sí | Sí | 1.6000 | 3.0000 |
EVD-008 | KPI posterior | measurement | High | No | Sí | 1.5000 | 2.5000 |
EVD-009 | Cierre manual justificado | manual_closure | Medium | Sí | Sí | 0.8000 | 0.5000 |
EVD-010 | Acta / reporte ejecutivo | executive_record | High | Sí | Sí | 1.3000 | 2.0000 |
EVD-011 | Cliente / proveedor contactado | external_contact | Medium | Sí | Sí | 1.1000 | 1.5000 |
EVD-012 | Validación de dirección | executive_validation | Critical | Sí | No | 1.8000 | 3.0000 |
Migración V030__create_evidence_definitions.sql. PostgreSQL 15+. Define la tabla canónica, sus constraints e índices. El seed (V031) carga sobre esta estructura.
-- ============================================================ -- FARO-SQL-006 · V030__create_evidence_definitions.sql -- Catálogo canónico de evidencias FARO MVP -- Engine: PostgreSQL 15+ -- ============================================================ CREATE TABLE IF NOT EXISTS faro.evidence_definitions ( evidence_definition_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), evidence_code text NOT NULL, name text NOT NULL, short_name text NULL, evidence_family text NOT NULL, evidence_type text NOT NULL CHECK ( evidence_type IN ( 'document', 'screenshot', 'approval', 'comment', 'order', 'external_proof', 'policy_change', 'kpi_snapshot', 'manual_closure', 'meeting_record', 'contact_record', 'executive_validation', 'system_log', 'other' ) ), description text NOT NULL, executive_purpose text NOT NULL, allowed_submission_modes text[] NOT NULL DEFAULT ARRAY[]::text[], allowed_file_types text[] NOT NULL DEFAULT ARRAY[]::text[], required_metadata_keys text[] NOT NULL DEFAULT ARRAY[]::text[], can_be_user_submitted boolean NOT NULL DEFAULT true, can_be_system_generated boolean NOT NULL DEFAULT false, requires_review boolean NOT NULL DEFAULT true, can_close_action boolean NOT NULL DEFAULT false, default_reviewer_role text NULL, minimum_reviewer_role text NULL, trust_level text NOT NULL CHECK ( trust_level IN ('low', 'medium', 'high', 'critical') ), confidence_weight numeric(9,4) NOT NULL DEFAULT 1.0000, score_confidence_impact numeric(9,4) NOT NULL DEFAULT 0.0000, retention_policy text NOT NULL DEFAULT 'standard', audit_level text NOT NULL CHECK ( audit_level IN ('basic', 'standard', 'strict', 'critical') ) DEFAULT 'standard', related_action_families text[] NOT NULL DEFAULT ARRAY[]::text[], related_tension_codes text[] NOT NULL DEFAULT ARRAY[]::text[], related_action_codes text[] NOT NULL DEFAULT ARRAY[]::text[], validation_rules jsonb NOT NULL DEFAULT '{}'::jsonb, 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_evidence_definitions_code_version UNIQUE (evidence_code, version) ); -- Un solo activo por código CREATE UNIQUE INDEX IF NOT EXISTS uq_evidence_definitions_one_active_per_code ON faro.evidence_definitions (evidence_code) WHERE status = 'active'; -- Índices de búsqueda y filtrado CREATE INDEX IF NOT EXISTS idx_evidence_definitions_code ON faro.evidence_definitions (evidence_code); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_family ON faro.evidence_definitions (evidence_family); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_type ON faro.evidence_definitions (evidence_type); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_status ON faro.evidence_definitions (status); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_trust_level ON faro.evidence_definitions (trust_level); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_can_close ON faro.evidence_definitions (can_close_action); -- GIN para búsqueda en arrays CREATE INDEX IF NOT EXISTS idx_evidence_definitions_related_actions ON faro.evidence_definitions USING gin (related_action_codes); CREATE INDEX IF NOT EXISTS idx_evidence_definitions_related_tensions ON faro.evidence_definitions USING gin (related_tension_codes); COMMENT ON TABLE faro.evidence_definitions IS 'Catálogo canónico de evidencias FARO. Define las pruebas aceptadas para validar acciones, cierres, auditoría y confianza de ejecución.';
Decisión técnica: mismo patrón que tension_definitions — 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". Los índices GIN sobre related_action_codes y related_tension_codes aceleran las queries de "qué evidencia aplica a qué tensión/acción".
Migración V031__seed_evidence_definitions_mvp.sql. Carga EVD-001 a EVD-012 con ON CONFLICT (evidence_code, version) DO UPDATE para re-ejecución segura. Verbatim del seed oficial FARO-SQL-006.
-- ============================================================ -- FARO-SQL-006 · V031__seed_evidence_definitions_mvp.sql -- Seed Catálogo Canónico de Evidencias MVP FARO -- Version: v1.0 -- ============================================================ BEGIN; INSERT INTO faro.evidence_definitions ( evidence_code, name, short_name, evidence_family, evidence_type, description, executive_purpose, allowed_submission_modes, allowed_file_types, required_metadata_keys, can_be_user_submitted, can_be_system_generated, requires_review, can_close_action, default_reviewer_role, minimum_reviewer_role, trust_level, confidence_weight, score_confidence_impact, retention_policy, audit_level, related_action_families, related_tension_codes, related_action_codes, validation_rules, status, version, metadata ) VALUES -- ============================================================ -- EVD-001 -- ============================================================ ( 'EVD-001', 'Documento cargado', 'Documento', 'documentary', 'document', 'Archivo cargado como respaldo de una acción, decisión, política, análisis o entrega.', 'Permitir que el cierre de una acción quede respaldado por un documento verificable.', ARRAY['upload','manual'], ARRAY['pdf','docx','xlsx','csv','png','jpg'], ARRAY['file_name','submitted_by','submitted_at'], true, false, true, true, 'general_manager', 'area_manager', 'medium', 1.0000, 1.0000, 'standard_5_years', 'standard', ARRAY['commercial','finance','stock','purchasing','operations','data_quality','direction'], ARRAY[]::text[], ARRAY[]::text[], '{ "max_file_size_mb": 25, "requires_file_hash": true, "requires_storage_uri": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-002 -- ============================================================ ( 'EVD-002', 'Captura de sistema', 'Captura sistema', 'system_proof', 'screenshot', 'Captura o exportación visual de un sistema interno o externo que respalda una acción o dato.', 'Respaldar visualmente cambios, estados, cargas, stock, reportes, fuentes o configuraciones.', ARRAY['upload','manual','system_capture'], ARRAY['png','jpg','jpeg','pdf'], ARRAY['source_system','captured_at','submitted_by'], true, true, true, true, 'area_manager', 'area_manager', 'medium', 1.0000, 1.0000, 'standard_5_years', 'standard', ARRAY['stock','data_quality','operations'], ARRAY['TNS-006','TNS-027','TNS-028'], ARRAY['ACT-STK-001','ACT-STK-002','ACT-DQ-001','ACT-DQ-002'], '{ "requires_source_system": true, "requires_capture_date": true, "accepted_sources": ["erp", "crm", "pos", "bank", "spreadsheet", "faro", "external_system"] }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-003 -- ============================================================ ( 'EVD-003', 'Registro de aprobación', 'Aprobación', 'approval', 'approval', 'Registro formal de aprobación realizada por responsable autorizado.', 'Asegurar que una decisión o cambio crítico fue aprobado por el nivel correspondiente.', ARRAY['workflow','system'], ARRAY[]::text[], ARRAY['approved_by','approved_at','approval_scope'], false, true, false, true, 'general_manager', 'area_manager', 'high', 1.3000, 1.5000, 'strict_7_years', 'strict', ARRAY['commercial','finance','stock','purchasing','direction'], ARRAY[]::text[], ARRAY['ACT-DIR-003'], '{ "requires_approver_user_id": true, "requires_role_validation": true, "requires_timestamp": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-004 -- ============================================================ ( 'EVD-004', 'Comentario validado', 'Comentario validado', 'workflow', 'comment', 'Comentario operativo o ejecutivo validado por un responsable autorizado.', 'Permitir trazabilidad mínima cuando la evidencia es una explicación, gestión o justificación revisada.', ARRAY['manual','workflow'], ARRAY[]::text[], ARRAY['comment','submitted_by','validated_by','validated_at'], true, true, true, false, 'general_manager', 'area_manager', 'low', 0.7000, 0.5000, 'standard_5_years', 'basic', ARRAY['operations','data_quality','direction'], ARRAY['TNS-009','TNS-010','TNS-027','TNS-028','TNS-029'], ARRAY['ACT-OPS-001','ACT-OPS-002','ACT-OPS-003','ACT-DQ-001','ACT-DQ-002'], '{ "requires_comment_min_length": 20, "requires_validator": true, "cannot_close_critical_action_alone": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-005 -- ============================================================ ( 'EVD-005', 'Orden emitida', 'Orden emitida', 'operational_order', 'order', 'Orden de compra, transferencia, reposición, despacho o instrucción operativa emitida.', 'Probar que una acción operativa dejó de ser intención y pasó a ejecución concreta.', ARRAY['upload','system','manual'], ARRAY['pdf','xlsx','csv','png','jpg'], ARRAY['order_number','order_date','responsible_user_id'], true, true, true, true, 'area_manager', 'area_manager', 'high', 1.2500, 1.5000, 'standard_5_years', 'standard', ARRAY['stock','purchasing','operations'], ARRAY['TNS-006','TNS-008','TNS-021'], ARRAY['ACT-STK-001','ACT-STK-002'], '{ "requires_order_number": true, "requires_order_date": true, "requires_related_product_or_supplier": false }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-006 -- ============================================================ ( 'EVD-006', 'Comprobante externo', 'Comprobante externo', 'external_proof', 'external_proof', 'Comprobante emitido por tercero: pago, transferencia, recibo, factura, nota, acuerdo o constancia externa.', 'Respaldar hechos que no dependen solo del registro interno de la empresa.', ARRAY['upload','manual','integration'], ARRAY['pdf','png','jpg','jpeg','xlsx'], ARRAY['external_party','document_date','submitted_by'], true, true, true, true, 'finance_manager', 'area_manager', 'high', 1.4000, 2.0000, 'strict_7_years', 'strict', ARRAY['finance','purchasing','commercial'], ARRAY['TNS-004','TNS-005'], ARRAY['ACT-FIN-001'], '{ "requires_external_party": true, "requires_document_date": true, "requires_file_hash": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-007 -- ============================================================ ( 'EVD-007', 'Cambio de política', 'Cambio política', 'policy', 'policy_change', 'Documento, registro o aprobación que acredita un cambio de política comercial, financiera, operativa o de datos.', 'Probar que una tensión estructural fue abordada con una regla de gobierno y no solo con una acción aislada.', ARRAY['upload','workflow','system'], ARRAY['pdf','docx','xlsx','png','jpg'], ARRAY['policy_name','approved_by','effective_from'], true, true, true, true, 'general_manager', 'general_manager', 'critical', 1.6000, 3.0000, 'strict_7_years', 'critical', ARRAY['commercial','finance','stock','purchasing','direction'], ARRAY['TNS-001','TNS-002','TNS-015','TNS-016'], ARRAY['ACT-COM-001','ACT-COM-003','ACT-PUR-003','ACT-DIR-003'], '{ "requires_policy_name": true, "requires_approval": true, "requires_effective_from": true, "requires_scope": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-008 -- ============================================================ ( 'EVD-008', 'KPI posterior', 'KPI posterior', 'measurement', 'kpi_snapshot', 'KPI posterior a la acción que permite medir si la intervención generó impacto.', 'Cerrar el ciclo dato → acción → resultado, midiendo si la acción funcionó.', ARRAY['system','integration'], ARRAY[]::text[], ARRAY['kpi_code','period_start','period_end','calculated_at'], false, true, true, false, 'general_manager', 'area_manager', 'high', 1.5000, 2.5000, 'standard_5_years', 'strict', ARRAY['commercial','finance','stock','operations','data_quality','direction'], ARRAY[]::text[], ARRAY[]::text[], '{ "requires_kpi_snapshot_id": true, "requires_comparison_period": true, "cannot_be_manually_uploaded": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-009 -- ============================================================ ( 'EVD-009', 'Cierre manual justificado', 'Cierre justificado', 'manual_closure', 'manual_closure', 'Justificación formal para cerrar una acción cuando no existe evidencia documental completa.', 'Permitir cierres excepcionales sin romper trazabilidad, pero marcando menor confianza.', ARRAY['workflow','manual'], ARRAY[]::text[], ARRAY['justification','submitted_by','approved_by','reason_code'], true, true, true, true, 'director', 'general_manager', 'medium', 0.8000, 0.5000, 'strict_7_years', 'strict', ARRAY['operations','direction'], ARRAY[]::text[], ARRAY[]::text[], '{ "requires_justification_min_length": 50, "requires_approval": true, "cannot_close_recurrent_critical_tension_alone": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true, "exceptional": true}'::jsonb ), -- ============================================================ -- EVD-010 -- ============================================================ ( 'EVD-010', 'Acta, minuta o reporte ejecutivo', 'Acta/reporte', 'executive_record', 'meeting_record', 'Acta, minuta, reporte ejecutivo o documento de reunión donde se registra análisis, decisión o seguimiento.', 'Dar respaldo formal a decisiones ejecutivas, comités, revisiones y planes de acción.', ARRAY['upload','system','workflow'], ARRAY['pdf','docx','xlsx','png','jpg'], ARRAY['meeting_date','participants','submitted_by'], true, true, true, true, 'general_manager', 'area_manager', 'high', 1.3000, 2.0000, 'standard_5_years', 'standard', ARRAY['commercial','finance','stock','purchasing','operations','direction'], ARRAY['TNS-009','TNS-026','TNS-030'], ARRAY['ACT-COM-004','ACT-COM-005','ACT-FIN-003','ACT-DIR-001','ACT-DIR-002'], '{ "requires_meeting_date": false, "requires_participants": false, "requires_summary": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-011 -- ============================================================ ( 'EVD-011', 'Cliente/proveedor contactado', 'Contacto externo', 'external_contact', 'contact_record', 'Registro de contacto con cliente, proveedor, referente externo o contraparte relevante.', 'Probar gestión activa frente a mora, proveedor crítico, negociación o reclamo.', ARRAY['manual','workflow','integration'], ARRAY['pdf','png','jpg','eml','msg'], ARRAY['external_party','contact_date','contact_result','submitted_by'], true, true, true, true, 'area_manager', 'area_manager', 'medium', 1.1000, 1.5000, 'standard_5_years', 'standard', ARRAY['finance','purchasing','commercial'], ARRAY['TNS-004','TNS-005','TNS-020','TNS-023'], ARRAY['ACT-FIN-001','ACT-FIN-006','ACT-PUR-002'], '{ "requires_external_party": true, "requires_contact_date": true, "requires_contact_result": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ), -- ============================================================ -- EVD-012 -- ============================================================ ( 'EVD-012', 'Validación de dirección', 'Validación dirección', 'executive_validation', 'executive_validation', 'Validación formal de dirección sobre una acción, política, cierre, excepción o decisión crítica.', 'Asegurar que decisiones de alto impacto queden aprobadas por el nivel correcto.', ARRAY['workflow','system'], ARRAY[]::text[], ARRAY['validated_by','validated_at','validation_scope'], false, true, false, true, 'director', 'general_manager', 'critical', 1.8000, 3.0000, 'strict_7_years', 'critical', ARRAY['commercial','finance','stock','purchasing','operations','data_quality','direction'], ARRAY['TNS-001','TNS-004','TNS-009','TNS-010','TNS-019','TNS-026','TNS-030'], ARRAY['ACT-COM-001','ACT-COM-002','ACT-FIN-005','ACT-DIR-001','ACT-DIR-002','ACT-DIR-003'], '{ "requires_validated_by": true, "requires_role_validation": true, "requires_timestamp": true, "cannot_be_uploaded_as_file_only": true }'::jsonb, 'active', 1, '{"canonical": true, "mvp": true}'::jsonb ) ON CONFLICT (evidence_code, version) DO UPDATE SET name = EXCLUDED.name, short_name = EXCLUDED.short_name, evidence_family = EXCLUDED.evidence_family, evidence_type = EXCLUDED.evidence_type, description = EXCLUDED.description, executive_purpose = EXCLUDED.executive_purpose, allowed_submission_modes = EXCLUDED.allowed_submission_modes, allowed_file_types = EXCLUDED.allowed_file_types, required_metadata_keys = EXCLUDED.required_metadata_keys, can_be_user_submitted = EXCLUDED.can_be_user_submitted, can_be_system_generated = EXCLUDED.can_be_system_generated, requires_review = EXCLUDED.requires_review, can_close_action = EXCLUDED.can_close_action, default_reviewer_role = EXCLUDED.default_reviewer_role, minimum_reviewer_role = EXCLUDED.minimum_reviewer_role, trust_level = EXCLUDED.trust_level, confidence_weight = EXCLUDED.confidence_weight, score_confidence_impact = EXCLUDED.score_confidence_impact, retention_policy = EXCLUDED.retention_policy, audit_level = EXCLUDED.audit_level, related_action_families = EXCLUDED.related_action_families, related_tension_codes = EXCLUDED.related_tension_codes, related_action_codes = EXCLUDED.related_action_codes, validation_rules = EXCLUDED.validation_rules, status = EXCLUDED.status, metadata = EXCLUDED.metadata, updated_at = now(); COMMIT;
Verbatim del seed oficial. Las 12 entradas se presentan in extenso y sin recortes, idénticas a FARO-SQL-006 · V031__seed_evidence_definitions_mvp.sql. El cierre con ON CONFLICT (evidence_code, version) DO UPDATE SET ... updated_at = now() hace que la migración sea idempotente: aplicar dos veces produce el mismo estado final.
La tabla faro.evidence (donde se cargan las evidencias reales por empresa) gana 4 campos derivados del catálogo y un trigger que mapea automáticamente el evidence_definition_id en cada insert/update.
-- Refuerzo de faro.evidence con campos canónicos ALTER TABLE faro.evidence ADD COLUMN IF NOT EXISTS evidence_definition_id uuid NULL, ADD COLUMN IF NOT EXISTS validation_score numeric(9,4) NULL, ADD COLUMN IF NOT EXISTS reviewed_status text NULL CHECK ( reviewed_status IS NULL OR reviewed_status IN ('pending','approved','rejected','needs_more_info') ), ADD COLUMN IF NOT EXISTS reviewed_reason text NULL; -- Backfill de referencias en datos existentes UPDATE faro.evidence e SET evidence_definition_id = ed.evidence_definition_id FROM faro.evidence_definitions ed WHERE ed.evidence_code = e.evidence_code AND ed.status = 'active' AND e.evidence_definition_id IS NULL;
Decisión técnica: no se fuerza FK todavía. Datos demo o históricos pueden tener evidence_code fuera del catálogo activo; primero se limpia, después se agrega FK. Orden conservador, menos heroico, más sano.
CREATE OR REPLACE FUNCTION faro.set_evidence_definition_id() RETURNS trigger AS $$ BEGIN IF NEW.evidence_code IS NOT NULL AND NEW.evidence_definition_id IS NULL THEN SELECT evidence_definition_id INTO NEW.evidence_definition_id FROM faro.evidence_definitions WHERE evidence_code = NEW.evidence_code AND status = 'active' LIMIT 1; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_set_evidence_definition_id ON faro.evidence; CREATE TRIGGER trg_set_evidence_definition_id BEFORE INSERT OR UPDATE OF evidence_code ON faro.evidence FOR EACH ROW EXECUTE FUNCTION faro.set_evidence_definition_id();
El catálogo expone funciones canónicas que el motor evaluador y la UI deben usar en lugar de hardcodear lógica. Misma forma que tension_definitions y action_definitions: API estable, lógica adentro.
Verifica si un código existe como evidencia activa. Lo usa el parser YAML, el motor evaluador y los tests para validar referencias.
CREATE OR REPLACE FUNCTION faro.evidence_code_exists(p_evidence_code text) RETURNS boolean AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM faro.evidence_definitions WHERE evidence_code = p_evidence_code AND status = 'active' ); END; $$ LANGUAGE plpgsql STABLE;
Determina si una acción tiene toda la evidencia requerida aprobada. Es la función que el workflow de cierre debe consultar antes de pasar una acción a closed.
CREATE OR REPLACE FUNCTION faro.action_has_required_evidence(p_action_id uuid) RETURNS boolean AS $$ DECLARE v_required_count integer; v_approved_count integer; BEGIN SELECT COUNT(*) INTO v_required_count FROM faro.v_action_evidence_status WHERE action_id = p_action_id; SELECT COUNT(*) INTO v_approved_count FROM faro.v_action_evidence_status WHERE action_id = p_action_id AND evidence_status = 'approved'; IF v_required_count = 0 THEN RETURN false; END IF; RETURN v_required_count = v_approved_count; END; $$ LANGUAGE plpgsql STABLE;
Calcula el score de confianza acumulado de una acción sumando el confidence_weight de cada evidencia aprobada (peso completo) o submitted (50%). Lo usa el motor de Score para decidir cuánto recupera la acción.
CREATE OR REPLACE FUNCTION faro.calculate_action_evidence_confidence(p_action_id uuid) RETURNS numeric AS $$ DECLARE v_score numeric; BEGIN SELECT COALESCE( SUM( CASE WHEN aes.evidence_status = 'approved' THEN ed.confidence_weight WHEN aes.evidence_status = 'submitted' THEN ed.confidence_weight * 0.5 ELSE 0 END ), 0 ) INTO v_score FROM faro.v_action_evidence_status aes JOIN faro.evidence_definitions ed ON ed.evidence_code = aes.evidence_code AND ed.status = 'active' WHERE aes.action_id = p_action_id; RETURN ROUND(v_score, 4); END; $$ LANGUAGE plpgsql STABLE;
CREATE OR REPLACE VIEW faro.v_action_required_evidence AS SELECT a.company_id, a.action_id, a.action_code, a.title AS action_title, ad.name AS action_definition_name, required_evidence.evidence_code, ed.name AS evidence_name, ed.evidence_type, ed.trust_level, ed.can_close_action, ed.requires_review FROM faro.actions a LEFT JOIN faro.action_definitions ad ON ad.action_code = a.action_code AND ad.status = 'active' CROSS JOIN LATERAL unnest( COALESCE( ARRAY( SELECT jsonb_array_elements_text(a.payload->'evidence_required_codes') ), ad.evidence_required_codes, ARRAY[]::text[] ) ) AS required_evidence(evidence_code) LEFT JOIN faro.evidence_definitions ed ON ed.evidence_code = required_evidence.evidence_code AND ed.status = 'active';
CREATE OR REPLACE VIEW faro.v_action_evidence_status AS WITH required AS ( SELECT a.company_id, a.action_id, a.action_code, a.title AS action_title, required_evidence.evidence_code FROM faro.actions a LEFT JOIN faro.action_definitions ad ON ad.action_code = a.action_code AND ad.status = 'active' CROSS JOIN LATERAL unnest( COALESCE(ad.evidence_required_codes, ARRAY[]::text[]) ) AS required_evidence(evidence_code) ), submitted AS ( SELECT e.company_id, e.action_id, e.evidence_code, COUNT(*) FILTER (WHERE e.status IN ('submitted','approved')) AS submitted_count, COUNT(*) FILTER (WHERE e.status = 'approved') AS approved_count FROM faro.evidence e GROUP BY e.company_id, e.action_id, e.evidence_code ) SELECT r.company_id, r.action_id, r.action_code, r.action_title, r.evidence_code, ed.name AS evidence_name, ed.trust_level, COALESCE(s.submitted_count, 0) AS submitted_count, COALESCE(s.approved_count, 0) AS approved_count, CASE WHEN COALESCE(s.approved_count, 0) > 0 THEN 'approved' WHEN COALESCE(s.submitted_count, 0) > 0 THEN 'submitted' ELSE 'missing' END AS evidence_status FROM required r LEFT JOIN submitted s ON s.company_id = r.company_id AND s.action_id = r.action_id AND s.evidence_code = r.evidence_code LEFT JOIN faro.evidence_definitions ed ON ed.evidence_code = r.evidence_code AND ed.status = 'active';
El catálogo no decide solo si una evidencia cierra. La regla compuesta combina can_close_action, trust_level, criticidad de la acción y reglas específicas en validation_rules.
Una acción puede pasar a in_verification cuando tiene al menos una evidencia cargada (cualquier tipo, en estado submitted o superior). Esto saca la acción del estado "abierto sin avance" pero no necesariamente la cierra. Es un puente, no un cierre.
closed deben cumplirse las cinco condiciones simultáneamente:
action_definitions.evidence_required_codes.evidence_definitions con status = 'active'.reviewed_status = 'approved'.can_close_action = true) o se combina con validación.minimum_reviewer_role).critical en la tensión que la disparó) solo debería cerrarse si tiene:
EVD-012 · Validación de dirección aprobada, oEVD-007 + EVD-003 (cambio de política + aprobación), oEVD-006 + EVD-012 (comprobante externo + validación), oEVD-010 + EVD-012 (acta ejecutiva + validación).EVD-004 · Comentario validado tiene can_close_action = false y la regla "cannot_close_critical_action_alone": true codificada en validation_rules. Sirve para seguimiento, explicación, avance parcial, justificación o soporte documental menor. No reemplaza evidencia formal en acciones que pesan.
Ejecutar en orden después de aplicar V030 + V031. 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 12 registros con status = 'active'. Ni más ni menos.
SELECT COUNT(*) AS active_evidence_definitions FROM faro.evidence_definitions WHERE status = 'active';
El índice único parcial debería prevenirlo, pero esta query lo verifica explícitamente.
SELECT evidence_code, COUNT(*) AS total FROM faro.evidence_definitions WHERE status = 'active' GROUP BY evidence_code HAVING COUNT(*) > 1;
Regla 07 del gobierno: si no se puede explicar para qué sirve ejecutivamente, no entra al catálogo. El campo no puede ser NULL ni vacío.
SELECT evidence_code, name FROM faro.evidence_definitions WHERE status = 'active' AND (executive_purpose IS NULL OR trim(executive_purpose) = '');
El check constraint debería prevenirlo, pero esta query lo verifica. Solo se aceptan low, medium, high, critical.
SELECT evidence_code, name FROM faro.evidence_definitions WHERE status = 'active' AND trust_level NOT IN ('low', 'medium', 'high', 'critical');
Regla 06: si can_close_action = true y requires_review = false, el tipo debe ser approval o executive_validation (ya tienen su propio workflow).
SELECT evidence_code, name, evidence_type, requires_review, can_close_action FROM faro.evidence_definitions WHERE status = 'active' AND can_close_action = true AND requires_review = false AND evidence_type NOT IN ('approval', 'executive_validation');
Cada código en action_definitions.evidence_required_codes debe existir como evidencia activa. Si no, el motor crearía acciones con evidencia inválida.
SELECT ad.action_code, ad.name AS action_name, evidence_code FROM faro.action_definitions ad CROSS JOIN LATERAL unnest(ad.evidence_required_codes) AS evidence_code LEFT JOIN faro.evidence_definitions ed ON ed.evidence_code = evidence_code AND ed.status = 'active' WHERE ad.status = 'active' AND ed.evidence_code IS NULL;
Cada código en tension_definitions.evidence_required debe existir como evidencia activa. Si no, las reglas YAML crearían tensiones con cierre imposible.
SELECT td.tension_code, td.name AS tension_name, evidence_code FROM faro.tension_definitions td CROSS JOIN LATERAL unnest(td.evidence_required) AS evidence_code LEFT JOIN faro.evidence_definitions ed ON ed.evidence_code = evidence_code AND ed.status = 'active' WHERE td.status = 'active' AND ed.evidence_code IS NULL;
Cada evidencia real cargada para la empresa demo debe apuntar a un código activo del catálogo. Si aparece algo fuera, hay seed demo desactualizado.
SELECT DISTINCT e.evidence_code FROM faro.evidence e LEFT JOIN faro.evidence_definitions ed ON ed.evidence_code = e.evidence_code AND ed.status = 'active' WHERE e.company_id = '10000000-0000-0000-0000-000000000001' AND ed.evidence_code IS NULL;
El catálogo de evidencias cierra el contrato Tensión → Acción → Evidencia. Estos son los puntos donde se consume, se valida o se extiende.
30 tensiones canónicas TNS-001..TNS-030. Los códigos en related_tension_codes de cada evidencia resuelven contra este catálogo.
Catálogo canónico MVP de acciones (paralelo a este pero para ACT-*). Las acciones definen qué evidencia requieren para cerrarse.
DDL completo del sistema FARO Connect. Incluye faro.evidence (datos) y ahora faro.evidence_definitions (catálogo).
UI de carga de evidencia para responsables. Valida metadata, archivo, tamaño y rol del cargador antes de enviar al workflow de revisión.
Catálogo extendido de 300 acciones con RACI y workflow. Cada acción referencia qué evidencia requiere; este catálogo es la fuente única de qué tipos son válidos.
300 tensiones extendidas v2 con DSL. Las que tienen evidence_required resuelven contra los 12 códigos canónicos de este catálogo.
1.500 cruces KPI↔TNS↔ACT. Permite verificar que cada acción del MVP tiene evidencia válida del catálogo canónico.
Diagnóstico ejecutivo que usa los códigos EVD canónicos como base para validar cierre de acciones en empresa cliente.
Con este documento queda completo el contrato canónico Tensión → Acción → Evidencia. Los próximos pasos son patchear el motor evaluador (FARO-ENG-003.1) para que enriquezca evidencia desde catálogo, y construir la UI de carga (FARO-UI-003) para responsables.
→ Volver al hub modelos NDA