# Roadmap de SiPi hacia adopción real

Prioridades ordenadas por impacto/urgencia. Cada ítem tiene un objetivo concreto
y verificable — no "mejorar X" sino qué comando/archivo/resultado tiene que existir
al terminarlo.

## Prioridad Alta

### 1. Ecosistema de paquetes
- [x] `sipi.json` por paquete: `nombre`, `version`, `descripcion`, `punto_entrada`, `dependencias`.
- [x] Registro central mínimo viable: repo de GitHub con `index.json` (nombre → versiones → URL + sha256 del zip). Plantilla lista para subir tal cual en `herramientas/plantilla_registro/`.
- [x] `sipi paquete publicar` — empaqueta (.zip) y publica: si se le pasa `--registro <clon_local>` (con permisos de `git push`) hace commit+push solo; si no, imprime el fragmento exacto de `index.json` a pegar y dónde subir el `.zip` (un Release de GitHub sirve gratis).
- [x] `sipi paquete instalar <paquete>[@rango]` — resuelve dependencias declaradas en el `sipi.json` del paquete a un nivel, descarga, **verifica sha256** (aborta si no coincide — protección real contra paquetes alterados/corruptos), y cachea en `sipi_paquetes.lock.json`.
- [x] Versionado semver básico (`^1.2.0`, `~1.2.0`, `>=1.2.0`, exacto, `*`) al resolver — implementado sin dependencias externas en `sipi_registro.py`.

### 2. Rendimiento para producción
- [x] `compilar_a_python` ya existe — falta que la documentación y el flujo de `sipi publish`/deploy lo recomienden como paso obligatorio antes de producción, no opcional.
- [ ] `sipi perfil archivo.sipi` — perfilador que muestre tiempo por función/línea (usar `cProfile` sobre el AST ya interpretado es el camino más corto).
- [ ] Cachear el `.pyc` del código ya compilado a Python para arranques repetidos más rápidos.

## Prioridad Media

### 3. Herramientas de desarrollo
- [x] `sipi test` (y su alias `sipi probar`) ahora descubre automáticamente todo archivo `*_test.sipi` en el proyecto, lo corre con el motor real, cuenta OK/FALLO leyendo las mismas líneas que `afirmar` ya imprime en modo pruebas, y con `--junit reporte.xml` escribe un reporte JUnit XML estándar listo para GitHub Actions/Jenkins/GitLab CI. Si no hay `*_test.sipi` en el proyecto, sigue corriendo la suite interna del motor (`tests/test_suite.py`) como antes, sin romper compatibilidad.
- [x] `sipi depurar archivo.sipi` — depurador CLI **real** (`sipi_depurador.py`), no el viejo `--depurar` que solo imprimía cada línea. Breakpoints (`b 12`), step (`paso`), continuar (`continuar`), inspección de variables locales y globales en el punto exacto de la pausa (`variables`, `ver nombre`), y cortar la ejecución (`salir`). Reutiliza el `hook_linea`/`DepuracionDetenida` que ya existían para el depurador visual del editor, en vez de duplicar esa infraestructura.
- [x] `registrar_log`/`log_info` ahora soportan salida configurable vía `sipi.toml` (`[logging] destino = "archivo_rotativo" | "syslog" | "remoto"`), usando `logging.handlers` real de Python (RotatingFileHandler, SysLogHandler, HTTPHandler) — antes solo escribía a un `sipi.log` fijo.

### 4. Interoperabilidad
- [ ] `importar_python "requests"` — expone el intérprete de Python ya embebido para llamar librerías reales desde SiPi. Riesgo de seguridad: documentar que esto rompe el sandbox y debe ser opt-in explícito.
- [ ] Bindings de `compilar_a_python`/`compilar_a_js` documentados como forma oficial de exponer funciones SiPi a otros stacks.

### 5. Documentación y comunidad
- [ ] Sitio con la documentación ya existente (`docs/`) publicado (GitHub Pages sirve para arrancar, cero costo).
- [ ] Canal de Discord.
- [ ] 3–5 videos cortos: "API en 5 minutos con SiPi", "Panel en vivo con `canal_tiempo_real`", etc.

