Ir al contenido

Pesos y clasificación

Este manual distingue tres cosas distintas que a veces se confunden:

  1. Puntuación interna (score) que el clasificador suma por cada nodo candidato.
  2. Confianza que se muestra al usuario (derivada del mejor score frente al segundo).
  3. Peso de completitud del vault en el script de auditoría audit_vault_signals.py (calidad documental del nodo, no el score en tiempo real).

La fuente de verdad operativa del API es src/pages/api/catalogar-incidencia.ts (funciones classifyIncident y scoreCandidate). El explorador web usa una versión simplificada en src/components/explorer/ExplorerApp.tsx (scoreNodeForIncident): los números no coinciden al 100 % con el API, pero la idea es la misma.

El atributo fm_type (hard | soft | mixto) en cada hoja no entra en la fórmula de score del clasificador; solo describe el tipo de FM asociado al nodo. Definición y criterios: Ontología y taxonomía → Campo fm_type.

El campo ai.disambiguation del dataset normalizado procede del vault: bloque > **Desambiguación:** en la ficha (si existe) o, si no, la primera línea > del cuerpo (breadcrumb). Ese texto se incluye en searchText al generar scripts/generate-normalized-taxonomy.js, de modo que la cobertura semántica y coincidencias por tokens pueden usar también esas frases. Sigue existiendo la pista disambiguationHint en la respuesta del API para la mejor hoja (no es una bonificación numérica separada).


  1. Se normaliza el texto (minúsculas, sin acentos, tokenización).
  2. Si el mensaje trae el patrón Texto canónico: … Texto original: …, solo el tramo canónico entra en la clasificación (el original queda para trazabilidad).
  3. Para cada nodo del dataset normalizado se calcula un score sumando contribuciones (tokens, frases, reglas contextuales).
  4. Se descartan candidatos con score ≤ SCORE_MIN (actualmente 0.0001).
  5. Se ordenan por score descendente.
  6. Coherencia jerárquica (reglas declarativas): puede reordenar el top entre hojas hermanas con el mismo parentId sin modificar los scores numéricos. Detalle de campos, API y flujo de trabajo: Coherencia jerárquica (catalogación).
  7. El primero del ranking tras ese paso es la mejor hoja (o el mejor candidato según reglas de hoja).
  8. La confianza se obtiene con computeConfidence(mejorScore, segundoScore) y se compara con minConfidence (por defecto 0,55 si el cliente no envía el parámetro), posiblemente relajado por getEffectiveMinConfidence según el tipo de evidencia (ver §4).

2. Pesos base por tipo de coincidencia (API)

Sección titulada «2. Pesos base por tipo de coincidencia (API)»

Estos valores son aditivos: cuantas más evidencias encajen, mayor es el score del nodo.

ConceptoEfecto típicoNotas
Tokens del nombre del nodo+1,8 por token del nombre que aparezca en el mensajeIntersección de tokens.
ID del nodo en el texto (p. ej. 1.2.1.4.1)+8Refuerzo fuerte si el usuario o un sistema citan el código.
Slug del nodo en el texto+5Similar al ID, con umbral de longitud para evitar ruido.
Keywords (ai.kw en taxonomía)+3,2 por keyword que coincideFrases completas: substring en texto normalizado; palabra suelta: token presente.
Señales (frase completa en texto)+4,5 por señalFunción phraseListScore.
Señales (solo solapamiento de tokens ≥ 0,45)+ overlap × 3,4overlap = tokens comunes / tokens de la frase.
EjemplosIgual criterio que señalesMisma función phraseListScore.
Cobertura semántica (searchText del nodo)Si la proporción de tokens del mensaje presentes en el nodo es ≥ 0,34: + proporción × (8,5 si hoja, × 4,2 si no)Prioriza hojas cuando el vocabulario encaja.
Cobertura jerárquica (breadcrumb)Si ≥ 0,4: + proporción × (2,2 hoja / 1,1 resto)
Nombre de tramo de breadcrumb (≥ 8 caracteres) en el texto+1,6 por coincidenciaHasta las que apliquen.

Además existen muchas reglas contextuales (biohazard/limpieza, tipo declarado en el formulario, domiciliación bancaria, juntas, actas, contratos, seguridad, filtraciones vs fugas, etc.) que suman o restan bonos o penalizaciones fijas a ramas concretas de la taxonomía. Están implementadas en el mismo scoreCandidate: al cambiar el comportamiento hay que revisar también los casos de prueba en scripts/eval-catalogacion.ts y scripts/catalogacion-gold-cases.json.

