Files
brahman/renaser/ROADMAP.md
T
sergio 42fee6fcbc feat(renaser): Fase 20 — Akasha Over Ether (grafo distribuido)
Tres mensajes y un EtherType propio bastan para extender el grafo de
objetos —direccionado por contenido, ya BLAKE3— a otras maquinas
renaser que escuchen en la misma red de capa-2. Sin TCP, sin IP,
sin DNS.

Crate nueva 'akasha/' (no_std compartido, gemela de 'formato',
excluida del workspace):

  - MensajeAkasha enum con SolicitarObjeto(id), ProveedorObjeto(id,
    payload), AnunciarRaiz(id).
  - Codec: postcard (mismo que ya usa el grafo en disco).
  - EtherType: 0x88B5. MAX_PAYLOAD_AKASHA = 1486 (MTU sin fragmentar).
  - Helpers componer_frame(src, dst, msg) y analizar_frame(bytes) que
    distinguen EtherType ajeno, frame truncado y payload basura.
  - 6 pruebas unitarias en verde.

Modulo nuevo 'kernel/src/akasha.rs' con tres oficios:

  1. Demuxer (drenar_y_demultiplexar): drena la cola RX del dispositivo
     virtio-net y demultiplexa: frames AoE con payload valido los
     procesa el respondedor; el resto va a una cola del userspace que
     'sys_net_recibir' ahora lee. Frames 0x88B5 con payload
     no-postcard (saludo de pregon) se cuentan y tambien viajan al
     userspace.

  2. Atencion de mensajes (procesar):
     - SolicitarObjeto(id): consulta almacen::recuperar; si tenemos el
       objeto, respondemos ProveedorObjeto unicast con objeto.serializar()
       y re-hashing de defensa en profundidad.
     - ProveedorObjeto(id, payload): verifica blake3(payload)==id antes
       de absorber con almacen::almacenar.
     - AnunciarRaiz(id): si ignoramos el nodo, le solicitamos al emisor.

  3. Faro periodico (difundir_raiz cada 5 s): broadcast del hash del
     manifiesto actual. Cadencia medida contra reloj::milisegundos(),
     no contra los awaits — el interprete wasmi de los apps degrada
     la cadencia de EsperaFrame::await a varios cientos de ms, asi
     que se mide contra el reloj monotono y los oficios per-fotograma
     se enganchan al tic del compositor (cuyo latido es fiable).

Contadores ResumenAkasha (rx/tx por variante, descartados, cola del
usuario) listos para un futuro indicador AoE en la barra de tareas.

Cambios complementarios:

  - sys_net_recibir lee de akasha::pop_usuario, no de
    drivers::red::recibir_en (que queda #[allow(dead_code)] como
    primitiva del driver para diagnostico).
  - tarea_red queda corta: envia un ARP al gateway y termina. El
    demuxer y el faro viven en el tic del compositor.

Verificacion:

  - 'cargo test -p akasha' → 6 pruebas en verde.
  - QEMU headless 60 s con -object filter-dump → 14 frames: 11
    AnunciarRaiz (Δ promedio 5.86 s sobre 5.00 s de target), 2 ARP
    y el pregon hello. Cada AnunciarRaiz lleva el hash del manifiesto
    '2f3deadfcc7dae25..' en 33 bytes postcard sobre 47 bytes de frame.
  - COM1 vuelca 'akasha :: ANUNCIO emitido :: raiz=2f3deadfcc7dae25..'
    en cada disparo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 05:14:43 +00:00

23 KiB
Raw Blame History

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 discomontar 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.

Fase 11 — el reloj del sistema como capacidad de host (completada)

Hasta la Fase 10 una aplicación sólo sabía cuántas veces la habían llamado, no cuánto tiempo había pasado. La Fase 11 le da al userspace un sentido del tiempo. Verificada en QEMU (sendkey).

  • Capacidad sys_tiempo_mono: los milisegundos monótonos desde el arranque —la décima función del host—. El temporizador (PIT) ya late a 100 Hz; reloj expone esa cuenta y env la inyecta. Lectura pura, jamás retrocede.
  • App nueva pulso: un compás visual cuya escena es una función PURA del reloj del host. Dos instancias, nazcan cuando nazcan, laten al unísono — la prueba de que el tiempo es absoluto, no una cuenta de fotogramas.
  • El userspace de génesis crece de 5 a 6 apps.

