Commit Graph
942 Commits
Author SHA1 Message Date
sergio 9c9a8a8003 estado: cosecha granja 2026-07-27T15:09:35Z — avance del árbol KDE 2026-07-27 11:09:35 -04:00
sergioandClaude Opus 4.8 328c7219aa gnome onda 2: cola driver aislada incoming-gnome-onda2
Cola de build para el worker (patrón onda1): SÓLO los 5 targets listos
(gjs/graphene/pango/gdk-pixbuf/gtk4) + su cierre de deps que vive en
incoming-gnome/ (islas glib/glib-introspected/g-i/py3-setuptools + la cadena
spidermonkey/nspr/nasm/cbindgen). Todas las deps ya selladas ⇒ cache-hit; el
worker sólo mide los 5. Excluye mutter/gnome-shell/gdm (deps no listas) para
no quemar compute en builds condenados. Byte-idénticas al corpus/incoming-gnome
⇒ hashes idénticos (resolver sibling→parent auto-consistente).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 11:04:05 -04:00
sergioandClaude Opus 4.8 4ecfa2ab0b gnome onda 2: islas dinámicas del stack GUI + gjs
Autoría Fase 1 (laptop, cero compute) de la onda 2 GNOME (gjs → gnome-shell).
Patrón isla dinámica (SHADOW del corpus estático, resolver hermano→padre):
link=dynamic, default_library=both (.a interno + .so p/ scanner/gjs),
introspection=enabled ⇒ producen su typelib. Todas hashean limpio.

- gjs: declara glib-introspected (su g-ir-scanner sobre GjsPrivate necesita los
  .gir CORE; hidratación directa, no transitiva). Deps ya TODAS selladas ⇒ listo
  para construir — primer nodo de onda 2, no necesita gtk4.
- graphene/pango/gdk-pixbuf: islas + Graphene-1.0/Pango-1.0/GdkPixbuf-2.0.typelib.
- gtk4: isla + Gtk-4.0/Gdk-4.0/Gsk-4.0.typelib. Revierte los hacks del mundo
  estático (sed libgtk_dep, fat-archive). ITERATIVA: el scan arrastra el cierre
  transitivo (wayland/mesa/libdrm/epoxy) aún estático — walls esperados en worker.

Deuda de alcance declarada: sub-deps C (cairo/harfbuzz/etc.) siguen corpus
estáticas embebidas; si duplican estado en runtime se escalan a isla puntual.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 11:02:14 -04:00
sergio df23b70d8f estado: cosecha granja 2026-07-25T09:37:55Z — avance del árbol KDE 2026-07-25 05:37:55 -04:00
sergioandClaude Opus 4.8 ade217cf06 gnome isla: glib-introspected SELLA (b3:c12cb9fa) — typelibs CORE ✓ GATE PASS
El test definitivo del keystone: glib con -Dintrospection=enabled produce los
typelibs CORE (GLib/GObject/Gio/GModule/GioUnix/GLibUnix/GIRepository) usando
g-ir-scanner+compiler sobre GLib misma. SELLA ⇒ g-ir-compiler SÍ sirve para lo
core bajo musl; el SIGSEGV anterior era EXCLUSIVO de los .gir X11/cairo (que no
queremos, Wayland-only). La introspección funciona end-to-end ⇒ gjs→gnome-shell
destrabado.

Rompe el ciclo glib↔g-i: glib-introspected → g-i → glib(stage1, sin introspección),
sin ciclo. Clave: declara glib(stage1) en deps para hidratar libglib-2.0.so.0 y que
g-ir-scanner (que _giscanner.so dlopea) CORRA al configure (hammer hidrata deps
DIRECTAS, no transitivas — diagnosticado con una sonda musl).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 05:21:58 -04:00
sergio 5296e91498 estado: cosecha granja 2026-07-25T05:36:10Z — avance del árbol KDE 2026-07-25 01:36:12 -04:00
sergioandClaude Opus 4.8 d83979d6ce gnome isla: gobject-introspection SELLA (b3:935cedf3) — keystone GNOME
El palo largo del stack GNOME, sellado. link=dynamic (consistente con la glib .so
de la isla, evita mezcla de estado GType) + build_introspection_data=false: g-i 1.84
sólo generaba aquí los typelibs EXTERNOS de X11/cairo (cairo/xlib/xft/xrandr/xfixes/
win32) — que NO queremos (Wayland-only) y sobre los que g-ir-compiler hace SIGSEGV
bajo musl. Los typelibs CORE (GLib/GObject/Gio) los produce glib (absorbió
girepository). g-i aquí = las TOOLS (g-ir-scanner/compiler) + libgirepository-1.0.so.