Un inventario orientativo de reglas añadidas o reforzadas recientemente (garaje, humedades, portal, CCTV, etc.) está en §9; los valores exactos siguen en código.


3. De score a “probabilidad” (confianza)

Sección titulada «3. De score a “probabilidad” (confianza)»

El score no es una probabilidad entre 0 y 1. La confianza se calcula así (computeConfidence):

  • margen = max(mejorScore − segundoScore, 0)
  • confianza = 0,35 + margen / (mejorScore + segundoScore + 6)
  • Resultado acotado entre 0 y 0,99 y redondeado a 4 decimales.

Intuición: si el segundo clasificado queda muy cerca del primero, el margen es pequeño y la confianza baja aunque el score absoluto sea alto.


4. Umbrales: minConfidence y relajación automática

Sección titulada «4. Umbrales: minConfidence y relajación automática»
  • minConfidence (query/body JSON): umbral mínimo para marcar reviewRequired = false. Por defecto 0,55 si no se envía (tanto el endpoint legacy como POST /api/v1/catalogar-incidencia).
  • getEffectiveMinConfidence puede bajar el umbral efectivo cuando hay evidencias fuertes o combinaciones previstas (contratos con dominio alineado, domiciliación bancaria, tipo declarado con rama preferida, heurísticas de biohazard/limpieza, varias líneas de evidencia semántica, etc.). Así se evita pedir revisión humana en escenarios donde el modelo ya es explícito en el código.
  • Strict vs relajado (importante): en catalogar-incidencia.ts (rutas GET/POST sin versión), si el cliente envía minConfidence, se pasa strictMinConfidence: true y no se aplica la relajación: el umbral aplicado es exactamente el pedido. En cambio POST /api/v1/catalogar-incidencia llama a classifyIncident sin esa opción (sigue el valor por defecto strictMinConfidence: false), así que puede aplicarse getEffectiveMinConfidence aunque el cuerpo traiga minConfidence.

Para afinar política de revisión humana se tocan estas funciones y, si aplica, el valor por defecto de minConfidence en cada endpoint.


scoreNodeForIncident en el explorador usa coeficientes parecidos pero distintos (p. ej. keywords ×3 frente a ×3,2, señales/ejemplos con pasos ligeramente diferentes, base +0,35 en hojas). No uses el explorador como referencia numérica exacta del API; úsalo como orientación visual.


6. Auditoría del vault: pesos de completitud (no son el clasificador)

Sección titulada «6. Auditoría del vault: pesos de completitud (no son el clasificador)»

El script analisis/audit_vault_signals.py calcula un score 0–10 de “¿el nodo está bien documentado?”, no de clasificación:

ComponentePeso en el score de completitud
Keywords (objetivo ≥ 6)0,30
Señales de alarma (objetivo ≥ 4)0,40
Ejemplos reales (objetivo ≥ 2)0,30

Cada componente se normaliza a 0–1 según cuántos ítems hay frente al objetivo y se combina en una nota 0–10. Sirve para priorizar mejoras editoriales en el vault, no para decidir el nodo ganador en runtime.


7. Cómo gestionar o cambiar los pesos (checklist)

Sección titulada «7. Cómo gestionar o cambiar los pesos (checklist)»
  1. Clasificación en producción (API): editar constantes y reglas en scoreCandidate, phraseListScore, overlapRatio y listas de frases en src/pages/api/catalogar-incidencia.ts.
  2. Documentación: tras cambiar bonificaciones o criterios de desambiguación, actualizar §9 de esta página (intento + nodos ±) para que producto y mantenimiento compartan la misma referencia.
  3. Coherencia UI: si quieres paridad explorador/API, alinear manualmente ExplorerApp.tsx (no está automatizado).
  4. Regresión: ejecutar npm run eval:catalogacion (evalúa contra casos oro).
  5. Dataset: los keywords/señales/ejemplos vienen del vault → vault_to_taxonomy.pytaxonomy.js → generación de taxonomy.normalized.json. Mejorar datos suele importar más que retocar un +0,2 en el código.
  6. Completitud documental: ajustar W_KEYWORDS, W_SENALES, W_EJEMPLOS o los objetivos TARGET_* en audit_vault_signals.py si cambias el estándar de calidad del vault.