### 6. ORM y migraciones
- [x] `clase Usuario hereda_de Modelo` + `nombre = ""` (los campos son las mismas declaraciones de valor por defecto que `clase` ya soportaba) → `modelo_vincular "Usuario" a bd`, `modelo_crear_tabla`, `modelo_guardar` (INSERT/UPDATE automático), `modelo_buscar`/`modelo_buscar_uno` (con condición SQL parametrizada), `modelo_eliminar`. El tipo de columna SQL se infiere del valor por defecto de cada campo — no hace falta declarar tipos aparte.
- [ ] Migraciones automáticas que generen el diff a partir de cambios en las clases (`migracion_crear`/`migracion_aplicar` ya existen pero son manuales, no comparan el modelo declarado contra el schema real).

### 7. Seguridad
- [x] Auth por API key + rate limiting ya existen en `iniciar_api_web` (`requerir_autenticacion`, `limitar_peticiones`).
- [x] Soporte JWT (HS256, sin dependencias externas — interoperable con PyJWT/jsonwebtoken, verificado). `requerir_autenticacion "secreto" con_jwt` reemplaza la clave estática por tokens con expiración; `jwt_crear`/`jwt_verificar` como builtins; la función que atiende la ruta recibe los datos del token en `peticion["usuario"]`.
- [x] Analizador de patrones inseguros integrado a `--revisar`: ya detectaba inyección SQL (interpolación directa en consultas) y credenciales hardcodeadas; se agregó detección de **XSS** (HTML armado con datos de `peticion`/`query`/`cuerpo` sin pasar por el nuevo builtin `escapar_html`).

## Prioridad Baja

### 8. Microservicios y contenedores
- [x] `generar_dockerfile` y métricas Prometheus (`/metricas`) ya existen.
- [x] Lectura automática de `sipi.toml` al arrancar: sección `[entorno]` se vuelca a variables de entorno reales del proceso, cualquier otra sección queda disponible con `configuracion_obtener "seccion.clave"`, y `iniciar_api_web` (sin argumentos) usa `[servidor] puerto` del `.toml` si existe.
- [ ] Health checks configurables por el usuario, no solo el `/salud` fijo.

### 9. Marketing
- [ ] Un post explicando por qué existe SiPi (LinkedIn/Medium/Dev.to).
- [ ] Página de inicio generada con `pagina_web` mostrando 2-3 casos de uso reales.

---

## Hecho en esta sesión (fuera del roadmap de arriba, reportado por el usuario)

- **Editor (`editor_sipi.py`)**: el área de código no tenía ninguna scrollbar (ni
  vertical ni horizontal) y los números de línea se desincronizaban del scroll con
  la rueda del mouse. Se agregaron ambas scrollbars, se sincronizó el scroll
  vertical entre el texto y los números de línea, y se agregó soporte de rueda
  de mouse (vertical normal, Shift+rueda para horizontal) en Windows/Mac/Linux.
  También se agregó scrollbar al panel de "vista previa en vivo".
- **Consola al ejecutar (Windows)**: la ventana `cmd` que se abre con "Ejecutar"
  ahora tiene un título real (`SiPi - archivo.sipi`) en vez de aparecer como una
  ventana genérica de `cmd.exe`, y limpia la pantalla (`cls`) después de fijar
  la página de códigos UTF-8 (`chcp 65001`), para que ese comando no quede visible.
- **Nueva función web "sorprendente"**: `canal_tiempo_real "/ruta"` +
  `enviar_evento "mensaje" a "/ruta"` — Server-Sent Events reales sobre la misma
  API HTTP ya existente. Permite paneles en vivo, notificaciones push o chats sin
  escribir websockets a mano ni instalar nada externo. Probado de punta a punta:
  un cliente conectado a `/eventos` recibe el mensaje en tiempo real apenas otra
  ruta llama a `enviar_evento`.

## Hecho en esta sesión — continuación (ítems del roadmap arriba)

- **Ítem 3 (`sipi test`)**: descubrimiento automático de `*_test.sipi`, ejecución
  real de cada uno, conteo de casos OK/FALLO, y reporte JUnit XML con `--junit`.
  Probado de punta a punta: 2 aserciones (una que pasa, una que falla a propósito)
  producen el conteo correcto, código de salida 1, y un XML válido con el `<failure>`
  correspondiente.
