01 · Resumen ejecutivo

Primera biblioteca canónica de evidencias FARO MVP

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:

  • Tensión detectada (catálogo TNS-001..TNS-030, ya canónico).
  • Acción recomendada (catálogo ACT-* en construcción).
  • Evidencia requerida (este catálogo, primer pase canónico).

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.

02 · Reglas de gobierno del catálogo

8 reglas que separan evidencia de comentario

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.

Regla 01

Evidencia ≠ comentario

Un comentario es relato. Una evidencia es prueba con metadata, archivo o aprobación. FARO los trata distinto y los pondera distinto.

Regla 02

Trust level inmutable

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.

Regla 03

Código inmutable

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.

Regla 04

No se borra, se archiva

Si un tipo deja de usarse, pasa a status = archived. Borrar evidencias rompe las referencias en datos históricos de faro.evidence.

Regla 05

Comentario solo no cierra crítico

EVD-004 (comentario validado) puede acompañar pero no cerrar acciones críticas por sí solo. Regla codificada en validation_rules.

Regla 06

Cerrar requiere revisión o validación

Toda evidencia con can_close_action = true debe tener requires_review = true o ser de tipo approval / executive_validation.

Regla 07

Toda evidencia tiene propósito ejecutivo

El campo executive_purpose no puede estar vacío. Si no se sabe qué cierra ejecutivamente, no entra al catálogo.

Regla 08

Catálogo es fuente única

YAML, parser, motor, UI, tests y reportes consumen faro.evidence_definitions. Prohibido nombres hardcodeados o evidencias sin código en producción.

03 · Trust levels explicados

4 niveles de confianza · qué cierra qué

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.

Low 1

Confianza baja · seguimiento

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
Medium 4

Confianza media · respaldo operativo

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
High 5

Confianza alta · prueba formal

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
Critical 2

Confianza crítica · gobierno

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.

04 · Estructura oficial

Los 21 campos canónicos por ficha

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_codetext · uniqueCódigo canónico inmutable. Formato EVD-NNN.EVD-001
nametextNombre canónico ejecutivo de la evidencia.Documento cargado
short_nametext · nullNombre corto para tablas densas y UI compacta.Documento
evidence_familytextFamilia conceptual (documentary, system_proof, approval, workflow, etc.).documentary
evidence_typeenumTipo 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
descriptiontextQué representa técnicamente (1-2 líneas).Archivo cargado como respaldo de una acción, decisión, política, análisis o entrega.
executive_purposetextPara qué sirve ejecutivamente al cierre.Permitir que el cierre de una acción quede respaldado por un documento verificable.
allowed_submission_modestext[]Cómo se puede cargar (upload, manual, workflow, system, integration, system_capture).upload manual
allowed_file_typestext[]Extensiones aceptadas si la evidencia es archivo.pdf docx xlsx csv png jpg
required_metadata_keystext[]Claves obligatorias que debe enviar quien la carga.file_name submitted_by submitted_at
can_be_user_submittedbooleanSi la puede cargar un usuario manualmente.true
can_be_system_generatedbooleanSi el sistema puede generarla automáticamente.false
requires_reviewbooleanSi requiere revisión humana para considerarse aprobada.true
can_close_actionbooleanSi por sí sola puede cerrar una acción (sujeto a criterio).true
default_reviewer_roletext · nullRol que revisa por defecto.general_manager
minimum_reviewer_roletext · nullRol mínimo que puede revisarla.area_manager
trust_levelenumNivel de confianza. Valores: low, medium, high, critical.medium
confidence_weightnumericPeso de confianza para el cálculo de cierre.1.0000
score_confidence_impactnumericImpacto en la dimensión de confianza del Score.1.0000
retention_policytextPolítica de retención (standard_5_years, strict_7_years).standard_5_years
audit_levelenumNivel de auditoría requerido. Valores: basic, standard, strict, critical.standard
validation_rulesjsonbReglas 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.

05 · Las 12 evidencias canónicas

EVD-001 a EVD-012 · fichas completas

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.

EVD-001
Medium Cierra

Documento cargado

Familia: documentary · Tipo: 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.

Modos carga
uploadmanual
Archivos
pdfdocxxlsxcsvpngjpg
Metadata
file_namesubmitted_bysubmitted_at
Revisor
area_manager → general_manager · requires_review:
▸ validation_rules
{
  "max_file_size_mb": 25,
  "requires_file_hash": true,
  "requires_storage_uri": true
}
conf_weight 1.0000 score_impact 1.0000 retención: standard_5_years
EVD-002
Medium Cierra

