tawasuyu

sergio/takana

> 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…

TOML 1373Shell 116Rust 74Markdown 641915 Sutichaykuna

sandbox: el merge de deps cae en el store (mismo fs), no en la raíz — desbloquea kio

merge_deps_layer funde las deps en UNA capa overlay por hardlinks (cp -al) para
no desbordar el lowerdir de overlayfs (tope ~4096B por página). Pero calculaba
la ruta del merge en deps.parent().parent() = <store>/../.dmerge, asumiendo que
el store está en <base>/store del MISMO fs. En el worker el store es un VOLUMEN
bind-montado (/opt/hammer/store en /dev/sdb, /opt/hammer en /dev/sda1) ⇒ el merge
caía en la raíz, cp -al fallaba cross-device, y el fallback apilaba las ~50 deps
de kio directo → lowerdir 5315B > 4096B → "bwrap: Can't make overlay mount" →
kio (EL keystone, gatea 36) imposible de construir. Por eso estaba clavado.

Fix de una línea: el merge va en el padre INMEDIATO de las deps (= el store
mismo), garantizado mismo fs. Confirmado en el worker: cp -al a /opt/hammer/.dmerge
falla "Invalid cross-device link"; a /opt/hammer/store/.dmerge funciona.
En el laptop andaba por casualidad (store y su padre en el mismo fs).

`.dmerge` (dot-prefix) es invisible para el store lookup/build-state como .times.
cosecha excluye /.dmerge del rsync (es scratch de hardlinks; sin -H rsync lo
expandiría a copias reales).

Descubierto levantando el worker para poblar tiempos: yupana keystones apuntó a
kio, la campaña falló ahí, y el radio de lowerdirs (5315B) destapó la causa. Una
"sorpresa de entorno" (infra del sandbox, fuera del grafo) que el frente de
timing sacó a la luz.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

6a0dc40a05b2cab933e5e3f033fe973b33d01677 · ruwaq sergio · (3 killa ñawpaq) · tayta b9da01631 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 1

crates/hammer-build/src/sandbox.rs

2 qillqakuna · +9 −4

diff --git a/crates/hammer-build/src/sandbox.rs b/crates/hammer-build/src/sandbox.rs
index a33e1f9b..efabadfa 100644
--- a/crates/hammer-build/src/sandbox.rs
+++ b/crates/hammer-build/src/sandbox.rs
@@ -209,13 +209,18 @@ impl Sandbox {
         for d in &self.deps {
             d.hash(&mut h);
         }
-        // Junto al store para compartir filesystem (hardlinks no cruzan fs). El store suele estar en
-        // `<base>/store`; ubicamos el merge en `<base>/.dmerge/<id>`. Derivamos <base> del primer dep.
+        // DENTRO del store (el padre INMEDIATO de las deps), no en `<store>/../`: los hardlinks NO
+        // cruzan filesystems, y el store puede ser un mount aparte (en el worker es un VOLUMEN
+        // bind-montado: `/opt/hammer/store` en /dev/sdb, `/opt/hammer` en /dev/sda1). Con
+        // `.parent().parent()` el merge caía en la raíz ⇒ `cp -al` cross-device fallaba ⇒ fallback al
+        // apilado directo ⇒ overflow del lowerdir en kio (5315B > 4096B) y build imposible. El padre
+        // inmediato de un dep ES el store, siempre mismo fs que las deps. `.dmerge` (dot-prefix) no
+        // matchea `<hash>-<name>` ⇒ invisible para el store lookup y build-state, como `.times`.
         let base = self
             .deps
             .first()
             .and_then(|d| std::fs::canonicalize(d).ok())
-            .and_then(|d| d.parent().and_then(|p| p.parent()).map(|p| p.to_path_buf()))
+            .and_then(|d| d.parent().map(|p| p.to_path_buf()))
             .unwrap_or_else(|| PathBuf::from("."));
         let merged = base.join(".dmerge").join(format!("{:x}", h.finish()));
         let done = merged.join(".done");
diff --git a/scripts/farm/cosecha-cron.sh b/scripts/farm/cosecha-cron.sh
index 0c987362..a1312c6a 100755
--- a/scripts/farm/cosecha-cron.sh
+++ b/scripts/farm/cosecha-cron.sh
@@ -68,7 +68,7 @@ else
       continue
     fi
     # 2. RECOGE: store sellado worker→laptop (CAS, merge seguro).
-    if rsync -az -e "$SSH" "root@$ip:$REMOTE/store/" "$ROOT/store/" 2>&1 | tail -2; then
+    if rsync -az --exclude /.dmerge -e "$SSH" "root@$ip:$REMOTE/store/" "$ROOT/store/" 2>&1 | tail -2; then
       echo "   cosecha ✓"
     else
       echo "   ⚠ cosecha falló — sigo"