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 1572Shell 203Rust 109Markdown 993728 Definiciones

fix(granja): un fichero de estado NUEVO trababa el adelanto de la rama, para siempre

Bloqueo circular, destapado al añadir `docs/state/cierres.json` y medido en la caja: la
comprobación «el árbol ya coincide con el destino» usaba `git diff <commit> -- <ruta>`, y **`git
diff` ignora las rutas SIN SEGUIR**. Para un fichero de estado nuevo el commit lo tiene y el índice
no, así que aparece eternamente como «difiere» ⇒ la rama no adelanta ⇒ el fichero nunca pasa a
seguido ⇒ vuelve a diferir. El síntoma era «la rama local queda detrás» en CADA ciclo, por un
fichero que en el disco era byte a byte el publicado.

Ahora se compara el contenido del disco: `git hash-object` del fichero contra el blob del commit,
que funciona igual para rutas seguidas y sin seguir. Una ruta que el commit tiene y el disco no
cuenta como diferencia, que es lo correcto — ahí el ff sí traería algo nuevo y no debe saltarse.

Control en repo de juguete con un fichero de estado nuevo apareciendo: ciclo 1 adelanta, ciclo 2
sigue limpio, `HEAD == origin/main` y cero sucios.

Es la tercera vez en esta serie que el fallo no está en lo que el guion hace sino en lo que una
herramienta NO ve: `git diff` y los untracked acá, `git merge --ff-only` mirando índice-contra-HEAD
en vez de árbol-contra-destino antes, y `du` colgándose en el subárbol gordo el otro día.

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

ab24009d1808c228b0ea15ada75a7bc32403fbb5 · por Sergio · (hace 12 d) · padre 2d271187b · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

1 archivos · +23 −1

diff --git a/scripts/farm/publicar-estado.sh b/scripts/farm/publicar-estado.sh
index b8ee5145..a14acebd 100755
--- a/scripts/farm/publicar-estado.sh
+++ b/scripts/farm/publicar-estado.sh
@@ -78,6 +78,21 @@ done
 # `push`. Eso no es un error: es la carrera normal de un repo compartido, y la respuesta correcta
 # es reconstruir el commit sobre la cabeza nueva, no forzar. `--force` nunca aparece acá: pisaría
 # el trabajo del otro, que es justo lo que el latido no debe poder hacer ni por accidente.
+# ¿El árbol de trabajo ya tiene, byte a byte, lo que el commit destino pone en cada ruta que el
+# fast-forward tocaría? Se compara `git hash-object` del fichero EN DISCO contra el blob del commit,
+# que funciona igual para rutas seguidas y sin seguir — y una ruta que el commit tiene y el disco no
+# cuenta como diferencia, que es lo correcto: ahí el ff sí traería algo nuevo.
+_arbol_coincide_con() {
+  local destino="$1" ruta blob disco
+  for ruta in $(git diff --name-only HEAD "$destino" 2>/dev/null); do
+    blob="$(git rev-parse "$destino:$ruta" 2>/dev/null)" || return 1
+    [ -f "$ruta" ] || return 1
+    disco="$(git hash-object -- "$ruta" 2>/dev/null)" || return 1
+    [ "$blob" = "$disco" ] || return 1
+  done
+  return 0
+}
+
 intento=0
 while :; do
   intento=$((intento + 1))
@@ -177,8 +192,15 @@ while :; do
     # intacto y reescribe el índice —y por eso va GUARDADO por «el índice no tiene nada»: el índice
     # es estado COMPARTIDO (regla 2) y pisar lo que otro agente dejó en `git add` es exactamente el
     # daño que este repo ya documentó. Si hay algo stageado, no se toca y se dice.
+    # ⚠ La comprobación «el árbol ya coincide con el destino» se hace COMPARANDO EL CONTENIDO DEL
+    # DISCO, no con `git diff <commit> -- <ruta>`. Y es un bloqueo circular medido (2026-10-10, al
+    # añadir `cierres.json`): `git diff` **ignora las rutas sin seguir**, así que un fichero de
+    # estado NUEVO aparece eternamente como «difiere» —el commit lo tiene, el índice no— y la rama
+    # no adelanta nunca; pero volverlo seguido es justamente lo que el adelanto haría. El síntoma
+    # era «la rama local queda detrás» en cada ciclo, para siempre, por un fichero que en el disco
+    # era byte a byte el publicado.
     elif git diff --cached --quiet HEAD 2>/dev/null \
-         && git diff --quiet "$commit" -- $(git diff --name-only HEAD "$commit") 2>/dev/null; then
+         && _arbol_coincide_con "$commit"; then
       git reset --mixed -q "$commit" \
         && echo "   rama local al día (el árbol ya tenía el contenido publicado)" \
         || echo "   la rama local queda detrás — lo publicado NO depende de eso"