Captura de sistema

Familia: system_proof · Tipo: 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.

Modos carga
uploadmanualsystem_capture
Archivos
pngjpgjpegpdf
Metadata
source_systemcaptured_atsubmitted_by
Tensiones
TNS-006TNS-027TNS-028
Acciones
ACT-STK-001ACT-STK-002ACT-DQ-001ACT-DQ-002
▸ validation_rules
{
  "requires_source_system": true,
  "requires_capture_date": true,
  "accepted_sources": ["erp", "crm", "pos", "bank", "spreadsheet", "faro", "external_system"]
}
conf_weight 1.0000 score_impact 1.0000 auditoría: standard
EVD-003
High Cierra

Registro de aprobación

Familia: approval · Tipo: 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.

Modos carga
workflowsystem
Archivos
no aplica · workflow registro
Metadata
approved_byapproved_atapproval_scope
Acciones
ACT-DIR-003
Revisor
area_manager → general_manager · requires_review: no (es workflow auto)
▸ validation_rules
{
  "requires_approver_user_id": true,
  "requires_role_validation": true,
  "requires_timestamp": true
}
conf_weight 1.3000 score_impact 1.5000 retención: strict_7_years
EVD-004
Low No cierra

Comentario validado

Familia: workflow · Tipo: 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.

Modos carga
manualworkflow
Metadata
commentsubmitted_byvalidated_byvalidated_at
Tensiones
TNS-009TNS-010TNS-027TNS-028TNS-029
Acciones
ACT-OPS-001ACT-OPS-002ACT-OPS-003ACT-DQ-001ACT-DQ-002
Revisor
area_manager → general_manager · requires_review:
▸ validation_rules
{
  "requires_comment_min_length": 20,
  "requires_validator": true,
  "cannot_close_critical_action_alone": true
}
conf_weight 0.7000 score_impact 0.5000 auditoría: basic
EVD-005
High Cierra

Orden emitida

Familia: operational_order · Tipo: 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.

Modos carga
uploadsystemmanual
Archivos
pdfxlsxcsvpngjpg
Metadata
order_numberorder_dateresponsible_user_id
Tensiones
TNS-006TNS-008TNS-021
Acciones
ACT-STK-001ACT-STK-002
▸ validation_rules
{
  "requires_order_number": true,
  "requires_order_date": true,
  "requires_related_product_or_supplier": false
}
conf_weight 1.2500 score_impact 1.5000 auditoría: standard
EVD-006
High Cierra

Comprobante externo

Familia: external_proof · Tipo: 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.

Modos carga
uploadmanualintegration
Archivos
pdfpngjpgjpegxlsx
Metadata
external_partydocument_datesubmitted_by
Tensiones
TNS-004TNS-005
Acciones
ACT-FIN-001
▸ validation_rules
{
  "requires_external_party": true,
  "requires_document_date": true,
  "requires_file_hash": true
}
conf_weight 1.4000 score_impact 2.0000 retención: strict_7_years
EVD-007
Critical Cierra

Cambio de política

Familia: policy · Tipo: 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.

Modos carga
uploadworkflowsystem
Archivos
pdfdocxxlsxpngjpg
Metadata
policy_nameapproved_byeffective_from
Tensiones
TNS-001TNS-002TNS-015TNS-016
Acciones
ACT-COM-001ACT-COM-003ACT-PUR-003ACT-DIR-003
▸ validation_rules
{
  "requires_policy_name": true,
  "requires_approval": true,
  "requires_effective_from": true,
  "requires_scope": true
}
conf_weight 1.6000 score_impact 3.0000 auditoría: critical
EVD-008
High No cierra

KPI posterior

Familia: measurement · Tipo: 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ó.

Modos carga
systemintegration
Archivos
no aplica · snapshot calculado
Metadata
kpi_codeperiod_startperiod_endcalculated_at
Revisor
area_manager → general_manager · requires_review:
▸ validation_rules
{
  "requires_kpi_snapshot_id": true,
  "requires_comparison_period": true,
  "cannot_be_manually_uploaded": true
}
conf_weight 1.5000 score_impact 2.5000 auditoría: strict
EVD-009
Medium Cierra

Cierre manual justificado

Familia: manual_closure · Tipo: 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.