Fase 12 — la bocina del PC como capacidad de host (completada)

La Fase 11 le dio al userspace un reloj; la Fase 12, una voz. La bocina del PC se suma a la matriz de capacidades. Verificada en QEMU.

  • Driver drivers/altavoz: el canal 2 del PIT como generador de onda cuadrada
    • la compuerta del puerto 0x61. El canal 0 (latido del kernel) no se toca.
  • Capacidad sys_tono(frecuencia_hz) —la undécima—. La bocina es un recurso único: pertenece a la ventana ENFOCADA, como el teclado desde la Fase 8c. Al cambiar el foco, el compositor la calla.
  • App nueva tonada: toca una escala de Do mayor y la dibuja como una escalera de barras. Junta el reloj (sys_tiempo_mono) y la bocina (sys_tono). El userspace de génesis crece de 6 a 7 apps.
  • Verificado por captura: la onda cuadrada de la bocina, enrutada a un WAV, late a la frecuencia media de la escala.

Fase 13 — ratón, puntero y arrastre de flotantes (completada)

Hasta la Fase 12 renaser dialogaba sólo con el teclado; las ventanas flotantes nacían en cascada y allí se quedaban. La Fase 13 trae el ratón: un puntero, clic-para-enfocar y arrastre del marco de las flotantes. Verificada en QEMU (mouse_move / mouse_button del monitor).

  • Driver drivers/raton: el ratón PS/2 cuelga del dispositivo auxiliar del 8042 + la IRQ12. El driver despierta el aux, programa su IRQ, le ordena reportar, ensambla paquetes de 3 bytes con guarda del bit-3.
  • El puntero como capa de presentación: Pantalla::estampar_puntero pinta un sprite de flecha de 12×18 sobre el framebuffer, DESPUÉS de copiar el lienzo. El lienzo nunca lo contiene — hace de save-under natural—.
  • El compositor gana atender_raton: botón bajando → clic-para-enfocar (sobre cualquier ventana viva); si la enfocada flota, arranca un ARRASTRE con el desfase de agarre; el botón sostenido la sigue al puntero; al soltar, fin.

Fase 14 — la identidad del escritorio: nombres y barra de tareas (completada)

Las ventanas eran anónimas; el escritorio no sabía nombrar lo que mostraba. La Fase 14 le pone un nombre a cada cuarto y una barra al pie con la lista de quienes lo habitan. Verificada en QEMU.

  • Cada Ventana lleva un nombre: String —el del manifiesto, o el del orquestador al engendrarla en vivo—. Plantilla lo guarda para las copias.
  • Una franja de 40 px al pie reservada como area_taskbar. area_apps la descuenta — las ventanas teselan y flotan sin tapar la barra ni la consola.
  • consola gana los tipos Taskbar / CeldaTaskbar y los métodos pintar_taskbar y pintar_etiqueta. La pestaña enfocada lleva el índigo del foco; la desalojada, su color de baliza; el resto, el slate.
  • Un clic dentro de la barra enfoca la ventana de la pestaña pulsada, sin iniciar arrastre. El compositor encuentra la celda con celda_taskbar_en.

Mejora estructural — mapeador MMIO en el kernel (entre fases 13 y 14)

Los BAR prefetchables 64-bit que OVMF aloja en la ventana PCI de 64 bits NO los mapea bootloader_api. El kernel gana memory::mmio, que envuelve la tabla L4 activa y abre páginas hacia las regiones MMIO que virtio-drivers le pide. KernelHal::mmio_phys_to_virt llama al mapeador antes de devolver el puntero. Trata PageAlreadyMapped y ParentEntryHugePage como éxito silencioso. Los marcos para tablas intermedias salen del banco DMA. Esta mejora resolvió el #PF inexplicable en máquinas con un OVMF que coloca el BAR del virtio-blk fuera de los primeros 4 GiB.

Fase 15 — la voz del sistema (completada)

