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>