# ========================================================================= # Clasificador de fases del proceso selectivo # Buscador Multisearch — Intervención 1 # ========================================================================= # # Este archivo define las palabras-ancla por fase y la lógica para # etiquetar cada hit del buscador. Se carga al arrancar y se aplica # después del matching por patrones del diccionario maestro. # # Para usarlo desde Python: # # import yaml # with open('01_fases.yaml') as f: # cfg = yaml.safe_load(f) # fase = clasificar_fase(fragmento, cfg) # # La función `clasificar_fase` debe seguir la lógica de la sección # `clasificador.orden_evaluacion` de abajo. # ========================================================================= version: "1.0" descripcion: | Clasifica cada coincidencia del buscador en una de las cuatro fases del ciclo de vida de un proceso selectivo. La fase asignada determina prioridad en el email, persistencia en BD de procesos y disparo de pipelines adicionales (extracción de temario, calendarización). # ========================================================================= # FASE 1: OFERTA DE EMPLEO PÚBLICO (OEP) # ========================================================================= oep: nombre: "Oferta de Empleo Público" codigo: "oep" descripcion: | Acto de planificación anual que autoriza un número de plazas por cuerpo. No es la convocatoria — es el anuncio de que existirá. prioridad_email: 2 # 1=máxima, 4=mínima color_email: "#3B82F6" # azul # Palabras-ancla FUERTES: bastan por sí solas para clasificar como OEP ancla_fuerte: - "oferta de empleo publico" - "oferta publica de empleo" - "se aprueba la oferta de empleo" - "aprobacion de la oferta de empleo" - "OEP \\d{4}" - "OEP del ejercicio" - "plazas autorizadas para nuevo ingreso" - "tasa de reposicion" - "tasa adicional" - "tasa extraordinaria" - "tasa de estabilizacion" - "plan de estabilizacion del empleo" - "plan plurianual de empleo" - "anexo de plazas autorizadas" # Palabras-ancla DE REFUERZO: solas no clasifican, sumadas refuerzan ancla_refuerzo: - "distribucion territorial de plazas" - "cuerpos y escalas" - "subgrupo de clasificacion profesional" - "promocion interna" - "acceso libre" - "reserva personas con discapacidad" - "discapacidad intelectual" - "real decreto \\d+/\\d{4}" - "decreto \\d+/\\d{4} por el que se aprueba" - "acuerdo del consejo de gobierno" - "acuerdo de la mesa general de negociacion" # Pistas estructurales pistas: boletines_tipicos: - "BOE" - "BOJA" - "DOG" - "DOGC" - "DOGV" - "BOPV" - "BON" - "BOA" - "BOC" - "BOCYL" - "DOCM" - "DOE" - "BOIB" - "BOR" - "BOPA" longitud_documento_min_paginas: 3 contiene_tabla_plazas_por_cuerpo: true meses_tipicos_publicacion: [3, 4, 5, 6] # ========================================================================= # FASE 2: BASES DE LA CONVOCATORIA (la más importante) # ========================================================================= bases: nombre: "Bases de la convocatoria" codigo: "bases" descripcion: | Documento que regula el proceso: temario, ejercicios, tasas, tribunal, criterios de valoración. ES LA FASE CLAVE para una academia: contiene el temario que hay que preparar. prioridad_email: 1 # máxima color_email: "#10B981" # verde ancla_fuerte: - "bases reguladoras de la convocatoria" - "bases especificas de la convocatoria" - "bases generales de la convocatoria" - "bases que han de regir" - "bases que rigen la convocatoria" - "convocatoria de pruebas selectivas" - "proceso selectivo para el ingreso" - "proceso selectivo para la cobertura" - "proceso selectivo para la provision" - "proceso selectivo de estabilizacion" - "sistema selectivo de" - "sistema de seleccion" - "fase de oposicion" - "fase de concurso" - "concurso-oposicion" - "concurso de meritos" - "concurso oposicion libre" - "primer ejercicio de la oposicion" - "segundo ejercicio de la oposicion" - "ejercicios de la oposicion" - "pruebas de la fase de oposicion" - "anexo i: programa" - "anexo i.- programa" - "anexo i programa" - "anexo ii: temario" - "anexo: temario" - "anexo programa" - "anexo temario" - "programa de la fase de oposicion" - "temario de la fase de oposicion" - "parte general del programa" - "parte especifica del programa" - "parte general del temario" - "parte especifica del temario" - "tribunal calificador" - "composicion del tribunal calificador" - "designacion del tribunal" - "sistema de baremacion" - "valoracion de meritos" - "criterios de valoracion" - "baremo de meritos" - "calificacion de las pruebas" - "requisitos de los aspirantes" - "condiciones de los aspirantes" - "derechos de examen" - "tasa de derechos de examen" - "tasa por participacion en pruebas selectivas" ancla_refuerzo: - "turno libre" - "turno de promocion interna" - "turno de reserva" - "caracter del nombramiento" - "tipo de contratacion" - "regimen juridico" - "naturaleza de la relacion" - "supuestos de incompatibilidad" - "presentacion telematica" - "modelo de solicitud" - "modelo oficial de solicitud" - "criterios de desempate" - "calificacion final" - "puntuacion final" - "reconocimiento medico" - "curso selectivo" - "periodo de practicas" - "fase de practicas" - "prueba de conocimiento de idioma" - "prueba de catalan" - "prueba de valenciano" - "prueba de euskera" - "prueba de gallego" pistas: boletines_tipicos: - "BOPB" - "BOP" # cualquier BOP provincial - "BOCM" - "BOJA" - "DOG" - "DOGC" - "DOGV" - "BOPA" - "BOPV" - "DOCM" - "DOE" - "BOIB" - "BOC" longitud_documento_min_paginas: 8 longitud_documento_max_paginas: 100 contiene_tabla_temario: true suele_citar_la_OEP_origen: true # ========================================================================= # FASE 3: APERTURA DE PLAZO DE SOLICITUDES # ========================================================================= apertura: nombre: "Apertura de plazo de solicitudes" codigo: "apertura" descripcion: | Convocatoria formal que abre el plazo de presentación de instancias. Para procesos estatales sale en el BOE. Disparador de acción inmediata: avisar a los suscriptores. prioridad_email: 1 # alta color_email: "#F59E0B" # ámbar ancla_fuerte: - "plazo de presentacion de solicitudes" - "plazo de presentacion de instancias" - "plazo para la presentacion de solicitudes" - "plazo de \\d+ dias habiles" - "plazo de veinte dias habiles" - "veinte dias habiles contados a partir del dia siguiente" - "veinte dias naturales contados a partir del dia siguiente" - "contados a partir del dia siguiente al de la publicacion" - "inscripcion en el proceso selectivo" - "inscripcion en pruebas selectivas" - "presentacion telematica de solicitudes" - "solicitudes de participacion en el proceso" - "tasa por derechos de examen" - "modelo 790" - "administracion.gob.es/pag/ips" - "sede electronica para la inscripcion" - "se convoca proceso selectivo" - "resolucion de \\d+ de \\w+ de \\d{4}.*por la que se convoca" - "orden \\w+/\\d+/\\d{4}.*por la que se convoca" ancla_refuerzo: - "tasa de \\d+[,.]?\\d* euros" - "ingreso de la tasa" - "abono de la tasa" - "modelo de instancia" - "instancia normalizada" - "documentacion a aportar" - "fecha del primer ejercicio" - "cronograma orientativo" - "lugar de celebracion del primer ejercicio" pistas: boletines_tipicos: - "BOE" # estatal por excelencia - "BOJA" - "DOG" - "DOGC" # Locales también, dependiendo de la administración: - "BOPB" - "BOP" longitud_documento_min_paginas: 2 longitud_documento_max_paginas: 15 suele_citar_las_bases_origen: true # ========================================================================= # FASE 4: SUB-FASES POSTERIORES (lista de admitidos, tribunal, etc.) # ========================================================================= subfases: nombre: "Sub-fases del proceso en curso" codigo: "subfase" descripcion: | Eventos posteriores a la apertura: correcciones, listas, tribunales, resultados, adjudicaciones, nombramientos. Útiles para personas que ya están en el proceso. prioridad_email: 3 # media color_email: "#9CA3AF" # gris subtipos: correccion_errores: nombre: "Corrección de errores" ancla: - "correccion de errores" - "subsanacion de errores" - "errata en la convocatoria" - "correccion de error material" ampliacion_plazo: nombre: "Ampliación de plazo" ancla: - "ampliacion del plazo de presentacion" - "ampliacion del plazo de solicitudes" - "nuevo plazo de presentacion" - "se amplia el plazo" lista_provisional_admitidos: nombre: "Lista provisional de admitidos" ancla: - "lista provisional de admitidos" - "relacion provisional de aspirantes admitidos" - "aspirantes admitidos y excluidos con caracter provisional" - "plazo de subsanacion" - "subsanar la causa de exclusion" lista_definitiva_admitidos: nombre: "Lista definitiva de admitidos" ancla: - "lista definitiva de admitidos" - "relacion definitiva de aspirantes admitidos" - "aspirantes admitidos con caracter definitivo" - "fecha del primer ejercicio" - "lugar de celebracion del primer ejercicio" - "fecha hora y lugar de celebracion" composicion_tribunal: nombre: "Composición del tribunal" ancla: - "composicion del tribunal calificador" - "nombramiento del tribunal" - "designacion de los miembros del tribunal" - "presidente del tribunal" - "secretario del tribunal" - "vocales del tribunal" plantilla_respuestas: nombre: "Plantilla de respuestas" ancla: - "plantilla provisional" - "plantilla correctora provisional" - "plantilla definitiva" - "respuestas correctas del primer ejercicio" - "alegaciones a la plantilla" resultados_ejercicio: nombre: "Resultados de ejercicio" ancla: - "calificaciones del primer ejercicio" - "calificaciones del segundo ejercicio" - "relacion de aspirantes que han superado" - "resultados del ejercicio" - "puntuaciones obtenidas" aprobados_sin_plaza: nombre: "Bolsa de aprobados sin plaza" ancla: - "relacion de aprobados sin plaza" - "bolsa de empleo de aspirantes" - "constitucion de la bolsa" - "aspirantes que han aprobado sin obtener plaza" lista_aprobados: nombre: "Lista definitiva de aprobados" ancla: - "relacion definitiva de aprobados" - "propuesta de nombramiento" - "aspirantes propuestos para el nombramiento" - "han superado el proceso selectivo" adjudicacion_destinos: nombre: "Adjudicación de destinos" ancla: - "adjudicacion de destinos" - "eleccion de destino" - "asignacion de destinos" - "vacantes ofertadas para su adjudicacion" - "destinos a ofertar" nombramiento: nombre: "Nombramiento" ancla: - "nombramiento como funcionario de carrera" - "nombramiento como personal laboral fijo" - "toma de posesion" - "juramento o promesa" - "diligencia de toma de posesion" # ========================================================================= # CLASIFICADOR: lógica de asignación de fase # ========================================================================= clasificador: # Orden de evaluación: se aplican las reglas en este orden y se asigna # la primera fase que dispare. Si ninguna dispara, fase = desconocida. orden_evaluacion: - bases # se evalúa primero porque es la más informativa - apertura - oep - subfases - desconocida # Casos especiales (cuando varias fases podrían disparar) conflictos: # Si dispara BASES y APERTURA a la vez (porque las bases incluyen ya # el plazo), prevalece BASES (el evento más completo). - condicion: "bases AND apertura" asignar: bases # Si dispara OEP y BASES, prevalece BASES (las bases citan la OEP # de la que proceden, pero la fase real es BASES). - condicion: "oep AND bases" asignar: bases # Si dispara OEP y APERTURA, prevalece APERTURA (la convocatoria # menciona la OEP de origen). - condicion: "oep AND apertura" asignar: apertura # Si dispara una sub-fase Y una fase principal, prevalece la sub-fase # solo si el patrón temático coincide con poca distancia del ancla # de sub-fase. Si no, prevalece la principal. # Esta lógica se implementa en código, no en YAML. # Umbrales numéricos umbrales: # Cuántas ancla_fuerte distintas debe haber para clasificar # automáticamente (1 suele bastar). min_ancla_fuerte: 1 # Si no hay ancla_fuerte pero hay anclas de refuerzo, cuántas # necesita para clasificar min_ancla_refuerzo_si_no_fuerte: 3 # Si solo hay 1 ancla_fuerte de oep + texto largo de bases + cita a # cuerpos: prevalece bases. Implementar en código. # Para fases desconocidas, aplicar las reglas R1-R14 de exclusiones del # documento `diccionario_maestro_oposiciones.md` y bajar a BAJA si # corresponde. # Salida del clasificador para cada hit: esquema_salida: fase: "bases | apertura | oep | subfase | desconocida" subtipo: "(solo si fase=subfase) correccion_errores | ampliacion_plazo | ..." ancla_disparadas: ["lista de palabras-ancla que coincidieron"] score: "0.0-1.0 (cuánta seguridad hay en la clasificación)" pistas_estructurales: ["lista de pistas que reforzaron la decisión"] # ========================================================================= # PSEUDO-CÓDIGO DE REFERENCIA (Python) # ========================================================================= # # def clasificar_fase(fragmento: str, contexto_completo: str, # boletin: str, paginas: int, cfg: dict) -> dict: # """ # fragmento: ±300 chars alrededor del patrón temático # contexto_completo: todo el bloque del boletín que rodea el patrón # boletin: código del boletín (BOE, BOPB, ...) # paginas: longitud del documento donde aparece # """ # import re # from unidecode import unidecode # # # Normalizar texto (minúsculas, sin acentos) # texto = unidecode(contexto_completo.lower()) # # resultados = {} # for codigo_fase in ['bases', 'apertura', 'oep']: # fase_cfg = cfg[codigo_fase] # fuertes = [] # refuerzos = [] # # for ancla in fase_cfg['ancla_fuerte']: # if re.search(unidecode(ancla.lower()), texto): # fuertes.append(ancla) # # for ancla in fase_cfg['ancla_refuerzo']: # if re.search(unidecode(ancla.lower()), texto): # refuerzos.append(ancla) # # score = len(fuertes) * 1.0 + len(refuerzos) * 0.3 # resultados[codigo_fase] = { # 'fuertes': fuertes, # 'refuerzos': refuerzos, # 'score': score # } # # # Si ninguna fase tiene fuertes ni 3+ refuerzos, intentar sub-fases # max_score = max(r['score'] for r in resultados.values()) # if max_score < 1.0: # for subtipo, sub_cfg in cfg['subfases']['subtipos'].items(): # for ancla in sub_cfg['ancla']: # if re.search(unidecode(ancla.lower()), texto): # return { # 'fase': 'subfase', # 'subtipo': subtipo, # 'ancla_disparadas': [ancla], # 'score': 0.8 # } # return {'fase': 'desconocida', 'score': 0.0} # # # Aplicar conflictos # activas = [f for f, r in resultados.items() if r['score'] >= 1.0] # # if 'bases' in activas: # fase_asignada = 'bases' # elif 'apertura' in activas: # fase_asignada = 'apertura' # elif 'oep' in activas: # fase_asignada = 'oep' # else: # # Solo hay refuerzos, asignar la fase con más score # fase_asignada = max(resultados.keys(), # key=lambda k: resultados[k]['score']) # # return { # 'fase': fase_asignada, # 'ancla_disparadas': (resultados[fase_asignada]['fuertes'] # + resultados[fase_asignada]['refuerzos']), # 'score': min(resultados[fase_asignada]['score'] / 3.0, 1.0) # }