La bocina pertenecía al app enfocado (Fase 12), pero el kernel necesita hablar también: un acorde al arrancar, un repique al lanzar una app, un bajo al desalojarla. Verificada en QEMU con captura PCM a WAV.

  • altavoz gana una cola de notas (SECUENCIA: Mutex<VecDeque<(u32,u32)>>) y un reloj de fin (FIN_NOTA: AtomicU64). agendar(&[(frec, ms)]) encola; atender() —invocada por la tarea del compositor cada fotograma— pasa a la nota siguiente cuando la actual termina. kernel_sonando() gatea a los apps: mientras el kernel habla, sys_tono ignora a las apps.
  • Catálogo: VOZ_BIENVENIDA (Do-Mi-Sol), VOZ_LANZAR (repique ascendente), VOZ_CERRAR (descendente), VOZ_DESALOJO (bajo grave).
  • Hitos: kernel_main agenda el acorde antes de ejecutor.run. nacer_ventana, cerrar y desalojar lo agendan al hacer su trabajo.
  • Pestañas de la barra de tareas: tinta calculada por brillo del fondo, así la pestaña crema del desalojo por memoria ya no lleva texto invisible.

Fase 16 — la barra viva: lanzador y reloj (completada)

La barra de tareas era pasiva. Esta fase la activa con un botón lanzador a la izquierda («+», equivalente táctil de Alt+N) y un reloj mm:ss a la derecha que late cada segundo. Verificada en QEMU con dos capturas separadas en el tiempo: el reloj avanza de 0:17 a 0:29.

  • compositor: layout reorganizado — lanzador a la izquierda (36 px), celdas en el medio, reloj a la derecha (80 px). clic_en_launcher enruta el clic al contador PARTOS; la tarea del compositor lo recoge y lanza.
  • compositor::tick_reloj() — invocada cada fotograma; recompone sólo cuando el segundo del reloj monótono cambia respecto al último mostrado.
  • consola::Taskbar crece con launcher, reloj y reloj_region. pintar_taskbar dibuja la cruz del lanzador como dos rectángulos cruzados (sin depender de la tipografía) y rotula el reloj.

Fase 17 — bitacora, el editor que recuerda (completada)

memoriosa (Fase 7c) demostró que un app podía persistir su huella. La Fase 17 lo lleva al gesto natural: un editor de texto. Tecleas, reinicias renaser, el texto sigue ahí. Verificada en QEMU.

  • Nuevo crate apps/bitacora/: lienzo 480×280, tipografía 8×8 (crate font8x8) escalada x2 a 16×16, render pixel a pixel desde la memoria del propio app. Buffer 512 bytes, wrap a 28 columnas, Enter / Backspace, persiste cada cambio con sys_estado_guardar. Mapeo de scancodes US a ASCII (minúsculas).
  • GENESIS crece de 7 a 8 apps; bitacora es la maestra al arrancar.
  • CELDA_TASKBAR_ANCHO baja de 150 a 130 px para que las ocho pestañas quepan holgadas con el lanzador y el reloj.

Fase 18 — red: virtio-net y el primer hola al exterior (completada)

renaser hablaba solo. Esta fase abre una boca y una oreja al exterior con virtio-net, reutilizando el KernelHal del disco y el mapeador MMIO. Al arrancar, el kernel envía un ARP request al gateway de QEMU; lee la respuesta y la registra. Verificada con captura pcap.

  • Driver drivers/red: monta VirtIONet<KernelHal, PciTransport, 16>, expone enviar(frame) y drenar_rx(callback). Sin pila TCP/IP — solo ethernet crudo —; la composición de paquetes se hace en el llamante.
  • componer_arp_request: helper para construir el ARP request inicial.
  • interrupts::registrar_irq_red + handler de IDT, gemelo del de disco.
  • Tarea tarea_red en el reactor: envía el ARP al arrancar, drena RX en cada fotograma y vuelca cada paquete a COM1.
  • QEMU args ganan -netdev user,id=net0 -device virtio-net-pci.

Líneas abiertas posteriores: capacidades sys_net_* para que los apps también hablen; una pila mínima ARP/IP/UDP; reciclado de las ranuras de ventana cerradas; audio con varias voces (PCM).

Fase 19 — voz del userspace hacia la red (completada)