Cadena del muro (6 capas): py3-setuptools → wrapper -static/-shared → wrapper
--export-dynamic/.so → glib dinámica → glib default_library=both → introspection_data
off. El scanner (ejecuta código del target, el miedo real) CORRE bit a bit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:30:49 -04:00
sergioandClaude Opus 4.8 b57ce69311 gnome isla: glib default_library=both (.a + .so)
g-i (link=static) compila binarios internos que hacen `-static -lglib-2.0`; con la
glib sólo-shared, zig falla "unable to find static system library glib-2.0" (no hay
.a). La isla necesita AMBOS: el .so para que g-ir-scanner resuelva la introspección
(y gjs lo dlopee en runtime), el .a para el link estático interno de los consumidores.
default_library=shared → both.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:25:21 -04:00
sergioandClaude Opus 4.8 319cfd83ec gnome isla: glib dinámica (shadow de la corpus) para destrabar introspección
El fork elegido: isla dinámica para GNOME. Piedra angular = glib como .so real,
porque g-ir-scanner exige "shared libraries" (el typelib mapea a una lib que gjs
dlopea en runtime) y la corpus es sólo libglib-2.0.a.

Variante link=dynamic (-Ddefault_library=shared) en la cola GNOME. NO toca
recipes/glib.toml (estática, la consume KDE/corpus entero — cambiarla re-hashea
cientos). Por el orden del resolver (hermano→padre) SOMBREA la corpus SÓLO para
recetas GNOME; el resto del árbol intacto. Deps internas (libffi/pcre2/zlib) siguen
estáticas embebidas en el .so. introspection=disabled (los typelibs los produce g-i
externamente, evita el ciclo glib↔g-i).

g-i re-hashea a 8c3e5dd1 (dep glib static→dynamic); prueba de fuego en worker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:18:24 -04:00
sergioandClaude Opus 4.8 d4eb77df14 harness: -static cede ante TODO link dinámico (no sólo -shared)
El wrapper anterior (quita -static con -shared) destrabó la extensión Python de
g-i, pero g-i es dinámico en 3 puntos y el fallo saltó a los otros dos:
"error: using shared libraries requires dynamic linking" en (a) las tools que
linkean libgirepository-1.0.so y (b) el dumper del scanner con -Wl,--export-dynamic.

Generalizo la regla del wrapper: -static se quita ante cualquier marcador de link
dinámico — -shared, -rdynamic, --export-dynamic, o un shared object (.so/.so.N) en
la línea. Todos son casos donde -static es contradictorio de por sí. El link
estático normal (exe/.a sin marcadores) y el compile puro quedan byte-idénticos.
Verificado contra las 2 líneas reales que fallaban + 2 casos de no-regresión.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:09:48 -04:00
sergioandClaude Opus 4.8 437d5bb103 harness: wrapper linker-driver que quita -static en links -shared
Las extensiones Python (python.extension_module → shared_module) son .so que el
intérprete del sandbox debe dlopen; intrínsecamente dinámicas. El harness inyecta
LDFLAGS=-static para link=static, y meson/autotools lo aplican a TODOS los targets
por igual ⇒ el .so sale ET_EXEC y dlopen da "Exec format error" (el muro de
gobject-introspection: _giscanner.cpython-312.so no cargaba).

Fix estructural (elegido sobre flip-a-dynamic): ensure_layout materializa en el
rootfs dos wrappers (hammer-zig-cc/-cxx sobre zig cc/c++) que QUITAN -static SÓLO
cuando el link lleva -shared. -static+-shared es contradictorio ⇒ correcto por
construcción: transparente (byte-idéntico) para todo link normal, arregla TODA
extensión Python futura, no sólo g-i.

Hash-safe: el ArtifactHash se deriva de inputs (receta+deps), no de los bytes ⇒
no re-hashea ninguno de los 700+ sellados (cache-hit intacto); sólo cambia builds
nuevos con .so dinámicos. Verificado: rota positional params, preserva orden y
espacios; transparente sin -shared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:04:23 -04:00
sergioandClaude Opus 4.8 ee2f3b6de3 gnome onda-1: py3-setuptools + destrabar los 2 fallos de la 1ª molienda
El worker molió la onda 1: gsettings-desktop-schemas SELLÓ (hash 4777231b
reproducido exacto). Los otros 2 fallaron con causas limpias:

- gobject-introspection: meson.build:29 exige `python3 (setuptools)` importable
  (instala giscanner como paquete python); el python3 del rootfs no lo trae.
  Fix: receta py3-setuptools (puro-python, copia a site-packages, sin pip ni red
  — espejo de meson.toml) + declararla en [deps].build.
- gnome-desktop: sub-declaré gsettings-desktop-schemas (schemas_dep en meson:62);
  ya sellada ⇒ añadida a [deps].build. Avanza el diagnóstico al siguiente muro
  real (iso-codes / xkeyboard-config / libseccomp, frontera genuina de la receta).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 00:44:02 -04:00
