Medido en el worker, con el único cambio de /bin/sh en una copia por hardlinks del
lab (sed/grep/awk siguen siendo busybox) y stores tirables. Control busybox: 3/3
recetas selladas. brush: 0/3.
Lo que pasa: 56/57 del banco POSIX (igual que busybox), 0 rechazos sobre las 1130
fases de shell del corpus, parsea el configure de ffmpeg, funciona como argv[0]=sh
y con el patrón de las cards de arje.
Lo que falla: el configure corre entero pero el libtool que GENERA sale con un
nivel de escapado de menos en 25 líneas, y ese fichero ya no lo parsea ningún
shell. El parser de brush está bien — parsea sin quejarse el libtool del control.
Mecanismo exacto no determinado: echo, sustitución de comando y el propio
func_quote_for_eval de libtool dan idéntico en ambos shells aislados.
Y un dato independiente del bug: 813us de arranque contra 91us de busybox (8,9x),
sobre decenas de miles de shells por configure. El binario son 7,25 MB contra los
1,23 MB del busybox con sus 401 applets.
De paso: brush selló con el mismo hash que traía build-state del otro hub.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El §7.undecies dejó la bóveda declarada y a NADIE capaz de abrirla: ninguna
imagen traía un binario que sembrara `pacha_llavero::SEED_IDENTIDAD`. Esta es
esa unidad.
De las dos formas posibles entra `agora-cli`, y el motivo no es que sea mejor:
el wizard `churay-welcome-llimphi` SÍ tiene binario (medido: `src/main.rs` sin
`[[bin]]`, o sea que cargo lo descubre), pero decide además backend de IA,
dotfiles, fondo de pantalla y chasqui — la experiencia de primer arranque
entera, que no se decide dentro de una unidad del navegador.
⚠ Y antes de poder declararlo apareció lo que lo volvía imposible: sin
`AGORA_PASSPHRASE`, `Sesion::abrir()` caía en la frase de desarrollo
"agora-dev" con un aviso por stderr y un ✓ en pantalla. La cadena que eso toca:
frase → Argon2id → ChaCha20-Poly1305 que cifra la seed → la clave con la que
`boveda` descifra su base. O sea, en una imagen de escritorio, la bóveda de
todo el mundo cerrada con una palabra escrita en el fuente, y nada que falle.
Arreglado en tawasuyu (`fd08dc03a`): variable > terminal (se pregunta, sin eco,
y DOS veces en la génesis, donde un error de tipeo no se nota hasta que la seed
ya no se recupera) > desarrollo sólo si no hay a quién preguntarle. La decisión
vive en una función pura con cuatro tests, probada AL REVÉS: con el brazo
`Preguntar` borrado falla con `left: Desarrollo / right: Preguntar`.
Pin `9967b02c` → `da5fb8968` ⇒ `b3:46529e14`, 1,9 M, sellado en el worker con
la guarda PEGADA al build. Mirado por dentro (regla 3) y probado como
artefacto, con control negativo: `identity new` + `unlock` deja
`user pacha:id:default: 32` en `/proc/keys`, y con la frase equivocada contesta
«autenticación fallida» y NO re-siembra.
El muro del `Cargo.lock` por cuarta vez, con la causa cambiada: esta vez no la
puso quien tocó el lock sino otro agente que metió `shuma-taller` en un
`Cargo.toml`. Cerrado en el worker, donde el registro está completo: +1 línea.
Y el lock del árbol compartido traía otra vez el malo (índice y árbol con dos
versiones distintas, las dos rotas), así que el commit se armó con
`commit-tree` sin pasar por el índice.
Corrección al §7.undecies: el verbo es `agora-cli unlock`, no
`agora-cli identity unlock`.
El guardián de coherencia pasa de SEIS lugares a SIETE, con su cuarto control
negativo; los cuatro, en verde.
Queda: la herencia del llavero de SESIÓN entre procesos hermanos (sin medir —
y `/proc/keys` como root no la mide), y `pacha`/`pacha-secretos` en
`perfil.servidor` con el mismo hueco.
Medido contra el artefacto sellado (401 symlinks) cruzado con build-state.json:
148 applets ya tienen dueño sellado Y en perfil, 125 tienen dueño sellado que no
viaja en ninguna imagen (uutils, brush, findutils, diffutils, arje-zero, hammerd),
y de los 128 sin dueño 105 son basura que se borra.
Dos hallazgos que cambian el plan: busybox entra a los 7 perfiles como dep de BUILD
de 24 recetas, no como raíz de producto en targets.toml; y brush (shell Rust) ya
está sealed, sin validar y sin perfil.
docs/state/busybox-applets.tsv es la tabla applet-por-applet (generada), con 24
parejas marcadas NO-drop-in.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cierra el renglón que quedaba en vuelo cuando se commiteó la sección: `boveda` `b3:5c43a827` (22 M)
y `shuma-pregunta` `b3:cd4277c5` (21 M), selladas en el worker.
Y miradas por dentro, que es la regla 3: el árbol del artefacto trae el binario, el `.desktop` del
§7.decies y nada más, y `strings` encuentra en el ELF el aviso del arreglo («NO se levanta el socket
del navegador»). Que el arreglo esté en el commit no dice que esté en el binario: es exactamente la
lección del §7.quinquies, donde el host conocía los verbos y la función igual no existía.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seguir con lo que el §7.decies dejó abierto —quién levanta la app, de dónde sale la raíz de las
claves— terminó en una respuesta incómoda y en un bug que valía la pena encontrar.
La cadena, medida hacia atrás desde la app:
· `raiz_de_identidad()` saca la seed del llavero del KERNEL (`pacha_llavero::SEED_IDENTIDAD`);
· la escriben dos lugares en todo tawasuyu: `agora-cli identity unlock` y `churay-welcome-runner`;
· `agora-cli` está sellado y en `perfiles: []` — en ninguna imagen. Y aunque se declarara, su pin es
del 2026-06-18, donde no existen ni `SEED_IDENTIDAD` ni `desbloquear` (git grep sobre el pin, con
HEAD de control: 4 y 1 aciertos);
· `churay-welcome` no tiene receta en takana.
⇒ en ninguna imagen hay un binario capaz de sembrar la identidad. No es que el usuario no la
desbloqueó: es que no tiene con qué.
Y lo que el navegador veía NO era «cerrada». Cuando `abrir()` falla, la app levantaba el socket
igual, sobre `bóveda_imposible()` —un sled en /tmp/boveda-sin-abrir-<pid>—, así que la extensión
recibía `locked:false, count:0` y un `vault.save` consentido guardaba en un temporal que muere con
el proceso. La ventana decía la verdad; el navegador, lo contrario. Arreglado en tawasuyu
(`7917fbb96`) con test de regresión en los dos sentidos, y probado al revés: con el `if`
neutralizado, el test falla con el mensaje que corresponde.
Pin de las dos recetas a `6f0408d40`, que trae además el `Cargo.lock` cerrado. Ahí apareció la
vuelta que no estaba escrita: la «operación mínima» del §7.octies (`cargo metadata` sin `--locked`)
corrida en una jaula con el registro de cargo INCOMPLETO devuelve 0 y deja un lock al que le faltan
dos miembros del workspace — y su diff se ve MÁS mínimo que el correcto (−15 líneas contra +1). Que
diera byte a byte igual al de otra sesión no lo confirmaba: las dos se calcularon con el mismo
instrumento roto.
Y una trampa más, medida hoy: la guarda de receta del §7.quinquies.bis NO alcanza para una TANDA.
Puesta una vez al principio, `shuma-pregunta` selló bien y `boveda` —once minutos después— dio
«artefacto ya en el store» sobre la receta VIEJA, porque el latido revierte el árbol del worker en
el medio. La guarda va pegada a CADA build, y la cura de fondo es publicar la receta antes de
construir.
De paso, dos correcciones a lo que este mismo frente escribió hace unas horas:
· el `app_id`: llimphi SÍ lo pone (`with_name`, con el nombre del ejecutable de piso) ⇒ la ventana
es `boveda`, igual que el basename del `.desktop`, y por eso no hace falta `StartupWMClass`. Lo
que sí queda mal es el TÍTULO, que dice «llimphi»;
· el GL: que las imágenes sean iris-only no es una decisión pendiente sino una escrita (SDD 14), y
el caso de la VM ya tiene camino — los runbooks montan `mesa-llvmpipe` como capa.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El §7.novies dio la función por cerrada: las seis etapas del guardián de metal en verde, con el
navegador de verdad y el diálogo a la vista. Lo que seguía abierto era la decisión 1 del §7.sexies
—«en qué imágenes se declaran»—, escrita como NO mientras ninguna app llimphi pudiera pintar. Ese
motivo se cayó el 2026-09-18, así que antes de tomarla se volvió a medir en vez de darla por sabida:
atuq sealed perfiles=[cosmic, gnome, kde, sway]
puriy-costura sealed perfiles=[cosmic, gnome, kde, sway]
boveda sealed perfiles=[]
shuma-pregunta sealed perfiles=[]
`sealed` con `perfiles: []` es sellado ≠ instalado: la lección de `foot`, que targets.toml repetía
QUINCE veces antes de hoy y que igual volvió a morder. Las dos entran a los cuatro perfiles de
escritorio, las dos o ninguna —sin el dueño `vault.match` no ofrece nada; sin el diálogo,
`Command::new` falla y TODO `vault.fill` se deniega—: media bóveda es una que niega todo en
silencio. ~43 M por imagen (22 M + 21 M medidos), contra los ~1,25 GiB que ya lleva el §6.7.
Y al declararlas apareció el hueco de una capa más arriba: la receta instalaba `/usr/bin/boveda` y
nada más, y los lanzadores de los cuatro escritorios leen `/usr/share/applications`. La app viajaría
en la imagen sin existir para quien la usa — la misma forma de fallo que esto viene persiguiendo.
Entra `boveda.desktop`, con tres cosas medidas antes de escribirlo:
· el icono existe: `dialog-password` está en breeze-icons (6), adwaita (1) y cosmic-icons (2). El
cuarto perfil lleva sólo hicolor, que no trae iconos: ahí cae al genérico, que es degradarse;
· lo acepta el `desktop-file-validate` del store, con `atuq.desktop` de control. Deja un hint sobre
`Security`, y las dos formas de callarlo lo cambian por uno PEOR (dos categorías principales ⇒ la
app aparece dos veces en el menú). Se queda como está;
· ⚠ y lo que NO puede hacer: emparejar la ventana con el lanzador. `llimphi_ui::run` no llama nunca
a `with_name` ⇒ winit no manda `set_app_id` y la ventana sale SIN app_id y con el título
"llimphi". Por eso no hay `StartupWMClass`. Vale para toda app llimphi; se arregla en llimphi.
La receta se reconstruyó en el worker con la guarda del §7.quinquies puesta (`### receta verificada
3f1072cc` antes de compilar nada, porque el latido revierte la receta cada media hora y un acierto
de caché sobre la vieja imprime SELLADA en cero segundos): `b3:b0c6adc4` ⇒ `b3:3f1072cc`, 22 M, con
el árbol mirado por dentro y la entrada dentro del artefacto.
Y el guardián de coherencia pasa de CINCO lugares a SEIS: el sexto es `targets.toml` —quién DECLARA
al dueño en la imagen—, con control positivo (`atuq` tiene que estar, o el chequeo está leyendo el
campo equivocado) y su propio control negativo, el tercero. Probado en los dos sentidos: cuatro
perfiles en verde, y `--negative-control-perfil` en rojo.
Abierto, y dicho como lo que es: quién levanta la app con la sesión (atado a la decisión 2 del
§7.sexies, la raíz de las claves), y que el único proveedor de GL de las cuatro imágenes es iris
—mesa-llvmpipe en ningún perfil—, que la bóveda hereda y no agrega.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>