Si añades reglas nuevas al clasificador, documenta en §9 el intento (qué conflicto resuelven), los nodos afectados y los órdenes de magnitud (+/−); enlaza al bloque de código (comentarios // ── … ── en scoreCandidate) y amplía scripts/catalogacion-gold-cases.json cuando el caso sea estable.


9. Reglas contextuales relevantes (inventario)

Sección titulada «9. Reglas contextuales relevantes (inventario)»

Tabla de referencia de desambiguaciones con bonificaciones/penalizaciones aditivas sobre el score base. Condiciones exactas (substrings tras normalizar el texto) en catalogar-incidencia.ts, función scoreCandidate. Las cifras son las vigentes en código a 2026-04-05; si difieren, prevalece el archivo TS.

TemaCondición resumidaPenaliza (Δ)Refuerza (Δ)
Ruido en garaje/parkingruido + zona garaje/parking/sótano; sin ventilación/extractor/CO; sin puerta de garaje en foco1.5.3.1: −9,54.1.3.4: +8,2
Portal abierto vs garajeportal o “entrada al edificio” + “queda abierta/oberta”1.9.1.2: −126.3.1.1: +9
CCTV / grabacióncamara + graba / grabacion / funcionamiento1.1.2.3.1: −106.3.2.1: +9,5
Timbrepresencia de timbre11.1.5: −91.6.2.1: +8
Puerta comunitaria (seguimiento)puerta + comunitaria + continuidad/fallo; sin caldera/calefacción1.2.2.1.1: −126.3.1.1: +8
Cableado visiblecable/cableado + visible/visto/techo1.2.1.4.4: −99.2.2: +8,5
Corriente de aireentra aire / corriente de aire / cerramiento no estanco1.1.2.2.2: −96.3.1.1: +7,5
Bomba / grupo de presión(bomba o grupo+presion) + (ruido/urgente/revisar/revision/tarda) + agua1.2.1.3.2: −11; 3.4.3.2: −101.2.1.2.3: +11
Agua recurrente en garajegaraje + agua + recurrente/“otra vez”/“sigue”; sin atasco/bajante/fecales…1.2.3.1.2: −91.2.1.4.5: +8,5
Humedad en techo sin lluviatecho/sostre + humedad/mancha; sin lluvia/gotera/cuando llueve1.1.2.2.2: −71.2.1.4.4: +6,5
Mancha en pared sin lluviapared + mancha/taca; sin lluvia/gotera1.1.2.2.2: −6,51.2.1.4.4: +6
Fuga pequeñafuga + pequeña/petita/tuberia1.2.1.4.1: +10
Grieta parking/garajegrieta + parking/garaje + pared/paramento/muro1.1.1.1.2: +9
Pintura techo portalportal + techo + pintura/pelando/desconchado/deterioro1.2.1.4.4: −69.8.2: +10
Olor en ascensorascensor + olor/huele/olia10.1.6: +7
Pitido sin calderapitido y sin caldera1.2.2.1.1: −104.1.3.4: +7,5
Luz en rellano/patio/escalera (no ascensor)luz/iluminacion/alumbrado/llum + rellano/patio/pati/… + apagado/fuera de servicio/…; sin ascensor/elevador/montacargas1.4.2.1: −141.3.2.3: +11,5
Alumbrado de emergenciaemergencia + luz/alumbrado/luminaria + fallo; sin ascensor1.4.2.1: −141.3.3.1: +11,5
Trámite / alcance de seguroseguro/aseguradora/poliza + incidencia/alcance/siniestro/…; sin caldera/calefaccion1.2.2.2.1: −133.1.4.1: +10,5
Puerta ascensor rápida o puertas (ajuste)ascensor + puerta + rapido/demasiado/…; refuerzo existente para 1.4.2.21.4.1.2: −111.4.2.2: +9 (y −5,5 a 1.4.2.1)
Ascensor solo lentitud / esperaascensor + tiempo de espera / espera excesiva / tarda+mucho; sin parada/avería/fuera de servicio1.4.2.1: −911.1.3: +8,5

Nodos nuevos en taxonomía (vault) que entran en el juego de puntuación por keywords y por las filas anteriores: 1.2.1.4.5 (agua en garaje/sótano origen indeterminado), 1.2.1.2.3 (grupo de presión / bomba de impulsión AFS), 4.1.3.4 (ruido en zona común sin origen identificado). Flujo de datos: analisis/vault/vault_to_taxonomy.pytaxonomy.jsnpm run generate.

Informes de caja negra: el script scripts/report-124.ts clasifica los textos canónicos de analisis/clasificaciones_124_incidencias.md y escribe analisis/informe-124.md; no sustituye eval:catalogacion pero sirve para regresión rápida tras tocar reglas o el vault.


Última actualización (UTC): 2026-04-05 12:00:00 UTC