sergio 5db4c6931a estado: cosecha granja 2026-07-25T04:00:51Z — avance del árbol KDE 2026-07-25 00:00:51 -04:00
sergioandClaude Opus 4.8 da26b3a280 gnome onda-1: cola aislada incoming-gnome-onda1 para el worker
Las 3 raíces de la onda 1 (gsettings-desktop-schemas, gobject-introspection,
gnome-desktop) copiadas a una cola propia + añadida al QUEUES del worker-loop.
Aislar evita que el worker dispare rebuilds de spidermonkey/mutter (onda 2/3).

El cierre real de RECETAS de las 3 es 39 nodos, 0 en incoming-kde: el "gap del
resolver" que temía era de seed-edges (.pc cairo→libX11), NO de deps declaradas.
El espinazo corpus (38 nodos: gtk4/cairo/pango/gdk-pixbuf en recipes/) está 100%
sellado ⇒ el worker cachea todo e sólo construye las 3. Hashes byte-idénticos a
los sellos de incoming-gnome (base_dir no entra al hash).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 23:31:27 -04:00
sergio 4ebcba1301 estado: cosecha granja 2026-07-24T19:45:44Z — avance del árbol KDE 2026-07-24 15:45:44 -04:00
sergioandClaude Opus 4.8 6f9e30bcaf gnome: las 10 raíces del perfil escritorio-gnome — el perfil CIERRA (mapa real)
Autoradas top-down feature-minimal en incoming-gnome (parte por subagentes, parte
a mano tras un stall de API): gobject-introspection, gjs, gsettings-desktop-schemas,
gnome-desktop, gnome-session, gnome-settings-daemon, mutter, gnome-shell, gdm,
xdg-desktop-portal-gnome. Las 10 parsean (hash dry-run). Versiones GNOME 48 salvo
gnome-desktop (44.5: upstream no corta estable de la lib compartida tras 44.5).

Con las raíces, el perfil escritorio-gnome CIERRA: 70 nodos, 60 YA sellados, 10 en
deuda (las raíces), en 3 ondas topológicas. Contra los 613-694 del cierre nixpkgs:
la sobreestimación 5-10x confirmada en vivo. La frontera GENUINA que aún no tiene
receta va documentada como comentarios FRONTERA en cada TOML (json-glib, libei,
colord, gcr, libsecret, polkit, ibus, at-spi2, accountsservice, linux-pam, upower,
geoclue, libnotify, iso-codes, xdg-desktop-portal, libseccomp; + gtk3/x11 que
g-settings-daemon 48 aún exige incondicional). Deuda de resolver: pipewire/pulseaudio/
alsa-lib/xkeyboard-config existen en incoming-kde pero resolve_dep_path no ve esa cola.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 15:42:12 -04:00
sergio 4ae5a3422c estado: cosecha granja 2026-07-24T19:15:34Z — avance del árbol KDE 2026-07-24 15:15:34 -04:00
sergio 8669d5b45a estado: cosecha granja 2026-07-24T18:45:21Z — avance del árbol KDE 2026-07-24 14:45:21 -04:00
sergioandClaude Opus 4.8 afd867ea51 yupana: drenar reckona honesto un perfil sin cierre (guardián GNOME)
drenar --perfil escritorio-gnome erraba 'no encontré un grafo (¿corriste
build-state.py?)' — mentira: el grafo GNOME existe, pero NINGUNA raíz del perfil
(mutter/gnome-shell/gdm) está autorada ⇒ 0 nodos etiquetados con el perfil, y la
comprobación por etiqueta en cargar() fallaba. Dos correcciones:
  · cargar(): una cola NO-corpus identifica su grafo unívocamente ⇒ matchear por
    cola; la etiqueta sólo desambigua dentro de corpus (perfiles solapados).
  · main(): ámbito vacío con perfil ≠ 'imagen completa' — es 'SIN CIERRE todavía:
    0 raíces autoradas', y apunta a autorar top-down.
KDE (162 sellados) y corpus (769/4-deuda) sin regresión. El yupana-gnome queda
armado en las 4 capas: objetivo, radio/grafo, keystones y drenar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 14:23:12 -04:00
sergioandClaude Opus 4.8 9a028ba04f gnome: SPIDERMONKEY (mozjs 128) SELLA en el hub — keystone caído
El motor JS de Mozilla, keystone del frente GNOME (gjs→gnome-shell cuelgan de él),
sella b3:c48dbd10: libmozjs-128.so + libjs_static.a + shell js128 + mozjs-128.pc +
550 headers. Compiló el C++ entero a -O3 -j8 sin OOM en el hub (31GB/0 swap, al filo).

Seis capas iteradas desde el borrador:
  1-2. FIX DE INFRA: el rootfs builder tenía clang pero NO el paquete  (Alpine
       separa los binutils LLVM del compilador). Sin llvm-ar/llvm-objdump/llvm-profdata
       configure aborta. bootstrap-devfs.sh: +llvm22 en NEEDED + paso 3a-ter que
       symlinkea la suite llvm-* a /usr/bin (Alpine la deja en /usr/lib/llvm22/bin sin
       exponerla). Aplicado ya al rootfs real (.dev-fs/alpine).
  3. triple: mozjs no traduce vendor ; 4. debe COINCIDIR con el host de rustc
     (); fijado ese exacto.
  5. venv de mach: cada fase es un bwrap con /tmp fresco ⇒ el venv no sobrevivía de
     configure a compile. Anclado a /src/.mozbuild (persiste, es scratch).
