Coherencia jerárquica en catalogación
Tras el scoring heurístico habitual, el clasificador aplica una capa de coherencia jerárquica: puede reordenar el ranking cuando el nodo líder y otro hermano (mismo parentId) compiten y se cumplen reglas explícitas alineadas con la desambiguación del vault. No suma ni resta score: solo intercambia posiciones en el top cuando las condiciones declaradas se cumplen.
Motivación
Sección titulada «Motivación»Evita el sesgo symptom dominance: un síntoma muy lexicalizado (p. ej. puertas del ascensor) no debe ganar si el texto describe varios ejes y el vault indica un nodo más general bajo el mismo padre (p. ej. 1.4.2.5 frente a 1.4.2.2).
Dónde vive el código
Sección titulada «Dónde vive el código»| Pieza | Ubicación |
|---|---|
| Reglas versionadas | src/data/catalogacion-coherence-rules.v1.json (version + array rules) |
| Motor puro | src/lib/catalogacion-coherence.ts (applyCoherenceRules, loadCoherenceRulesVersion) |
| Hook en el clasificador | src/pages/api/catalogar-incidencia.ts — dentro de classifyIncident, después de ordenar por score y antes de tomar best / second para la confianza |
| Contrato v1 | src/pages/api/v1/catalogar-incidencia.ts — reexpone coherenceAdjustments y coherenceRules en el JSON minimal |
Esquema de una regla (JSON)
Sección titulada «Esquema de una regla (JSON)»Cada elemento de rules tiene esta forma (campos obligatorios salvo excludeNormalizedSubstrings):
| Campo | Significado |
|---|---|
id | Identificador estable para auditoría y trazabilidad en coherenceAdjustments. |
parentId | Padre común: solo se comprueba coherencia si el líder en taxonomía tiene este parentId. |
ifLeadingNodeId | La regla solo se considera si el número 1 del ranking (tras reglas anteriores) es exactamente este nodo. |
preferNodeId | Hermano que debe pasar a la primera posición si el resto de condiciones se cumple. |
maxLeaderMinusPreferredScore | Tope de separación en score: leader.score − preferred.score debe ser ≤ este valor para aplicar el ajuste (evita saltos cuando el preferido va muy rezagado). |
preferredMaxRank | El preferido debe estar ya entre las primeras posiciones 0…preferredMaxRank (índice en el ranking tras reglas previas). |
when.allTokenGroupsHit | Lista de grupos de palabras clave. Debe cumplirse que cada grupo tenga al menos un acierto en el texto (ver siguiente apartado). |
excludeNormalizedSubstrings | Opcional. Si el texto normalizado contiene cualquiera de estas subcadenas (tras quitar acentos y minúsculas), la regla no se aplica. |
reason | Texto breve que se devuelve en la API y sirve de explicación humana. |
Cómo matchean las palabras de when
Sección titulada «Cómo matchean las palabras de when»El motor usa el mismo texto normalizado (minúsculas, sin acentos) y el conjunto de tokens del mensaje que el resto del clasificador:
- Palabra con espacios en la regla: se busca como substring en el texto normalizado.
- Palabra sin espacios: debe aparecer como token en el mensaje, con longitud mínima 3 caracteres (tokens más cortos se ignoran para reducir ruido).
Comportamiento del motor
Sección titulada «Comportamiento del motor»- Las reglas se evalúan en el orden del array; una promoción puede hacer que una regla posterior vea otro líder.
- Si una regla aplica, el nodo preferido pasa a la posición 1; el resto conserva el orden relativo (el antiguo líder queda detrás).
- Al nodo promovido se le añade una línea en
evidence:Ajuste coherencia jerárquica: <ruleId>(visible en alternativas del modofull/ en depuración).
Regla en producción (v1)
Sección titulada «Regla en producción (v1)»La versión actual del fichero incluye la regla elev-142-multisymptom-prefer-225-over-222 bajo parentId 1.4.2: con señales de puertas/cabina y otro eje (vibración, paradas, garaje, recurrente, mantenimiento, etc.), sin exclusiones de parada total / fuera de servicio / atrapamiento, promueve 1.4.2.5 cuando el líder sería 1.4.2.2 y el gap de score no supera el umbral configurado.
Respuesta API
Sección titulada «Respuesta API»coherenceAdjustments: array de{ ruleId, fromNodeId, toNodeId, reason }; vacío si no hubo cambio.model.coherenceRules(respuesta completa declassifyIncident): cadena de versión del fichero de reglas (p. ej.v1).humanReadable.coherenceAdjustments: misma información para lectura junto al resto de campos amigables.
En POST /api/v1/catalogar-incidencia, el JSON minimal incluye coherenceAdjustments y coherenceRules en la raíz (la versión se toma de model.coherenceRules internamente). Los esquemas OpenAPI en public/openapi/ describen estos campos para integraciones externas.
Regresión y mantenimiento
Sección titulada «Regresión y mantenimiento»- Tras cambiar reglas o taxonomía, ejecutar
npm run eval:catalogacion; losnodeIdde las reglas deben existir en el dataset normalizado. - Añadir o ajustar entradas en
scripts/catalogacion-gold-cases.jsonantes de endurecer una regla nueva.
Cola de trabajo por familias
Sección titulada «Cola de trabajo por familias»Para listar padres con ≥2 hojas (candidatos a nuevas reglas), con metadatos de desambiguación del vault:
npm run coherence:queueSalida JSON en stdout (script scripts/list-coherence-sibling-queue.ts). Priorizar por familia (F01, F04, F10…) y añadir siempre un caso gold antes de activar una regla nueva.
Oleadas recomendadas
Sección titulada «Oleadas recomendadas»- Completar reglas y gold para un
parentIdacotado (prototipo:1.4.2). - Ejecutar
npm run eval:catalogacion. - Repetir por familia usando la salida de
coherence:queue.
Relación con «Pesos y clasificación»
Sección titulada «Relación con «Pesos y clasificación»»La coherencia jerárquica es posterior al score descrito en Pesos y clasificación: primero se calculan y ordenan candidatos; después puede reordenarse el top entre hermanos; después se calcula la confianza con el primero y el segundo del ranking ya ajustado.