feat: guardián no_std de núcleos compartidos + doc de integración renaser
Endurece y documenta la integración renaser↔brahman tras el piloto mirada-layout. - scripts/check-shared-cores.sh: compila cada núcleo compartido registrado para x86_64-unknown-none. Si un núcleo recobra `std` en silencio (dep descuidada), falla aquí y no semanas después en renaser. Hoy cubre mirada-layout. - docs/renaser-integracion.md: por qué renaser es un workspace aparte, el modelo núcleos-duales/superficies-por-plataforma, cómo se hace no_std un núcleo, y el estado del plan por etapas. Paso 2 (converger el CAS) DESCARTADO tras leer el código: arje-cas (blobs SHA256 sobre FS), renaser/almacen (DAG blake3+postcard sobre virtio-blk) y minga-core (Merkle-AST con hash estructural) son tres capas distintas, no una duplicación — converger impondría una abstracción equivocada. Razonado en el doc. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
2 qillqakuna · +154 −0
- docs/renaser-integracion.md +94 −0
- scripts/check-shared-cores.sh +60 −0
diff --git a/docs/renaser-integracion.md b/docs/renaser-integracion.md
new file mode 100644
index 0000000..c465c4e
--- /dev/null
+++ b/docs/renaser-integracion.md
@@ -0,0 +1,94 @@
+# renaser ↔ brahman — integración en el monorepo
+
+`renaser` es un kernel bare-metal SASOS (espacio de direcciones único,
+no-POSIX, `no_std`, x86_64). Vive en `renaser/` dentro de este repo. Este
+documento explica **cómo** convive con brahman y **qué** comparten.
+
+## Por qué un workspace de Cargo aparte
+
+renaser está en el mismo repo git pero es **su propio workspace de Cargo** —
+no un miembro del de brahman. Tres incompatibilidades lo imponen:
+
+| | brahman | renaser |
+| --- | --- | --- |
+| toolchain | `stable` | `nightly` (artifact-deps, `rust-src`) |
+| `panic` | unwind (lo necesita tokio) | `abort` (sin SO no hay unwinding) |
+| `cargo build` en la raíz | compila todo para el host | el kernel jamás debe compilarse para el host |
+
+`[profile]` y `rust-toolchain.toml` son **globales al workspace**: no se pueden
+mezclar. Por eso `brahman/Cargo.toml` lleva `exclude = ["renaser"]` y
+`renaser/Cargo.toml` es un `[workspace]` raíz independiente, con su propio
+`rust-toolchain.toml` y `.cargo/`. Cargo los trata como ajenos; los crates
+compartidos se referencian por `path` cruzando la frontera.
+
+## El modelo: núcleos duales, superficies por-plataforma
+
+La integración **no** es «cada crate compila para los dos lados». Es:
+
+- **Núcleos** — lógica pura (`*-core`, geometría, contratos). Se hacen
+ `no_std + alloc` y se comparten: el mismo crate compila para Linux y para
+ `x86_64-unknown-none`.
+- **Superficies** — IO y plataforma (daemons tokio, `sled`, gpui, smithay,
+ init con `nix`/`libc`; del lado renaser, el kernel y sus drivers). **No** se
+ comparten: cada plataforma tiene la suya. renaser no «importa» smithay;
+ provee su propio framebuffer.
+
+Un crate gana el tratamiento `no_std` **sólo cuando renaser de verdad lo
+enlaza**. La mayoría de brahman (apps gpui, ERP, transpilador, daemons) nunca
+corre en renaser y se queda `std`.
+
+## Núcleos compartidos
+
+| crate | rol | consumidor renaser |
+| --- | --- | --- |
+| `mirada-layout` | motor de teselado del compositor (geometría pura) | kernel, Fase 8 (compositor) |
+
+Cómo se hace `no_std` un núcleo (patrón de `mirada-layout`):
+
+1. `#![cfg_attr(not(test), no_std)]` + `extern crate alloc;` — los tests
+ siguen corriendo con `std`; el crate enviado es `no_std`.
+2. `std::collections` → `alloc::collections`; `Vec`/`vec!` → `use alloc::…`.
+3. Punto flotante (`sqrt`/`ceil`/`round`) → crate `libm` (no están en `core`).
+4. `serde` opcional tras una feature: los consumidores Linux la activan, el
+ kernel no.
+5. Dependencias declaradas directas (no `workspace = true`): un núcleo que
+ cruza fronteras de workspace se mantiene autocontenido.
+
+### El guardián
+
+`scripts/check-shared-cores.sh` compila cada núcleo registrado para
+`x86_64-unknown-none`. Si un núcleo recobra `std` (p. ej. al añadir una
+dependencia descuidada), falla ahí. **Correrlo tras tocar un núcleo
+compartido.** Al promover un crate nuevo, añadirlo al array `CORES` del script.
+
+## Plan por etapas — estado
+
+- **Paso 0 ✅** — renaser movido a `renaser/`, workspace propio, `exclude`.
+- **Paso 1 ✅** — `mirada-layout` → `no_std`; el kernel de renaser lo
+ `path`-depende cruzando workspaces. Mecanismo validado.
+- **Paso 2 — descartado.** El plan era «converger el CAS». Al leer el código
+ no se sostiene: son **tres capas distintas**, no una duplicación.
+ - `arje-cas` — blobs SHA256 sobre el sistema de archivos. SHA256 lo fija el
+ contrato `Card` (`module_sha256`); es una *superficie* Linux.
+ - `renaser/almacen` — DAG de objetos (payload + hijos), hash
+ `blake3(postcard)`, log sobre virtio-blk. Es una *superficie* bare-metal.
+ - `minga-core` — Merkle-AST con hash **estructural** (`hash_components`,
+ campo a campo, no `blake3(postcard)`): un esquema deliberadamente
+ distinto que permite verificar un nodo sin los bytes de sus hijos.
+ - Forzar un núcleo común impondría una abstracción equivocada (romper la
+ verificación estructural de minga, o cambiar el SHA256 del protocolo
+ `Card`). Lo único común —un newtype de hash de 32 bytes— no justifica
+ tocar el kernel verificado.
+- **Paso 3 — pendiente, bloqueado.** Converger el ABI WASM/`Card`. Requiere
+ primero unificar `wasmi`: brahman usa `0.40`, renaser `1.0`.
+- **Paso 4 ✅** — el guardián `no_std` (`scripts/check-shared-cores.sh`).
+
+Fase 8 de renaser (su propia hoja de ruta): el kernel usa `mirada-layout` para
+el compositor, con su framebuffer nativo.
+
+## Construir
+
+- brahman: `cargo build` en la raíz (ignora `renaser/`).
+- renaser: `cd renaser && cargo build -p boot` (kernel + imagen UEFI) o
+ `cargo run -p boot` (+ QEMU). Toma su toolchain nightly automáticamente.
+- guardián: `./scripts/check-shared-cores.sh`.
diff --git a/scripts/check-shared-cores.sh b/scripts/check-shared-cores.sh
new file mode 100755
index 0000000..b335a59
--- /dev/null
+++ b/scripts/check-shared-cores.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+# =============================================================================
+# brahman :: check-shared-cores.sh — guardián no_std de los núcleos compartidos
+# -----------------------------------------------------------------------------
+# Algunos crates de brahman son NÚCLEOS COMPARTIDOS: lógica pura que también
+# compila el kernel bare-metal de renaser (ver docs/renaser-integracion.md).
+# Para seguir siéndolo deben permanecer `no_std` — y eso se rompe en silencio
+# con sólo añadir una dependencia que arrastre `std`.
+#
+# Este script es la red de seguridad: compila cada núcleo registrado para
+# `x86_64-unknown-none` (el target del kernel de renaser). Si un núcleo
+# recobró `std`, la compilación falla aquí y no semanas después en renaser.
+#
+# Uso: ./scripts/check-shared-cores.sh
+# Sale 0 si todos los núcleos compilan no_std; 1 si alguno falla.
+# =============================================================================
+set -euo pipefail
+
+# --- Núcleos compartidos registrados -----------------------------------------
+# Al promover un crate a núcleo compartido (hacerlo `no_std` y enlazarlo desde
+# renaser), añádelo a esta lista. Es el contrato: lo que está aquí, renaser lo
+# puede consumir; mantenerlo no_std es obligatorio.
+CORES=(
+ mirada-layout # motor de teselado del compositor (Fase 8 de renaser)
+)
+
+TARGET="x86_64-unknown-none"
+
+cd "$(dirname "$0")/.."
+
+echo "guardián no_std — núcleos compartidos brahman ↔ renaser"
+echo "target bare-metal: ${TARGET}"
+echo
+
+# El target bare-metal debe estar instalado para el toolchain activo.
+if ! rustup target list --installed 2>/dev/null | grep -qx "${TARGET}"; then
+ echo "instalando el target ${TARGET}…"
+ rustup target add "${TARGET}"
+fi
+
+fallos=0
+for core in "${CORES[@]}"; do
+ printf ' %-20s ' "${core}"
+ if cargo build -q -p "${core}" --target "${TARGET}" 2>/tmp/check-core-"${core}".log; then
+ echo "ok — compila no_std"
+ else
+ echo "FALLA — recobró std o no compila bare-metal"
+ sed 's/^/ /' /tmp/check-core-"${core}".log
+ fallos=$((fallos + 1))
+ fi
+done
+
+echo
+if [ "${fallos}" -eq 0 ]; then
+ echo "todos los núcleos siguen siendo no_std (${#CORES[@]}/${#CORES[@]})."
+ exit 0
+else
+ echo "${fallos} núcleo(s) rompieron la garantía no_std."
+ exit 1
+fi