Modos carga
workflowmanual
Metadata
justificationsubmitted_byapproved_byreason_code
Revisor
general_manager → director · requires_review:
Excepcional
exceptional: true
▸ validation_rules
{
  "requires_justification_min_length": 50,
  "requires_approval": true,
  "cannot_close_recurrent_critical_tension_alone": true
}
conf_weight 0.8000 score_impact 0.5000 auditoría: strict
EVD-010
High Cierra

Acta, minuta o reporte ejecutivo

Familia: executive_record · Tipo: 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.

Modos carga
uploadsystemworkflow
Archivos
pdfdocxxlsxpngjpg
Metadata
meeting_dateparticipantssubmitted_by
Tensiones
TNS-009TNS-026TNS-030
Acciones
ACT-COM-004ACT-COM-005ACT-FIN-003ACT-DIR-001ACT-DIR-002
▸ validation_rules
{
  "requires_meeting_date": false,
  "requires_participants": false,
  "requires_summary": true
}
conf_weight 1.3000 score_impact 2.0000 auditoría: standard
EVD-011
Medium Cierra

Cliente / proveedor contactado

Familia: external_contact · Tipo: 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.

Modos carga
manualworkflowintegration
Archivos
pdfpngjpgemlmsg
Metadata
external_partycontact_datecontact_resultsubmitted_by
Tensiones
TNS-004TNS-005TNS-020TNS-023
Acciones
ACT-FIN-001ACT-FIN-006ACT-PUR-002
▸ validation_rules
{
  "requires_external_party": true,
  "requires_contact_date": true,
  "requires_contact_result": true
}
conf_weight 1.1000 score_impact 1.5000 auditoría: standard
EVD-012
Critical Cierra

Validación de dirección

Familia: executive_validation · Tipo: 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.

Modos carga
workflowsystem
Archivos
no aplica · validación workflow
Metadata
validated_byvalidated_atvalidation_scope
Tensiones
TNS-001TNS-004TNS-009TNS-010TNS-019TNS-026TNS-030
Acciones
ACT-COM-001ACT-COM-002ACT-FIN-005ACT-DIR-001ACT-DIR-002ACT-DIR-003
▸ validation_rules
{
  "requires_validated_by": true,
  "requires_role_validation": true,
  "requires_timestamp": true,
  "cannot_be_uploaded_as_file_only": true
}
conf_weight 1.8000 score_impact 3.0000 auditoría: critical
06 · Tabla maestra resumida

Vista pájaro · 12 evidencias en una grilla

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-001Documento cargadodocumentaryMedium1.00001.0000
EVD-002Captura de sistemasystem_proofMedium1.00001.0000
EVD-003Registro de aprobaciónapprovalHighNo1.30001.5000
EVD-004Comentario validadoworkflowLowNo0.70000.5000
EVD-005Orden emitidaoperational_orderHigh1.25001.5000
EVD-006Comprobante externoexternal_proofHigh1.40002.0000
EVD-007Cambio de políticapolicyCritical1.60003.0000
EVD-008KPI posteriormeasurementHighNo1.50002.5000
EVD-009Cierre manual justificadomanual_closureMedium0.80000.5000
EVD-010Acta / reporte ejecutivoexecutive_recordHigh1.30002.0000
EVD-011Cliente / proveedor contactadoexternal_contactMedium1.10001.5000
EVD-012Validación de direcciónexecutive_validationCriticalNo1.80003.0000
07 · DDL SQL · V030

faro.evidence_definitions · estructura física

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.

▸ V030__create_evidence_definitions.sql · PostgreSQL 15+
-- ============================================================
-- 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_definitionsUNIQUE 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".

08 · Seed SQL · V031

12 INSERT idempotentes con upsert

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.

▸ V031__seed_evidence_definitions_mvp.sql · 12 INSERTs · BEGIN/COMMIT · upsert idempotente
-- ============================================================
-- 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.

09 · Patch a faro.evidence + trigger

Refuerzo de la tabla operativa con campos canónicos

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.

▸ ALTER TABLE faro.evidence · campos derivados del catálogo canónico
-- 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.

▸ Trigger trg_set_evidence_definition_id · auto-mapeo en insert/update
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();
10 · Funciones helper + vistas

3 funciones SQL + 2 vistas para evaluar evidencia

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.

faro.evidence_code_exists(p_evidence_code text) RETURNS boolean

Verifica si un código existe como evidencia activa. Lo usa el parser YAML, el motor evaluador y los tests para validar referencias.

▸ función helper · STABLE
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;
faro.action_has_required_evidence(p_action_id uuid) RETURNS boolean

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.

