Sin TTY, --info=progress2 reescribe con \r y el progreso se acumula en
miles de copias de la misma línea. El respaldo corre DESATENDIDO, así que
ese log es la única forma de saber qué pasó; a 2,6 MB no se lee.
Mismo defecto y mismo arreglo que en worker-depositar.sh.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Montando gioser como segundo hub salió el defecto: `sealed_remoto` cuenta
cuántos sellados NO están en el disco de QUIEN calcula. El laptop tiene 219
artefactos y gioser 19, así que el mismo corpus da 700 y 751. Metido en un
fichero commiteado, las dos máquinas se lo pisarían en cada regeneración,
para siempre.
El estado del corpus es compartido; cuánto de él tiene esta máquina en el
disco, no. Se sigue diciendo en el resumen, donde es útil y no genera churn.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1. build-farm.sh — vulkan-loader fallaba con «io: File name too long (os
error 36)» en TODOS los ciclos y sella sin una queja ejecutado en serie
(comprobado a mano en el worker). La firma no estaba en la lista de
colisiones del reintento serial, así que nunca se reintentaba: fallaba,
contaba como deuda, y al ciclo siguiente fallaba igual.
Un fallo que se repite IDÉNTICO no es intermitente: es uno que nadie
está reintentando.
Se añade la firma, pero el defecto de fondo era que faltarla fuese MUDO
— la lista sólo puede crecer si alguien se entera de que se quedó corta.
Ahora lo no reintentado se dice, con las primeras 120 letras del log.
2. farm-up.sh — no sembraba work/farm-sellados.txt. Un worker recién
creado arrancaba con el manifiesto rancio horneado en la golden: 1172
contra 1241 del hub, así que reconstruía lo que el hub ya tenía sellado
(vulkan-loader entre ellos, y encima fallando).
Es el mismo error de método que farm-sync.sh ya se documentó a sí mismo:
«lo puse allí, di el bucle por cerrado, y la churn siguió porque hay DOS
rutas». Había dos otra vez y sólo una estaba arreglada.
Tras el arreglo las cuatro colas dan 1/1 construyen (0 fallan) y el perfil
escritorio-kde cierra 162/162.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cadena completa medida hoy: el worker depositó 63 artefactos (1,34 GB) en
8 s a 153 MB/s, y el hub los promovió con mv. Respaldo 1542 → 1605, buzón
en 0, guardián cuadrando. Contra los 440 kB/s del laptop, 348×.
Dos fallos de la prueba, que importan más que el resultado:
1. `ssh` cortaba con «Host key verification failed» porque la granja REUSA
IPs y la host key cambia con razón. Como el stderr iba a /dev/null, el
error salía como «no obtuve la pública del worker»: culpaba al worker
cuando el problema estaba en el known_hosts del laptop. Ahora va por
ssh_worker(), que purga la entrada vieja — correcto sólo acá, porque la
identidad del worker es su label hcloud, no su llave.
2. verificar-buzon daba «aislado ✓» sin haber probado que escribe. El
aviso de host key se comía el head -1, y el testigo se llamaba .btest,
que `ls` no muestra. Un testigo invisible no prueba nada. Ahora exige
las dos mitades y las dos están verdes: escribe en su buzón, y
../hammer/store no existe para él.
Y el progreso de rsync sólo con TTY: sin terminal reescribe con \r y deja
miles de copias de la misma línea. 8 segundos bastaron para un log
ilegible; en el latido sería cada media hora.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Los permisos de subcuenta del Storage Box son BINARIOS: --readonly sí o no.
No hay append-only ni write-sin-delete (verificado en la API, no recordado).
Así que la contención se hace por alcance: el worker escribe en un BUZÓN
cuyo home es incoming/, y hammer/store sencillamente no existe para él. Lo
máximo que puede destruir es lo que él mismo depositó y aún no se promovió,
que sigue estando en el volumen. Un permiso puede estar mal puesto; un
directorio fuera de tu home, no.
La promoción es un mv DENTRO del mismo filesystem: un rename, instantáneo,
cero bytes por la red. Eso es lo que la hace viable con un uplink de
440 kB/s — el laptop manda órdenes, los datos van worker→box por dentro de
Hetzner (122 MB/s, 280×).
Medido de la shell del box, que NO es un bash:
· no hay `for` ⇒ los lotes se arman en el hub
· `a; b` no encadena de fiar ⇒ una orden por conexión
· `mv a b c dest/` sí acepta varios orígenes ⇒ cientos por conexión
· `find` no existe y devuelve 0 EN SILENCIO ⇒ parece «no hay respaldo»
Y la trampa que motivó partir el trabajo en dos conjuntos: `mv A dest/` con
dest/A ya existente NO falla, mete A DENTRO y deja dest/A/A. Como el store
es CAS, un artefacto ya respaldado es idéntico ⇒ no se mueve, se borra del
buzón. Los dos caminos probados de punta a punta con un artefacto falso,
recuento verificado y sin anidar.
Defensa en profundidad aparte: plan de snapshots diario (03:17 UTC, retiene
7 de 10) y la carpeta ZFS visible para recuperar ficheros sueltos sin
rollback. La subcuenta no las alcanza: viven en la cuenta, con el token que
el worker no tiene.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El store de trabajo se mudó al volumen de la granja y el laptop quedó con
219 artefactos: los de fuente privada (que la granja no puede rehacer) más
lo que todavía no está respaldado. 979 artefactos verificados en el box se
borraron de acá, y con ellos el caché .dmerge de 92 G que sostenía sus
bloques: 128 G → 8,2 G, 115 G libres.
Eso rompía tres cosas que leían el disco local como si fuera la verdad:
- build-state.py habría reportado `never` sobre ~950 sellados y el latido
lo habría COMMITEADO. Un grafo recién escrito miente con más autoridad
que uno viejo. Ahora resuelve la presencia contra la unión del store y
los manifiestos, y expone `sealed_remoto` para que «el store se mudó»
no se lea nunca como «el corpus creció».
- farm-sync.sh armaba el manifiesto con `ls ./store`, así que le habría
dicho al worker «el hub tiene 220» y el worker habría rehecho ~950. Es
el bucle de churn que el propio fichero documenta, al revés. Ahora es la
unión, con un guardián que aborta si el manifiesto encoge.
- cosecha-cron.sh bajaba el store entero cada 30 min: habría deshecho la
mudanza sola, como la poda de 24 G que se deshacía en 2026-08-07. Ahora
baja sólo la lista de nombres.
Los cuatro grafos regenerados dan idéntico a antes del recorte
(766/11/2), que es la prueba de que no se perdió nada.
Queda abierto: los artefactos nuevos viven SÓLO en el volumen hasta que
alguien corra una pasada de respaldo. El volumen tiene borrado protegido,
pero es una copia.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dos cosas medidas al traer los 167 GB.
1. `rsync -a` SIN `-H` no preserva los enlaces duros, y el store comparte ficheros entre artefactos
justamente así. Llegó inflado: 76 G en el box → 159 G en el volumen, con **0 ficheros de nlink>1**
al llegar — ésa es la prueba de que se perdieron, no una sospecha. (El 76 G del box es además ZFS
comprimido, así que las dos cosas se sumaban y parecía peor.) El contenido es correcto —es CAS y
los hashes casan—, pero ocupa de más y el volumen no sobra.
2. El respaldo conserva artefactos que el hub YA podó. Son SUPERADOS: existe otro con el hash
vigente, y no pueden dar cache-hit nunca porque la receta que los nombraba cambió. Eran 544 de
1536 · 31 G. Podados con work/store-gc-superados.txt como lista.
El guardián es RECONTAR tras el rm: «borré 544» y «hay 544 menos» son afirmaciones distintas, y
sólo la segunda es la que importa. Cuadró.
Volumen: 992 artefactos vigentes, 95 G libres de 246.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MEDIDO, no supuesto: el uplink de la oficina da 440 kB/s ⇒ los 127 G del store son 82 horas. Subir
el store desde el laptop no es lento, es imposible. Pero el Storage Box está en hel1 y el worker
está en hel1: por la red interna la misma copia va a 122 MB/s. Son 280×.
⇒ El laptop deja de ser el camino de los datos. Sólo manda las RECETAS (26 M).
POR QUÉ SUBCUENTA Y NO LA CUENTA PRINCIPAL. El worker es efímero y se borra solo; darle la
credencial principal sería darle permiso de borrado sobre el ÚNICO respaldo que existe. Un respaldo
al que puede escribir la máquina de la que hay que protegerse no es un respaldo. La subcuenta acota
el daño a cero por construcción: --readonly, --reachable-externally=false, home acotado a hammer/.
LA VERIFICACIÓN ES NEGATIVA. «Sólo lectura» es una afirmación sobre lo que el sistema IMPIDE, así
que leer no la prueba. Hay que intentar escribir y borrar y exigir que fallen:
rm → «Read-only file system» · scp → «dest open: Failure» · respaldo intacto.
El script trae ese paso como subcomando `verificar` y sale ≠0 si la subcuenta resulta escribir.
Dos gotchas que costaron:
· la API exige contraseña con mayúscula+minúscula+número+símbolo aunque después se use llave;
· la shell del Storage Box es RESTRINGIDA: acepta ls/mkdir/rm pero NO redirección, así que
`echo k > authorized_keys` falla EN SILENCIO (crea el directorio, no el fichero). Va con scp.
La llave se genera EN EL WORKER (nunca viaja una privada desde el laptop) y muere con él.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El bloque del volumen es una cadena entrecomillada que se manda al worker, así que un backtick ahí
no es tipografía: es SUSTITUCIÓN DE ÓRDENES. Mis comentarios de la commit anterior citaban
`volume attach` y `blkid` con backticks ⇒ la shell intentó EJECUTAR «volume attach» («volume:
command not found») y a partir de ahí el resto del bloque se mandó mutilado: mkfs.ext4 sin
dispositivo, mountpoint sin argumento.
Por eso los comentarios originales de ese mismo bloque escapan los backticks con \`. Yo escribí los
míos con el estilo del resto del fichero, que es correcto FUERA de la cadena y venenoso dentro.
Arreglado quitándolos: en un comentario que viaja por SSH, la comilla no vale lo que cuesta.
El volumen no sufrió: sigue con su filesystem del 17 de julio y montado.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Poblar el volumen con el store del hub son horas de rsync sin un solo `hammer build`. El dead-man
sólo miraba builds y latido ⇒ acumulaba ticks y borraba el worker A MITAD DE LA COPIA. El volumen
sobrevive (para eso está), pero la transferencia muere y hay que reanudarla a mano; sobre un enlace
lento eso puede no converger nunca.
`pgrep -x` y no `pgrep -f`: `-f` mira la línea de órdenes entera y se auto-matchea con el propio
dead-man si su ruta contiene la cadena. Ese error ya nos hizo informar cuatro veces procesos «vivos»
que estaban muertos.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Investigando por qué el worker nuevo arrancó con 2 artefactos en vez de ~900, apareció esto.
BOMBA 1 — `rm -rf $REMOTE/store` sin comprobar si es punto de montaje.
La guarda era `[ -d ] && [ ! -L ]`: basta en un server creado desde la golden ORIGINAL, donde
/opt/hammer/store es un directorio normal. Pero al re-snapshotear un worker (ayer, para meterle
Rust y Go) la imagen se llevó también LA CONFIGURACIÓN DE MONTAJE ⇒ el server nuevo monta el
volumen en esa ruta AL ARRANCAR, antes de que corra el «rescate». Entonces el `rm -rf` borra A
TRAVÉS DEL MONTAJE y se lleva el store del volumen entero — justo lo que el volumen existe para
proteger.
Evidencia: el volumen pasó de ~900 artefactos a 2, pero NO se perdió el filesystem (lost+found
de julio, 17 montajes, .dmerge intacto). Se borró el CONTENIDO, no el disco. Ahora hay
`mountpoint -q`: si ya está montado no hay nada que rescatar ni que borrar.
BOMBA 2 — `mount … || { mkfs.ext4 -F …; }`. Formatear ante CUALQUIER fallo de montaje, incluida
la carrera normal entre `volume attach` y la aparición del dispositivo. Un hipo de segundos
destruía el volumen. Ahora sólo formatea si `blkid` dice que NO tiene filesystem; si lo tiene y
no montó, aborta y lo dice.
Las dos comparten la misma forma: un fallback destructivo que asume la causa benigna. `mv -n`
está bien elegido (no pisa), pero el `rm -rf` que lo sigue anulaba esa prudencia.
Y una consecuencia que hay que asumir: re-snapshotear un worker NO conserva el store — los
artefactos viven en el volumen, que no entra en la imagen. La golden aporta toolchain y sistema;
la caché la aporta el volumen. Hoy la imagen decía traer store y no lo trae.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cierre de la reparación. Lo que faltaba eran cuatro recetas que caían todas por `libsndfile`
—cuyo configure de autotools sólo busca python2.x— y `gnome-shell`, que había que rehacer.
Selladas en el hub: wireplumber, xdg-desktop-portal, xdg-desktop-portal-cosmic,
xdg-desktop-portal-gnome y gnome-shell.
ESTADO FINAL DE LOS PERFILES:
base 51/51 · cli 74/74 · escritorio-sway 121/121 · escritorio-kde 162/162
escritorio-cosmic 88/89 · escritorio-gnome 122/125
Lo que queda NO es deuda técnica sino decisiones ya tomadas:
· gdm, gnome-session, gnome-settings-daemon → CERRADAS por decisión (GTK3, 2026-08-08);
· portal-probe → git privado por SSH, HUB-ONLY estructural.
⚠ HALLAZGO EN LA GOLDEN NUEVA, que hay que arreglar antes de confiar en ella: el volumen
persistente `harkaq-cosecha` se monta ENCIMA de `/opt/hammer/store` y **tapa el store horneado
en la imagen**. El worker nuevo arrancó con 2 artefactos en vez de los ~900 que trae el
snapshot, así que la caché de la golden es hoy inútil: el bind del volumen la esconde. El
toolchain sí se heredó bien (cargo/rustc 1.96.0, go 1.26.4 verificados en el arranque).
⇒ O el volumen deja de montarse sobre esa ruta, o la golden no necesita traer store. Hoy hace
las dos cosas y se anulan.
Por eso estas cinco se construyeron en el hub y no en la granja: para cinco recetas no valía la
pena resolver el solapamiento, y el hub las tenía todas cacheadas.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
COSMIC cerró 25 de 30 raíces. De los 5 fallos, CUATRO daban el mismo mensaje —
«error: no suitable Python interpreter found»— en wireplumber, xdg-desktop-portal,
xdg-desktop-portal-cosmic y cosmic-settings-daemon.
NO ERA DE ELLAS, Y NI SIQUIERA ERA DE MESON. El error viene de un `configure` de AUTOTOOLS que
prueba `python2.2`, `python2.1`, `python2.0` —literalmente— y aborta al no hallarlos. Se
identificó por las flags del comando en el log (`--disable-mpeg --disable-full-suite`), que son
inconfundibles de **libsndfile**: una dep común a las cuatro.
Y declarar `python3` en `[deps]` NO ayuda —dos de las cuatro ya lo tenían—: el problema no es
que falte el intérprete, es que el script no reconoce ese NOMBRE. Autoconf respeta la variable
de entorno `PYTHON`, así que se le pasa `PYTHON=python3` y sella.
LA LECCIÓN, que hoy ya se repitió con `dbus-shared`: cuando varias recetas fallan con el MISMO
mensaje raro, el fallo está en una dep común — y **la forma de identificarla es mirar QUÉ
configure/meson.build lo emite**, no la receta que se estaba construyendo. Las flags del comando
y el número de línea del meson.build son la firma del paquete que realmente muere.
Aplicado a las tres copias (incoming-gnome, -cosmic, -kde), que dan el mismo hash. Y de paso
`cosmic-settings-daemon` sí necesitaba `python3` en deps, que no lo declaraba: dos causas
distintas bajo un mensaje idéntico.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Imagen 417847948 («hammer-golden-rust-go-2026-08-08») reemplaza a 408909310 como default de
farm-up.
EL PROBLEMA QUE CIERRA: hammer invoca `cargo vendor` y el toolchain Go en el HOST, no dentro
del sandbox — el vendoreo pasa ANTES de entrar a la caja. La golden vieja no los traía, así que
la granja no podía construir NINGUNA receta Rust ni Go: COSMIC entero, las 228 Rust y las 362
Go del corpus. El 76% del catálogo dependía de UNA SOLA máquina, el hub — justo lo que el
respaldo de ayer intentaba dejar de asumir.
VERIFICADO ANTES DE SNAPSHOTEAR, no después: `cosmic-bg` —que minutos antes moría con
`spawn cargo vendor: No such file`— sella en el worker. Un snapshot de una máquina a medio
arreglar es peor que ninguno.
MISMAS VERSIONES QUE EL HUB (cargo/rustc 1.96.0, go 1.26.4) a propósito: introducir un skew de
toolchain nuevo mientras se arregla otro es cómo se fabrican los fallos que nadie reproduce. Y
1.96 es además el techo MSRV del sandbox ya documentado.
NO RELAJA LA HERMETICIDAD: cargo/go son herramientas de FETCH, del mismo orden que `git` para
clonar. El build sigue ocurriendo dentro del sandbox con el árbol ya vendoreado. Es lo contrario
del caso «no engordar el rootfs del worker», que habla del rootfs DEL SANDBOX.
El PATH queda persistido en /etc/profile.d/hammer-toolchain.sh para que sobreviva a los logins
no interactivos de la granja. Y la imagen trae el store del worker al momento del snapshot (KDE
y GNOME reconstruidos hoy), así que los workers nuevos arrancan con más caché.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Al lanzar COSMIC, sus 30 raíces fallaron de golpe con «spawn cargo vendor: No such file».
Medido:
worker: cargo AUSENTE · rustc AUSENTE · go AUSENTE
hub: cargo ✓ · rustc ✓ · go ✓
hammer invoca `cargo vendor` en el HOST, no dentro del sandbox — el vendoreo pasa ANTES de
entrar a la caja. El worker no trae toolchain de Rust ni Go ⇒ la granja no puede construir
NINGUNA receta Rust o Go: COSMIC entero, las 228 Rust del corpus y las 362 Go. **El 76% del
catálogo sólo puede construirse en el hub**, que es UNA SOLA MÁQUINA — justo lo que el respaldo
de ayer intentaba dejar de asumir.
ESTO EXPLICA HACIA ATRÁS todos los «no construyó» de esta campaña (amp, anew, apko, atlas, bom,
broot, cargo-audit, cargo-hack, git-absorb). Yo lo atribuí a «necesitan red para sus módulos» y
lo escribí así en el SDD 23 y en memoria. Era falso: **falta el binario**, no la red.
Y ARREGLARLO NO ROMPE LA HERMETICIDAD: cargo/go aquí son herramientas de FETCH, del mismo orden
que `git` para clonar — se usan para traer y fijar deps ANTES del build, no dentro del sandbox.
Instalarlos en la imagen golden no relaja el aislamiento; el build sigue ocurriendo en la caja
con el árbol ya vendoreado. Es lo contrario del caso «no engordar el rootfs del worker», que
habla del rootfs DEL SANDBOX.
⇒ Decisión de aprovisionamiento, no de arquitectura, y desbloquea tres cuartas partes del
catálogo para la granja.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`mutter`, `gnome-shell` y `xdg-desktop-portal-gnome` fallaban las tres con «ERROR: Unhandled
python exception». Las tres YA tenían `--wrap-mode=nodownload` en su propia receta, así que no
era eso — hasta que el log mostró la línea culpable:
meson.build:372:11: ERROR: Unhandled python exception
<urlopen error unknown url type: https>
WARNING: failed to download with error: name 'ssl' is not defined
La misma línea 372 que el fallo de `dbus` de hace unas horas. No fallaban ellas: fallaba una
DEP que arrastran, `dbus-shared`, cuya sombra en incoming-gnome e incoming-cosmic no tenía la
flag. La canónica del corpus y la sombra de KDE sí la tenían; estas dos no.
⇒ UNA flag ausente en una sombra tumbaba TRES raíces de perfil en GNOME y bloqueaba COSMIC de
paso. Y el mensaje nunca nombra la red: «Unhandled python exception» se lee como un bug de
meson y es que el sandbox es hermético a propósito.
Lección de método: cuando tres recetas fallan con el MISMO error y las tres ya tienen el
arreglo obvio, el fallo está en una dep común, no en ellas. La línea de meson.build en el
mensaje es lo que lo identifica — es la firma del paquete que realmente muere.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
perl-xml-parser, libpcap, libnl, lm-sensors, libxkbcommon, vulkan-loader y dbus — las siete
sombras de incoming-kde cuyas deps sí estaban al día, o sea el origen de la deriva. 7 de 7
selladas, sin un solo fallo: confirma el diagnóstico de que no había muro técnico, sólo
artefactos que nadie había reconstruido.
Quedan 79, todas aguas abajo. En vez de ir ola por ola se lanzó la construcción de las 11
RAÍCES del perfil y hammer resuelve la clausura solo — que es para lo que sirve el grafo de
deps y evita adivinar el orden a mano.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diagnóstico completo. No es daño de la campaña del split ni un fallo de store-gc.
LO MEDIDO, en orden:
1. 86 nodos del perfil sin artefacto en su hash vigente.
2. NO lo causó el split: revertidas una por una todas las recetas tocadas hoy (3 bibliotecas
base, 30 hojas, dbus, 38 de la 2ª tanda) el número NO se movió de 198 en ningún caso.
3. La FRONTERA son 7 recetas —las únicas cuyas deps sí están al día—: dbus, libnl, libpcap,
libxkbcommon, lm-sensors, perl-xml-parser, vulkan-loader. Las otras 79 cuelgan de ellas.
4. Las 7 son SOMBRAS de incoming-kde, no las canónicas. Las del corpus están al día, y por eso
el problema es INVISIBLE desde el grafo del corpus — que es justo el que yo miraba.
5. No fue store-gc: sus hashes vigentes no figuran en ningún manifiesto de borrado, y tres nunca
se podaron. (Lo sospeché porque la regla de «superado» es por NOMBRE y una sombra comparte
nombre con la canónica; la sospecha era razonable y los manifiestos la descartan.)
6. Ni el hub ni el worker los tienen. No están en otro sitio: NO ESTÁN.
LA CAUSA DE FONDO, que importa más que KDE: la cola se construyó en workers EFÍMEROS, el sync
del store es unidireccional (worker→hub) y esos workers ya no existen. Cuando algo del sustrato
compartido cambió después, las sombras se re-hashearon y nadie las reconstruyó, porque el hub
nunca fue la máquina donde vivía ese escritorio.
⇒ Con flota efímera y sync unidireccional, un escritorio puede dejar de ser
reconstruible-desde-el-store SIN QUE NINGÚN INDICADOR LO DIGA. El grafo seguía reportando
162/162 desde un JSON generado semanas antes.
Coste de arreglarlo: 86 reconstrucciones en la granja, empezando por las 7 de la frontera. No
hay muro técnico conocido — son recetas que ya construyeron. Es cómputo, no investigación.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Al desplegar la 2ª tanda de hojas noté 198 recetas de las colas de escritorio sin artefacto
vigente (KDE 133, GNOME 37, COSMIC 24) y asumí que las había roto yo. **No.**
LO VERIFIQUÉ REVIRTIENDO, una causa por vez: las 3 bibliotecas base (expat, zstd, ncurses), las
30 hojas de la 1ª tanda, `dbus`, y las 38 de la 2ª. **El número no se movió de 198 en ningún
caso.** Y mirando el histórico, `escritorio-kde` está en 76/162 en TODOS los commits recientes
—09:10, 09:41, 10:12, 10:44, 11:16, 11:49— o sea desde antes de que la campaña empezara.
EL ERROR FUE MÍO Y DE MÉTODO: escribí «KDE cierra 162/162» leyendo
`docs/state/build-state-kde.json` **sin regenerarlo**. Es un fichero GENERADO, y un generado que
no se regenera es una foto vieja con aspecto de dato fresco. El mismo tipo de fallo que citar el
«79%» midiendo otra unidad: el dato existía, lo que fallaba era de cuándo era.
⇒ Y hay un aviso de fondo para toda la sesión: **medí «cero daño colateral» sobre el grafo
`--wlr`, que sólo carga corpus + incoming-wlr.** Las colas de escritorio son INVISIBLES ahí, así
que ese «cero» era cierto en el grafo que miraba y no decía nada del catálogo completo. Para
juzgar impacto hay que cargar TODAS las colas.
Las 38 de la 2ª tanda quedan revertidas: hasta entender los 198 no conviene añadir cambios
encima. Las 30 de la 1ª y las 5 del piloto siguen puestas y verificadas.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
base 51/51 · cli 74/74 · escritorio-sway 121/121. Cosecha verificada: cero artefactos en el
worker que el hub no tenga.
De la tanda: 25 de 30 selladas. Los 5 fallos, ninguno causado por el split:
· cargo-audit, cargo-hack, git-absorb — 'spawn cargo vendor': el grafo las clasifica como clase
`c` porque declaran compiler=gcc para sus deps de C, pero por dentro son Cargo. Filtrar por la
clase del grafo NO basta.
· hammerd — git privado por SSH (HUB-ONLY, como las de tawasuyu).
· coreutils — 'you should not run configure as root'. Esto NO lo causó el split: es DERIVA. La
receta llevaba tiempo sin poder construirse en el lab actual y nadie lo sabía porque su
artefacto viejo seguía en el store. Es exactamente lo que la campaña destapa.
⚠ Y de ahí sale un riesgo que conviene nombrar: cada receta que deja de reconstruir convierte su
artefacto viejo en un REHÉN — store-gc no puede podarlo (es el único ejemplar) y nadie puede
regenerarlo. Hoy son ~12 G inmovilizados, y crecen con cada receta que se rompe en silencio.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>