El diseño es la parte que vale: NO SELLA NADA. Modificar una receta le cambia el ArtifactHash, así
que medirlo a lo bruto habría dejado una docena de duplicados basura en un store que se respalda. En
vez de eso se inyecta `set -e` en cada fase Y un `exit 77` al final de la última: el build siempre
falla, nunca sella, y el veredicto se lee en el código de salida — 77 significa que todas las fases
corrieron enteras bajo set -e. Queda en scripts/farm/exp-ec.sh.
Muestra de 12 recetas ligeras (los pesos pesados quedan fuera por tiempo, y el sesgo va declarado):
10 sobreviven sin tocar nada, 1 se rompe, 1 inconcluso por timeout.
El que se rompe es `e2fsprogs`, y mirarlo de cerca cambia lo que significa: su ./configure aborta con
`external uuid library not found` pese a que la receta pasa --disable-libuuid, y hoy eso se traga
—comprobado: la misma receta sin set -e y con exit 77 LLEGA al 77—. Pero el artefacto que sella está
bien: 149 ficheros con e2fsck, mke2fs, los cuatro fsck.ext* y los mkfs.ext*. O sea que ahí `-ec` no
atrapa un bug: rompe una receta que funciona. Ése es el coste, y es el número que no se podía
adivinar leyendo: ~8%, unas 8 recetas sobre las 96 expuestas.
También se corrige el recuento: 96, no 89. El 89 salía de restar 142−53 dando por hecho que las 53
con `set -e` propio estaban todas dentro de las 142, y no lo estaban.
jaula-preparar suma lo que hizo falta para poder correr todo esto desde adentro: rsync/python3/jq/
cargo enlazados del store, y el cargador de musl, sin el cual python3 y cargo no arrancan en una
imagen glibc.
Cuarto defecto de la misma familia que los tres que el script ya repone, encontrado construyendo
DESDE la jaula: los binarios que el agente necesita no están en la imagen de Arch, pero sí sellados
en `/store`, que la instancia ya tiene concedido. Son musl estáticos y corren dentro de una imagen
glibc, así que no hay que instalar nada — sólo enlazarlos.
El que costó encontrarlo es `patch`: takana aplica los parches FUERA del sandbox, o sea que lo busca
en el PATH de la jaula, no en el del lab. `wtype` (sin parches) construía y `zsh` (con seis) moría en
`spawn patch: No such file or directory`. El `patch` del lab no sirve de nada acá: es musl DINÁMICO
y no arranca en una imagen glibc.
Los wrappers ya viven en /work/<usuario>/bin, que es bind del anfitrión y sobrevive al recreate; lo
único que se pierde es el enlace en el PATH.
El agente que trabaja enjaulado encontró y arregló tres defectos a mano, pero viven en el `upper`,
que por el D3 del ADR 0015 es caché descartable: al primer `recreate` se pierden. Esto es esa mano,
escrita.
1. No hay entrada en /etc/passwd para el uid de adentro: ssh y git mueren con «No user exists for uid
1001» y ni intentan conectar. Pasa porque la instancia de persona va con root = false —si no, el
CLI se ve uid 0 y rechaza --dangerously-skip-permissions— y ese uid no existe en la imagen Arch.
2. /etc/ssh/ssh_config.d es de la capa inferior y su dueño cae fuera del mapa (nobody), así que ssh
ABORTA con «Bad owner or permissions»; no degrada, aborta. El directorio no se puede mover (EXDEV
en overlay), así que se redirige el Include a una copia propia.
3. known_hosts se siembra desde el anfitrión, que es lo que evita el StrictHostKeyChecking contra el
worker la primera vez —y el ~/.ssh de adentro ya pasó a rw en el manifiesto, para que ssh pueda
escribirlo cuando aparezca un host nuevo—.
Escribe en el upper como la PERSONA, no como root: si no, le dejaría ficheros que ella no puede tocar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>