Files
yt-channel-scraper/docs/superpowers/specs/2026-08-22-bat-doctor-design.md
T

132 lines
6.1 KiB
Markdown

# 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).