Volver a Novedades
v2.10.5-r67Nuevas funcionesCorreccionesOptimizacionesArquitectura

Lian AI 2 v2.10.5-r67

Progreso independiente y auditable por conversación.

Lian AI 2 v2.10.5-r67

Inteligencia Conversacional Omnicanal

  • Progreso independiente y auditable por conversación.
  • Etapas ponderadas con porcentaje real y redistribución cuando una etapa no aplica.
  • Drawer desde Inbox con contexto, tiempos, pipeline de procesamiento, multimedia y reporte.
  • Centro Inteligencia Conversacional en Lian Admin.
  • Filtros por prioridad, estado, multimedia, agente, pipeline, outcome, fecha, reporte pendiente y aprendizaje pendiente.
  • API interna filtrable de backlog con autenticación, tenant scope y límites de respuesta.

Ampliación omnicanal, créditos e importación

  • El universo de Inteligencia Conversacional parte de todas las conversaciones canónicas del tenant, no sólo de conversaciones con un run previo ni de una fuente Kommo.
  • Histórico de conversaciones del negocio consolida Web Chat, WhatsApp, Inbox, Kommo e importaciones en una sola superficie, con desglose por canal.
  • Consumo previsto del backlog se expresa en créditos y desglosa mensajes/análisis semántico, imágenes/OCR, audio/transcripción, PDF, otros documentos y video.
  • Los costos técnicos en USD del backlog y de Operación últimas 24 h sólo se renderizan para Super Administrador; los negocios ven créditos.
  • Cobertura y aprendizaje por agente incorpora créditos de análisis atribuibles a cada agente a partir de modelo/tokens persistidos.
  • Conversaciones incorpora una barra simétrica de acciones para Inteligencia Conversacional, exportación e importación.
  • La nueva importación de WhatsApp acepta el ZIP oficial con o sin multimedia, valida tamaño/entradas/rutas/ratio de compresión, lo procesa en la cola compartida, reutiliza la frontera segura de MediaAssetService, deduplica por hash/IDs externos y escribe en conversations/messages/media_assets canónicos.
  • Un ZIP reimportado no duplica conversación, mensajes ni adjuntos; si Inteligencia Comercial está habilitada, la conversación importada se descubre y encola para análisis sin crear un motor paralelo.

Priorización y backlog

  • Motor de prioridad 0–100 versionado/configurable.
  • Recencia, etapa, valor, interacción, outcomes, cobertura de agente, diversidad y aging.
  • Representatividad por agente, pipeline, etapa, producto y canal.
  • Anti-starvation configurable.
  • Backpressure global por tenant y semáforos distribuidos por etapa, deduplicación de jobs y reintentos acotados.
  • Discovery metadata-first para obtener valor temprano sin encolar todo el histórico.
  • Selector representativo por lote para evitar concentración temprana por agente, pipeline u outcome.

Kommo histórico

  • Descubrimiento de Talks cuando la conexión lo permite.
  • Importación paginada de mensajes y adjuntos.
  • Capability probe y estado degradado seguro ante scopes/plan insuficientes.
  • Idempotencia por talk, mensaje y adjunto.
  • Límites separados de concurrencia para histórico y adjuntos.
  • Wake-up incremental mediante webhooks oficiales de talk, mensaje entrante y mensaje saliente; el barrido paginado continúa como recuperación/backfill.

Multimedia e IA

  • Reutilización de STT y OCR existentes.
  • PDF: extracción de texto nativa y fallback OCR según capacidades del hosting.
  • Artefactos por hash/versión para evitar reproceso innecesario.
  • IA por chunks bidireccionales de todo el historial, con hash/versionado, evidencia, tokens y checkpoint atómico.
  • Reportes individuales versionados con evidencia restringida.
  • Estimación de tokens/costo usando la política y tarifas existentes.

Aprendizaje

  • LearningReadinessEvaluator para evitar recalcular perfiles sin evidencia nueva suficiente.
  • Perfiles de aprendizaje por agente humano o IA.
  • Reporte Comercial General progresivo.
  • Integración con minería/candidatos gobernados existente; no hay fine-tuning automático.

Seguridad y observabilidad

  • RBAC de lectura, gestión y evidencia.
  • CSRF y rate limit en acciones manuales.
  • Tenant isolation y auditoría.
  • Descarga de adjuntos con HTTPS, allowlist de hosts Kommo/configurados, revalidación de redirecciones y bloqueo de redes privadas.
  • Métricas de cola, duración, STT/OCR, tokens, costo y retries.

