> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…
fix(sandbox): CARGO_BUILD_JOBS=1 para serializar el backend paralelo de rustc (determinismo)
[VERIFICACIÓN EN CURSO — no confirmado aún] Stage 2 variante (b) destapó que
codegen-units=1 NO basta para reproducibilidad: el backend paralelo de rustc/LLVM
(ThinLTO + codegen) dimensiona su pool de hilos por el paralelismo disponible y sus
decisiones varían build-a-build a >1 hilo.
Evidencia: arje-zero divergía ~62 KB entre dos builds host idénticos (mismo rustc
1.91.1, mismo commit fijado, mismos flags), mientras un build serial (la VM tiene
1 vCPU, o taskset -c 0 en host) reproducía bit-a-bit a of_tree=9adefb82. El baseline
0039b2b9 se construyó en paralelo ⇒ referencia no-fiable. make/musl/busybox/hammerd
están limpios (descartados uno a uno); el único flaky es arje-zero por paralelismo.
CARGO_BUILD_JOBS=1 limita el jobserver a 1 token para serializar el backend. Test
in-flight: rebuild de arje-zero con todas las CPUs + JOBS=1 debe dar 9adefb82. Si el
pool de LLVM ignora el jobserver (usa affinity), habrá que fijar afinidad o LTO.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
diff --git a/crates/hammer-build/src/sandbox.rs b/crates/hammer-build/src/sandbox.rs
index 76481d43..0c15fcc3 100644
--- a/crates/hammer-build/src/sandbox.rs
+++ b/crates/hammer-build/src/sandbox.rs
@@ -187,6 +187,15 @@ impl Sandbox {
// repo upstream lo declare (SDD 09 §2). Inerte para builds no-Cargo (musl/busybox lo
// ignoran). Ver runbook §8c / SDD 11.
("CARGO_PROFILE_RELEASE_CODEGEN_UNITS", "1"),
+ // Reproducibilidad de builds Cargo (parte 2): `codegen-units=1` NO basta. El backend
+ // paralelo de rustc/LLVM (ThinLTO + codegen) lanza un pool de hilos dimensionado por la
+ // paralelismo disponible, y sus decisiones (orden de import/inline) varían build-a-build
+ // a >1 hilo ⇒ `arje-zero` divergía ~62 KB entre dos builds host idénticos, mientras un
+ // build serial (la VM tiene 1 vCPU, o `taskset -c 0`) reproducía bit-a-bit. `JOBS=1`
+ // limita el jobserver a 1 token ⇒ rustc serializa el backend ⇒ salida estable e
+ // independiente del nº de CPUs del que reconstruye. Lo cazó Stage 2 variante (b): host
+ // (paralelo) daba `0039b2b9…` no-reproducible vs VM (serial) `9adefb82…`. Ver SDD 09 §2.
+ ("CARGO_BUILD_JOBS", "1"),
];
if self.cache_dir.is_some() {
defaults.push(("ZIG_GLOBAL_CACHE_DIR", "/cache/zig"));