GPUI panic-ea si no encuentra ninguna fuente del fallback
(.SystemUIFont → Helvetica → Cantarell → DejaVu Sans → ...).
Fedora minimal no trae fuentes — sin esto el greeter crash al
inicializar text_system.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GPUI (mirada-greeter) requiere libvulkan.so.1 al iniciar; sin un ICD
no levanta. mesa-vulkan-drivers trae lavapipe (Vulkan por software vía
llvmpipe), apto para VPS sin GPU real.
También se agrega seatd al hint (preferido sobre noop para producción
porque maneja VT-switching correctamente).
El check de runtime ahora detecta libEGL, libvulkan, libgbm y libseat.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sin clang-devel, los crates *-sys que corren bindgen (libinput-sys,
wayland-sys) fallan en runtime con 'couldn't find libclang.so'. El
mensaje de WARN ahora lo lista explícitamente.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- seed arje-prod gana dos Cards antes de getty-tty1:
* kmod-gpu (OneShot): modprobe virtio_gpu — pone /dev/dri/card0
listo antes de que el compositor intente abrir DRM/KMS.
* carmen-dm (Restart): /usr/bin/mirada-compositor --greeter --drm,
con MIRADA_GREETER_BIN apuntando a /usr/bin/mirada-greeter.
- install-arje-as-init.sh gana paso 1b: build nativo (no-musl) de
mirada-compositor y mirada-greeter. GPUI/Mesa/EGL son dinámicos
contra glibc — la cadena DM no puede vivir en el binario musl
estático de arje-zero. Si el build falla por dev-libs ausentes,
se imprime la lista de paquetes Fedora que faltan y se sigue
(la instalación de arje-zero no se rompe).
- En el paso de instalación, los binarios del compositor se copian
a /usr/bin/ sólo si el build de paso 1b tuvo éxito; ldconfig
comprueba libEGL en runtime y avisa si falta.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sin systemd ni NetworkManager, arje-zero quedaba sin red y sin sshd:
útil como bare init, inútil para sacar logs de una VPS sin pegado en
la consola web. Dos Cards nuevas en el seed prod:
- `net-up`: corre `/usr/sbin/arje-net-up` (script nuevo en scripts/),
que pone up todas las interfaces y arranca `dhclient -d` en
foreground sobre la primera no-loopback. Fallback a dhcpcd o
busybox-udhcpc si dhclient no está. Crea de paso /run/sshd y
/var/empty/sshd para que sshd no tenga que pelearlos. Restart
supervisión.
- `sshd`: corre `/usr/sbin/sshd -D -e` (foreground + log a stderr).
Usa las host keys que Fedora ya tenía. Restart supervisión.
El install script copia arje-net-up.sh a /usr/sbin/arje-net-up.
Prerequisito en el host (no automatizable desde acá): si la VPS no
tiene un cliente DHCP (Fedora Cloud trae sólo NetworkManager por
defecto), el script duerme con el link up y no obtiene IPv4. En ese
caso instalar antes del próximo boot: `dnf install dhcp-client`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Síntoma: el screenshot del usuario en la VPS Hetzner mostraba systemd
booteando y se quedaba congelado en el último printk del kernel justo
antes del switch-root. arje-zero arrancaba bien pero su salida iba al
serial invisible.
Causa: el cmdline traía `console=tty1 console=ttyS0,115200` — y el
kernel hace que `/dev/console` apunte al ÚLTIMO `console=`, así toda la
salida de stdout/stderr de arje-zero (tracing + banner de la rescue
shell) caía en ttyS0 (serial), no en la VGA que muestra noVNC.
Dos arreglos:
- Orden de consolas invertido en el menuentry → `/dev/console` = tty1
(lo que efectivamente se ve en la consola web del proveedor).
- arje-zero también escribe a `/dev/kmsg` (ring buffer del kernel), que
el kernel hace eco a TODAS las consolas registradas — el mecanismo
que usa systemd para que sus mensajes salgan tanto en VGA como en
serial. Defense in depth: el banner de rescue y un eco temprano
«despierta como PID 1» aparecen sí o sí en cualquier consola.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Desde Fedora 34 / RHEL 9, /boot/efi/EFI/<distro>/grub.cfg es un wrapper
que sourcea /boot/grub2/grub.cfg — y grub2-mkconfig se niega a
sobreescribirlo ("will overwrite the GRUB wrapper. Please run [...] on
/boot/grub2/grub.cfg instead"). Mi loop de detección lo encontraba
primero y fallaba. Apuntamos directo al canónico.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El `>/dev/null` del paso 1 ocultaba lo que pasaba: si faltaba un
prerrequisito o el build moría, sólo se veía «paso 1/5» y el script
salía silencioso. Cambios:
- Paso 0 nuevo: chequeo de cargo / musl-gcc / busybox / cpio / gzip /
rust target con mensajes accionables por distro (Fedora + Debian).
- El build de cargo deja fluir su salida a la terminal — incluida la
espera de 10-20 min la primera vez, así no parece un cuelgue.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diagnóstico: en el VPS Fedora arje-zero caía como PID 1 y el cmdline
traía `panic=10`, así que el kernel rebooteaba cada 10 s. Tres causas
encadenadas, todas arregladas:
1) **Cmdline `ro` + sin `/run` tmpfs.** El menuentry montaba `/` como
sólo lectura (systemd lo remonta rw temprano; arje no). Sin eso, el
socket del bus interno se intenta crear sobre un FS de sólo lectura
y falla con EROFS → spawn_bus devuelve Err → PID 1 sale → kernel
panic. arje-kernel ahora remonta `/` rw en el bootstrap y monta
`/run`, `/tmp`, `/dev/pts`, `/dev/shm` como tmpfs — superficies
escribibles aunque la raíz quede ro.
2) **PID 1 saliendo en cualquier `?`.** Doctrina dura nueva: PID 1
NUNCA puede salir. Cualquier error de arranque ahora cae a una
`emergency_shell()` que imprime el diagnóstico en `/dev/console`,
abre `/bin/sh` y, si la shell muere, la reabre — así el operador
puede reparar en vez de mirar la máquina reiniciarse en bucle.
3) **El script no conocía grub2 (Fedora).** `install-arje-as-init.sh`
sólo probaba `update-grub` (Debian) y `grub-mkconfig` (Arch). Ahora
detecta `grub2-mkconfig` y resuelve el `grub.cfg` correcto
(UEFI/BIOS, fedora/redhat/centos/almalinux/rocky). El menuentry
también pasa de `ro` a `rw` — el remount es belt-and-suspenders.
Mismo arreglo en `uninstall-arje.sh`.
Renaser intacto: estos cambios son Linux-side puro (arje-kernel y
arje-zero usan nix/libc/tracing); renaser sólo comparte mirada-layout y
formato, ninguno tocado.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
Nuevo crate `crates/init/arje-absorb`: lee la configuración de un init
clásico y la traduce a una Tarjeta Semilla (Card JSON) con cada
servicio como hija genesis de arje-zero. El paso «absorber» de la
migración a arje — para no perder los servicios al cambiar de init.
- Absorbers: sysvinit (/etc/inittab), runit (runsvdir o /etc/sv),
dinit (/etc/dinit.d), openrc (/etc/runlevels). Autodetección.
- Modelo intermedio ForeignService → Card vía brahman-card (validado).
- `--with-carmen`: agrega carmen-dm (gestor de login gráfico).
- CLI: --from/--root/--output/--label/--with-carmen. 24 tests, clippy
limpio.
`scripts/migrate-to-arje.sh`: orquesta absorber → validar → (carmen:
compila+instala mirada dinámico) → install-arje-as-init.sh. El init
viejo queda intacto; arje se elige en GRUB. --dry-run no toca nada.
systemd no se absorbe (units no son texto trivial) — para systemd
sigue la capa de shims + seeds/arje-host.card.json.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El rename ente→arje dejó referencias stale al binario PID 1 y a los
shims. Los nombres reales (verificados con cargo metadata) son todos
arje-*: arje-zero, los 14 arje-*-compat, arje-echo, arje-policy-provider,
arje-bus, arje-brain.
- build-arje-initrd.sh, install-arje-as-init.sh, uninstall-arje.sh,
run-arje-qemu.sh: `-p ente-*` → `-p arje-*`, paths /sbin/arje-zero y
/usr/sbin/arje-*, RUST_LOG arje_zero=info.
- seeds/arje-prod y arje-host: los exec `/usr/sbin/ente-*-compat`
apuntaban a binarios que no existirían tras instalar — corregidos a
`/usr/sbin/arje-*`. (validate.sh no chequea exec, por eso «validaban»
igual; al boot real habrían fallado.)
Intactos a propósito: `/ente/` (directorio canónico de la Semilla) y
`ente.slice/*` (jerarquía cgroup). Las 3 seeds validan.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Flujo seguro de adopción: arje se instala como entrada GRUB
alternativa, no toca systemd ni /sbin/init. Booteás arje cuando
querés, volvés a systemd si rompe (rollback instantáneo desde el
menú).
Artefactos nuevos:
- scripts/install-arje-as-init.sh: instala binarios musl-static a
/usr/sbin/ y /usr/bin/, copia seed a /ente/seed.card.json, agrega
menuentry "arje" a /etc/grub.d/40_custom usando init=/sbin/ente-zero
con kernel + initrd nativos. NO cambia GRUB_DEFAULT. Idempotente
(regenera el bloque ARJE-MENUENTRY si existe).
- scripts/uninstall-arje.sh: revierte binarios + menuentry. Conserva
/ente/seed.card.json por si la editaste.
- seeds/arje-host.card.json: seed para máquina real con 15 cards:
tmpfiles + mount-fstab + swap-on + dbus-system + 11 compat shims +
dhcpcd + sshd + agetty. Validada.
- docs/arje-replace-systemd.md: filosofía vs systemd ("no acapara
porque no genera, sólo arranca lo declarado"), lista exhaustiva de
servicios systemd que NO deben migrarse (ModemManager, snapd, cups,
unattended-upgrades, etc.), tabla diferencial de UX vs systemd
(systemctl restart → kill PID, systemctl enable → editar seed),
checklist pre-primer-boot, instrucciones de rollback y cómo hacer
arje default sólo cuando estés seguro.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Para "ver" la administración del init desde el shell que arrancó dentro
del initramfs hacían falta clientes que hablen los 4 sockets Unix. Los
exists como examples de cada crate; los empaquetamos ahora.
build-arje-initrd.sh:
- cargo build --example brahman-status -p brahman-admin
- cargo build --example busctl -p ente-bus
- cargo build --example brainctl -p ente-brain
- Copia los 3 a /usr/bin/ del initrd.
docs/arje-boot.md §6b reescrita con:
- Tabla de sockets corregida (defaults a /tmp/ cuando no hay
XDG_RUNTIME_DIR/TMPDIR, que es el caso en initrd).
- Cookbook de los 3 CLIs con ejemplos de sesión típica dentro de la VM.
- Nota para vendorear socat-static via EXTRA_BINS si querés conectar
crudo a un socket.
§1 layout actualizado con /usr/bin/{brahman-status,busctl,brainctl}.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sin musl, PID 1 panic con "error while loading shared libraries:
libgcc_s.so.1" porque el initramfs no incluye libgcc/glibc/ld-linux.
Solución estándar: target x86_64-unknown-linux-musl produce un ELF
totalmente estático.
Cambios en scripts/build-arje-initrd.sh:
- ARJE_TARGET=x86_64-unknown-linux-musl por default (override con env).
- Chequeo del target instalado antes de buildear; mensaje accionable
con los comandos exactos (rustup target add..., apt install
musl-tools, etc.) si falta.
- Sanity check con `file`: aborta si ente-zero quedó dinámico.
- Sanity check para busybox: aborta si el BUSYBOX_BIN apunta a un
binario dinámico (la otra causa #1 de panic).
- BIN_DIR ahora apunta a target/$TARGET/release/.
Docs (docs/arje-boot.md):
- §2a explica el porqué de musl.
- §2b lista requisitos del host (rustup target, musl-tools, busybox-static).
- §7 sección nueva de troubleshooting con el síntoma exacto del
libgcc_s panic + 3 escenarios comunes más.
- Checklist pre-deploy actualizado con el chequeo de "statically linked".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Iter 22. Cierra el set de hoy: future-me (o cualquier nuevo collab)
levanta el escenario completo con un comando.
crates/apps/brahman-demo/ con 3 binarios:
- brahman-demo-broker: Server::bind standalone con Broker. Reemplaza
a ente-zero para demos (ente-zero es PID 1 con kernel surface,
child subreaper, bus, brain, audit — overkill).
- brahman-demo-producer: Card con flow.output[demo-stream:json].
- brahman-demo-consumer: Card con flow.input[demo-feed:json] —
mismo type → matchea con producer.
Env vars en los 3: BRAHMAN_INIT_SOCKET, BRAHMAN_BROKER_CONTEXT,
BRAHMAN_DEMO_LABEL/FLOW/TYPE, RUST_LOG.
scripts/bootstrap-demo.sh:
- Modes: all (default) / broker / only.
- Cleanup-safe: trap mata todos los PIDs spawneados (SIGTERM grace
+ SIGKILL fallback) y borra el socket.
- Espera al socket antes de spawnear (evita ENOENT en handshake).
- Logs separados por proceso bajo $BRAHMAN_DEMO_LOG_DIR.
Smoke end-to-end (sin DISPLAY): consumer recibe MatchEvent
{ Available, demo-feed ← demo-stream, via: Exact, pinned: false }
automáticamente cuando entra el producer. Match fluye por el push
channel del broker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>