QA

  • Regresiones de progreso, scoring, aging, retries, readiness, checkpoints, seguridad y arquitectura.
  • Escenario sintético obligatorio: 1,800 conversaciones, 8 agentes, 6 pipelines y más de 25,000 mensajes.
  • GitHub Actions presenta startup_failure antes de crear jobs en el repositorio; no representa un fallo de una prueba r67 y se mantiene como bloqueo externo de CI hasta que el runner pueda iniciar.

Correcciones de cierre

  • La reactivación de un ciclo se serializa con SELECT ... FOR UPDATE: un segundo scheduler no puede limpiar chunks/checkpoints después de que otro ya reactivó o inició el run. Los runs terminales se redescubren comparando conversations.updated_at contra analyzed_source_updated_at, no contra el timestamp sólo descubierto, preservando recuperación ante fallos del reset.
  • Al reactivar una conversación para un nuevo ciclo se eliminan los conversation_analysis_chunks del ciclo anterior antes de reiniciar checkpoints. Esto evita mezclar chunks obsoletos cuando el nuevo ciclo produce menos particiones, mientras los reportes históricos permanecen versionados para auditoría.
  • El scheduler recupera runs no terminales huérfanos (queued, normalización, multimedia, contexto, IA, reporte y aprendizaje) cuando ya no existe un job activo; los failed mantienen clasificación retryable y next_retry_at gobernados.
  • La selección de tenants del scheduler usa round-robin persistente con cursor y wrap sobre platform_settings, evitando que tenants con IDs altos queden fuera por un LIMIT fijo. No requiere migración de esquema.
  • Los snapshots de análisis quedan congelados mientras un ciclo está activo: Discovery ya no puede cambiar responsable, lead, pipeline, outcome, source_updated_at ni la topología de stages durante Normalize/IA/Report. Fuente nueva llegada en vuelo queda pendiente y dispara el siguiente ciclo sólo cuando el anterior termina, evitando declarar como cubierta evidencia que no pasó por todas las etapas.
  • La contención del mutex por conversación se trata como backpressure: el job actual termina y deja un único intento futuro deduplicado, evitando agotar jobs.max_attempts antes de que conversation_analysis_stages.attempts pueda gobernar el retry.
  • El scheduler central de Conversation Intelligence dejó de depender de una conexión Kommo activa: recorre tenants activos con conversaciones y descubre el modelo canónico omnicanal; el modo kommoOnly se conserva sólo para usos explícitos.
  • Discovery cierra tenant scope en todos los resolvers de lead y calcula representación de responsable/pipeline/etapa/producto con el mismo vínculo directo→Talk. Las métricas se agregan en SQL y la responsabilidad humana prevalece sobre IA, evitando doble conteo y cargas completas en memoria.
  • Lian Admin muestra el estado de evidencia vigente junto a experimentos y activaciones. Si un patrón cae a below_threshold o missing_pattern, desaparecen sólo Iniciar/Reanudar/Activar y se explica que las nuevas exposiciones están detenidas; pausar, completar, medir o revertir siguen disponibles para conservar trazabilidad.
  • La evidencia vigente gobierna toda nueva exposición experimental: candidatos de patrón con below_threshold o missing_pattern no pueden crear, iniciar/reanudar ni activar experimentos. Las mediciones de exposiciones ya realizadas pueden completarse para conservar trazabilidad; candidatos manuales y cambios locked_changed aún elegibles mantienen su flujo.
  • La activación productiva revalida la evidencia vigente del patrón: below_threshold y missing_pattern bloquean la activación incluso si el candidato ya estaba aprobado. El chequeo existe en servicio y se repite dentro de la transacción con el candidato/patrón bloqueados, cerrando la ventana TOCTOU; candidatos manuales y evidencia locked_changed elegible conservan su flujo.
  • La programación de knowledge.commercial quedó single-flight para jobs pendientes: se permite un job en ejecución y un único follow-up pendiente por tenant, evitando acumulación de duplicados sin perder continuidad cuando un lote devuelve has_more.
  • La medición posterior de guías ya no trunca silenciosamente a las primeras 500 versiones solicitadas: normaliza el conjunto completo y consulta commercial_guide_exposures en chunks de hasta 500 guide_id, preservando tenant scope y todos los snapshots de vigencia pedidos.
  • Los jobs knowledge.commercial se serializan por tenant mediante advisory lock antes de materializar o retirar guías, evitando carreras entre lotes concurrentes que podían terminar en colisiones de índices únicos o reintentos completos innecesarios.
  • El refresco automático de evidencia de candidatos pre-test usa control optimista por version; una ejecución concurrente o tardía ya no puede sobrescribir silenciosamente una versión más nueva ni registrar un evento evidence_refreshed sobre un write perdido.
  • El repositorio de asignaciones gobernadas exige contexto conversacional explícito: si no recibe signalKeys, devuelve vacío en vez de consultar todas las asignaciones del tenant. El runtime sigue pasando únicamente las claves presentes, evitando cargas globales accidentales después de eliminar el antiguo LIMIT 100.
  • La creación/activación de experimentos refuerza en repositorio el contrato de guía (20–2000 caracteres y nombre válido), no sólo en el servicio. La materialización filtra activaciones legacy con contenido inválido, evitando batches venenosos que se reencolen sin producir una guía utilizable.
  • El scheduler de minería comercial dejó de inspeccionar sólo los primeros 50–500 tenants activos. Ahora recorre tenants con keyset pagination por id hasta llenar el cupo o agotar la población, evitando starvation de empresas con IDs altos cuando los primeros tenants no tienen el plan de aprendizaje habilitado.
  • El runtime sólo sustituye una activación kept por una guía materializada cuando esa guía aplica al valor de señal actual, conserva evidencia utilizable y tiene contenido válido; una guía no aplicable o debilitada ya no deja al agente sin fallback.
  • Las asignaciones con guía vacía se descartan antes de decidir variante o registrar exposición, evitando contaminar métricas con tratamientos que nunca llegaron al prompt.
  • El Recorrido del Cliente aplica su límite de 5,000 pasos agregados sobre la actividad más reciente del período y luego reordena cronológicamente por lead. Se elimina el sesgo hacia IDs antiguos cuando el tenant supera la ventana operativa; Lian Admin lo explica explícitamente.
  • Journey Intelligence usa el último outcome conversacional válido en rutas y el último outcome válido por lead en fuentes, con fallback a leads.stage. El agregador conserva won/lost y añade abandoned/no_response; terminal y la tasa de cierre usan los cuatro resultados. Lian Admin rotula correctamente la métrica como “Tasa de cierre”.
  • La minería comercial se serializa por tenant mediante advisory lock. Jobs duplicados, reintentos o ejecuciones manuales concurrentes ya no pueden procesar el mismo checkpoint en paralelo ni sobrescribirlo fuera de orden; sólo el job que obtiene el lock puede encadenar has_more.
  • La reconciliación de evidencia contextual evita NOT IN con cardinalidad no acotada: carga los patrones existentes del lead/señal, calcula la diferencia en memoria y elimina obsoletos en chunks de 500.
  • La reconciliación periódica por lead prioriza las 2,000 observaciones más recientes y luego las procesa en orden temporal ascendente; conversaciones largas dejan de reanalizar únicamente evidencia antigua.
  • La purga de privacidad invalida también result_json de experimentos y measurement_json de activaciones cuya exposición incluía la conversación eliminada, preservando estados/eventos gobernados pero evitando métricas materializadas contaminadas.
  • El refresco de outcomes de evidencia comercial ya no depende únicamente de leads.updated_at: incluye leads evaluados por observaciones nuevas y por reevaluaciones periódicas, evitando que patrones existentes conserven un outcome anterior cuando cambia el estado conversacional sin modificar el lead.
  • La purga derivada cubre además customer_journey_events, lead_intelligence_history y sales_copilot_suggestions, eliminando proyecciones, análisis y sugerencias ligadas a la conversación por ID numérico o canónico sin tocar citas, órdenes, pagos, handoffs ni otros hechos operativos de negocio.
  • La purga derivada elimina también commercial_learning_exposures y commercial_guide_exposures de la conversación, evitando conservar referencias directas y evitando que una conversación purgada siga afectando mediciones de experimentos, activaciones o vigencia de guías. Los objetos gobernados (candidatos, experimentos y guías) se preservan como historial.
  • Los proveedores de señales comerciales (interaction, attention_gap, journey, segment) ya no descartan IDs por encima de 200: procesan lotes grandes en chunks de 200 y conservan todas las señales del ciclo de minería.
  • Los proveedores de interacción y lapsos de atención resuelven la conversación de un lead mediante vínculo directo o kommo_conversation_talks, evitando perder mensajes, tiempos de respuesta, follow-ups y alertas cuando Kommo sólo enlaza por Talk.
  • El repositorio de patrones usa un único resolver tenant-scoped de conversación para leads: leads.conversation_id y fallback por kommo_conversation_talks. Freshness, observaciones y contextos periódicos ya no pierden canal/agente/mensajes cuando un lead Kommo sólo está enlazado por Talk.
  • La medición de experimentos/activaciones y la vigencia observada de guías resuelven el lead de una conversación por vínculo directo y, si no existe, por kommo_conversation_talks. Así el fallback previo al reporte canónico conserva won/lost también en conversaciones Kommo enlazadas sólo por Talk, siempre con aislamiento por tenant.
  • El runtime de guías dejó de cargar las primeras 100 asignaciones globales del tenant antes del matching. Ahora solicita sólo asignaciones cuyas signal_key están presentes en la conversación, mantiene la comparación normalizada del valor en PHP y elimina el truncamiento global que podía ocultar una guía relevante en tenants con mucha gobernanza activa.
  • La minería de patrones carga todos los contextos periódicos combinados en chunks de 200, sin truncar a los primeros 200 cuando coinciden refrescos de interacción, segmentos, contexto, brechas de atención y recorridos.
  • La reconciliación de evidencia contextual conserva el conjunto completo de patrones vigentes por señal; se eliminó el corte a 20 IDs que podía borrar evidencia válida de segmentos adicionales.
  • La reconciliación periódica de minería ya no pierde leads cuando combina múltiples fuentes de evaluación: leadContextsByIds() procesa todos los IDs por chunks de 200. La limpieza de evidencia de contexto tampoco recorta a 20 patrones conservados, evitando borrar segmentos/señales válidas por cardinalidad.
  • El baseline de commercial_patterns usa el último reporte conversacional válido, incluye won/lost/abandoned/no_response en el universo terminal y resuelve conversaciones Kommo enlazadas por kommo_conversation_talks, evitando comparar evidencia canónica contra un baseline legacy.
  • La minería incremental dejó de truncar silenciosamente refrescos de outcomes a 200 leads o recálculos a 500 patrones: mantiene lotes acotados por query, pero recorre todos los IDs tocados.
  • El selector representativo usa identidad tipada human:<id> / ai:<id>, por lo que IDs numéricos iguales entre vendedor humano y agente IA ya no colisionan en la diversidad del lote.
  • Agent Learning calcula disponibilidad con la identidad del último análisis con reporte válido y usa la asignación actual sólo como fallback sin evidencia canónica, evitando que reasignaciones posteriores alteren cobertura/readiness históricos.
  • La vigencia observada de guías comerciales usa outcomes canónicos del último reporte válido, con abandoned/no_response explícitos y fallback legacy sólo cuando no existe análisis utilizable. La política de freshness conserva su carácter observacional/no causal y recibe un denominador terminal coherente con experimentos y patrones.
  • La medición de experimentos y activaciones usa el último reporte conversacional válido como outcome canónico, con fallback legacy sólo cuando no existe reporte. abandoned y no_response participan explícitamente en el denominador terminal y se conservan por separado en el snapshot de cohortes; causal_claim=false permanece intacto.
  • El runtime de guías comerciales ahora vuelve a evaluar la evidencia vigente del patrón antes de aplicar experimentos, activaciones o guías materializadas. Si la evidencia cae a below_threshold o desaparece el patrón, la recomendación deja de inyectarse en el prompt sin cambiar automáticamente el estado gobernado del candidato; cambios que siguen siendo elegibles permanecen activos hasta revisión.
  • La purga de privacidad de Inteligencia Conversacional quedó integrada en PrivacyLayerService como frontera administrativa no expuesta en UI. Un mutex distribuido por conversación serializa workers y purga para impedir que OCR/STT/reportes reaparezcan durante la invalidación; se eliminan runs, observaciones, outbox, evidencia de patrones y snapshots derivados, se recalculan patrones afectados, se invalidan perfiles históricos y se preservan artefactos multimedia compartidos con otras conversaciones. La reconstrucción queda desactivada por defecto hasta que el flujo de privacidad vuelva la fuente no elegible.
  • El resumen de cobertura de Inteligencia Conversacional usa ahora la última versión con reporte válido y separa ganadas, perdidas, abandonadas, sin respuesta y abiertas. El drill-down global por agente muestra el mismo desglose y renombra la métrica a “Tasa de cierre observada”, coherente con el denominador terminal completo.
  • Agent Learning ya no colapsa abandonos y casos sin respuesta dentro de open: stats y readiness usan won/lost/abandoned/no_response como terminales, open_count queda reservado a conversaciones abiertas y el desglose extendido se versiona en la evidencia del perfil sin alterar la tabla física. Lian Admin muestra Ganadas, Perdidas, Abandonos, Sin respuesta, Abiertas y Confianza en español.
  • Los agregados globales de pipeline, agente y producto conservan por separado won, lost, abandoned, no_response y open; la tasa observada de cierre usa todos los outcomes terminales y los warnings de sesgo también detectan muestras dominadas por abandono o falta de respuesta.
  • no_response deja de ser una categoría nominal: CommercialOutcomeClassifier deriva si el último ciclo entrante recibió respuesta usando timestamps canónicos. Discovery, reporte y minería de patrones alimentan la misma señal, preservando won/lost como outcomes autoritativos.
  • El aprendizaje semántico conserva la última evidencia con reporte válido aunque exista una versión de análisis posterior todavía sin reporte; el refresco global usa ahora el boundary de reporte listo en lugar de exigir que el run completo ya sea terminal.
  • Se restauró el merge del enriquecimiento IA del reporte, que era invocado pero no estaba implementado. El merge aplica allowlist, límites de longitud/lista, confidence acotada y evidencia validada; la IA no puede sobrescribir outcome.
  • El reporte resuelve leads Kommo tanto por conversación directa como por kommo_conversation_talks, con tenant scope, y el outcome final clasificado se persiste de vuelta en el run para mantener alineados reporte, backlog y agregados globales.
  • Los perfiles de aprendizaje por agente usan la identidad canónica guardada en el análisis para estadísticas y señales. Reasignar una oportunidad ya no transfiere aprendizaje histórico; los reanálisis se distinguen de conversaciones realmente nuevas y la cobertura se mantiene entre 0% y 100%.
  • Backlog, detalle y reporte global ignoran versiones pending/failed al elegir el reporte más reciente; una regeneración incompleta ya no puede eclipsar la última versión utilizable.
  • El Reporte Comercial General diferencia conversaciones analizadas de reportes realmente agregados para señales/intenciones/objeciones, manteniendo el límite operativo de 1,000 por rendimiento. También se localizaron al español el estado y la etiqueta de confianza visibles.
  • El refresco incremental del reporte global cuenta como nuevas únicamente las conversaciones cuyo análisis vigente terminó desde la última generación; runs históricos sustituidos ya no provocan refrescos espurios.
  • El agregado global de reportes toma únicamente la última versión de reporte perteneciente al último análisis de cada conversación; un reanálisis nuevo ya no mezcla inteligencia con un reporte histórico del análisis anterior.
  • Rendimiento por pipeline y warnings de balance ganado/perdido usan los snapshots pipeline_external_id y outcome guardados en el análisis, evitando que cambios posteriores en Kommo alteren retrospectivamente la inteligencia global.
  • El reporte global, la confianza por diversidad y los warnings de sesgo atribuyen conversaciones al agent_type/agent_ref_id guardado en el análisis. Reasignar un lead después ya no cambia retrospectivamente el rendimiento histórico ni la muestra de aprendizaje.
  • El endpoint individual de perfiles de aprendizaje ahora consulta directamente por tenant, tipo e ID de agente y ya no depende de los primeros 300 perfiles ordenados; listado y detalle comparten la misma normalización de profile_json y evidencia resumida.
  • Los facets de pipeline usan ahora la misma resolución que el backlog visible y su filtro: pipeline actual del lead cuando existe, con fallback al pipeline_external_id persistido. Esto evita opciones de filtro que no correspondan a las filas mostradas tras cambios de pipeline.
  • Lian Admin dejó de filtrar en JavaScript una muestra fija: la cola usa GET server-side con búsqueda, filtros, facets completos y paginación de 100 filas. Los agentes se filtran por agent_type/agent_ref_id canónicos y el pipeline visible cae de forma segura al pipeline_external_id persistido.
  • El read model del backlog queda fijado al análisis más reciente de cada conversación; el reporte mostrado/filtrado pertenece al mismo analysis_id, evitando mezclar un reanálisis nuevo con un reporte histórico. La resolución de lead reutiliza conversation_analysis_runs.lead_id antes del fallback de descubrimiento, reduciendo subconsultas correlacionadas.
  • El backlog filtrable dejó de aplicar filtros sobre una muestra ya limitada a 500 filas: prioridad, estado, agente, pipeline, outcome, multimedia y fechas se resuelven ahora en SQL tenant-scoped, con limit/offset, conteo total exacto y next_offset; not_applicable se considera completado al evaluar aprendizaje pendiente.
  • El scheduler dejó de crear kommo.reconcile por una ruta paralela: usa el mismo enqueue single-flight que las acciones manuales y pasa el connection_id esperado. El enqueue reporta reused para distinguir un job ya activo de uno nuevo y evitar contarlo dos veces.
  • KommoSyncProgressService::enqueue() opera single-flight por tenant+conexión: un advisory lock serializa solicitudes concurrentes y reutiliza el run/job pending|running cuyo job siga pending|processing, evitando reconciliaciones duplicadas por doble clic o solicitudes simultáneas.
  • kommo.appointment.sync queda serializado por tenant+conexión+cita y guarda checkpoints separados de Task/Note en appointments.metadata_json bajo kommo_appointment_sync[connection_id]. Cada side effect remoto exitoso persiste su hash/ID antes del siguiente, evitando duplicados en retries, fallos parciales o jobs concurrentes.
  • El estado de crm_sync_runs ya no puede saltar entre conexiones: enqueue/create/begin/update/complete validan la conexión Kommo del run en la propia sentencia SQL, begin() nunca reasigna connection_id, y un run de otra cuenta se rechaza explícitamente. fail() conserva la capacidad de cerrar runs históricos descartados como stale.
  • La creación/actualización outbound de leads y contactos se serializa por tenant+connection_id+entidad local mediante advisory locks. Dos jobs concurrentes ya no pueden observar simultáneamente “sin mapping” y emitir dos POST remotos antes de guardar el vínculo.
  • Los hashes de nota/task generados por IA en Kommo dejan de ser metadata global del lead: ahora viven en kommo_ai_sync[connection_id]. Al reconectar otra cuenta no se hereda el estado de la anterior; los hashes legacy sólo se migran cuando el tenant nunca tuvo otra conexión Kommo, y cada éxito remoto persiste su hash inmediatamente con guard de conexión activa.
  • La cola incorpora un contrato genérico para fallos no reintentables. Kommo usa ese contrato cuando un POST tiene resultado remoto ambiguo (error de transporte/estado 0/5xx/408/425) o recibe un 4xx definitivo: el job pasa a dead en vez de repetir ciegamente un side effect que podría duplicar leads, contactos, notas, tasks o respuestas Salesbot.
  • Salesbot serializa cada request por tenant+conexión+request_key, reutiliza jobs ya pendientes/procesando/completados/dead y evita reenviar IA ante retries del mismo return_url; la creación de conversación también se serializa por entidad.
  • Las escrituras locales de Salesbot (conversación, vínculo a cliente/lead y mensaje inbound) exigen que el mismo connection_id siga activo en la propia sentencia SQL, y el proceso vuelve a validar antes de automatizaciones/Agente IA.
  • Las importaciones inbound de contactos, leads y compañías condicionan cada mutación local a que el mismo connection_id siga activo en la propia sentencia SQL; una desconexión concurrente ya no puede escribir datos de la cuenta anterior después de la revocación.
  • Dashboard e Integration Hub mantienen un snapshot consistente de la misma cuenta Kommo: Health, progreso, logs y diagnóstico API reciben el connection_id esperado y fallan/retornan idle si esa conexión deja de ser la vigente durante la lectura.
  • La configuración sensible del Agente Kommo (incluida la Secret Key descifrada) sólo puede leerse desde una conexión active/error del mismo tenant; el repositorio ya no confía únicamente en que el caller haya validado la conexión.
  • El preview de reconciliación en sesión queda ligado al connection_id que lo generó y se descarta al desconectar/cambiar cuenta; Health Check usa sólo jobs/credenciales de la conexión vigente y marca explícitamente la ausencia de credencial activa.
  • La deduplicación/diagnóstico de jobs deja de usar patrones ambiguos tipo connection_id=1%: compara el valor JSON hasta , o }, evitando colisiones con IDs como 10/100 en Event Bridge, scheduler, histórico, dashboard y Health.
  • El progreso de sincronización mostrado en dashboard y polling se limita al connection_id Kommo activo; al cambiar/desconectar cuenta ya no reaparece el último run de una conexión histórica.
  • Los diagnósticos del dashboard Kommo (logs de webhook y jobs pendientes/procesando) quedan filtrados por la conexión activa, evitando mezclar actividad de cuentas históricas del mismo tenant.
  • Las lecturas de credenciales Kommo ahora exigen tenant_id y conexión vigente; disconnect() revoca conexión+credenciales en una sola transacción y el dashboard consulta pipelines/usuarios con un cliente fijado al connection_id que está mostrando.
  • La activación/revocación de conexión y el almacenamiento cifrado de credenciales Kommo confirman en una sola transacción para OAuth y token privado; KommoTokenManager no puede reactivar credenciales si la conexión fue revocada durante el flujo.
  • Las escrituras de mappings, configuración del Agente Kommo y conflictos sólo se ejecutan si el mismo connection_id continúa activo; un conflicto de una cuenta reemplazada ya no puede modificar clientes/leads locales ni marcarse resuelto como vigente.
  • Las acciones manuales posteriores a conexión (postConnect, preview, instalación de campos, verificación de webhook y refresh de capacidades) quedan fijadas al connection_id resuelto una sola vez; KommoReconciliationService valida que su cliente sticky corresponda a esa misma conexión.
  • Las mutaciones operativas de Kommo (capabilities_json, last_webhook_at e intake de eventos) sólo se aplican si la conexión sigue activa/error para el mismo tenant; la suscripción de webhooks verifica además que su cliente esté fijado a esa misma conexión.
  • La external_key de media_assets para adjuntos Kommo incorpora connection_id, evitando que dos cuentas del mismo tenant reutilicen el mismo asset por coincidencia de mensaje/URL bajo la constraint tenant-global de medios.
  • Los webhooks Kommo sin external_event_id usan una clave sintética determinística para que el índice idempotente funcione también sin ID remoto; además, el handler sólo procesa un evento si logra reclamarlo atómicamente y no revive estados dead.
  • Salesbot separa external_thread_id y messages.external_id por connection_id, evitando colisiones entre cuentas Kommo sucesivas con los mismos IDs de lead/contact o request key; el fallback legacy sólo reutiliza datos de la misma conexión.
  • Se cerró la carrera de cambio de cuenta durante jobs/HTTP Kommo: connection_id se propaga hasta API, tokens e importadores; el cliente queda fijado a una sola conexión, revalida después de la respuesta y un refresh tardío no puede reactivar credenciales de una cuenta reemplazada.
  • Los jobs Kommo stale por desconexión/cambio de cuenta se descartan de forma terminal y auditada en lugar de consumir cinco reintentos; runs de reconciliación y eventos webhook asociados quedan cerrados explícitamente.
  • Los jobs Kommo quedan anclados a connection_id: reconciliación, sync saliente, citas, webhooks e historial no pueden saltar a otra cuenta si el tenant cambia de conexión mientras hay trabajo pendiente; la deduplicación también queda separada por conexión.
  • Se aisló el namespace por cuenta/conexión Kommo: una cuenta distinta ya no reutiliza la fila, mappings, Talks ni IDs de mensajes de una cuenta previa; webhooks revocados se rechazan y markSync sólo modifica la conexión vigente. La compatibilidad con datos r67 legacy se conserva únicamente cuando kommo_connection_id coincide.
  • r67 declara ext-mbstring como requisito de plataforma, el actualizador verifica la extensión y la guía de despliegue la incluye en el preflight para evitar fallos tardíos en las rutas intensivas de texto.
  • El filtro de agente usa claves tipadas (human:<id> / ai:<id>) en Lian Admin y admite agent_type en el API, evitando colisiones entre IDs humanos e IA y distinguiendo nombres repetidos.
  • La resolución de nombres de responsables humanos en backlog, detalle, perfiles y reporte global ahora exige membresía del usuario en el tenant; una asignación obsoleta o inconsistente ya no puede resolver identidad fuera del negocio ni caer al nombre de un agente IA.
  • El endpoint de reporte y el detalle ya no exponen evidence_json sin commercial_intelligence.analysis.evidence.read; las vistas autorizadas de evidencia quedan auditadas.
  • El filtro de outcome del backlog usa el outcome analítico persistido, incluyendo abandoned y no_response, en lugar de reconstruir sólo won/lost/open desde la etapa del lead.
  • Evidencia estructurada por mensaje/timestamp/participante/tipo de fuente/asset.
  • Procesamiento canónico de eventos inbound y outbound.
  • Caché IA invalidada cuando cambia la versión del prompt.
  • Polling robusto del aprendizaje global compartido.
  • Retries para deadlock, lock-wait timeout y pérdida temporal de conexión MariaDB.
  • Persistencia Kommo serializada por Talk y timestamps fallback determinísticos.
  • Cobertura de muestra por agentes, pipelines, productos y outcomes.
  • Servicio tenant-scoped para purga/invalidez de datos derivados y reconstrucción gobernada.
  • Reporte global ampliado con tiempos de respuesta (media/mediana/p90), desempeño observado por agente/pipeline/producto, oportunidades de automatización y recomendaciones para agentes digitales.