No re-hashea artefactos (el rootfs no entra al hash). OJO: el worker golden también
necesita llvm22 (ya cubierto por bootstrap-devfs.sh para la próxima provisión).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 14:17:13 -04:00
sergioandClaude Opus 4.8 ebac490f39 estado: grafo GNOME refleja wave-1 sellada (login1 + nspr/nasm/cbindgen)
4 artefactos sellados en el hub, verificados --check:
  arje-logind-compat b3:410b6088 (login1 shim, estático musl)
  nasm b3:33383070 · nspr b3:d7b71315 · cbindgen b3:e59e4193
grafo GNOME CIERRA + topo-sort OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 13:19:42 -04:00
sergio a627fdeac6 estado: cosecha granja 2026-07-24T13:14:16Z — avance del árbol KDE 2026-07-24 09:14:16 -04:00
sergioandClaude Opus 4.8 3a4a566659 gnome: cbindgen — filtrar --bin (lib+bin homónimos rompían cargo rustc)
cbindgen expone lib Y bin con el mismo nombre; el codegen del binario final
(cargo rustc -- -C target-feature=+crt-static -C relocation-model=static) es
ambiguo con dos targets ('extra arguments to rustc can only be passed to one
target'). flags=['--bin','cbindgen'] fija el target. Sella b3:e59e4193 en el hub.
Cierra la wave-1 de leaves GNOME: nasm b3:33383070, nspr b3:d7b71315, cbindgen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 08:53:16 -04:00
sergio 8f8f3e66b8 estado: cosecha granja 2026-07-24T07:13:27Z — avance del árbol KDE 2026-07-24 03:13:27 -04:00
sergioandClaude Opus 4.8 69969a460c gnome: receta arje-logind-compat — login1 YA existe en tawasuyu (no hay que empaquetar elogind)
El daemon shim D-Bus de org.freedesktop.login1 ya está autorado y maduro en el
monorepo tawasuyu (arje-compat, un binario por servicio). Yo lo había dado por
inexistente grepeando SÓLO el repo hammer, no tawasuyu — error. seatd da asiento
(DRM/input), login1 da sesiones, y login1 = esto: arje-logind-compat implementa el
subset del Manager que GNOME/KDE consultan al boot (ListSessions/Seats/Users,
Inhibit, Can*/PowerOff/Reboot/Suspend, IdleHint) traduciendo al bus interno de arje,
fuera de PID1 y supervisado.

Receta HUB-ONLY (fuente gitea:22 ⇒ worker secretless da Connection refused). Pineada
a 06184e43 (rama selfhost/arje-zero-attest-lockfile): más nueva que la de arje-zero
porque trae el reorg arje-compat + el Cargo.lock del workspace en raíz ⇒ build
--locked reproducible. Sella dry-run: b3:410b6088. No hace falta C-ABI sd-login ni
PAM: la sesión se registra por el bus arje (mirada-greeter→fractal), no por pam_systemd.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 03:02:03 -04:00
sergio 4cf1761d5a estado: cosecha granja 2026-07-24T01:59:49Z — avance del árbol KDE 2026-07-23 21:59:49 -04:00
sergioandClaude Opus 4.8 b79651bbf6 gnome: autora mozjs (spidermonkey 128) + su wave-1 de leaves (nspr/nasm/cbindgen)
El keystone del frente. spidermonkey.toml es PRIMER BORRADOR — mozjs no sella a la
primera sobre musl (mach/configure no lo auto-detecta el lab ⇒ fases a mano, iterar
en worker ccx33+). Anclado al APKBUILD musl de Alpine: source del árbol firefox
128.14.0esr (sha real), clang, icu in-tree, nspr+zlib del sistema, shared-js.

Leaves que faltaban (ninguno estaba en el rootfs ni tenía receta):
  nspr 4.36 (autotools), nasm 2.16.03 (autotools), cbindgen 0.27.0 (Cargo).

Las 4 parsean (hash dry-run OK) y pueblan el grafo: yupana radio nspr/cbindgen ya
ven a spidermonkey como dependiente. Capa grafo del yupana-gnome VIVA y reckonando.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 16:11:00 -04:00
sergioandClaude Opus 4.8 d33fc94fc5 gnome: enciende la CAPA GRAFO del yupana-gnome
build-state.py gana --gnome (análogo a --kde): carga recipes/incoming-gnome/ y sale
a build-state-gnome.json. drenar/yupana/seed-graph aprenden ese grafo (keystones,
drenar --perfil escritorio-gnome, radio de nodos incoming-gnome, frontera). Hoy la
cola está vacía ⇒ el grafo trae 0 nodos gnome; se poblará al aterrizar recetas y ahí
drenar/keystones reckonan solos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 16:05:40 -04:00
sergioandClaude Opus 4.8 0b333b4c9e gnome: integra el frente a yupana — perfil escritorio-gnome + reckoning honesto
1. targets.toml: [perfil.escritorio-gnome] (9 raíces de sesión, cola incoming-gnome)
   ⇒ `yupana objetivo` ya lo ve; fluye por targets.py. build-state lo SALTA hasta
   que la cola se cargue (--gnome), así declararlo no reporta raíces fantasma.
2. seed-gnome.py OPTIMIZADO: hornea la triage (sustitución/tooling/opcional/espinazo)
   como HIPÓTESIS con el caveat "el cierre de nixpkgs sobreestima ~5-10×", marca el
   keystone (spidermonkey→gjs→gnome-shell), y deja de mentir con el 465 crudo. El
   espinazo (353) se reporta como COTA ALTA, no como lista de build.

Falta (se activa al autorar): grafo build-state-gnome + flag --gnome ⇒ keystones/
drenar nativos sobre GNOME. Hoy la capa OBJETIVO del yupana-gnome está; la GRAFO no.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:58:23 -04:00
sergioandClaude Opus 4.8 224b15f231 gnome: añade seed-gnome.py + los mapas del subtree (faltaron en 72de19c)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:50:17 -04:00
sergioandClaude Opus 4.8 72de19c3e0 gnome: arranca el frente — sembrado el subtree desde nixpkgs (mapa, no lista de build)
seed-gnome.py corre el cierre transitivo de las raíces GNOME sobre metadata de
nixpkgs y clasifica conocida/frontera/nix-ismo/lab. Hallazgo: el cierre de nixpkgs
SOBREESTIMA ~5-10× la frontera de hammer (arrastra códecs ffmpeg, plugins gstreamer,
samba, openjdk, sphinx docs — todo opcional). El número real sólo emerge autorando
top-down feature-minimal.

Sólido: 155 deps ya tienen receta; palos largos = spidermonkey(mozjs)+gjs;
gobject-introspection es build-tooling. Cola aislada recipes/incoming-gnome/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:49:48 -04:00
sergioandClaude Opus 4.8 b98995b7b4 deadman: NO contar farm-worker-loop como trabajo (3er bug del dead-man)
El loop del worker está SIEMPRE vivo (idle-loopea con la cola vacía). Contarlo
en hay_trabajo() reseteaba los ticks a 0 cada 10 min ⇒ el worker NUNCA acumulaba
idle ⇒ NUNCA se auto-mataba. Quedó 2h17m idle quemando € (2ª vez).

El loop construyendo YA se detecta por su hijo `hammer build`; el loop vacío NO
es trabajo. Se afina el match a `release/hammer.* build ` y se suma `campana-deuda`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 14:14:16 -04:00
sergio 815b311021 estado: cosecha granja 2026-07-23T08:08:36Z — avance del árbol KDE 2026-07-23 04:08:36 -04:00
sergioandClaude Opus 4.8 2bd1944173 deadman: --puede-borrar sourcea /etc/hammer-deadman.env (o daba falso-negativo)
Cazado con el 1er worker real: el token vive en /etc/hammer-deadman.env (lo carga
systemd como EnvironmentFile), pero corrido A MANO (farm-up --puede-borrar) ese
fichero no se lee solo ⇒ mi cadena de fallback no lo veía ⇒ decía 'sin token' y
farm-up habría DESTRUIDO un worker que sí puede matarse. Fix: sourcear el
EnvironmentFile antes de la cadena de tokens desnudos. Verificado en worker real:
'SÍ: puedo borrar mi id=154276696'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 03:48:41 -04:00
sergioandClaude Opus 4.8 3de75a5229 granja: el dead-man del worker se mata SOLO (sin hub) — 3 bugs + gioser doble-blindado
El worker DEBE matarse solo, sin depender de la laptop (es la razón de ser del
dead-man: vive en el worker; el volumen hace que morir no pierda nada). El reaper
del hub queda sólo como último recurso. El dead-man estaba TRIPLEMENTE roto:

 1. TOKEN EN EL FICHERO EQUIVOCADO: hay 2 caminos de creación con el token en
    lugares distintos (farm-up → /etc/hammer-deadman.env; harkaq-vol → /root/
    .hcloud-token). La service lee sólo el primero ⇒ un worker del otro camino
    quedaba sin token, disparaba pero salía 1 "sin HCLOUD_TOKEN". Fix: deadman.sh
    busca el token EN CADENA (volumen primero, que es lo más persistente).
 2. REGEX DEL ID ROTO: la API devuelve JSON con espacio ("id": 126, no "id":126)
    y el dead-man usaba '"id":[0-9]+' ⇒ NUNCA resolvía su id, aun con token
    válido. Fix: '"id":[[:space:]]*[0-9]+'. (Doblemente roto: por eso NUNCA murió.)
 3. FIRING ≠ CAN-DELETE: farm-up sólo verificaba que el timer dispara. Ahora
    corre `deadman.sh --puede-borrar` (token en cadena + ve su id en la API) y si
    NO puede matarse, DESTRUYE el worker ahí mismo. Un worker que no se autodestruye
    es inadmisible ⇒ jamás debe existir.

gioser DOBLE-BLINDADO en TODOS los sitios de borrado (lista negra por nombre +
label role=hammer-worker), igual que farm-down ya tenía: reaper, farm-up-destroy,
deadman, y el helper de harkaq-vol. "Ahí está nuestra vida." Verificado vivo (104d).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 03:23:42 -04:00
sergioandClaude Opus 4.8 be06314336 granja: el reaper dropea de .fleet los workers que ya no existen en hcloud
Sin esto un server borrado se quedaba en .fleet para siempre (describe falla ⇒
'sin label' ⇒ nunca se dropeaba). Ahora si no existe en hcloud, se saca.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 03:08:13 -04:00
sergioandClaude Opus 4.8 1203f86cda granja: reaper HUB-SIDE — la garantía "vps idle inadmisible" deja de depender del worker
INCIDENTE (2026-07-23): un worker quedó 3.5h idle quemando € mientras el usuario
dormía. El dead-man del worker estaba "activo" (timer disparando cada 10 min)
pero FALLABA con exit 1 en cada tick: llegaba a matarse pero su
/etc/hammer-deadman.env no tenía token válido ⇒ salía 1 "sin HCLOUD_TOKEN" y
nunca se borraba. Verificaron que el timer DISPARA, no que puede BORRAR —
firing ≠ can-delete.

Causa de fondo: la garantía dependía de que CADA worker se auto-provisione bien
un token, y eso falla EN SILENCIO. Un invariante que depende de una provisión
frágil no es un invariante.

FIX en dos capas (defensa en profundidad):
 1. REAPER HUB-SIDE (cosecha-cron.sh): el hub tiene un token que funciona y el
    latido corre cada 30 min aunque no haya sesión (setsid). Un worker sin trabajo
    activo REAPER_MAX=2 ciclos (~1h) se BORRA desde el hub, con el MISMO blindaje
    de label role=hammer-worker (gioser jamás pasa). Cubre "dead-man del worker
    roto". El dead-man del worker sigue cubriendo "hub caído".
 2. farm-up verifica CAN-DELETE, no sólo firing: que el token del worker vea su
    propio id en la API (lo mismo que hace al morir). Si no puede, LO GRITA al
    provisionar en vez de descubrirlo 3.5h tarde.

Acción inmediata tomada: worker borrado a mano (label verificado), €0 baseline
restaurado — sólo queda gioser (protegido, fijo). Todo estaba cosechado.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 03:05:12 -04:00
sergio ada3767e0e estado: escritorio-kde COMPLETO 162/162 — el overlay fix desbloqueó el frente entero
La campaña de 40 nodos KDE selló 40/40, 0 fallidas: kio (desbloqueado por 6a0dc40)
arrastró la cascada y completó el escritorio. De 85/162 al abrir el catálogo a
162/162. 41 tiempos reales cosechados para el camino crítico pesado.
2026-07-23 02:45:56 -04:00
sergio 89e807f793 estado: cosecha granja 2026-07-23T03:32:31Z — avance del árbol KDE 2026-07-22 23:32:31 -04:00
sergio 794b869cb8 estado: cosecha granja 2026-07-23T03:01:33Z — avance del árbol KDE 2026-07-22 23:01:33 -04:00
sergio 431fe071f5 estado: cosecha granja 2026-07-23T02:30:30Z — avance del árbol KDE 2026-07-22 22:30:30 -04:00
sergio 605620d8b7 estado: cosecha granja 2026-07-23T01:59:17Z — avance del árbol KDE 2026-07-22 21:59:17 -04:00
sergioandClaude Opus 4.8 8c10c0a908 yupana: modelo EXTRA-GRAFO — preflight aprende los patrones de hueco de entorno
El grafo modela deps (R1: Receta×Receta). El entorno es OTRA capa: R2 (Receta×
Capacidad, qué exige un build) y R3 (Host×Capacidad, qué ofrece la máquina).
Construible = clausura(R1) ∧ R2⊆R3. Esos huecos viven FUERA del grafo (infra del
sandbox, toolchain, layout de fs) y una matemática de grafos sola no los ve —
pero SÍ se aprenden, como patrones con predictor, calibrados contra fallos reales.

`yupana preflight <receta>` corre los patrones ANTES de construir. Primer patrón:
overlay-lowerdir, la cicatriz de kio. Habría marcado kio antes de quemar la
campaña descubriéndolo a los golpes:

  kio: 52 deps ⇒ lowerdir ~5346B > 4096B (una página) ⇒ depende del merge

CALIBRADO, no adivinado: el estimador daba corto (2974B "ok") hasta usar el
prefijo que bwrap VE en runtime (/oldroot/…, ruta del worker, no la del hub).
Con eso: kio estimado 5346B vs real 5315B — 31B de error, sin fudge. El primer
predictor "obvio" mentía con confianza; la lección de siempre.

preflight --perfil escritorio-kde destapa lo sistémico: las 40 recetas KDE
profundas CUELGAN del merge (plasma-desktop: 114 deps → 11708B, casi 3× el
límite). Todo el escritorio dependía del fix 6a0dc40. El pre-flight vuelve
VISIBLE y contable una fragilidad que antes sólo se manifestaba fallando.

Registro extensible (PATRONES_ENTORNO): futuros = capacidad-de-host (rootfs
laptop≠worker, techo MSRV — acumular observaciones), skew de toolchain (zig-skew
— fingerprint por artefacto). harkaq ya MIDE R2 (evidencia negativa); esto lo
vuelve consultable + pre-vuela. Guardián: kio marcado + estimador calibrado.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 21:42:42 -04:00
sergio 7f2ebdbb8b estado: cosecha granja 2026-07-23T01:28:20Z — avance del árbol KDE 2026-07-22 21:28:20 -04:00
sergioandClaude Opus 4.8 6a0dc40a05 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>
2026-07-22 21:06:10 -04:00
sergio b9da01631d estado: cosecha granja 2026-07-23T00:26:38Z — avance del árbol KDE 2026-07-22 20:26:38 -04:00
sergioandClaude Opus 4.8 85b5a9bc46 yupana: instrumentar duración de build en el worker → camino crítico PESADO
El peso que le faltaba a las ondas: sin él, critical-path = nº de pasos; con él,
ETA real en segundos.

INSTRUMENTACIÓN (worker):
  scripts/farm/build-timed.sh envuelve `hammer build` midiendo la pared y la
  registra en $STORE/.times/<hash>-<host>.json — un SIDECAR del store, NUNCA
  dentro del artefacto. La duración es no determinista (varía por máquina/carga)
  ⇒ no puede tocar el ArtifactHash. Keyed por hash (CAS-safe: dos workers no se
  pisan) + host (varias muestras por receta). Viaja al hub con el rsync de store
  que ya hace la cosecha; ninguna herramienta del store lo confunde con artefacto.
  Sólo builds REALES (pared ≥ UMBRAL 3s) — los cache-hits no envenenan la mediana.
  campana-deuda.sh ahora construye vía build-timed.sh (transparente, mismo exit).

CONSUMO (hub): yupana._tiempos() carga name→mediana de segundos; keystones
computa el CAMINO CRÍTICO pesado = longest weighted path del subgrafo de deuda
(peso = segundos de build). La cadena más larga hay que construirla en SERIE
aunque haya ∞ workers ⇒ es la ETA con paralelismo infinito. Degrada con gracia:
sin datos, peso=1 y el camino crítico = nº de pasos (lo que ya daban las ondas).

Verificado: con muestras sintéticas da "ETA 19 min sobre 5 pasos, kio → kparts →
frameworkintegration → breeze → plasma-integration"; sin datos degrada a "5 pasos
(SIN datos)". store/.times está git-ignorado (metadata de máquina, no se commitea).

LÍMITE honesto (en la cabecera de build-timed.sh): `hammer build` arrastra deps ⇒
la pared incluye deps no selladas. En orden topológico (drenar) las deps ya están
selladas y la pared mide sobre todo ESTA receta — cota superior buena para pesar.
La precisión exacta pediría instrumentar el sellado dentro de hammer-build (Rust).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 20:25:09 -04:00
sergioandClaude Opus 4.8 4f609080df yupana: los 2 "bugs" de duplicados eran falsos positivos MÍOS — detector afinado, 0 reales
El usuario pidió arreglar itstool y la sombra de dbus. Apliqué el reflejo
(`yupana radio` + diff completo antes de tocar) y NINGUNO era un bug: ambos eran
patrones deliberados y documentados que mi detector, demasiado superficial, leyó
mal. Si los "arreglaba" a ciegas rompía dos builds.

  · dbus: corpus/dbus (estático) e incoming-kde/dbus (dinámico) NO son redundantes
    — qtbase linkea libdbus-1.so dinámicamente para Qt6DBus. El detector comparó
    sólo versión+sha+deps, no el BUILD. Borrar la sombra rompía KDE.
  · itstool: es un STUB documentado (`[source]=carrier`). El itstool real es
    Python con libxml2-bindings ausentes en el lab; este genera un script inline y
    sólo PRESTA el tarball de gettext-tiny. Apuntarlo al itstool real rompía
    appstream (radio 5) con un source que ni compila acá.
    Los 3 *-hello son el mismo patrón carrier; prison/prison-scanner una variante
    cross-nombre (misma fuente, WITH_ZXING distinto).

FIX = el detector, no las recetas. Tres señales que le faltaban:
  1. huella de BUILD en la firma de sombra (estático≠dinámico ⇒ no redundante).
  2. CARRIER: ≤1 receta del grupo construye la fuente ⇒ el resto presta el tarball.
     Señal: ¿invoca make/meson/cmake/ninja/cargo? (comentarios strippeados — la
     prosa "invocación de meson" de un stub daba falso builder, lo cazó el guardián).
  3. variante cross-nombre: ≥2 builders con BUILD distinto = deliberado, no bug.
Resultado: 0 colisiones reales (invariante c se cumple), 4 carrier + 14 variantes
+ 12 sombras justificadas, todas benignas.

Guardián extendido: ancla que el detector agrupa por FUENTE (itstool↔gettext-tiny)
y NO cría lobos (itstool=carrier, dbus=variante deliberada).

LECCIÓN: el reflejo del radio/diff antes de tocar evitó dos borrados destructivos
guiados por un falso positivo de mi propia herramienta. Medir antes de creer, aun
a la propia yupana.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 20:14:10 -04:00
sergioandClaude Opus 4.8 619a30187c yupana: keystones — el camino crítico real, con la matemática correcta (AND, no OR)
`yupana keystones` rankea los nudos EN DEUDA por cuánto trabajo BLOQUEADO libera
su sellado (cierre inverso transitivo restringido a la deuda). Sellá de arriba
hacia abajo y la cascada cae lo antes posible.

CORRIGE UN ERROR MÍO: dije "árbol de dominadores = keystones". Lo medí y es
FALSO. El dominador ingenuo asume alcanzabilidad OR (basta un camino), pero
construir es AND (hacen falta TODAS las deps): kcoreaddons depende de dbus/libdrm
/mesa además de qtbase ⇒ hay un camino de desbloqueo que evita qtbase y el
dominador-OR lo pierde. La métrica correcta bajo AND es el cierre inverso
transitivo. Y el crudo lo gana el toolchain (make gatea 313, inútil) ⇒ el
keystone accionable es el cierre restringido a la deuda, y sólo cuenta si el
nudo mismo está en deuda (un sellado ya está disponible, no gatea nada).

Estado actual (qtbase ya sellado, era EL keystone con 117 gateados):
   kio        36   ← sellarlo libera 36 recetas KDE bloqueadas
   kparts     19
   kcmutils   17
   ksvg       14
   libplasma  13
Ése es el camino crítico ahora.

El dominador SÍ entra, en su uso legítimo: la columna `exclusivo` = retención
estilo GC (nodos que sólo dependen de mí). kwin=9 (sus plugins privados),
libksysguard=3. Responde "si suelto esta feature, cuánto más puedo soltar".

Sin datos nuevos (no necesita duración de build). Cuando instrumentemos tiempos,
el mismo cierre se vuelve camino crítico PESADO (ETA real).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 20:03:56 -04:00
sergioandClaude Opus 4.8 0f3a1dc394 yupana: invariante (c) CANÓNICO — detector de duplicados por evidencia de fuente
`yupana duplicados` caza nudos que son el MISMO paquete bajo nombres/colas
distintos, agrupando por lo que BAJA (sha/url), no por el nombre. Clasifica:

  colisión-fuente — mismo sha, familias de nombre DISTINTAS ⇒ casi seguro un
                    sha copiado por error. ACCIONABLE.
  variante        — mismo sha, misma familia (zlib/zlib-shared, mesa-*) ⇒
                    diversificación deliberada estático/shared, OK (14 vistas).
  sombra          — mismo nombre en >1 cola; redundante si versión+sha+deps
                    coinciden (una sobra), justificada si difieren.

HALLAZGO INMEDIATO — el detector encontró un bug real en su primera corrida:
  itstool.toml dice versión 2.0.7 pero su url+sha apuntan al tarball de
  gettext-tiny (29cc165e…). Construiría la fuente equivocada. radio itstool=1,
  gettext-tiny=78 ⇒ el sha copiado es el de itstool.
Otras 3 colisiones son demos (adwaita-hello/libadwaita, sourceview-hello/
gtksourceview, radio 0) o subcomponentes (prison/prison-scanner) — a revisar,
no urgentes. Y 1 sombra redundante: incoming-kde/dbus es byte-idéntica a
corpus/dbus (mismo hash de artefacto) ⇒ los 114 consumidores KDE podrían
apuntar a corpus/dbus sin rebuild.

NO funde nada solo: reporta a docs/state/duplicados.json y deja el juicio al
humano (como el triaje). El radio de cada nudo dice cuál es el canónico (el de
mayor radio). Guardián extendido: test-yupana-radio.py falla si el detector
deja de ver colisiones de fuente (agrupar por nombre en vez de sha = invariante
c ciego).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:59:20 -04:00