# Diseño: arranque automático e inteligente para no-técnicos (doctor.ps1) Fecha: 2026-08-22 Estado: aprobado en conversación ## Problema Los `.bat` actuales son wrappers finos de dos `.ps1` robustos, pero asumen un entorno ya preparado. Para una persona no técnica: - Si falta Python (o `python` es el stub falso de la Microsoft Store), el error parpadea y la ventana desaparece sin que se entienda nada. - Si faltan dependencias (`pip install -e ".[web]"` nunca se corrió), uvicorn muere con un traceback ilegible. - Los errores terminan con la ventana cerrándose: imposible leer qué pasó. ## Objetivo Doble clic en `start-server.bat` = la aplicación abre en el navegador, siempre. El script detecta y repara el entorno por sí mismo. Un solo icono para el usuario; `stop-server.bat` queda como acompañante. ## Enfoque elegido (B) Separación de responsabilidades: **entorno** vs **ciclo de vida**. ``` start-server.bat ──> scripts/doctor.ps1 (NUEVO) ├─ ¿server ya vivo? ── sí --> abrir navegador, fin ├─ resolver Python (py -3 > python > python3) │ └─ ninguno válido --> winget install │ └─ sin winget --> abrir python.org + ERROR ├─ import-test de deps │ └─ falla --> pip install -e ".[web]" ├─ ffmpeg presente? -- no --> aviso suave NO bloqueante └─ ok --> scripts/start-server.ps1 -PythonExe $py └─ puertos, healthz, browser (SIN CAMBIOS de lógica) ``` `start-server.ps1` conserva toda su lógica verificada (sondas TCP rápidas, limpieza de entradas obsoletas, barrido 8000-8100, apertura de navegador). Único cambio permitido: parámetro opcional `-PythonExe` (default `python`) usado en la línea de comando de uvicorn. ### Por qué `-PythonExe` es necesario Tras una instalación fresca vía winget, el PATH de la sesión actual **no** incluye el Python nuevo. El doctor resuelve la ruta concreta (`%LocalAppData%\Programs\Python\Python312\python.exe`) y se la pasa al launcher; sin esto, el primer arranque post-instalación fallaría. ## Flujo detallado del doctor 1. **Server vivo primero** (antes de cualquier chequeo de entorno): sondea el puerto registrado en `.run/server.info`; si responde, abre el navegador y termina con exit 0. Evita instalar dependencias solo para decir "ya está corriendo". 2. **Resolver Python**, candidatos en orden: `py -3`, `python`, `python3`. Cada candidato es válido solo si: - ejecuta `--version` y la salida matchea `Python 3.` con versión ≥ 3.10; - su ruta **no** contiene `WindowsApps` (stub de la Store que no ejecuta nada). 3. **Instalar Python si falta**: `winget install --id Python.Python.3.12 --silent --accept-package-agreements --accept-source-agreements`. Después de instalar, sondear rutas conocidas (`%LocalAppData%\Programs\Python\*`, `C:\Program Files\Python312\`) antes de rendirse. Sin winget disponible: abrir `https://www.python.org/downloads/` en el navegador + instrucción en lenguaje simple + exit ≠ 0. 4. **Import-test de dependencias**: `& $py -c "import fastapi, uvicorn, jinja2, sse_starlette, yt_dlp"`. **Nunca** importa `yt_scraper.webapp.app` aquí: ese import abre la DB real del proyecto vía `config.yaml`, corre migraciones y `reconcile_markdown` (gotcha documentado en CLAUDE.md). Si falla el test: `-m pip install -e ".[web]"` mostrando progreso ("instalando por primera vez, puede tardar un par de minutos"). Si falta pip: `-m ensurepip`. 5. **ffmpeg**: `Get-Command ffmpeg`; ausente → aviso amarillo no bloqueante ("la descarga de audio no estará disponible; todo lo demás funciona"). 6. Delegar: `& start-server.ps1 -PythonExe $py` + passthrough de args. 7. Propagar exit code. ## Reglas de ventana (.bat) | Resultado | Ventana | |---|---| | Exit 0 | mensaje verde + cuenta regresiva ~5 s → cierra sola | | Exit ≠ 0 | **queda abierta** (`pause`) con causa legible + últimas líneas de log | Hoy los errores parpadean y desaparecen: es la regla más importante del cambio. Aplica a ambos `.bat`. ## Mensajes Español plano, sin jerga dirigida al usuario final ("servidor", "conexión"; no "puerto", "PID", "uvicorn", "PATH"): - `[ok] Servidor listo en http://localhost:8000 — abriendo tu navegador...` - `[ok] El servidor ya estaba corriendo — abriendo...` - `[info] Instalando Python automáticamente (~25 MB)…` - `[info] Instalando las piezas que faltan por primera vez (1-2 min)…` - Error: `Algo falló al iniciar el servidor. Esto fue lo último que hizo:` El pulido de copys aplica también a los mensajes visibles de `start-server.ps1` y `stop-server.ps1` (solo texto; cero cambios de lógica). ## Errores cubiertos | Caso | Detección | Acción | |---|---|---| | Stub falso Microsoft Store | `--version` falla o ruta `*WindowsApps*` | Siguiente candidato | | Sin Python válido | 3 candidatos fallan | winget silencioso; sin winget → python.org + ERROR | | PATH fresco post-instalación | winget OK | Sondeo de rutas conocidas | | pip ausente | `-m pip --version` falla | `ensurepip` | | Deps rotas/faltantes | import-test falla | `pip install -e ".[web]"` | | ffmpeg ausente | `Get-Command` vacío | Aviso amarillo no bloqueante | | Error de arranque | exit ≠ 0 del launcher | Ventana queda abierta con log | ## Fuera de alcance - No se toca lógica de puertos, healthz, browser ni cancelación del launcher. - No hay `setup.bat` separado (el doctor es el setup). - No se instalan `[dev]` ni `[analysis]`: solo core + `[web]`, lo necesario para correr la aplicación. - Sin tests automatizados nuevos de PowerShell (el repo no tiene infra para eso); verificación manual guiada por `-CheckOnly`. ## Verificación - `doctor.ps1 -CheckOnly`: reporta qué haría sin cambiar nada (cada rama de decisión observable sin efectos). - Escenarios manuales: server ya vivo → solo navegador; server apagado → arranque completo; stop limpio tras arranque; ventana persistente ante error simulado (p. ej. PATH sin Python en un subproceso controlado).