Cierre de consistencia semántica del reanálisis

  • Los read models semánticos de reporte global, cobertura, sesgo y aprendizaje por agente seleccionan la última ejecución con report_status=completed y un reporte válido del mismo analysis_id. Un reanálisis todavía activo no sustituye prematuramente la última evidencia utilizable.
  • Cuando el reporte de la nueva ejecución termina, esa ejecución pasa a ser la frontera semántica vigente sin depender de que las etapas de aprendizaje posteriores hayan concluido.
  • La misma regla se aplica a Agent Learning, evitando que perfiles y agregados mezclen el ciclo nuevo con un reporte perteneciente a un análisis anterior.
  • Las regresiones r67 de escala y seguridad/arquitectura fijan explícitamente esta frontera y evitan volver a seleccionar ejecuciones sin reporte actual listo.
  • No se requiere migración adicional: se reutiliza conversation_analysis_runs.report_status y el vínculo versionado de conversation_analysis_reports.analysis_id.
  • El manifest r67 se vuelve a sellar después de estas correcciones; la promoción productiva continúa condicionada a un Quality Gate ejecutable porque GitHub Actions sigue fallando antes de crear jobs.

Corrección de sellado previa al paquete r66 → r67

  • La validación integral del delta r66→r67 previa a generar el ZIP detectó seis hashes históricos desfasados en release-manifest.json aunque los archivos fuente ya correspondían al head r67.
  • Se resincronizaron los hashes de Customer Journey, Segment Intelligence, PdoCommercialPatternRepository y tres regresiones históricas afectadas; no hubo cambio funcional ni de esquema en esos archivos.
  • El paquete incremental sólo se genera después de volver a validar los 129 archivos versionados del delta contra el manifest corregido.

