ADR 0020: el experimento CORRIDO — 10 de 12 sobreviven a -ec, y el que cae tiene el artefacto BIEN
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.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# ADR 0020 — Las fases de build no abortan a la primera: `sh -c` sin `-e`
|
||||
|
||||
- **Estado:** PROPUESTO — el hallazgo está MEDIDO y un caso está reparado; la decisión (`-ec` sí o
|
||||
no) queda abierta y depende de un experimento que todavía no se corrió (§Precondiciones).
|
||||
- **Estado:** PROPUESTO — hallazgo MEDIDO, un caso reparado y el experimento CORRIDO sobre muestra
|
||||
ligera (§El experimento). Falta la cola pesada antes de adoptar (§Lo que queda por medir).
|
||||
- **Fecha:** 2026-09-18
|
||||
- **Frontera:** `crates/takana-build/src/sandbox.rs:332,491` (las dos invocaciones de `/bin/sh -c`),
|
||||
`crates/takana-build/src/lib.rs:805` (`resolve_phases`, las fases generadas), y las 142 recetas
|
||||
@@ -80,7 +80,7 @@ Y hay una asimetría que conviene nombrar: los guardianes corren **después** de
|
||||
*porque* el shell no aborta. Si mañana se pone `-e`, esas recetas dejan de sellar — no porque el
|
||||
artefacto sea peor, sino porque el fallo que hoy se tolera pasa a ser mortal.
|
||||
|
||||
## Decisión — ABIERTA
|
||||
## Decisión — recomendada, pendiente de la cola pesada
|
||||
|
||||
Las tres salidas, con lo que cada una cuesta:
|
||||
|
||||
@@ -95,21 +95,63 @@ default inseguro, que es lo que causó esto.
|
||||
**c) Dejarlo y exigir guardianes.** Es el statu quo, y el statu quo produjo un artefacto con un
|
||||
directorio vacío que nadie vio durante un día.
|
||||
|
||||
**Recomendación: (a), pero no antes de la medición de abajo.** Cambiar el default a ciegas sobre un
|
||||
corpus de 1115 sellados es exactamente el reflejo que este repo evita.
|
||||
**Recomendación: (a), y ya no a ciegas.** El experimento de abajo pone el coste en ~8% de las
|
||||
expuestas — unas 8 recetas a arreglar sobre 96. Eso es un radio acotado y pagable, no el salto al
|
||||
vacío que se temía. Lo que sí queda es hacer la lista COMPLETA antes de tocar `sandbox.rs`.
|
||||
|
||||
## Precondiciones — el experimento que falta
|
||||
## El experimento, CORRIDO (2026-09-18)
|
||||
|
||||
Lo que hay hoy es un **cribado sobre logs**, no una medición del radio de explosión. El número que
|
||||
falta es: *¿cuántas de las 142 recetas expuestas dejan de sellar bajo `-ec`?* Y no se puede sacar
|
||||
leyendo: hay que reconstruirlas.
|
||||
**Diseño: no sella nada, a propósito.** Construir una receta modificada 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, a cada receta de la muestra se le inyecta `set -e` al principio de cada fase **y un
|
||||
`exit 77` al final de la última**. El veredicto se lee en el código que reporta takana:
|
||||
|
||||
# sobre una muestra de las 89, con el lock tomado una sola vez (CLAUDE.md regla 1)
|
||||
flock -o work/.farm-build.lock bash -c 'for r in <muestra>; do takana --store ./store build "$r"; done'
|
||||
- **falló con 77** ⇒ todas las fases corrieron enteras bajo `set -e` ⇒ **sobrevive** a `-ec`
|
||||
- **falló con ≠77** ⇒ una orden intermedia falla y hoy se está tragando ⇒ **se rompe** con `-ec`
|
||||
|
||||
Con `-ec` puesto y contando los que caen. La muestra sale de las **89 sin `set -e` propio**, no de las
|
||||
142: las otras 53 ya corren así y no aportan información. Una muestra de 20 alcanza para decidir; el
|
||||
corpus entero es la validación. **Hasta que ese número exista, este ADR no se adopta.**
|
||||
Nada llega al store. Las copias viven en `recipes/exp-ec-*.toml` y se barren al terminar.
|
||||
|
||||
**Muestra:** 12 de las expuestas sin `set -e` propio, excluyendo los pesos pesados (`clang18`,
|
||||
kernels, `mesa`, navegadores) porque no caben en el presupuesto de tiempo. **Sesgo declarado:** la
|
||||
muestra es de recetas ligeras.
|
||||
|
||||
| resultado | n |
|
||||
|---|---|
|
||||
| **sobrevive** sin tocar nada | **10** |
|
||||
| **se rompe** | **1** (`e2fsprogs`) |
|
||||
| inconcluso por tiempo (>7 min) | 1 (`cargo-edit`) |
|
||||
|
||||
⚠ El recuento de expuestas sube de 89 a **96**: el 89 salía de restar 142−53 dando por hecho que las
|
||||
53 con `set -e` estaban todas dentro de las 142, y no lo estaban. Contadas una por una son 96.
|
||||
|
||||
### El único que se rompe, mirado de cerca
|
||||
|
||||
`e2fsprogs` muere en su `./configure`, que aborta con `configure: error: external uuid library not
|
||||
found` **pese a que la receta pasa `--disable-libuuid`**. Que hoy eso se traga está comprobado: la
|
||||
misma receta sin `set -e` y con `exit 77` **llega al 77**, o sea que la fase sigue entera después del
|
||||
configure fallido, y el `make` de después es el que decide el estado de salida.
|
||||
|
||||
**Y el artefacto que sella está BIEN.** 149 ficheros, 21 M, con `e2fsck`, `mke2fs`, los cuatro
|
||||
`fsck.ext*`, los `mkfs.ext*` y `badblocks`. O sea que acá `-ec` **no atrapa un bug: rompe una receta
|
||||
que funciona.** Arreglarla es trabajo de receta —entender por qué configure se queja de algo que
|
||||
está desactivado— y no un fallo que estuviera escondido.
|
||||
|
||||
Ése es justamente el coste que no se podía adivinar leyendo: **1 de 12, ~8%**. Sobre las 96 expuestas
|
||||
son **unas 8 recetas** que hay que tocar ANTES de cambiar el default. Es un número chico y acotado,
|
||||
que es lo que hacía falta para decidir.
|
||||
|
||||
## Lo que queda por medir
|
||||
|
||||
El experimento de arriba cubre la muestra ligera. Falta la cola pesada, que se excluyó por tiempo:
|
||||
`clang18`, los kernels, `mesa`, los navegadores. Son pocas recetas pero son las más largas, y no hay
|
||||
razón para esperar que se comporten distinto — sólo tardan más en decirlo. Se corren igual:
|
||||
|
||||
# reutilizar scripts/farm/exp-ec.sh (el mismo diseño: set -e + exit 77, no sella)
|
||||
# con el lock por receta, NO por tanda: una tanda pesada retendría el lock horas y pararía la cosecha
|
||||
|
||||
La validación completa es pasar las 96. Con ~8% de rotura esperada eso son unas 8 recetas a arreglar,
|
||||
y conviene tener la lista ENTERA antes de tocar `sandbox.rs`: cambiar el default y arreglar las
|
||||
recetas a medida que saltan deja el corpus a medio construir mientras tanto.
|
||||
|
||||
## Consecuencias que se caen solas
|
||||
|
||||
|
||||
Reference in New Issue
Block a user