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
LearningReadinessEvaluatorpara 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_failureantes 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 comparandoconversations.updated_atcontraanalyzed_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_chunksdel 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; losfailedmantienen clasificación retryable ynext_retry_atgobernados. - 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 unLIMITfijo. 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_atni 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_attemptsantes de queconversation_analysis_stages.attemptspueda 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
kommoOnlyse 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_thresholdomissing_pattern, desaparecen sóloIniciar/Reanudar/Activary 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_thresholdomissing_patternno pueden crear, iniciar/reanudar ni activar experimentos. Las mediciones de exposiciones ya realizadas pueden completarse para conservar trazabilidad; candidatos manuales y cambioslocked_changedaún elegibles mantienen su flujo. - La activación productiva revalida la evidencia vigente del patrón:
below_thresholdymissing_patternbloquean 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 evidencialocked_changedelegible conservan su flujo. - La programación de
knowledge.commercialquedó 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 devuelvehas_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_exposuresen chunks de hasta 500guide_id, preservando tenant scope y todos los snapshots de vigencia pedidos. - Los jobs
knowledge.commercialse 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 eventoevidence_refreshedsobre 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 antiguoLIMIT 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
idhasta 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
keptpor 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 conservawon/losty añadeabandoned/no_response;terminaly 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 INcon 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_jsonde experimentos ymeasurement_jsonde 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_historyysales_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_exposuresycommercial_guide_exposuresde 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_idy fallback porkommo_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 conservawon/losttambié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_keyestá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_patternsusa el último reporte conversacional válido, incluyewon/lost/abandoned/no_responseen el universo terminal y resuelve conversaciones Kommo enlazadas porkommo_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_responseexplí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.
abandonedyno_responseparticipan explícitamente en el denominador terminal y se conservan por separado en el snapshot de cohortes;causal_claim=falsepermanece 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_thresholdo 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
PrivacyLayerServicecomo 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 usanwon/lost/abandoned/no_responsecomo terminales,open_countqueda 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_responseyopen; 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_responsedeja de ser una categoría nominal:CommercialOutcomeClassifierderiva si el último ciclo entrante recibió respuesta usando timestamps canónicos. Discovery, reporte y minería de patrones alimentan la misma señal, preservandowon/lostcomo 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/failedal 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_idyoutcomeguardados 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_idguardado 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_jsony 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_idpersistido. 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_idcanónicos y el pipeline visible cae de forma segura alpipeline_external_idpersistido. - 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 reutilizaconversation_analysis_runs.lead_idantes 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 ynext_offset;not_applicablese considera completado al evaluar aprendizaje pendiente. - El scheduler dejó de crear
kommo.reconcilepor una ruta paralela: usa el mismo enqueue single-flight que las acciones manuales y pasa elconnection_idesperado. El enqueue reportareusedpara 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/jobpending|runningcuyo job sigapending|processing, evitando reconciliaciones duplicadas por doble clic o solicitudes simultáneas.kommo.appointment.syncqueda serializado por tenant+conexión+cita y guarda checkpoints separados de Task/Note enappointments.metadata_jsonbajokommo_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_runsya no puede saltar entre conexiones: enqueue/create/begin/update/complete validan la conexión Kommo del run en la propia sentencia SQL,begin()nunca reasignaconnection_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
POSTtiene resultado remoto ambiguo (error de transporte/estado 0/5xx/408/425) o recibe un 4xx definitivo: el job pasa adeaden 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 mismoreturn_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_idsiga 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_idsiga 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_idesperado 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/errordel 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_idque 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_idKommo 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_idy conexión vigente;disconnect()revoca conexión+credenciales en una sola transacción y el dashboard consulta pipelines/usuarios con un cliente fijado alconnection_idque 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;
KommoTokenManagerno 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_idcontinú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 alconnection_idresuelto una sola vez;KommoReconciliationServicevalida que su cliente sticky corresponda a esa misma conexión. - Las mutaciones operativas de Kommo (
capabilities_json,last_webhook_ate 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_keydemedia_assetspara adjuntos Kommo incorporaconnection_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_idusan 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 estadosdead. - Salesbot separa
external_thread_idymessages.external_idporconnection_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_idse 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
markSyncsólo modifica la conexión vigente. La compatibilidad con datos r67 legacy se conserva únicamente cuandokommo_connection_idcoincide. - r67 declara
ext-mbstringcomo 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 admiteagent_typeen 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_jsonsincommercial_intelligence.analysis.evidence.read; las vistas autorizadas de evidencia quedan auditadas. - El filtro de outcome del backlog usa el outcome analítico persistido, incluyendo
abandonedyno_response, en lugar de reconstruir sólowon/lost/opendesde 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=completedy un reporte válido del mismoanalysis_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_statusy el vínculo versionado deconversation_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.jsonaunque los archivos fuente ya correspondían al head r67. - Se resincronizaron los hashes de Customer Journey, Segment Intelligence,
PdoCommercialPatternRepositoryy 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 paraupgrade_v2_10_5_r67.phpantes 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 introduceRequire all grantedni 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_classesdel updater deja de tratar una interfaz como clase concreta: aceptaclass_exists()ointerface_exists(), corrigiendo el falsoREVISARdeConversationAnalysisRepositoryInterface. - 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.