SDD 25 §4 dejó el hallazgo escrito y sin guardián: los kernels de hammer se
construyen sin CONFIG_MEMCG, `memory.max` no existe, y arje descarta el error
al escribirlo ⇒ una Card pide un tope de memoria, corre SIN tope, y la única
huella es un `warn!`. Nadie lo veía porque la máquina de desarrollo SÍ trae
MEMCG: el fallo sólo existe del lado del artefacto sellado.
`hammer kernel contract` declara qué pedazos de interfaz de kernel usa el
userland POR NOMBRE (con consumidor, fichero y CÓMO FALLA HOY si no está) y los
comprueba contra un `.config` YA PRODUCIDO — no contra la receta: entre el
`scripts/config -e X` y el `.config` hay un `olddefconfig` que puede tragarse el
símbolo en silencio.
Por perfil, no global — misma lección que el gate de hardware: `linux.toml` es
el kernel de QEMU del selfhost-verify, no hospeda Cards, y su hash es
load-bearing del baseline `of_tree`. Exigirle contabilidad de memoria sería
rechazar una receta sana.
Medido sobre el store: **2 de 11 configs sellados cumplen su perfil**; los 9
`anfitrion-cards` fallan por MEMCG (apagado A MANO: `# CONFIG_MEMCG is not
set`) y les falta PSI. El kernel vivo de esta máquina pasa las 11 exigidas —
que es exactamente por qué el bug sobrevivió.
Distingue apagado explícito de ausente (un símbolo que el .config ni nombra
puede ser un renombrado entre versiones), y un kernel sin perfil declarado
queda SIN COMPROBAR en vez de contar como aprobado.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACUcwo9mZsE5ocYVE9npih
En Debian `patch` entra de regalo dentro de `build-essential`; al desglosar la rama dnf a
gcc/g++/make sueltos se cayó sin que nadie lo notara. El campo `patches = [...]` de una
receta lo aplica hammer DEL LADO DEL HOST, fuera del sandbox, así que no alcanza con que
el rootfs lo traiga —lo trae, `/usr/bin/patch` está en el alpine de los dos labs— y por
eso el diagnóstico "rootfs laptop ≠ worker" no aplicaba acá.
Medido en dev.gioser.net: `cairo-shared` moría con `spawn patch: No such file or
directory` y detrás caían `pango` y `gtk4`. El stack GUI entero de GNOME por un binario
de 129 KB ausente en el host.
Regla que queda escrita: toda herramienta que hammer invoque HOST-SIDE va en esta lista,
no en `[deps]` de la receta — declararla en la receta re-hashearía cairo y todo GNOME
debajo, para arreglar algo que no es de la receta.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
Tercer sitio con la misma pregunta mal hecha, encontrado con el grep que la lección del
commit anterior pedía hacer: `has` (tapado 2026-08-10), `seal` (tapado hoy) y `hydrate`,
que seguía con `is_dir()` pelado. Un directorio vacío pasaba el chequeo, proyectaba 0
ficheros y devolvía un HydrateReport de éxito.
Duele especial acá porque el escritorio se hidrata así (`hammer hydrate <hash> --into`,
137/137 en KDE): un FHS proyectado desde nada sale «OK» y falla mucho más tarde, sin
rastro de qué artefacto faltaba.
Queda a propósito sin tocar `hammer-mirror::index`: ahí el vacío se autocorrige, porque
indexa por `of_tree` y el contenido difiere del origen ⇒ el sync lo trae.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
`has()` define presencia como «tiene al menos una entrada» —hay test desde hace tiempo—
pero `seal()` usaba `is_dir()`, que también es cierto para un directorio vacío. Con eso
`seal` devolvía Ok, tiraba el árbol recién construido, y el build logueaba `sealed` y
salía 0. Dos nociones distintas de «está» en el mismo struct, y la que decide si el
trabajo se guarda era la mala.
Medido en el worker dev.gioser.net: 1457 directorios vacíos en el store se comían cada
sellado. `openssl-threads` compilaba entero —headers, libcrypto.a, libssl.a, los .pc— y
sellaba NADA; python3 se construía después sin openssl y quedaba sin `_ssl`, y con eso
morían glib y 4 recetas más de GNOME. El error salía a tres recetas de distancia de la
causa y no nombraba openssl ni una vez. Probado quitando el vacío: el MISMO build sella
150 ficheros con OPENSSL_THREADS, mismo hash.
Se usa `remove_dir` y no `remove_dir_all`: sólo tiene éxito sobre un vacío, así que si
algo dejó contenido ahí entremedio falla ruidoso en vez de borrar un artefacto bueno.
No mueve hashes (testigo zlib idéntico).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
Es el mismo fósil que el propio script documenta para GNOME, repetido con las colas
que nacieron después. Las 25 recetas en deuda de COSMIC no fallaban: nadie las
intentaba, porque su cola no estaba en la lista. Una cola ausente no da error, da
silencio — el mismo modo de fallo que "el corpus no está en las QUEUES del worker".
Se añade la regla en el comentario: cola nueva y línea QUEUES, en el mismo commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
16 tasas de Linux medidas en momento (KVM, 4 vCPU, bajo carga): piso de
syscall, /proc como API de texto, fork vs espacio de direcciones del padre,
enlazado dinámico, VFS, io_uring, THP, namespaces. Programas en C y salidas
crudas en docs/evidencia/tasas-kernel-2026-08-29/.
Lo que sale de medir y después verificar contra las recetas: los kernels de
hammer se construyen sin CONFIG_MEMCG (no está en x86_64_defconfig y no tiene
default y), y arje/sandokan escriben memory.max descartando el error. Un tope
de memoria pedido por una Card no se aplica y sólo deja un warn.
Tres resultados que contradicen el consejo de manual y quedan documentados:
THP 3x más lento que 4K con defrag=madvise, io_uring 2,8x más lento que pread
sobre tmpfs, y stat cuesta lo mismo en tmpfs que en ext4 (es tasa del VFS).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACUcwo9mZsE5ocYVE9npih
La cabecera decía 'def 408909310' y la línea 38 usa 417847948 desde el 2026-08-08.
La 408909310 es justo la que NO traía rust ni go — la que dejaba fuera al 76% del
catálogo — así que el comentario apuntaba a la imagen rota.
Un comentario que nombra un id concreto es una referencia, no prosa: si alguien lo
lee y re-apunta IMAGE a mano, revive el bug que el propio fichero documenta debajo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
Sexta de la familia. El arreglo estaba HECHO en disco desde hace horas y lo
reporté como cerrado, pero nunca llegué a commitearlo — sólo se vio al revisar
`git status` por otra cosa. Sin esto, el arreglo se perdía.