CreaRack-SL

Lanzador Estable F3 — Auto-update desatendido transparente (onedir + setup stub)

Descripción

Plan F3 del Lanzador Estable es eliminar la carrera del antivirus contra la re-extracción de .pyd nativos en cada arranque del Agente.

Cambios:

  1. Bootstrap de --onefile → --onedir (los .pyd viven en _internal, sin re-extracción en cada arranque).
  2. Setup stub (CreaRackAgent-Setup.exe, scripts/agent/setup_stub.py): un onefile stdlib-only que despliega el onedir en %APPDATA% una sola vez.
  3. Rollback silencioso mejorado: si un paquete falla, reintenta y luego cae al embebido.

Problema que resuelve

Raíz del bug pydantic_core / _overlapped

El bootstrap en onefile se re-extrae a un directorio temporal _MEIxxxx en cada arranque. Durante esa extracción:

  • Windows Defender (y otros AV) escanean la extracción en tiempo real.
  • Un .pyd nativo puede ser bloqueado en ese preciso momento.
  • El arranque falla con pydantic_core / _overlapped / _sqlite3.

Síntomas

  • No-determinista (depende del timing del AV).
  • Afecta a arranques normales (no solo tras update).
  • Reintento manual → funciona (AV “soltó” la lib tras el primer intento).

Solución F3

Con --onedir:

  • Los .pyd viven en disco (_internal/...) de forma permanente.
  • Se escanean una sola vez en la instalación.
  • El antivirus no tiene nada que morder en posteriores arranques.
  • El AV no puede interrumpir una lib que no se está extrayendo.

Arquitectura F3

1. Bootstrap en --onedir

  • Compilado con --onedir en lugar de --onefile.
  • Código en _internal/ → fijo en disco.
  • Mucho más pequeño que el onefile (~15-20 MB vs ~35 MB).

2. Setup stub (CreaRackAgent-Setup.exe)

  • Otro onefile, pero stdlib-only (solo librerías de Python standard).
  • Se ejecuta una sola vez (instalación).
  • Funciones:
    • Extrae el onedir embebido.
    • Despliega en %APPDATA%\CreaRackAgent.
    • Configura startup, protocolo crearack://, toasts.
    • Lanza el Agente.
  • Script: scripts/agent/setup_stub.py.
  • Único onefile que queda en la máquina de usuario.

3. Vista de descarga (core/views.download_agent)

  • Sirve el instalador (CreaRackAgent-Setup.exe), no el bootstrap.
  • El usuario descarga e instala una sola vez (momento supervisado).

4. Agente simplificado

  • core/installer.py se simplifica: ya no copia el .exe (roto en onedir).
  • El bootstrap ya no se auto-instala (el stub lo hace).
  • Resultado: Agente onedir siempre corre desde el directorio de instalación (%APPDATA%\CreaRackAgent).

Validación E2E

Status: Pendiente en VM limpia con Defender real (task #187).

Prueba en vivo (07-07, Agent 2.15.0 beta)

  • Dani (onedir): Se actualizó solo, sin ventanas, de 2.15.0 → 2.15.1.
  • Edu (onefile viejo, control): Falló con _sqlite3 (AV mordiendo la re-extracción) → reinstalación del onedir → OK.
  • Conclusión: La contraposición onefile-falla / onedir-funciona es la prueba definitiva del fix.

Notas de implementación

  1. Hallazgo 1 (documentado para futuro): El onefile re-extrae .pyd en cada relanzamiento → AV puede morder uno.

    • Solución: --onedir (aplicada en F3).
  2. Hallazgo 2 (arreglado en 2.14.1): Al transicionar de embebido a primer paquete, previous.txt vacío → watchdog se perdía.

    • Solución: _watchdog_script borrador de current.txt, caída al embebido (aplicada en feature—agent-lanzador—rollback-silencioso-infalible).

Migración de flota legacy

Antes de tocar el sidecar de versión (que ordena updates):

  1. Reinstalar con el nuevo instalador (onedir).
  2. El bootstrap onedir es un binario nuevo (diferente hash que onefile).
  3. Una máquina sin bootstrap recibiría url=Setup.exe → intentaría swap del instalador (inválido).

Plan de flujos

  1. Instalación fresca: User descarga CreaRackAgent-Setup.exe → setup despliega onedir en %APPDATA% → Agente corre.
  2. Auto-update: Agente descarga paquete → verifica → swap de current.txt → relanza.
  3. Rollback: Paquete falla → reintenta → cae al embebido (o previous.txt si existe).

Tests nuevos

  • tests/agent/test_setup_stub.py (+6 casos): extrae exe, preserva datos, reemplaza _internal, lee versión.
  • tests/agent/test_agent_launcher.py (+3 casos): lógica de rollback del watchdog.

Véase también

  • [[feature—agent-lanzador—rollback-silencioso-infalible]]
  • [[feature—agent-lanzador—paquete-firmado-ed25519]]
  • [[feature—agent-lanzador—bootstrap-zip]]
  • [[incident—20260707—bootstrap-2-14-0-roto]]
  • [[concept—agent-lanzador—cadena-fallback]]