- **Ítem 8 (`sipi.toml`)**: parser TOML mínimo (sin dependencias externas, compatible
  con Python 3.7+) que se carga automáticamente al arrancar cualquier programa si hay
  un `sipi.toml` junto a él. `[entorno]` se vuelca a variables de entorno reales
  (`variable_entorno` las lee sin cambios); cualquier otra sección se lee con la nueva
  función `configuracion_obtener "seccion.clave" -> variable`; y `iniciar_api_web`
  (sin número de puerto) usa `[servidor] puerto` si está definido. Probado de punta
  a punta: un `sipi.toml` con puerto 8942 hace que tanto `configuracion_obtener` como
  `iniciar_api_web` sin argumentos levanten el servidor en ese puerto.
- Se corrió la suite de regresión completa (`tests/test_suite.py` + `tests/test_robustez.py`,
  33 tests en total) después de todos los cambios: sigue en 0 fallos.

## Hecho en esta sesión — ítem 7 (seguridad: JWT + XSS)

- **`escapar_html`** (builtin nuevo): convierte `<`, `>`, `&`, comillas a entidades
  HTML. Probado: `<script>alert(1)</script>` → `&lt;script&gt;alert(1)&lt;/script&gt;`.
- **Detección de XSS en `--revisar`**: si una cadena arma HTML interpolando un valor
  de `peticion`/`query`/`cuerpo` sin pasar por `escapar_html`, ahora aparece como
  hallazgo de seguridad con explicación concreta. Probado con una ruta de ejemplo
  que arma `<div>{peticion['cuerpo']['texto']}</div>` sin escapar.
- **JWT (HS256) sin dependencias externas**: `jwt_crear datos "secreto" expira_en 3600
  -> token` y `jwt_verificar token "secreto" -> datos`. Implementado a mano
  (base64url + HMAC-SHA256) usando solo la librería estándar de Python.
  **Verificado que es un JWT 100% estándar**: un token generado por SiPi se decodificó
  correctamente con PyJWT sin ningún ajuste.
- **`requerir_autenticacion "secreto" con_jwt`**: nuevo modo de autenticación de la API
  que reemplaza la clave estática por verificación de JWT con expiración. La función
  que atiende cada ruta recibe los datos decodificados del token en
  `peticion["usuario"]`. Probado de punta a punta contra un servidor real:
  sin token → 401; token válido → 200 con los datos del usuario; token con firma
  corrupta → 401.
- Se corrió la suite de regresión completa (33 tests) después de estos cambios:
  sigue en 0 fallos.

## Hecho en esta sesión — ítem 3 y 6 (herramientas de desarrollo + ORM)

- **Depurador CLI real** (`sipi_depurador.py`, nuevo archivo): breakpoints, step,
  inspección de variables locales/globales, y salir. Corre in-process (no como
  subprocess ciego) para tener acceso directo al estado real del intérprete en el
  momento exacto de la pausa. Reutiliza `hook_linea`/`DepuracionDetenida`, que ya
  existían para el depurador visual del editor de escritorio, en vez de duplicar
  esa lógica. Se encontró y corrigió en el camino un bug: `interprete.ejecutar()`
  atrapa `DepuracionDetenida` internamente y no la deja propagar, así que el
  mensaje de salida ("terminó normalmente" vs "cortado por el usuario") se decide
  ahora con una bandera explícita en vez de un `except` externo que nunca se
  disparaba. Probado de punta a punta: breakpoint dentro de un bucle (la variable
  se ve actualizarse en cada vuelta), breakpoint dentro de una función (parámetro
  visible antes de ejecutar la línea, variable local visible después de `paso`), y
  `salir` cortando la ejecución a mitad de camino.
- **Logging avanzado**: `[logging]` en `sipi.toml` con `destino = "archivo_rotativo"
  | "syslog" | "remoto"`, implementado con `logging.handlers` real de Python
  (RotatingFileHandler, SysLogHandler, HTTPHandler) en vez de código casero.
  Mantiene el comportamiento anterior (JSON Lines a `sipi.log`) si no se configura
  nada. Probado con rotación de archivo real (`tamano_maximo_mb`/`respaldos`).
- **ORM básico**: `clase X hereda_de Modelo` + `modelo_vincular`/`modelo_crear_tabla`/
  `modelo_guardar`/`modelo_buscar`/`modelo_buscar_uno`/`modelo_eliminar` sobre
  SQLite. El tipo de columna se infiere del valor por defecto de cada campo. Se
  encontró y corrigió un bug real en `_instanciar_clase`/`_cadena_de_clases`: una
  clase que hereda de un nombre no definido como clase real (como `Modelo`, que es
  una base virtual sin campos propios) explotaba con `KeyError`. Probado de punta a
  punta: crear tabla, insertar, buscar con condición SQL parametrizada, buscar por
  id, actualizar, y borrar — incluyendo que el tipo booleano se preserva yendo y
  viniendo de SQLite (que no tiene tipo booleano nativo).
