Files
brahman/renaser/ROADMAP.md
T
sergio 089afccbbc feat(renaser): Fase 10 — alta y baja de aplicaciones en vivo
El censo de aplicaciones deja de fijarse en el arranque: una app puede
nacer o cerrarse con el reactor ya en marcha.

- El reactor admite NACIMIENTOS en vivo: cola `NACIMIENTOS` +
  `engendrar()`, drenada al inicio de cada vuelta de `run()`;
  `Task::adoptar` acoge un futuro ya empaquetado.
- `Alt+Q` (`Mando::Cerrar`): baja limpia. El compositor saca la
  ventana enfocada del teselado y del orden-Z; la app advierte la
  baja (`ventana_cerrada`) y concluye su tarea — su memoria, su
  combustible y su canal de teclado se liberan. Sin baliza.
- `Alt+N` (`Mando::Lanzar`): alta en vivo. `nacer_ventana` añade la
  ventana y entrega su índice; el orquestador instancia el WASM y
  engendra su tarea. Las apps de génesis dejan su bytecode cacheado
  como `Plantilla`; cada `Alt+N` instancia una en rotación.

Verificado en QEMU (sendkey): tres Alt+N hacen crecer el escritorio
de 5 a 8 ventanas; tres Alt+Q lo reducen de 8 a 5. Kernel estable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:26:25 +00:00

193 lines
11 KiB
Markdown

