El auto-update del Agente aprende a esperar al antivirus: se acabaron las actualizaciones rotas (v1.45.11 · Agent 2.13.5)
Resumen ejecutivo
Problema: El auto-update del Agente corría más rápido que el antivirus. Cuando el Agente descargaba y ejecutaba una versión nueva en segundos, Windows Defender aún estaba analizándola “en la nube” — la extracción del onefile quedaba retenida/congelada, causando arranques “vivos pero no respondiendo” que el watchdog confundía con fallos y hacía rollback de versiones buenas (s201: diagnosticado 05-07-2026 con el primer rescate autónomo real).
Solución: Tres piezas en Agent 2.13.5 (terminal/agent/core/updater.py):
-
Prescan explícito de Defender del binario descargado (antes del swap)
MpCmdRun -Scan -ScanType 3 -File, síncrono, best-effort- Replica el “tiempo muerto” entre descarga y ejecución que hace fiable a la instalación manual
- Sin Defender (otro AV, MpCmdRun ausente), se salta
-
Watchdog paciente —
WaitHealthycon sondeo cada 10 s- Ventanas: 150 s (primer arranque) / 120 s (retry) / 120 s (post-rollback)
- Antes: checks únicos a 30+20 s → mataba arranques vivos retenidos por el análisis
- Ahora: el vigilante respeta el tiempo del análisis cloud
-
version.txtauto-reconciliado al arrancar- Tras un rollback, el binario restaurado viejo no toca
version.txt - En el siguiente arranque,
cleanup_old_exe()comprueba queversion.txtcoincida conAGENT_VERSION - Evidencia del bug: 05-07-2026,
version.txt=2.13.4con 2.13.3 corriendo
- Tras un rollback, el binario restaurado viejo no toca
Cambios técnicos
terminal/agent/core/updater.py
_defender_prescan(path) (nueva función):
- Busca
MpCmdRun.exeen%ProgramFiles%\Windows Defender - Lanza escaneo síncrono con timeout 180 s
- Return codes: 0 (limpio) / 2 (amenaza detectada, self-test posterior fallará y el swap se aborta)
- Si MpCmdRun no existe, se salta con traza
"prescan Defender omitido" - Best-effort: nunca bloquea el ciclo de actualización (exceptions capturadas)
_apply_swap() (modificado):
- Llama a
_defender_prescan(NEW_EXE)antes de_selftest_new_exe() - Orden: prescan → self-test → swap
Watchdog PowerShell (modificado — _launch_swap_watchdog):
function WaitHealthy($secs) {
# Poll cada 10s durante $secs segundos (antes: checks únicos)
$until = (Get-Date).AddSeconds($secs)
while ((Get-Date) -lt $until) {
if (Healthy) { return $true }
Start-Sleep -Seconds 10
}
return (Healthy)
}
- Primer arranque:
WaitHealthy 150 - Retry post-stop:
WaitHealthy 120 - Post-rollback:
WaitHealthy 120con logs diferenciados (HEALTHY vs “needs manual relaunch”)
cleanup_old_exe() (modificado):
- Tras eliminar
CreaRackAgent.old.exe, compruebaversion.txt - Si no coincide con
AGENT_VERSION, lo actualiza y loga"version.txt reconciliado (drift post-rollback)"
terminal/agent/version.py
AGENT_VERSION = "2.13.5"
- Changelog documenta las 3 piezas
- Nota: “Exige recompilar el .exe”
config/settings/base.py
APP_VERSION = "1.45.11"
tests/agent/test_agent_updater_trace.py (3 tests nuevos)
-
test_watchdog_script_sondea_paciente_no_check_unico- Verifica que el script contenga
WaitHealthyy “polling health up to 150s” - Regresión contra el comportamiento impaciente de 2.13.4
- Verifica que el script contenga
-
test_defender_prescan_sin_mpcmdrun_no_revienta- Sin
MpCmdRun, el prescan se salta sin error - Simula CI/Linux o AV alternativo
- Sin
-
test_cleanup_reconcilia_version_txt_tras_rollback- Verifica que
version.txtsea actualizado porcleanup_old_exe() - Copia traza esperada en el log
- Verifica que
Impacto de usuario
- ✅ Reducción dramática de fallos de auto-update — el Agente ya no entra en carreras contra Defender
- ✅ Sin certificados de pago — el prescan es best-effort, no introduce dependencias nuevas
- ✅ Sin intervención manual — el watchdog paciente se recupera solo
- ✅ Actualización transparente — distribución vía Hetzner, primera ejecución con instalación fresca (regla de oro del bootstrap)
Detalles de propagación
- Status: v1.45.11 en HOLD en Hetzner (ejecutable no publicado aún)
- Estreno: instalación fresca + validación E2E manos-fuera en el siguiente release
- Cambios de ayuda: ninguno (el watchdog es interno)
- Regresión: NO — las defensas anteriores (self-test + rollback del swap) se mantienen intactas
Diario de diagnóstico s201
- Fecha: 05-07-2026
- Observación inicial: La instalación manual del Agente nunca falla; el auto-update sí
- Causa raíz: Entre descarga (navegador) y ejecución (doble clic) pasan MINUTOS → el análisis cloud de Defender termina; el auto-update ejecuta en SEGUNDOS → el análisis está a medias cuando se extrae el onefile
- Síntoma: “process alive but not responding” en la traza — no era un crash, era retencion por análisis
- Primer rescate autónomo: El watchdog de 2.13.4 intentó relanzar el Agente (era el propósito de s201), pero el sondeo impaciente (30+20 s únicos) mató arranques que estaban VIVOS esperando al análisis, haciendo rollback de binarios buenos
- Cierre: 2.13.5 con prescan proactivo + sondeo paciente
Véase también
- [[feature—terminal—traza-persistente-swap-auto-update]]
- [[concept—general—como-funciona-el-mecanismo-de-auto-update-del-local-agent]]
- [[entity—terminal—service—updater]]
- [[decision—20260705—prescan-defender-antes-del-swap]]