Volver a la wiki

Fix: Vigilante del auto-update funciona por fin (Agent 2.13.3, causa raíz cazada)

Descripción

Versión: Agent 2.13.3 (APP v1.45.9) — commit be210c6 (05-07-2026 11:24 UTC)
Componente: Watchdog (vigilante) post-swap del auto-update (terminal/agent/core/updater.py)
Cambio: Corrección de flags de creación de proceso Windows que hacía morir silenciosamente al vigilante.

El watchdog que debería relanzar automáticamente el Agente si una actualización falla o revertir a la versión anterior nunca llegaba a ejecutarse. Causa raíz: conflicto entre flags DETACHED_PROCESS y CREATE_NO_WINDOW en subprocess.Popen, que privaba a PowerShell de una consola válida → muere antes de la primera línea del script.


Lo que cambia

Antes (Agent ≤2.13.2)

# updater.py:_launch_swap_watchdog()
proc = subprocess.Popen(
    [ps_exe, "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-File", str(ps1)],
    creationflags=subprocess.DETACHED_PROCESS
    | subprocess.CREATE_NEW_PROCESS_GROUP
    | getattr(subprocess, "CREATE_NO_WINDOW", 0),
)

Síntoma:

Después (Agent 2.13.3+)

# updater.py:_launch_swap_watchdog()
proc = subprocess.Popen(
    [ps_exe, "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-File", str(ps1)],
    creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | getattr(subprocess, "CREATE_NO_WINDOW", 0),
    stdin=subprocess.DEVNULL,
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    close_fds=True,
)

Cambios:

  1. ❌ Quitar: subprocess.DETACHED_PROCESS (anula CREATE_NO_WINDOW — modos excluyentes).
  2. ✅ Mantener: CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW (consola propia, oculta).
  3. ✅ Añadir: stdin/stdout/stderr=DEVNULL (PowerShell obtiene handles válidos).

Comportamiento:


Verificación

Diagnóstico reproducido en laboratorio

El commit incluye una sección en terminal/agent/version.py documentando la reproducción del problema fuera del Agente:

Test de regresión

Archivo: tests/agent/test_agent_updater_trace.py::test_watchdog_launch_sin_detached_process


Impacto en la flota

VersiónWatchdogAuto-update fallido → Resultado
≤2.13.2❌ Mudo (muere silenciosamente)AV bloquea → Agente muerto hasta relanzar a mano
2.13.3+✅ Vivo y funcionalAV bloquea → Watchdog relanza o revierte automáticamente

⚠️ Transición hacia 2.13.3


Detalles técnicos

¿Por qué DETACHED_PROCESS mata el watchdog?

En Windows, subprocess.Popen(creationflags=...) acepta un conjunto de flags de CreateProcessW:

Son mutuamente excluyentes en la práctica: si usas ambos, Windows prioriza DETACHED_PROCESS e ignora CREATE_NO_WINDOW. El resultado es un proceso sin consola válida.

Cuando Python no proporciona handles explícitos (stdin/stdout/stderr):

¿Por qué funciona con CREATE_NO_WINDOW + DEVNULL?


Código afectado

ArchivoLíneasCambio
terminal/agent/core/updater.py249–269Flags de subprocess.Popen en _launch_swap_watchdog()
terminal/agent/version.py11–23Documentación de causa raíz en comentarios
tests/agent/test_agent_updater_trace.py53–69Test de regresión (src inspection)
config/settings/base.py10APP_VERSION 1.45.8 → 1.45.9
CHANGELOG.md9–15Entrada de release
RELEASE_NOTES.md12–22Nota técnica para usuarios

Cimiento arquitectónico

Esta es una corrección de bug crítico del cimiento agent-robustez F2 (introducido en 2.11.4):

El watchdog post-swap monitorea que la versión nueva responde (/health); si el AV la mató al arrancar, la relanza; si tampoco arranca, restaura la versión anterior — el auto-update ya no puede dejar un Agente muerto.

Hasta hoy, el watchdog no corría de verdad por el conflicto de flags. Ahora sí.


Véase también

Subir