# renaser — Hoja de ruta
Estado de las fases del proyecto. Para la arquitectura, ver `ARCHITECTURE.md`.
## Fases completadas
Todas verificadas en QEMU (captura de pantalla incluida en su momento).
### Fase 1 — el primer microsegundo
Arranque UEFI, adopción del framebuffer GOP, lienzo de doble búfer y la baliza
de pánico (franja roja al colapsar). Punto de entrada con `bootloader_api`.
### Fase 1.5 — empaquetado y arranque
Miembro `boot/`: constructor de la imagen de disco UEFI (crate `bootloader`
0.11, vía dependencia de artefacto) y lanzador de QEMU. `cargo run` pasa a
compilar, forjar la imagen y arrancar, todo de un gesto.
### Fase 2.0 — cimientos del manejo de fallos
GDT propia + TSS con stack de emergencia (IST) para el doble fallo. IDT con
manejadores de excepción de CPU. El breakpoint es recuperable; el resto de
excepciones encienden la baliza.
### Fase 2.1 — interrupciones de hardware
Remapeo del PIC 8259 fuera del rango de las excepciones. Temporizador (PIT) a
100 Hz e IRQ1 de teclado. El kernel pasa de "pintar una vez" a un bucle de
render despertado por el hardware.
### Fase 3 — memoria dinámica y reactor asíncrono
Heap de 64 MiB con `linked_list_allocator` como asignador global; manejador
propio de OOM (franja naranja). Reactor cooperativo: `Executor`, `Task`,
`Waker`. Texto vectorial con `fontdue`: el texto deja de ser mapa de bits.
### Fase 4 — el escudo de aislamiento WASM
Runtime `wasmi` `no_std`. Matriz de capacidades con dos funciones de host
(`sys_render_frame`, `sys_get_scancode`) y validación infranqueable de límites
de la memoria lineal. Primera app del userspace: `apps/hello_wasm`, un módulo
`wasm32` aislado que pinta y responde al teclado.
### Fase 5 — multitarea cooperativa, fuel y reloj
Unificación del reactor (Fase 3) y el runtime WASM (Fase 4). El ABI del
userspace pasa a `init`/`tick`: cada `tick` es un punto de cesión cooperativa.
`async_system::reloj` convierte la IRQ0 en el `Future` `EsperaFrame`, que marca
el compás de los fotogramas. Cada app es una `AplicacionWasm` persistente y una
tarea del reactor. Escudo de combustible (`fuel`): cada `tick` corre con un
presupuesto estricto; agotarlo desaloja la app sin tocar al kernel. Capacidades
ampliadas — regiones de dibujo por app y canal de teclado por app. Verificado
en QEMU con tres apps concurrentes, una de ellas díscola y desalojada en vivo.
### Fase 6.0 — cuotas de memoria y ciclo de vida
Completa el aislamiento espacial del userspace. Cada `AplicacionWasm` instancia
su `Store` con un `StoreLimits` (techo de memoria lineal de 4 MiB, vía
`Store::limiter`); rebasarlo es una trampa que desaloja la app con baliza
amarilla — gemela de la púrpura del desalojo por combustible. `Drop` para
`AplicacionWasm` reconcilia el ciclo de vida: da de baja el canal de teclado de
la difusión de la IRQ1. Verificado en QEMU con cuatro apps — una díscola
(desalojo temporal) y una glotona (desalojo espacial), ambas en vivo.
## Fase 6.1 — sustrato de almacenamiento (completada)
Estrategia incremental para el almacenamiento, frente al riesgo del hardware:
- **6.1a — Sonda PCI** *(hecha)*`drivers/pci.rs` enumera el bus PCI por
`0xCF8`/`0xCFC` y localiza el disco virtio-blk; `boot` forja el disco de
pruebas y lo adjunta como `virtio-blk-pci`. El muro del descubrimiento de
hardware queda derribado.
- **6.1b — HAL y lectura de sector** *(hecha)*`drivers/disco.rs`: asignador
de marcos «bump», `KernelHal` (el `trait Hal` de `virtio-drivers`: DMA y
traducción de direcciones) y `montar_y_leer_sector0`, que lee el sector 0 por
sondeo. Verificado por una firma que viaja del anfitrión al disco y vuelve.
- **6.1c — Grafo de objetos** *(hecha)*`almacen.rs`: el almacenamiento como
DAG direccionado por contenido —la identidad de un objeto es el hash BLAKE3
de su forma serializada (`postcard`); el disco se organiza como un log con
superbloque e índice—, y las cinco capacidades `sys_object_*` que lo exponen
al userspace. `drivers/disco.rs` gana un asignador de marcos con liberación
real (mapa de bits), escritura de sectores y un `VirtIOBlk` persistente. La
app `cronista` lleva la cuenta de los arranques en el grafo: la cuenta
perdura entre reinicios.
## Fase 6.2 — E/S de disco asíncrona por interrupción (completada)
La Fase 6.1 hizo hablar al disco, pero por **sondeo**: el procesador se quedaba
en espera activa vigilando el *used ring* de virtio. La 6.2 libera el
planificador cooperativo — la E/S de bloques pasa a ser **reactiva**:
- `EsperaDisco` — una transferencia de bloques como `Future` nativo, sobre la
API no bloqueante de `virtio-drivers` (`read_blocks_nb` / `peek_used` /
`complete_*`). Cede la CPU mientras el disco trabaja.
- La **IRQ del disco**`montar` descubre la línea de IRQ legada del
dispositivo (registro «Interrupt Line» del espacio de configuración PCI), la
enruta por el 8259 y registra su manejador; `atender_irq` reconoce la
interrupción y despierta a la tarea que aguardaba el bloque.
- `bloquear_en` — el puente para los contextos síncronos (el arranque, las
capacidades WASM): duerme la CPU con `hlt` en vez de sondear.
Decisión de ingeniería: las IRQ se enrutan por el **PIC 8259** que el kernel ya
gobierna, no por el IOAPIC — basta leer la línea que el firmware ya asignó.
Verificado en QEMU: el disco se enruta a la IRQ 11; una tarea-sonda del reactor
lee un bloque de forma asíncrona mientras las apps siguen pintando.
## Fase 7 — el userspace nace del Grafo de Objetos (completada)
Hasta la Fase 6, el userspace venía **empotrado en el binario del kernel**:
cuatro `include_bytes!` de `.wasm` y regiones escritas a mano. La Fase 7 lo
destierra — las aplicaciones pasan a ser objetos del grafo, gobernadas por un
**Manifiesto de Génesis** que también vive en el grafo. Plan completo en
`FASE7.md`.
- **7a — el Manifiesto (completada).** `manifiesto.rs`: tipos `Manifiesto` /
`EntradaApp` y carga desde el grafo. El superbloque gana el ancla
`manifiesto` (VERSION 1→2). `kernel_main` lee el manifiesto e instancia cada
app recuperando su bytecode del grafo, verificado por su hash.
- **7b — la imagen sembrada por `boot` (completada).** Nace la crate
`formato`, un núcleo `no_std` con el formato del grafo en disco, COMPARTIDO
por el kernel y el constructor de imagen `boot`. `boot` siembra el disco
virgen con el grafo ya poblado —bytecode y manifiesto—; el kernel pierde
todo `include_bytes!` del userspace. Su binario ya no carga ni un `.wasm`.
- **7c — persistencia inter-sesión (completada).** La app `memoriosa` graba
su estado como un objeto del grafo; el kernel lo ancla en la ranura
`EntradaApp.estado` y re-graba el manifiesto. Al despertar, `init` lo relee
y la app retoma donde quedó. Capacidades `sys_estado_cargar` /
`sys_estado_guardar`; el kernel custodia un manifiesto VIVO y mutable.
## Fase 8 — el compositor teselante e interactivo (completada)
El kernel deja de colocar las ventanas a mano: las **tesela**. El motor es
`mirada-layout` —el mismo núcleo `no_std` que ordena el compositor Wayland de
brahman—, enlazado por `path` cruzando la frontera de workspace. Plan completo
en `FASE8.md`.
- **8a — el compositor tesela (completada).** `compositor.rs` calcula un marco
por app con el algoritmo `MasterStack`. El kernel centra el fotograma natural
de cada app dentro de su marco; las apps no cambian una instrucción.
`region_x/y` del manifiesto quedan vestigiales — la posición la decide el
compositor.
- **8b — teselado interactivo (completada).** `Alt+Espacio` cicla los modos de
teselado en caliente. El kernel cachea el último fotograma de cada app y
recompone desde la caché: las apps estáticas sobreviven al re-teselado sin
enterarse del cambio.
- **8c — foco y enrutamiento selectivo (completada).** Una ventana enfocada,
con borde índigo; `Alt+J` / `Alt+K` mueven el foco entre las ventanas vivas.
El teclado deja de difundir: entrega cada tecla sólo a la app enfocada.
- **8d — manipulación de ventanas (completada).** El orden de teselado se
separa de la identidad de las ventanas. `Alt+Enter` promueve la ventana
enfocada a la celda maestra; `Alt+H` / `Alt+L` la reordenan. El foco viaja
con la ventana.
## Fase 9 — orden-Z y ventanas flotantes (completada)
El teselado de la Fase 8 repartía la pantalla sin solapamiento. La Fase 9 suma
un segundo modelo de composición —el SOLAPAMIENTO—: una ventana puede abandonar
el teselado y FLOTAR sobre las demás. Verificada en QEMU (`sendkey`).
- El `Escritorio` separa dos capas: las ventanas TESELADAS, al fondo; y las
FLOTANTES, encima, apiladas en un orden-Z (`flotantes`, de atrás hacia
adelante). Juntas son una partición de las ventanas.
- `Alt+F` alterna la ventana enfocada entre teselada y flotante. Una flotante
nace con un marco propio, en cascada, y al frente del orden-Z; al volver al
teselado se reincorpora a la rejilla, que se recalcula.
- Con flotantes vivas, el kernel deja de pintar ventana a ventana: RECOMPONE el
escritorio entero, capa a capa de atrás hacia adelante —el solapamiento se
resuelve por el orden del pintado—. Sin flotantes conserva el camino rápido
de la Fase 8.
- El foco recorre todas las ventanas; al posarse en una flotante, la alza al
frente: la flotante enfocada está siempre delante.
## Fase 10 — alta y baja de aplicaciones en vivo (completada)
Hasta la Fase 9 el censo de aplicaciones se fijaba en el arranque. La Fase 10
lo vuelve DINÁMICO: una app puede nacer o cerrarse con el reactor ya en marcha.
Verificada en QEMU (`sendkey`).
- El reactor admite NACIMIENTOS en vivo: una cola que `engendrar` alimenta y
que el ejecutor drena al inicio de cada vuelta, adoptando cada futuro como
tarea. El censo de tareas deja de ser inmutable tras el arranque.
- `Alt+Q` cierra la app enfocada: una baja LIMPIA. El compositor saca la
ventana del teselado y del orden-Z; la app, al advertir la baja, concluye su
tarea y `AplicacionWasm::drop` libera su memoria, su combustible y su canal.
- `Alt+N` lanza una app nueva: `nacer_ventana` la añade y entrega su índice; el
orquestador instancia el WASM y engendra su tarea. Las apps de génesis dejan
su bytecode cacheado como plantilla; cada `Alt+N` instancia una en rotación.
- El censo de ventanas sólo crece —los índices son la identidad, jamás se
reciclan—; una ventana cerrada queda como ranura inerte, fuera del teselado.
Líneas abiertas posteriores: más capacidades del host (temporización, audio);
reciclado de las ranuras de ventana cerradas.
## Principios que persisten entre fases
- Reutilizar infraestructura madura de la comunidad antes que reinventar.
- `unsafe` mínimo, confinado y justificado.
- Verificar cada fase en QEMU antes de cerrarla.
- `git commit` + `git push` tras cada iteración.