La Fase 18 hizo que el kernel hablara con la red. La Fase 19 le da la misma capacidad a los apps con tres capacidades nuevas, y estrena la primera app que las usa.

  • drivers::red::recibir_en(buf) -> usize: drena UN paquete por llamada, recicla el descriptor a la cola RX. El gemelo cooperativo de drenar_rx, dimensionado para el patrón que los apps usan.
  • Tres capacidades wasm/env nuevas: sys_net_mac (escribe la MAC en un buffer del módulo), sys_net_enviar(ptr, len) (envía un frame Ethernet crudo) y sys_net_recibir(salida, capacidad) (drena un paquete, devuelve los bytes copiados). Todas validan rango contra la memoria lineal del módulo y devuelven códigos negativos diagnósticos.
  • App pregon (4.2 KiB WASM): al arrancar pide su MAC, anuncia su presencia con un broadcast Ethernet (EtherType 0x88B5, payload "renaser :: hola desde mi red") y en cada tick drena un paquete y lo muestra en su lienzo 480×160 — título, MAC, cuentas TX/RX y datos del último frame entrante (tamaño, EtherType, src MAC).
  • tarea_red ya no drena RX: la posesión de la cola pasa al userspace. El kernel conserva sólo el envío del ARP de prueba al arrancar.
  • GENESIS crece de 8 a 9 apps; pregon queda en posición 2 (detrás de bitacora). CELDA_TASKBAR_ANCHO baja de 130 a 116 px para que las nueve pestañas + lanzador + reloj caben en 1280 px.

Verificada con -object filter-dump,...,file=/tmp/renaser.pcap. El pcap captura tres frames: el broadcast 0x88B5 de pregon, el ARP request del kernel y el ARP reply del gateway. El primero es el del huésped — la voz del userspace ya pasó al cable.

Líneas abiertas posteriores: una pila mínima ARP/IP/UDP para los apps; un servidor de eco / un cliente DNS de juguete; reciclado de las ranuras de ventana cerradas; audio con varias voces (PCM).

Fase 20 — Akasha Over Ether: el grafo distribuido (completada)

El grafo de objetos persistentes —direccionado por contenido, ya BLAKE3— deja de ser una propiedad LOCAL del disco y se vuelve una propiedad DISTRIBUIDA del cable. Sin TCP, sin IP, sin DNS: tres mensajes y un EtherType propio bastan.

  • Crate akasha/ (no_std compartido, gemela de formato): el protocolo. MensajeAkasha con SolicitarObjeto(id), ProveedorObjeto(id, payload), AnunciarRaiz(id). Serializado con postcard. Helpers componer_frame y analizar_frame. EtherType experimental 0x88B5. Seis pruebas unitarias.
  • Módulo kernel/src/akasha.rs: el respondedor. Drena la cola RX del dispositivo de red y demultiplexa: los frames AoE legítimos los procesa en el núcleo; el resto va a una cola del userspace que sys_net_recibir lee. Atiende SolicitarObjeto consultando almacen, absorbe ProveedorObjeto verificando integridad, registra AnunciarRaiz y, si ignoramos el nodo anunciado, le pedimos al emisor.
  • Faro periódico: cada 5 s, AnunciarRaiz con el hash del manifiesto se difunde por broadcast. La cadencia se mide contra el reloj monótono — no contra los awaits—, por lo que el ritmo del faro es independiente de cuánto trabajo del reactor consume cada vuelta.
  • tic_compositor: el pulso fiable. Los oficios AoE se enganchan al tic del compositor (cuyo latido cooperativo es el único garantizado bajo carga del reactor); una tarea propia con EsperaFrame::await en bucle no escalaba porque el intérprete wasmi de los apps degrada la cadencia de los awaits a varios cientos de ms.
  • sys_net_recibir lee de la cola del userspace que mantiene akasha, no del driver. drivers::red::recibir_en queda como primitiva del driver para futuras herramientas de diagnóstico.

Verificada con cargo test -p akasha (6 pruebas verdes) y con QEMU headless + -object filter-dump. En 60 s de captura: 11 AnunciarRaiz con Δ promedio 5.86 s, un ARP request + reply y el saludo en texto plano de pregon. La casa ya tiene su propio idioma de red — y un faro que late.

Líneas abiertas posteriores: una pila ARP/IP/UDP mínima para los apps; un peer real en una segunda VM para ver la replicación end-to-end AnunciarRaiz → SolicitarObjeto → ProveedorObjeto; un indicador AoE en la barra de tareas que pinte los contadores de ResumenAkasha; reciclado de las ranuras de ventana cerradas; audio con varias voces.

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.