Hotfix de acceso al updater r67

  • Se corrige upgrade/.htaccess: la whitelist histórica sólo permitía r38–r41 y provocaba 403 Forbidden para upgrade_v2_10_5_r67.php antes de ejecutar PHP.
  • r67 queda autorizado explícitamente, manteniendo denegados los demás scripts PHP no auditados de upgrade/.
  • El updater conserva la autorización de aplicación mediante AccessGuard::superAdmin(); no se introduce Require all granted ni una apertura general de la carpeta.
  • La regresión de seguridad/arquitectura verifica la whitelist r67 y el guard de Super Admin para evitar futuras releases inaccesibles por configuración web.

Hotfix de runtime y frontera CSP

  • El chequeo runtime_classes del updater deja de tratar una interfaz como clase concreta: acepta class_exists() o interface_exists(), corrigiendo el falso REVISAR de ConversationAnalysisRepositoryInterface.
  • Se eliminan los atributos style= r67 en las vistas de Inteligencia Conversacional y Conversaciones; las barras de progreso usan <progress> y clases CSS compatibles con CSP.
  • También se eliminan estilos inline construidos dentro del JavaScript del drawer de conversaciones, cerrando una violación CSP latente que el escáner de vistas no detectaba por ignorar cuerpos <script>.
  • La regresión r67 fija ambos contratos: validación de interfaces y ausencia de estilos inline en las dos superficies afectadas.
Versión anterior← v2.10.5-r66
Versión siguientev2.10.5-r68 →