- Se corrió la suite de regresión completa (33 tests) después de todos estos
  cambios: sigue en 0 fallos.

## Pendiente real para la próxima sesión

- Migraciones automáticas que generen el diff a partir de cambios en las clases
  del ORM (ítem 6). Es lo único que queda del roadmap original con un dueño claro
  y sin dependencia de infraestructura externa.

## Hecho en esta sesión — ítem 1 (registro central de paquetes)

- **`src/sipi_registro.py`** (nuevo): cliente completo del registro — semver
  propio sin dependencias (`Version`, `_rango_satisfecho`, soporta `^`, `~`,
  `>=`, exacto, `*`), `ClienteRegistro.buscar/resolver/instalar` (con
  resolución de dependencias a un nivel y verificación de `sha256`), y
  `empaquetar`/`publicar` para el lado de quien distribuye un paquete.
- **`sipi paquete crear/publicar/instalar/buscar`** (nuevo, en `sipi_cli.py`):
  interfaz de línea de comandos completa. `sipi paquete publicar --registro
  <clon_local>` automatiza el commit+push si el usuario administra el repo del
  registro; sin eso, imprime instrucciones manuales exactas — nadie se queda
  sin poder publicar solo por no tener permisos de escritura en el repo
  central.
- **`herramientas/plantilla_registro/`** (nuevo): `index.json` + `README.md`
  listos para subir tal cual a un repo de GitHub y tener un registro real
  funcionando en 5 minutos — sin servidor propio, GitHub lo sirve gratis vía
  `raw.githubusercontent.com`.
- **Por qué no hay un registro oficial ya poblado**: eso requeriría que alguien
  con autoridad sobre el proyecto SiPi cree y mantenga ese repo — no es algo
  que se pueda simular de forma honesta desde este entorno. Lo que sí queda
  listo y verificado es toda la infraestructura de software para que, apenas
  ese repo exista, funcione sin tocar una línea más de código.
- **Probado de punta a punta con un registro git real** (no simulado): se creó
  un repo git de verdad en disco, se publicó un paquete (`sipi paquete
  publicar --registro`), lo que generó un commit real con el `.zip` y el
  `index.json` actualizado con su hash sha256 real. Desde un proyecto
  distinto, se buscó (`sipi paquete buscar`) y se instaló
  (`sipi paquete instalar paquete@^1.0.0`) contra ese índice, y el `.sipi`
  resultante se importó y se llamó desde un programa real, con salida
  correcta. Además se probaron los dos casos límite de seguridad/UX: un
  `sha256` alterado en el índice aborta la instalación con un mensaje claro
  (protección real contra paquetes corruptos o manipulados), y un rango
  semver que ninguna versión cumple falla con un mensaje que lista las
  versiones disponibles en vez de un traceback.
- En el camino se encontró y corrigió un bug real: las URLs del `index.json`
  pueden ser relativas (como las que arma `publicar()`, ej. `paquetes/x.zip`)
  y no se resolvían contra la ubicación del propio índice — `urllib` fallaba
  con `unknown url type`. Se arregló con `urllib.parse.urljoin` contra
  `url_indice`, igual que resolvería un navegador un link relativo.

## Hecho en esta sesión — función web extra: `servir_carpeta`

- **`servir_carpeta "/publico" "carpeta_local"`** (nuevo comando SiPi): sirve
  archivos estáticos reales (imágenes, CSS, JS, PDFs) directo desde la API
  web, sin escribir una función que los lea a mano. Content-Type correcto
  vía `mimetypes`, con **protección real contra path traversal** (la ruta
  final se resuelve con `os.path.realpath` y se verifica que siga dentro de
  la carpeta registrada antes de servir nada; si no, 403).
- Probado de punta a punta con un servidor HTTP real corriendo en
  `localhost:8099`: `GET` a un `.html` y a un `.css` devuelven el contenido
  correcto con el `Content-Type` correcto, un archivo inexistente da 404, y
  dos intentos de escaparse de la carpeta (uno con `../` literal, otro con
  `%2f` codificado) quedan bloqueados. Corrida también la suite de regresión
  completa después (25/25 tests, sin fallos).

