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.
`cargo vendor --locked` sobre `fd08dc03a` muere con «cannot update the lock
file»: le faltaba la arista `shuma-taller`, que otro agente había metido en un
`Cargo.toml` sin el lock. Es la cuarta vez que este monorepo pone el mismo muro
(SDD 26 §7.quinquies.bis, §7.octies, §7.undecies).
Cerrado en el WORKER —sobre el árbol que takana ya había bajado, que es donde el
registro de cargo está completo—: +1 línea, cero checksums movidos. En la jaula
la misma operación devuelve 0 y borra miembros del workspace, con un diff que se
ve más mínimo que el correcto.
hash: b3:6520470e → b3:46529e14
La unidad 12 del SDD 26 quedó en esto (§7.undecies): la bóveda entró a las
cuatro imágenes y NADIE puede abrirla, porque ninguna trae un binario capaz de
sembrar `pacha_llavero::SEED_IDENTIDAD`. `agora-cli` es el único del corpus que
sabe hacerlo — y estaba sellado con `perfiles: []` y pineado al 2026-06-18,
donde el verbo todavía no existe (`git grep` sobre el pin: 0 y 0, con HEAD de
control dando 4 y 1).
Sube a `fd08dc03a`, que además trae el arreglo que este oficio vuelve
obligatorio: sin `AGORA_PASSPHRASE`, `Sesion::abrir()` caía en la frase de
desarrollo "agora-dev" con un aviso por stderr y un ✓ en pantalla. En una
máquina de trabajo es cómodo; en una imagen de escritorio es la bóveda de todo
el mundo cifrada con una palabra pública, porque el keystore va con Argon2id +
ChaCha20-Poly1305 bajo esa frase. Ahora con terminal se pregunta, sin eco y dos
veces al crear; la de desarrollo queda sólo para el caso sin terminal.
Y con el pin nuevo hace falta `cargo_vendor_dir`, que el pin viejo no
necesitaba: tawasuyu commitea su propio `vendor/` desde entonces.
hash: b3:e05c41f1 → b3:6520470e (sin construir todavía)
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>
`work_root` sale de `dirname(store)/work`, y con el store en `/store` el padre es `/`: todo el
scratch iba al overlay de 69 G de la jaula, que además es capa DESECHABLE — la caché de fuentes
vivía en algo que se tira. Mientras tanto `/dev/sdc`, 255 G, estaba al 9 %.
De los 6,8 G de `work/sources`, 5,4 G eran DOS COPIAS del mismo commit de tawasuyu: los árboles se
nombran por receta, no por commit, así que cada receta del monorepo cuesta otros 2,7 G. Queda
anotado que es deliberado (aislamiento del ADR 0012) y que no se deduplica de paso.
Arreglado con enlaces a `/work/sergio/work` en vez de con `TAKANA_WORK`: el override existe y
funciona, pero una docena de scripts llama a `takana build` y un export que hay que recordar se
olvida. Comprobado con un build real sin ninguna variable — rc=0, el árbol cayó en sdc y el hash
salió idéntico al de la corrida anterior. Overlay de 6,9 G a 14 G libres.
Anotado también que el worker NO tiene este problema (un solo disco de 196 G), que los enlaces se
van si la jaula se rehace, y que la premisa del `seal` (rename atómico ⇒ mismo filesystem) ya
estaba rota en el hub antes de esto, porque `/work` y `/store` son discos distintos.
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>
`jaula-herramientas.sh` deja el compilador, y eso alcanza hasta que algo toca una
biblioteca de C. `mirada-compositor` moría en su build script con «The
PKG_CONFIG_PATH environment variable is not set», y el mensaje engaña: las
dieciocho bibliotecas están en el store. Lo que no había era dónde verlas juntas
— los `.pc` del corpus declaran `prefix=/usr` porque se miran desde el sandbox de
`takana build`, que monta la clausura ahí.
La lista sale de `recipes/mirada-compositor.toml`, no de una copia que se pudra.
Se le suman dos cosas que ninguna receta nombra y que un sysroot a mano sí
necesita: `musl` (adentro del sandbox la libc la pone el sandbox; sin sus
cabeceras bindgen lee las de glibc y muere en 'stddef.h' file not found) y las
gemelas `<dep>-shared` cuando existen (la receta pide zlib/expat/libffi
estáticas, pero el producto es dinámico y al CORRER pide las .so).
Tres cosas que sólo aparecieron haciéndolo:
· La granja espeja el ÁRBOL ENTERO, no `/usr`. El primer intento perdía
`linux-pam` completo, que instala en /lib64 — y no falló compilando: falló con
el binario ya enlazado tomando el libpam de Arch y muriendo en __memcpy_chk.
· Los `-L` van explícitos y derivados de la granja. pkg-config sólo emite el del
módulo que le preguntan, y `pam-sys` no usa pkg-config: emite `link-lib=pam` y
nada más. Con el sysroot a medias eso daba verde porque lld caía al /usr/lib de
Arch; con el sysroot completo dice la verdad y no enlaza.
· El control corre `xkb_keysym_from_name` y no `xkb_context_new`: el contexto
necesita los datos de xkeyboard-config, que no están en la clausura, y el
control moría por algo que no estaba midiendo.
Medido adentro de la jaula, con el ambiente limpio (todo sale de la config de
cargo): `cargo build -p mirada-compositor` en 5m13s, y el binario arranca, elige
el backend DRM y llega hasta donde la jaula lo deja. Sin regresión: `format`
compila y los 14 tests de `llimphi-cpu` pasan.
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>
cargo exporta `CARGO=<ruta del binario REAL>` —el del store, no el envoltorio— y
hay macros que lo ejecutan: `proc-macro-crate` corre `$CARGO locate-project` para
ubicar la raíz del workspace. Adentro de la jaula ese exec moría con «No such
file or directory», que acá miente: el fichero existe y es ejecutable, el que
falta es el INTÉRPRETE. `crate_name()` devolvía Err y el derive `Type` de
zvariant caía a su última rama, `::zvariant` en vez de `::zbus::zvariant`:
error[E0433]: cannot find `zvariant` in the crate root (atspi-proxies 0.13.0)
Eso se lee como un defecto del lock del repo ajeno y NO lo es. Con el cargador
puesto en /lib, `llimphi-ui` de tawasuyu —winit + accesskit + wgpu— compila
entero en 2m17s. La clase es más grande que el caso: cualquier herramienta que
re-ejecute `$CARGO` o `$RUSTC` por ruta absoluta se rompía igual, en un crate
ajeno y a diez capas del origen.
El envoltorio ya prefería el cargador de la caja (`[ -x /lib/ld-musl… ]`); lo que
faltaba era ponerlo cuando no está. En la caja, que es musl, el guion se aparta.
Y va con su control, porque los trece de antes NO lo veían: todos entran por el
envoltorio. Brazo de control corrido con un cargador falso — los trece en verde y
el nuevo en rojo, que es exactamente el hueco.