feat(renaser): Fase 7 — apertura: plan y andamiaje del Manifiesto de Génesis
Abre la Fase 7 («apps que nacen del grafo»): destierra el include_bytes! del userspace — las apps pasan a ser objetos del grafo, gobernadas por un Manifiesto de Génesis que también vive en el grafo. Este commit es sólo plan + andamiaje; el kernel se comporta idéntico a la Fase 6.2. - FASE7.md — el plan de ataque: el problema de la génesis, las sub-fases 7a/7b/7c y los guardarraíles. - kernel/src/manifiesto.rs — andamiaje: tipos Manifiesto/EntradaApp + (de)serialización postcard completos; cargar/sembrar_genesis son esbozos hasta la 7a. Declarado en main.rs, aún sin cablear a kernel_main (#![allow(dead_code)] temporal). CHANGELOG y DIARIO al día. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -455,3 +455,28 @@ REACTIVA, guiada por la interrupción física del dispositivo.
|
||||
testigo de integridad del DAG en verde — la nueva E/S asíncrona lee y escribe
|
||||
el grafo sin un solo fallo. Las cuatro apps WASM siguen su curso, sin un
|
||||
sobresalto ni un micro-congelamiento.
|
||||
|
||||
## Fase 7 — Apertura: Apps que nacen del Grafo — 2026-05-22
|
||||
|
||||
Apertura de la Fase 7. Este commit asienta el plan y el andamiaje; **no
|
||||
cambia el comportamiento del kernel**. La Fase 7 destierra el
|
||||
`include_bytes!` del userspace: las aplicaciones pasan a ser objetos del
|
||||
grafo, y un Manifiesto de Génesis —también en el grafo— dicta qué arranca,
|
||||
con qué cuota y en qué región.
|
||||
|
||||
### Añadido
|
||||
- `FASE7.md` — el plan de ataque: el objetivo, el problema huevo-y-gallina
|
||||
de la génesis, las sub-fases 7a (manifiesto + carga desde el grafo, con
|
||||
semilla por el kernel), 7b (siembra de la imagen por `boot`, muerte del
|
||||
`include_bytes!`) y 7c (persistencia inter-sesión), y los guardarraíles.
|
||||
- `kernel/src/manifiesto.rs` — andamiaje del Manifiesto de Génesis. Los
|
||||
tipos `Manifiesto` / `EntradaApp` y la (de)serialización `postcard` están
|
||||
completos; `cargar` y `sembrar_genesis` son esbozos hasta la Fase 7a.
|
||||
La sub-región se guarda en campos `u32` de ancho fijo (formato en disco),
|
||||
no como `RegionPantalla` (`usize`, ancho de plataforma).
|
||||
|
||||
### Notas
|
||||
- El módulo se declara en `main.rs` pero aún no se cablea a `kernel_main`
|
||||
(`#![allow(dead_code)]` temporal, hasta que la 7a le dé un llamador). El
|
||||
kernel compila y se comporta idéntico a la Fase 6.2 — nada observable que
|
||||
verificar en QEMU en esta apertura.
|
||||
|
||||
@@ -221,6 +221,24 @@ casilla más cada vez— pero que se sentirá en todo lo que venga después. El
|
||||
y renaser ya no se miran fijamente: se hablan, y entre frase y frase, cada cual
|
||||
atiende lo suyo.
|
||||
|
||||
## El plano antes de la obra — abrir la Fase 7
|
||||
|
||||
Hay jornadas en las que no se levanta un muro: se dibuja. Esta fue una de
|
||||
ésas. Antes de tocar el corazón del kernel hubo que decidir, con calma,
|
||||
hacia dónde mover la siguiente piedra.
|
||||
|
||||
La pregunta era vieja y conocida: las aplicaciones de renaser todavía viajan
|
||||
escondidas dentro del propio kernel, cosidas a su binario. Pero renaser tiene
|
||||
un disco que recuerda, un tejido de objetos que perdura entre apagones. ¿Por
|
||||
qué, entonces, las apps no nacen de ahí, como todo lo demás?
|
||||
|
||||
Se escribió el plano de esa mudanza —el plan de la Fase 7— y se dejó puesta
|
||||
la primera viga: un cuaderno nuevo, el «Manifiesto», donde algún día estará
|
||||
escrito qué programas deben despertar, cuánta memoria se les presta y en qué
|
||||
rincón de la pantalla viven. Por ahora el cuaderno está en blanco y sus
|
||||
páginas son sólo molde; pero el molde ya tiene la forma exacta de lo que
|
||||
vendrá. La casa no cambió aún — sólo sabe, por fin, hacia dónde va a crecer.
|
||||
|
||||
---
|
||||
|
||||
*El diario continúa. La próxima página la escribirá la próxima jornada.*
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# renaser — Fase 7 :: Apps que nacen del Grafo
|
||||
|
||||
Plan de ataque. Para el estado general ver `ROADMAP.md`; para la arquitectura,
|
||||
`ARCHITECTURE.md`.
|
||||
|
||||
## El objetivo
|
||||
|
||||
Hoy el kernel lleva el userspace **empotrado en su propio binario**:
|
||||
`main.rs` tiene cuatro `include_bytes!` (`app.wasm`, `discola.wasm`,
|
||||
`glotona.wasm`, `cronista.wasm`) y cinco llamadas `encender_app` con regiones
|
||||
escritas a mano. Eso contradice la tesis de renaser: el almacenamiento es un
|
||||
**grafo de objetos direccionado por contenido**, no un binario monolítico.
|
||||
|
||||
La Fase 7 **destruye el `include_bytes!` del userspace**. Las aplicaciones
|
||||
pasan a ser objetos del grafo; el kernel las descubre, las verifica por su
|
||||
hash y las inyecta en caliente en `wasmi`. Qué apps arrancan, con qué cuota y
|
||||
en qué región lo dicta un **Manifiesto de Génesis** que también vive en el
|
||||
grafo. (La fuente `font.ttf` sigue empotrada: es del kernel, no del userspace.)
|
||||
|
||||
## El problema de la génesis
|
||||
|
||||
Hay un huevo-y-gallina: el kernel lee el manifiesto para saber qué cargar,
|
||||
pero el manifiesto y el bytecode tienen que haber sido escritos antes. En un
|
||||
disco virgen no hay nada. Dos vías para sembrarlo:
|
||||
|
||||
- **A — el kernel siembra.** En un disco sin manifiesto, el kernel graba en el
|
||||
grafo el bytecode de unas apps de génesis y un manifiesto por defecto. El
|
||||
bytecode de génesis llega vía `include_bytes!` — todavía.
|
||||
- **B — `boot` siembra la imagen.** El constructor de imagen (anfitrión)
|
||||
pre-puebla el disco con los objetos de bytecode y el manifiesto. El kernel
|
||||
jamás empotra una app.
|
||||
|
||||
B es el estado final puro, pero exige enseñarle a `boot` el formato del grafo
|
||||
(objetos, BLAKE3, log, superbloque) — trabajo de anfitrión considerable. Se
|
||||
ataca **incremental**, como las Fases 6.1a/b/c.
|
||||
|
||||
## Sub-fases
|
||||
|
||||
### 7a — El Manifiesto y la carga desde el grafo (semilla por el kernel)
|
||||
|
||||
1. **`manifiesto.rs`** *(andamiaje ya creado)* — tipos `Manifiesto` /
|
||||
`EntradaApp`, (de)serialización postcard. Hoy es un módulo `no_std` del
|
||||
kernel; no se comparte con las apps (la frontera app↔kernel es el ABI WASM
|
||||
numérico, no tipos Rust).
|
||||
2. **`almacen.rs`** — el `SuperBloque` gana un segundo ancla,
|
||||
`manifiesto: Option<Hash>`, gemelo de `raiz`. `VERSION` sube de `1` a `2`
|
||||
(un disco v1 se reformatea, como ya hace `init` con discos ajenos).
|
||||
Getters `manifiesto()` / `fijar_manifiesto()`.
|
||||
3. **`manifiesto::sembrar_genesis()`** — en un disco sin manifiesto: graba el
|
||||
bytecode de las apps de génesis (`include_bytes!`, **sólo aquí**), compone
|
||||
un `Manifiesto` por defecto con sus regiones y cuotas, lo graba y lo ancla.
|
||||
4. **`manifiesto::cargar()`** — lee el ancla del superbloque, recupera el
|
||||
objeto, lo deserializa.
|
||||
5. **`kernel_main`** — reemplaza las cinco `encender_app` escritas a mano por:
|
||||
cargar el manifiesto (o sembrarlo si falta) e iterar sus `EntradaApp`.
|
||||
6. **`wasm/mod.rs`** — el techo de memoria deja de ser la constante
|
||||
`TECHO_MEMORIA` y pasa a venir por-app del manifiesto (`EntradaApp`).
|
||||
7. **Verificar en QEMU** — la pantalla debe verse idéntica a la Fase 6.2
|
||||
(cinco apps en sus regiones), pero ahora **nacidas del grafo**.
|
||||
|
||||
### 7b — La imagen sembrada por `boot`; muere `include_bytes!`
|
||||
|
||||
- `boot` (anfitrión) aprende el formato del grafo y pre-puebla la imagen de
|
||||
disco con los objetos de bytecode + el manifiesto.
|
||||
- El kernel pierde los `include_bytes!` del userspace; `sembrar_genesis` se
|
||||
retira o queda como camino vacío de respaldo.
|
||||
|
||||
### 7c — Persistencia inter-sesión
|
||||
|
||||
- Una app (cronista evolucionada, o una nueva interactiva) guarda su estado
|
||||
mutado como un objeto nuevo del grafo al recibir teclado.
|
||||
- Cada `EntradaApp` usa su campo `estado: Option<Hash>` (ya previsto en el
|
||||
tipo). Al guardar, el kernel reescribe el manifiesto; al arrancar, le pasa
|
||||
ese estado a la app para que despierte donde quedó.
|
||||
- Probablemente una capacidad host nueva para que el kernel se entere del
|
||||
hash de estado nuevo que la app produjo.
|
||||
|
||||
## Guardarraíles (directiva de la arquitecta)
|
||||
|
||||
- **No romper `check-shared-cores.sh`.** Si algún tipo del manifiesto llegara
|
||||
a compartirse entre apps y kernel, debe habitar un núcleo estrictamente
|
||||
`no_std`. Hoy no se comparte: `manifiesto.rs` es kernel-only.
|
||||
- **Errores recuperables con `Result`.** Si el kernel lee del grafo un objeto
|
||||
de bytecode corrupto (su hash recomputado ≠ su id), `almacen::recuperar` ya
|
||||
lo detecta — devuelve `Err`. El kernel **niega esa instanciación**, pinta la
|
||||
baliza de desalojo en la región de esa app, y **sigue levantando el resto**.
|
||||
Un módulo podrido nunca tumba el arranque.
|
||||
|
||||
## Estructura de archivos
|
||||
|
||||
| archivo | estado | rol en la Fase 7 |
|
||||
| --- | --- | --- |
|
||||
| `kernel/src/manifiesto.rs` | **nuevo (7a)** | tipos `Manifiesto`/`EntradaApp` + (de)serialización + carga/siembra |
|
||||
| `kernel/src/almacen.rs` | a modificar (7a) | `SuperBloque.manifiesto`, `VERSION` 2, getters |
|
||||
| `kernel/src/main.rs` | a modificar (7a) | `kernel_main` itera el manifiesto en vez de `include_bytes!` |
|
||||
| `kernel/src/wasm/mod.rs` | a modificar (7a) | techo de memoria por-app desde el manifiesto |
|
||||
| `boot/` | a modificar (7b) | siembra la imagen de disco con el grafo |
|
||||
@@ -18,6 +18,7 @@
|
||||
// drivers — descubrimiento de hardware y E/S de disco asincrona por
|
||||
// interrupcion: el bus PCI y el virtio-blk (Fases 6.1, 6.2).
|
||||
// almacen — el grafo de objetos direccionado por contenido (Fase 6.1c).
|
||||
// manifiesto — el Manifiesto de Genesis: que apps nacen del grafo (Fase 7).
|
||||
// memory — el heap dinamico del kernel (`#[global_allocator]`).
|
||||
// async_system — el reactor cooperativo: ejecutor, tareas, wakers, teclado
|
||||
// y el reloj que marca el compas de los fotogramas (Fase 5).
|
||||
@@ -50,6 +51,7 @@ mod drivers;
|
||||
mod gdt;
|
||||
mod grafico;
|
||||
mod interrupts;
|
||||
mod manifiesto;
|
||||
mod memory;
|
||||
mod pic;
|
||||
mod sync;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
// =============================================================================
|
||||
// renaser :: kernel/src/manifiesto.rs — Fase 7 :: el Manifiesto de Génesis
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hasta la Fase 6, el userspace venia EMPOTRADO en el binario del kernel:
|
||||
// `include_bytes!` de cada `.wasm` y regiones escritas a mano. La Fase 7 lo
|
||||
// destierra: las aplicaciones pasan a ser OBJETOS DEL GRAFO, y lo que arranca
|
||||
// —con que cuota, en que region— lo dicta este Manifiesto de Genesis, que
|
||||
// tambien habita el grafo. El superbloque guarda su hash en un ancla propia.
|
||||
//
|
||||
// El kernel, al despertar: lee el ancla del superbloque, recupera el objeto
|
||||
// del manifiesto, lo deserializa, y por cada `EntradaApp` recupera el objeto
|
||||
// de bytecode —verificado por su hash— y lo inyecta en `wasmi`.
|
||||
//
|
||||
// ESTADO: andamiaje de la Fase 7a. Los tipos y la (de)serializacion estan
|
||||
// completos; `cargar` y `sembrar_genesis` son esbozos — se implementan al
|
||||
// abordar la 7a, cuando el superbloque gane su campo `manifiesto`. Ver
|
||||
// `FASE7.md` para el plan completo.
|
||||
// =============================================================================
|
||||
|
||||
// Fase 7a en construccion: el modulo aun no se cablea a `kernel_main`. El
|
||||
// `allow` cae en cuanto `cargar`/`sembrar_genesis` tengan llamador real.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::almacen::Hash;
|
||||
use crate::grafico::RegionPantalla;
|
||||
|
||||
/// Version del formato del manifiesto serializado. Independiente de la
|
||||
/// version del superbloque (`almacen::VERSION`): el manifiesto es un objeto
|
||||
/// del grafo, no una estructura de disco.
|
||||
pub const VERSION_MANIFIESTO: u32 = 1;
|
||||
|
||||
/// El Manifiesto de Genesis: la lista de aplicaciones que el kernel instancia
|
||||
/// al arrancar. Vive como un objeto del grafo de objetos; el superbloque
|
||||
/// guarda su hash en el campo `manifiesto`.
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Manifiesto {
|
||||
/// Version del formato — debe ser [`VERSION_MANIFIESTO`].
|
||||
pub version: u32,
|
||||
/// Las aplicaciones del userspace, en orden de arranque.
|
||||
pub apps: Vec<EntradaApp>,
|
||||
}
|
||||
|
||||
/// Una entrada del manifiesto: una aplicacion del userspace y todo lo que el
|
||||
/// kernel necesita para darle vida — su bytecode, su ventana, su cuota de
|
||||
/// memoria y, si lo tuviera, su ultimo estado persistido.
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct EntradaApp {
|
||||
/// Nombre legible — para los rotulos de la consola y la baliza.
|
||||
pub nombre: String,
|
||||
/// Hash del objeto del grafo que contiene el bytecode WASM de la app.
|
||||
pub bytecode: Hash,
|
||||
/// Sub-region del framebuffer asignada a la app. Campos de ancho fijo
|
||||
/// `u32` A PROPOSITO: esto es un formato EN DISCO. `RegionPantalla` usa
|
||||
/// `usize` (ancho dependiente de plataforma) y no sirve para serializar.
|
||||
pub region_x: u32,
|
||||
pub region_y: u32,
|
||||
pub region_ancho: u32,
|
||||
pub region_alto: u32,
|
||||
/// Techo de memoria lineal de la app, en bytes. Sustituye a la constante
|
||||
/// global `wasm::TECHO_MEMORIA` — cada app lleva su cuota.
|
||||
pub techo_memoria: u32,
|
||||
/// Hash del ultimo estado persistido de la app (Fase 7c). `None` hasta
|
||||
/// que la app guarde estado por primera vez.
|
||||
pub estado: Option<Hash>,
|
||||
}
|
||||
|
||||
impl EntradaApp {
|
||||
/// Construye la `RegionPantalla` que el kernel entiende a partir de los
|
||||
/// campos de ancho fijo del manifiesto.
|
||||
pub fn region(&self) -> RegionPantalla {
|
||||
RegionPantalla {
|
||||
x: self.region_x as usize,
|
||||
y: self.region_y as usize,
|
||||
ancho: self.region_ancho as usize,
|
||||
alto: self.region_alto as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Manifiesto {
|
||||
/// Serializa el manifiesto a su forma binaria `postcard` — la carga util
|
||||
/// del objeto del grafo que lo aloja.
|
||||
pub fn serializar(&self) -> Result<Vec<u8>, &'static str> {
|
||||
postcard::to_allocvec(self).map_err(|_| "manifiesto :: serializacion fallida")
|
||||
}
|
||||
|
||||
/// Reconstruye un manifiesto desde la carga util de su objeto. Rechaza
|
||||
/// un formato de version desconocida en lugar de malinterpretarlo.
|
||||
pub fn deserializar(bytes: &[u8]) -> Result<Manifiesto, &'static str> {
|
||||
let (manifiesto, _) = postcard::take_from_bytes::<Manifiesto>(bytes)
|
||||
.map_err(|_| "manifiesto :: deserializacion fallida")?;
|
||||
if manifiesto.version != VERSION_MANIFIESTO {
|
||||
return Err("manifiesto :: version de formato desconocida");
|
||||
}
|
||||
Ok(manifiesto)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lee el manifiesto del grafo: toma su hash del ancla del superbloque,
|
||||
/// recupera el objeto y lo deserializa. `Ok(None)` si el disco aun no tiene
|
||||
/// manifiesto anclado — el caller debe entonces sembrar la genesis.
|
||||
///
|
||||
/// ANDAMIAJE (Fase 7a-4): depende de `almacen::manifiesto()` —el nuevo ancla
|
||||
/// del superbloque— todavia por implementar (tarea 7a-2).
|
||||
pub fn cargar() -> Result<Option<Manifiesto>, &'static str> {
|
||||
todo!("Fase 7a-4: leer almacen::manifiesto(), recuperar el objeto y deserializar")
|
||||
}
|
||||
|
||||
/// Siembra el grafo en un disco sin manifiesto: graba el bytecode de las
|
||||
/// aplicaciones de genesis, compone un `Manifiesto` por defecto con sus
|
||||
/// regiones y cuotas, lo graba y lo ancla en el superbloque. Devuelve el
|
||||
/// hash del manifiesto recien anclado.
|
||||
///
|
||||
/// ANDAMIAJE (Fase 7a-3): la semilla TRANSITORIA — en la 7a el bytecode aun
|
||||
/// llega vacia `include_bytes!`; la 7b mueve la siembra al constructor de
|
||||
/// imagen `boot` y elimina el empotrado del kernel.
|
||||
pub fn sembrar_genesis() -> Result<Hash, &'static str> {
|
||||
todo!("Fase 7a-3: grabar los bytecodes de genesis + el manifiesto por defecto, y anclarlo")
|
||||
}
|
||||
Reference in New Issue
Block a user