name: canonizar-contrato-salud description: Lee contratos de salud en PDF y los convierte a un JSON canónico semántico y limpio, discriminando coberturas reales de metadatos y topes.
Skill: Canonización de Contratos de Salud (v2.0 Semántica)
Objetivo
Transformar contratos de salud heterogéneos (Isapre/Fonasa) en una representación JSON canónica, semántica y limpia. El objetivo es auditar financieramente, por lo que la precisión en topes, unidades y ámbitos es crítica.
Modelo Conceptual: Descubrimiento Dinámico de Paths (CRÍTICO)
Corrección Conceptual
El error no está en visualizar paths por prestación, sino en permitir que la prestación seleccione el path. En el modelo correcto, las prestaciones solo declaran elegibilidad para Oferta Preferente, y la determinación del path específico es una decisión dinámica en tiempo de auditoría, basada exclusivamente en el prestador efectivo utilizado por el paciente.
Regla de Oro para Auditoría
- Si el prestador no decide → el auditor está mal
- Si la prestación decide → el auditor está mal
- Solo el prestador decide el path
🛑 REGLAS DE ORO ANTIRUIDO (CRÍTICO)
1. Limpieza de Coberturas
El array coberturas debe contener SOLO prestaciones clínicas.
- PROHIBIDO incluir en
coberturas:- Rangos etarios ("0 a menos de 2 años", "80 y más años").
- Factores o primas (GES, CAEC).
- Títulos de tablas ("TABLA DE BENEFICIOS", "MODALIDAD INSTITUCIONAL").
- Textos vacíos o símbolos sueltos ("%", "*").
- Metadatos del plan ("TIPO DE PLAN", "USO DEL PLAN").
2. Clasificación de Ámbito (Keywords)
No usar "desconocido" perezosamente. Aplicar estas reglas de inferencia:
- HOSPITALARIO: Si contiene
pabellón,quirúrgic,anestesia,día cama,hospital,UCI,UTI,medicamentos en hospitalización. - AMBULATORIO: Si contiene
consulta médica,exámenes,imagenología,procedimientos ambulatorios. - MIXTO: Solo si explícitamente aplica a ambos o es un tope global.
3. Porcentajes vs Factores (No confundir)
- Porcentaje: Valor entre 0 y 100.
- Factor/Tope:
- Si valor > 1.0 (ej: 1.2, 2.0) -> Es un FACTOR o TOPE, nunca un porcentaje.
- Si valor <= 1.0 pero la unidad es AC2, UF, VAM -> Es un TOPE/FACTOR.
4. Semántica de "SIN TOPE"
"SIN TOPE" NO es "DESCONOCIDO". Es información jurídica positiva.
- Mapear a:
{ "tope_existe": false, "razon": "SIN_TOPE_EXPRESO_EN_CONTRATO", "valor": null, "unidad": null }.
5. Principio de Supremacía del Texto (Global)
Esta regla aplica a TODAS las columnas y filas sin excepción.
- Regla: Si el texto dentro de una celda contradice el título de su columna o fila, EL TEXTO MANDA.
- Caso Típico 1: Columna "Preferente" tiene una celda que dice "(Libre Elección)" -> Clasificar como
libre_eleccion. - Caso Típico 2: Fila "Hospitalario" tiene una celda que dice "Consulta Médica" -> Clasificar como
ambulatorio. - Caso Típico 3 (CRÍTICO): Si una celda en Preferente dice "Solo cobertura libre elección", IGNORA la columna y clasifícalo como
libre_eleccion. - Acción: Nunca generar datos contradictorios (ej:
tipo: preferenteconfuente: (MLE)). Divide la celda o re-clasifica según el contenido explícito.
6. FASE 0 — Detección de Bloques Verticales (BCC) (NUEVO)
Antes de interpretar filas como coberturas:
- Detecta celdas que:
- contienen porcentajes + “Sin Tope”
- mencionan prestadores
- se extienden visualmente sobre múltiples filas
- Marca esas celdas como BLOQUES DE COBERTURA COMPARTIDOS (BCC)
- Asocia cada BCC a todas las filas alineadas verticalmente.
7. Regla de Modalidades Derivadas (BCC)
Si una prestación está alineada verticalmente con un Bloque de Cobertura Compartido, la cobertura NO se define en la fila, sino que se expresa como múltiples modalidades derivadas del bloque.
8. Regla de Latencia
“Una prestación puede declarar múltiples modalidades preferentes simultáneamente. Estas NO son decisiones clínicas ni contractuales del paciente, sino opciones latentes que solo el prestador efectivo resolverá en auditoría.”
9. Habilidad de Análisis Estructural Visual (DBPV) (CRÍTICO)
Habilidad de Análisis Estructural Visual El agente debe identificar celdas que se extienden verticalmente y funcionan como bloques de cobertura compartidos, usando criterios de altura relativa, continuidad textual y alineación con múltiples filas de prestaciones. Estas celdas prevalecen sobre la lógica fila–columna tradicional.
INSTRUCCIÓN OPERATIVA: Si existe ambigüedad entre cobertura por fila y cobertura por bloque vertical, SIEMPRE priorizar el bloque vertical.
10. Arquitectura Híbrida Determinista (NUEVO - v3.0)
El Skill no delega la lógica a la IA. La IA solo actúa como "Ojos Refinados" (OCR Semántico). El "Cerebro" de la interpretación es algorítmico y reside en el código del Skill (execute_canonizer.ts):
- Visión Bruta (AI): Extrae texto y coordenadas.
- Lógica Determinista (Skill Code):
- Persistencia Vertical (Sticky): El código rellena huecos basándose en la última cobertura válida.
- Mapeo de Columnas: El código asigna topes basándose en índices de columna, no en "sentido común de IA".
- Confluencia (Flux Capacitor): El código detecta listas de prestadores y las enruta a un único objeto de beneficio.
Regla de Autoridad: Si la IA sugiere algo (ej. "Sin Tope" en una celda vacía) pero el Algoritmo Vertical dicta "80%", MANDA EL ALGORITMO VERTICAL. La IA provee los datos crudos, el Skill provee la Lógica de Negocio.
Esquema Canónico Final (v2.0)
El output debe ser un único objeto JSON que cumpla estrictamente con la siguiente interfaz:
interface CanonicalContract {
metadata: {
origen: "contrato_pdf";
fuente: string; // Nombre de la Isapre y Plan
vigencia: string; // Fecha inicio
tipo_contrato: "ISAPRE" | "FONASA" | "COMPLEMENTARIO";
};
coberturas: Array<{
ambito: "hospitalario" | "ambulatorio" | "mixto" | "desconocido";
descripcion_textual: string; // Nombre limpio de la prestación (ej: "Día Cama")
porcentaje: number | null; // 0-100. NULL si no es % de cobertura directa.
modalidades: Array<{ // Agrupar aquí las variantes
tipo: "preferente" | "libre_eleccion" | "institucional";
red?: string;
porcentaje?: number;
tope?: { // JOÍN LÓGICO ESTRICTO: Si hay tope específico, VA AQUÍ.
unidad: string;
valor: number;
// -- CAMPOS DE VALORIZACIÓN (CAPA 2) --
// El agente deja estos en null, el código auditor los llenará.
valor_clp?: number | null;
fecha_valorizacion?: string | null;
fuente_valorizacion?: string | null;
};
}>;
fuente_textual: string; // "[p.N] ..."
}>;
topes_generales: Array<{
ambito: "hospitalario" | "ambulatorio" | "mixto";
descripcion: string;
// --- OONTOLOGÍA UCA v1.0 ---
unidad: "UF" | "PESOS" | "VA" | "VAM" | "AC" | "AC2" | "V20" | "AM" | "UCR" | "SIN_TOPE" | "DESCONOCIDO";
familia: "monetaria_publica" | "arancelaria_privada" | "clausula_juridica" | "indeterminada";
tipo_logico: "valor_absoluto" | "multiplicador" | "ausencia_limite" | "indeterminada";
riesgo_juridico?: "Alto" | "Medio" | "Bajo" | "Muy Alto";
// ---------------------------
valor: number | null;
tope_existe: boolean;
razon?: "SIN_TOPE_EXPRESO_EN_CONTRATO";
periodo: "anual" | "evento" | "vida";
fuente_textual: string;
}>;
... (rest of schema)
### 📌 Referencia: Tabla Ontológica de Unidades (UCA v1.0)
Usa esta tabla para llenar `familia`, `tipo_logico` y `riesgo_juridico`:
| Sigla | Familia | Tipo Lógico | Riesgo |
| :--- | :--- | :--- | :--- |
| **UF / PESOS** | `monetaria_publica` | `valor_absoluto` | Bajo |
| **VA / VAM / AC / AC2 / V20** | `arancelaria_privada` | `multiplicador` | Alto |
| **SIN_TOPE** | `clausula_juridica` | `ausencia_limite` | Bajo |
| **DESCONOCIDO** | `indeterminada` | `indeterminada` | Muy Alto |
glosario_unidades: Array<{ // NUEVO: Definiciones explícitas encontradas en el texto
sigla: string; // Ej: "AC2", "VAM"
descripcion_contrato: string;// Ej: "Arancel Colmena 2.0 reajustable..."
valor_referencia?: number; // Si el contrato dice "valor referencial $35.000"
fuente_textual: string;
}>;
items_no_clasificados: string[]; // Todo lo que no sea prestación clínica ni tope claro
}
Detalle de Tipos de Unidad Arancelaria
Si encuentras siglas como AC2, VA, VAM:
unidad: Mantener la sigla original ("AC2", "VAM").tipo_unidad: "arancel_base".interpretable_como: "multiplicador".
Ejemplo de Mapeo Semántico
(A) Caso "Sin Tope" Texto PDF: "Día Cama: 100% Sin Tope"
{
"descripcion_textual": "Día Cama",
"porcentaje": 100,
"modalidades": [{ "tipo": "libre_eleccion", "tope": { "tope_existe": false, "razon": "SIN_TOPE_EXPRESO_EN_CONTRATO" } }]
}
(B) Caso Arancel AC2 Texto PDF: "Honorarios: Tope 2.2 AC2"
{
"unidad": "AC2",
"tipo_unidad": "arancel_base",
"valor": 2.2
}
Instrucciones de Procesamiento
- Lectura Secuencial: Lee página por página. Mantén el contexto de la tabla actual (cabeceras).
- Filtrado Activo: Antes de agregar algo a
coberturas, pregúntate: ¿Es esto una prestación médica? Si es una edad, un precio en pesos o una cabecera, IGÑÓRALO o ponlo en metadata si corresponde. - FASE DE NORMALIZACIÓN OBLIGATORIA (GroupBy):
Antes de generar el JSON final, debes ejecutar mentalmente un proceso de agrupación:
groupBy(prestacion_normalizada, ambito)- Si tienes 3 entradas para "Consulta Médica" (una por cada red/clínica), FUSIÓNALAS en un solo objeto
cobertura. - Mueve las diferencias (porcentaje, tope, red) al array
modalidades. - Resultado esperado: Una lista limpia de prestaciones únicas, donde cada una contiene todas sus variantes de cobertura. NO REPETIR la misma prestación 3 veces.
- Si tienes 3 entradas para "Consulta Médica" (una por cada red/clínica), FUSIÓNALAS en un solo objeto
11. REGLA DE AISLAMIENTO TOTAL (OBLIGATORIO)
Propósito: Evitar la contaminación de datos (data leakage) entre contratos de diferentes Isapres o planes.
- AISLAMIENTO ESTRICTO: Cada análisis de contrato es un evento único y aislado.
- PROHIBICIÓN DE MEMORIA CRUZADA: No se deben utilizar conocimientos específicos (prestadores, porcentajes, topes) de contratos procesados en la misma sesión o sesiones previas, a menos que sean parte explícita del documento actual.
- RESETEO DE CONTEXTO: Si el agente detecta que está "recordando" datos de una clínica que no aparece en el texto actual (ej: "Santa María" en un contrato de "Consalud"), debe detenerse y purgar el contexto antes de continuar.
Output
Retorna SOLO el objeto JSON válido. Sin markdown de código, sin explicaciones.