▸ función helper · STABLE · usa v_action_evidence_status
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;
faro.calculate_action_evidence_confidence(p_action_id uuid) RETURNS numeric

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.

▸ función helper · STABLE · pondera approved 100% y submitted 50%
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;

Vistas asociadas

▸ faro.v_action_required_evidence · qué evidencia se espera por acción activa
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';
▸ faro.v_action_evidence_status · cumplimiento por acción (missing / submitted / approved)
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';
11 · Reglas de cierre por evidencia

Cuándo una acción puede cerrarse · 4 niveles

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.

11.1 · Cierre mínimo

Pasa a in_verification con una evidencia cargada

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.

11.2 · Cierre validado

Cinco condiciones para pasar a closed

Para que una acción pase a closed deben cumplirse las cinco condiciones simultáneamente:
  • Tiene evidencia requerida según action_definitions.evidence_required_codes.
  • Cada código requerido existe en evidence_definitions con status = 'active'.
  • Cada evidencia cargada está en reviewed_status = 'approved'.
  • El tipo de evidencia permite cierre (can_close_action = true) o se combina con validación.
  • El aprobador tiene rol suficiente (igual o superior a minimum_reviewer_role).
11.3 · Cierre crítico

Acciones críticas necesitan EVD-012 o combinación fuerte

Una acción crítica (severidad critical en la tensión que la disparó) solo debería cerrarse si tiene:
  • EVD-012 · Validación de dirección aprobada, o
  • combinación EVD-007 + EVD-003 (cambio de política + aprobación), o
  • combinación EVD-006 + EVD-012 (comprobante externo + validación), o
  • combinación EVD-010 + EVD-012 (acta ejecutiva + validación).
Sin esto, una acción crítica cerrada con evidencia floja es deuda técnica disfrazada de avance.
11.4 · Comentario solo no alcanza

EVD-004 acompaña pero no cierra crítico

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.

12 · Validaciones post-seed

8 queries que deben dar el resultado esperado

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.

12.1 · Conteo Esperado: 12

Existen 12 evidencias activas

El catálogo MVP debe tener exactamente 12 registros con status = 'active'. Ni más ni menos.

▸ SQL
SELECT COUNT(*) AS active_evidence_definitions
FROM faro.evidence_definitions
WHERE status = 'active';
12.2 · Unicidad Esperado: 0 filas

No hay códigos duplicados activos

El índice único parcial debería prevenirlo, pero esta query lo verifica explícitamente.

▸ SQL
SELECT evidence_code, COUNT(*) AS total
FROM faro.evidence_definitions
WHERE status = 'active'
GROUP BY evidence_code
HAVING COUNT(*) > 1;
12.3 · Propósito Esperado: 0 filas

Toda evidencia activa tiene propósito ejecutivo

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.

▸ SQL
SELECT evidence_code, name
FROM faro.evidence_definitions
WHERE status = 'active'
  AND (executive_purpose IS NULL OR trim(executive_purpose) = '');
12.4 · Trust level Esperado: 0 filas

Toda evidencia tiene trust level válido

El check constraint debería prevenirlo, pero esta query lo verifica. Solo se aceptan low, medium, high, critical.

▸ SQL
SELECT evidence_code, name
FROM faro.evidence_definitions
WHERE status = 'active'
  AND trust_level NOT IN ('low', 'medium', 'high', 'critical');
12.5 · Cierre + revisión Esperado: 0 filas

Toda evidencia que cierra debe requerir revisión o ser validación ejecutiva

Regla 06: si can_close_action = true y requires_review = false, el tipo debe ser approval o executive_validation (ya tienen su propio workflow).

▸ SQL
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');
12.6 · Evidencia requerida por acciones Esperado: 0 filas

Toda evidencia requerida por acciones existe en catálogo

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.

▸ SQL
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;
12.7 · Evidencia requerida por tensiones Esperado: 0 filas

Toda evidencia requerida por tensiones existe en catálogo

Cada código en tension_definitions.evidence_required debe existir como evidencia activa. Si no, las reglas YAML crearían tensiones con cierre imposible.

▸ SQL
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;
12.8 · Demo Esperado: 0 filas

Toda evidencia de Empresa Demo Cuyo S.A. existe en catálogo

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.

▸ SQL · company_id de Empresa Demo Cuyo S.A.
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;
13 · Cross-references

Dónde se cruza este catálogo con el resto del pack

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.