Commit Graph
281 Commits
Author SHA1 Message Date
sergioandClaude Opus 4.8 61171bfe7f harkaq: Q2 RESUELTA — el runtime base son 5 paths, y aparece una 3ª categoría
Método (lo importante): NO se adivina, se mide. MODE=base corre SIN ninguna dep
declarada ⇒ sin clausura que pueda explicarlas, toda denegación es runtime base
por definición. Aísla la respuesta sin juicio de valor.

MODE=base, hello.c mínimo con zig cc: 18 denegaciones, 4 paths distintos
(contador del kernel 19 = 18 + canario ✓):
    8× /dev/urandom   6× /usr/lib/os-release   3× /dev/null   1× /usr/bin/env
Y el build salió rc=0: no son cosas que el build NECESITE, son cosas que INTENTA
— pero salen en todos los builds y sin tratarlas entierran la deuda real.

La partición cierra en TRES categorías, todas medidas (§4.2):
  - Contrato del sandbox: /src /out /tmp /dev/null(rw) /dev/urandom /proc
    /opt/zig — los monta BWRAP, no son Alpine ⇒ no son deuda. Ésta era la línea
    divisoria que faltaba.
  - Runtime base Alpine: /bin/sh /bin/busybox /lib/ld-musl /usr/bin/env
    /usr/lib/os-release. CINCO. ⇒ el resto de Alpine es deuda genuina, y eso
    hace viable todo el planteo.
  - Denegación ESPERADA (no estaba en el diseño): /usr/bin/gcc. zig cc lo sondea
    3× y el build sale rc=0 igual ⇒ NO es ruido a permitir, es la jaula haciendo
    su trabajo: concederla dejaría a zig invocar el gcc de Alpine por detrás,
    justo lo que la campaña "matar gcc" persigue a mano. Es D3 literal ("una
    denegación esperada no se calla, se CLASIFICA") y confirma que no tener
    `quiet` era correcto: silenciarla habría borrado el hallazgo.

El contraste con el mismo runtime base:
  MODE=base  rc=0  Impuro [ /usr/bin/gcc ]            ← esperada
  MODE=zlib  rc=1  Impuro [ /usr/lib/libz.so.1.3.2 ]  ← DEUDA PURA, sin ruido

Consecuencia de diseño para el Verdict: las denegaciones tienen que venir
CLASIFICADAS (base|esperada|deuda), no en lista plana. `Hermetico` debe
significar "cero deuda", no "cero denegaciones" — si no, ningún build real lo
alcanzaría jamás.

Gotchas medidos: /dev/null es destino de ESCRITURA (rw, no ro) y el piso duro es
/bin/sh→busybox→ld-musl (sin eso ni el canario corre ⇒ sólo SinEvidencia).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:28:47 -04:00
sergioandClaude Opus 4.8 24c6ab455e harkaq: §4 corregido (política POR FICHERO) + Q2 con método y primeros datos reales
CORRECCIÓN ESTRUCTURAL del §4 (otra herencia del marco nix). El Draft 2 decía
`fs_ro: [store paths de la clausura]`. Falso: esos paths NO existen dentro del
sandbox. `Sandbox::bwrap_args` apila las deps con --overlay-src y las FUNDE en
el mismo /usr que el rootfs Alpine, a propósito, para que el compilador las
encuentre sin plumbing de flags. Medido:

  /usr/include/zlib.h   (dep DECLARADA)        dev=63 ino=13641973
  /usr/include/stdio.h  (Alpine, NO declarado) dev=63 ino=4196788
  /usr/include          (el directorio)        dev=61 ino=15  ← overlayfs, uno

Una regla sobre /usr concede las dos ⇒ la evidencia no valdría nada. Ni `dev`
distingue. ⇒ La clausura se enumera FICHERO A FICHERO (computable: en el host
sabemos qué aporta cada dep). Dos consecuencias: `list` ≠ `ro` (pkgconf NECESITA
escanear /usr/lib/pkgconfig, pero listar no es leer; Landlock separa READ_DIR de
READ_FILE) y máscara por tipo (derechos de-sólo-dir sobre un fichero ⇒ EINVAL y
la regla entera se cae).

Piezas nuevas: harkaq-policy.sh (deriva la clausura, D1) + q2-runtime-base.sh
(responde Q2 midiendo, no adivinando) + harkaq-exec con `list`/máscara por tipo.

Q2, primeros datos con un build REAL en el sandbox REAL contra la dep zlib:
  estado: Impuro | canario: True | contador kernel: 3
      fs.read_file /usr/bin/env
      fs.read_file /usr/lib/libz.so.1.3.2   ← la zlib de ALPINE!

El build se linkaba contra la zlib de Alpine en vez de la dep declarada (que
aporta libz.a). Sin harkaq eso pasa en verde y el artefacto queda dependiendo de
Alpine. ES EXACTAMENTE EL BUG DEL §0, cazado en un build real.
Piso duro del runtime base: /bin/sh → /bin/busybox → /lib/ld-musl (sin eso ni el
canario corre ⇒ el mínimo es "lo que hace falta para que el canario pueda correr").

Dos rastrillos: el canario no puede depender de un binario (`cat` moría en
/bin/cat ⇒ ahora `read _ < $CANARY`, sólo builtins) ni vivir en /tmp (la política
concede `rw /tmp` ⇒ el canario caía DENTRO de la clausura y no denegaba nada).
El segundo lo cazó D9 MISMO: el lector se negó a certificar en vez de decir
Hermetico. El canario funcionando como se diseñó, sobre un bug de quien lo diseñó.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:20:39 -04:00
sergioandClaude Opus 4.8 4eecba06f4 harkaq: Fase 1 — la cadena corre de punta a punta (Hermetico / Impuro sobre kernel real)
Tres piezas nuevas, las del §4 del SDD:
  - harkaq-audit.c  lector de evidencia; HOST junto a hammerd, CAP_AUDIT_READ;
                    espera el canario (que revela el domain=), junta las
                    denegaciones de ESE dominio, cruza contra el contador del
                    kernel al liberarse, y emite el Verdict JSON de 3 estados.
  - harkaq-exec.c   aplica la política y execea el builder; DENTRO de bwrap,
                    estático (rootfs musl). Negocia el ABI por syscall (D7:
                    <min rechaza, <7 avisa SIN EVIDENCIA) y pone
                    LOG_NEW_EXEC_ON + TSYNC.
  - harkaq-run.sh   encadena lector+bwrap+exec, pone el canario con nonce y
                    espera a que el lector confirme que escucha (--ready-fd)
                    antes de arrancar el build: sin esa barrera el canario se
                    emitiría sin nadie escuchando y daría SinEvidencia por una
                    carrera, no por un problema real.

El hito, con comandos sintéticos sobre el kernel real (ABI 10):
  limpio  {"estado":"Hermetico","canario_visto":true,"contador_kernel":1,"denials":[]}
  impuro  {"estado":"Impuro","canario_visto":true,"contador_kernel":2,
           "denials":[{"blockers":"fs.read_file","path":"…/README.md",…}]}
Canario visto y contador coherente en ambos ⇒ los 3 estados de D9 funcionan.

Q1c contestada en la práctica: el privilegio vive en un helper chico con
`setcap cap_audit_read,cap_audit_control`, NO en hammerd entero.

Sutileza medida: lo que DAC ya bloquea es INVISIBLE para harkaq (el hook del
LSM no llega a correr). Descubierto porque el escenario "impuro" con
/root/.bashrc (drwx------) dio Hermetico: DAC lo bloqueó antes que Landlock.
No rompe D2 (si DAC lo bloqueó, el build tampoco lo usó ⇒ Hermetico es cierto)
pero acota el diagnóstico, y al escribir tests hay que elegir paths que DAC
permita o el control no controla nada.

Falta para cerrar Fase 1: harkaq-policy derivando de la clausura real + el
contraste receta-de-Alpinizada vs. receta-que-no. El rebuild del kernel
(SECURITY_LANDLOCK) NO bloquea el hito: sólo hace falta para que harkaq corra
DENTRO de hammer; el laptop ya está en ABI 10.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:04:27 -04:00
sergioandClaude Opus 4.8 6419f2a952 harkaq: Q1b CERRADA — la evidencia cruza el userns y el canario es la clave primaria
Banco: scripts/harkaq/q1b-attrib.c. Dos builds CONCURRENTES en bwrap
--unshare-all (los ns de Sandbox::bwrap_args), sin privilegio (uid 1000),
canarios con nonce distinto, lector en el host como root.

(a)  Los registros CRUZAN el userns/pidns/mountns (6 registros llegaron al
    lector del host) y cruzan con builds SIN privilegio, que es como corren de
    verdad. ⇒ harkaq-audit vive en el host junto a hammerd; la arquitectura
    del §4 se sostiene.
(b)  El canario con nonce ATRIBUYE: AAAA=1 BBBB=1, cero cruces con 2 builds
    en paralelo. ⇒ la granja puede construir en paralelo sin contaminarse la
    evidencia entre builds.

Tres hallazgos colaterales que valen más que el veredicto:
  - El contador quedó VALIDADO: dos `deallocated denials=1`, uno por dominio,
    cuadrando con 1 ACCESS cada uno ⇒ el chequeo anti-pérdida (nº ACCESS ==
    denials) está medido, no supuesto.
  - La identidad sobrevive a los ns: pid=8498 uid=1000 son del HOST (adentro
    del pidns la víctima es pid 1).
  - dev+ino identifican el OBJETO, no el BUILD: los 2 canarios dan el mismo
    ino=4457713 (ambos bindean /etc/hostname). Atribuir por dev/ino habría
    fundido dos builds leyendo el mismo fichero no declarado — el caso más
    común que harkaq va a ver. La clave es domain=, y el canario la revela.

⇒ D9 hace TRES trabajos con un mecanismo: honestidad (§3.4), clave primaria
(§3.5) y, vía el contador, detección de pérdida.

Nota de método: esta corrida también falló 2 veces más, y las 2 el banco
afirmó algo falso con total confianza. (1) `cat $canario >/dev/null` — /dev no
estaba en la clausura ⇒ sh fallaba en el REDIRECT y cat no corría; el rc=1 no
era del canario. (2) Como root, bwrap no pudo ni ejecutar el binario y el
veredicto imprimió "NADA cruzó ⇒ replantear la arquitectura" a partir de cero
estímulo (causa: --unshare-all mapea sólo uid 0→0; CAP_DAC_OVERRIDE en userns
sólo vale sobre uids MAPEADOS ⇒ root-en-userns no atraviesa un home
drwx------). Fix: drop_privs() + gate de estímulo (exit 4 si una víctima no
sale con status 0).

Van 3 veces en una sesión que un cero fue el instrumento y no el kernel, con
quien escribía el banco mirando de frente ese riesgo. harkaq sin canario no es
un riesgo de configuración: es el comportamiento por defecto.

Quedan Q1c (privilegio de harkaq-audit: mejor un helper acotado que hammerd
entero) y Q1d (qué ruta reporta exe= con --bind /src).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:12 -04:00
sergioandClaude Opus 4.8 ad0948cfb0 harkaq: Q1 CERRADA — la evidencia llega; + D9 (canario deliberado) y el banco de pruebas
Q1 era el gate del proyecto (¿llegan los registros AUDIT_LANDLOCK_* a un
lector?). Medido en el laptop (ABI 10) con scripts/harkaq/q1-audit.c:

   VIABLE. El multicast AUDIT_NLGRP_READLOG entrega
     blockers=fs.read_file path="/etc/passwd" dev="nvme1n1p6" ino=4458369
     + exe=/comm= del que lo intentó. Es el diagnóstico de de-Alpinización
     que el SDD promete, saliendo del kernel sin instrumentar nada.

Dos precondiciones que el Draft 2 no tenía, ambas medidas:
  - audit_enabled=1 NO viene de fábrica (sin audit=1 en cmdline, sin auditd)
    ⇒ cero registros de cualquier escenario. AUDIT_SET o audit=1 horneado.
  - LOG_NEW_EXEC_ON es OBLIGATORIO: same-exec=2 registros, new-exec=0,
    new-exec-logon=4. harkaq restringe y DESPUÉS execea el builder ⇒ sin el
    flag certificaría herméticos TODOS los builds, denials=[], sin un error.

D9 (nueva, no negociable): el canario lo fabrica harkaq. Se investigó si el
registro `deallocated denials=N` servía de verificación cruzada gratis: NO.
Medido con ventana de 6s, un dominio con flags default y denegación post-exec
no emite NADA (ni allocated, ni access, ni el contador); y el `allocated` es
perezoso (llega pegado al primer denial logueado) ⇒ su ausencia tampoco prueba
nada. Un build hermético y un lector ciego son bit-idénticos: denials=[]. El
Verdict pasa a 3 estados (Hermetico / Impuro / SinEvidencia).
El contador SÍ sirve para lo otro: nº ACCESS == denials caza registros
perdidos por backlog (riesgo real con la granja en paralelo).

Nota de método (§3.4): la 1ª corrida dio 0 en los 3 escenarios y "confirmaba"
la hipótesis. Era el instrumento roto (AUDIT_GET con NLM_F_ACK: el ACK llegaba
antes que la respuesta → enabled=-1 → nunca se encendía el audit). Se cazó
sólo porque el CONTROL (same-exec) también dio 0, y eso era imposible. Es el
modo de falla de harkaq en vivo sobre su propio banco. El test ahora aborta
(exit 4) si no confirma audit_enabled=1.

Nuevas Q1b (¿el lector ve a través del userns de bwrap? ¿cómo se atribuye un
registro a SU build con la granja en paralelo?) y Q1c (privilegio de
harkaq-audit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 13:23:19 -04:00
sergioandClaude Opus 4.8 e263b66ec1 mirada/USB: telemetría persistente en el pendrive + bump a mirada de hoy (fix musl en tawasuyu)
TELEMETRÍA (el pedido): el rootfs de la imagen es un initramfs = RAM pura y los logs iban a /run (tmpfs)
⇒ al apagar la máquina ajena no sobrevivía NADA. Ahora la imagen lleva 2da partición FAT32 MIRADALOG
(512M), montada por findfs+LABEL con -o sync (un cuelgue de GPU o corte de luz no se lleva los logs).
Cada arranque vuelca run-NNNN/ con: resumen (modo/GPU/driver), hardware (PCI vía sysfs, módulos, DRM,
input, firmware), pantallas (status/modes por conector), dmesg ANTES y DESPUÉS de mirada, seatd, y el log
del compositor+greeter con RUST_LOG=wgpu_core=debug + EGL_LOG_LEVEL=debug + LIBGL_DEBUG=verbose (para ver
por qué wgpu eligió el backend y si hay float16). Shell de rescate + . FAT32 a propósito: el
pendrive se lee después desde cualquier SO.

metal-usb-sdboot.sh gana DATA_MB/DATA_LABEL genéricos (partición de datos opcional en la GPT).

GOTCHAs verificados antes de confiar: el kernel linux-generic SÍ trae VFAT_FS=y + NLS + USB_STORAGE=y
(sin eso no montaba); el busybox de Alpine NO trae el applet 00:00.0 Host bridge: Intel Corporation Tiger Lake-UP3/H35 4 cores Host Bridge/DRAM Registers (rev 01)
00:02.0 VGA compatible controller: Intel Corporation TigerLake-LP GT2 [Iris Xe Graphics] (rev 01)
00:04.0 Signal processing controller: Intel Corporation TigerLake-LP Dynamic Tuning Processor Participant (rev 01)
00:07.0 PCI bridge: Intel Corporation Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #0 (rev 01)
00:08.0 System peripheral: Intel Corporation GNA Scoring Accelerator module (rev 01)
00:0a.0 Signal processing controller: Intel Corporation Tigerlake Telemetry Aggregator Driver (rev 01)
00:0d.0 USB controller: Intel Corporation Tiger Lake-LP Thunderbolt 4 USB Controller (rev 01)
00:0d.2 USB controller: Intel Corporation Tiger Lake-LP Thunderbolt 4 NHI #0 (rev 01)
00:12.0 Serial controller: Intel Corporation 500 Series Chipset Family On-Package Integrated Sensor Hub (rev 20)
00:14.0 USB controller: Intel Corporation 500 Series Chipset Family On-Package USB 3.2 Gen 2x1 (10 Gbs) xHCI Host Controller (rev 20)
00:14.2 RAM memory: Intel Corporation 500 Series Chipset Family On-Package Shared SRAM (rev 20)
00:14.3 Network controller: Intel Corporation Wi-Fi 6 AX201 (rev 20)
00:15.0 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package I2C Controller #0 (rev 20)
00:15.1 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package I2C Controller #1 (rev 20)
00:16.0 Communication controller: Intel Corporation 500 Series Chipset Family On-Package CSME HECI #1 (rev 20)
00:1c.0 PCI bridge: Intel Corporation 500 Series Chipset Family On-Package PCI Express Root Port #5 (rev 20)
00:1d.0 PCI bridge: Intel Corporation 500 Series Chipset Family On-Package PCI Express Root Port #9 (rev 20)
00:1f.0 ISA bridge: Intel Corporation 500 Series Chipset Family On-Package eSPI Controller (rev 20)
00:1f.3 Multimedia audio controller: Intel Corporation 500 Series Chipset Family On-Package High Definition Audio (HD Audio) (rev 20)
00:1f.4 SMBus: Intel Corporation 500 Series Chipset Family On-Package System Management Bus (SMBus) (rev 20)
00:1f.5 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package SPI (flash) Controller (rev 20)
39:00.0 Non-Volatile memory controller: Kingston Technology Company, Inc. NV2 NVMe SSD [SM2267XT] (DRAM-less) (rev 03)
3a:00.0 Non-Volatile memory controller: ADATA Technology Co., Ltd. IM2P33F3 NVMe SSD (DRAM-less) (rev 03) (sí findfs/blkid) ⇒ el dump de PCI
lee /sys/bus/pci/devices/*/ directo; sintaxis del init validada con busybox ash (no bash).

BUMP mirada: el pin era 9967b02c (18-jun) — 439 commits viejo. Ahora 9a17fefc, que incluye el fix de
portabilidad a musl que hice en tawasuyu (ioctl: glibc usa c_ulong, musl c_int ⇒ las constantes DRM
casteaban mal y mirada-compositor NO compilaba para musl). mirada-compositor ya selló (87ced528);
greeter/ctl en curso.

+ scripts/kde/{metal-desktop-image,plasma-start-metal}.sh del hilo KDE (imagen de escritorio en metal).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:20:55 -04:00
sergio dcae94f411 kde/Plasma: 🎉 H-SHELL — plasmashell carga el escritorio + panel sobre kwin (headless, soberano)
run-plasma-headless.sh lanza kactivitymanagerd antes de plasmashell (plasmashell aborta sin él).
RESULTADO: kwin_wayland --virtual composita + plasmashell carga org.kde.plasma.desktop (Desktop.qml),
el panel puebla applets, kactivitymanagerd corre, actividades registran, xkb funciona. El escritorio
KDE Plasma 6 PRENDE headless por software desde el rootfs musl soberano. Applets restantes (polish):
kickoff/notifications piden org.kde.coreaddons QML (kcoreaddons KCOREADDONS_USE_QML, cascadea) +
kirigami-addons (no construido); pager podado; iconos breeze + fuentes dejavu pendientes.
2026-07-14 03:55:20 -04:00
sergioandClaude Opus 4.8 c813664497 kde/Plasma: LANDMARK — kwin+plasmashell corren headless end-to-end (software, rootfs soberano)
- Fix clave: bwrap con rootfs merged como / (el hack loader --library-path rompía el dlopen
  de plugins de kwin → QPA create() core-dump). Paths FHS nativos + LD_LIBRARY_PATH lib64.
- kwin_wayland --virtual LEVANTA el compositor (socket wayland-0, compositing software tras
  fallar gbm); plasmashell CONECTA y arranca (QtQuick software). Stack Plasma 6 soberano
  (musl/zig-cc) EJECUTA end-to-end SIN GPU real.
- Bloqueo a H-shell: falta el shell org.kde.plasma.desktop (paquete plasma-desktop, no
  construido) → 'invalid corona'. Próximo: construir plasma-desktop + kpipewire + baloo.
- run-plasma-headless.sh reescrito con la sesión bwrap validada (dbus+kwin+cliente).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 00:02:46 -04:00
sergioandClaude Opus 4.8 725adbd487 kde/Plasma: mesa-swrast (GL software) + lanzador Plasma headless + handoff nocturno
- run-plasma-headless.sh: lanzador de sesión Plasma headless (software EGL/softpipe sobre KMS).
- mesa-swrast construido (softpipe, sin LLVM, sello c59738eb): swrast_dri/kms_swrast_dri.
- HANDOFF-noche-kde: kwin_wayland linkea+carga QPA pero create() del compositor crashea headless
  (virtio-gpu/EGL-sw/seat en musl, opaco sin gdb). El rootfs es para GPU Intel real (iris) →
  camino recomendado = imagen booteable para metal (laptop TigerLake). Estado + próximos pasos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 23:56:59 -04:00
sergioandClaude Opus 4.8 a7449a0b88 kde/Plasma: cierre runtime COMPLETO del rootfs + zlib soberano shared
- complete-closure.sh: escanea DT_NEEDED de todos los ELF del rootfs y proyecta del store
  sellado el artefacto que provee cada soname AUSENTE, iterando a punto fijo. Resuelve las
  deps runtime que el índice del repo NO lista (libmount.so.1/util-linux, libltdl, libzstd,
  libQt6UiTools). Sonames base (musl libc/loader) no se hidratan.
- zlib-shared.toml: variante DINÁMICA de zlib (el canónico es --static). El stack GUI NEEDED
  libz.so.1 por soname y ningún artefacto lo proveía → caía al libz.so.1 de Alpine (fuga de
  soberanía Capa 0). .so fabricado del libz.a PIC vía --whole-archive (soname libz.so.1).
- Resultado: rootfs kde-store-rootfs con 1269 .so, 0 sonames faltantes; kwin_wayland resuelve
  TODAS sus libs y carga su QPA (bloqueado sólo en render: worker sin GPU/llvmpipe).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 23:43:18 -04:00
sergioandClaude Opus 4.8 d6944b2cd9 kde/Plasma: hidratación del ESCRITORIO COMPLETO store-directa (rebuild-free), cierre runtime verificado
- hydrate-from-store.sh: proyecta artefactos SELLADOS del store al FHS vía hammer hydrate,
  sin reproduce (install-reproduce rebuildеa qtbase por consumidor — hashing frágil bajo
  régimen dinámico). Selección por-pkg = artefacto más reciente con mtime<hoy (cosecha final
  coherente de la granja). 137/137 proyectados, 0 faltantes, 1257 .so, 5.0G en kde-store-rootfs.
- Hashes elegidos = los sellados de la campaña (kwin 3a674cb6, plasma-workspace 284c862f,
  libplasma 963403fe, kscreenlocker 55120487, breeze df1d1e68, kio 44376420).
- Cierre runtime VERIFICADO completo: todos los NEEDED de plasmashell(30)/kwin_wayland(24)/
  startplasma-wayland(11)/krunner(19) + libs core resuelven en el rootfs — cero colgantes.
- hydrate-fhs.sh: soporte multi-target (TARGETS) + canon prefiere nombre real qt6-* (el alias
  fuerza cache-miss+rebuild) + más build-only excluidos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 23:26:26 -04:00
sergioandClaude Opus 4.8 08510c0424 kde/Plasma: hito H-QML PASADO — hidratación FHS del cierre runtime + reproducer QML
- repo-selfcontain.py: work/repo-kde auto-contenido (alias qt-corto→qt6-* + cierre base
  desde dist/repo), re-firmado 884 pkgs, repo verify trusted.
- hydrate-fhs.sh: hidrata el cierre runtime instalando cada pkg del cierre en el mismo
  prefix (install --prefix sólo baja el pkg pedido); 32 pkgs → work/kde-rootfs, 455 .so
  (libQt6Core/Gui/Qml/Quick + QPA offscreen + mesa/xcb/wayland/openssl).
- h-qml-run.sh + h-qml-test.cpp: QQmlApplicationEngine carga QtQuick Window+Text, compila
  zig-cc/musl contra el FHS, corre offscreen rc=0 (engine instancia el árbol QML).
- ADR 0011: sección resultado H-QML + deudas (target_bin espurio en libs, cache-miss por
  re-resolución de deps → qtbase más completo con SSL, fuentes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 22:22:54 -04:00
sergioandClaude Opus 4.8 fc8d68c66f kde/H-QML: GATE PASADO — reproducer QtQuick corre rc=0 offscreen
Capa 1 Qt6 completa y sellada: qtbase+qtshadertools+qtsvg+qtlanguageserver+
qtdeclarative(QtQuick full d23aba45)+ECM. h-qml-test.cpp (Window+Text via QtQuick)
instancia la escena y sale rc=0 con offscreen+software backend. El motor QML
—corazón de Plasma— probado end-to-end bajo el stack soberano dinámico musl/zig-cc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:28:39 -04:00
sergioandClaude Opus 4.8 af5a175e01 kde/H-Qt: reproducer de la app Qt de prueba (gate PASADO, rc=0 offscreen)
qtbase 6.11.1 SELLÓ (b3:7c7c747d…) — Core/Gui/Widgets/OpenGL + QPA wayland, todo
.so dinámico bajo musl+zig-cc. La app compila y linkea contra él; corrida en el
rootfs musl del worker con QT_QPA_PLATFORM=offscreen crea la ventana y el event
loop sale rc=0. Régimen dinámico del ADR 0011 probado end-to-end.
Hidratación runtime: mesa+libdrm del store + libxkbcommon.so.0 fabricada del .a
(PIC) — deuda Capa 0 (varios libs canónicos son static-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 16:06:04 -04:00
sergioandClaude Opus 4.8 071be00396 kde/H-Qt: receta qtbase de-Alpinizada (gate campaña KDE) + cola incoming-kde al worker
qt6-qtbase 6.11.1 desde Alpine community: conserva sus 3 parches de musl (LFS64/
DNS-resolver/symlinks), reescribe abuild→CMake/Ninja explícito. link=DINÁMICO
(política capa GUI, ADR 0011). Minimal para el gate: Wayland-only (xcb OFF),
icu/vulkan/cups/libproxy/libinput/accessibility OFF, double-conversion+libb2
bundled ⇒ compila reusando SOLO deps ya selladas, cero recetas nuevas.
sha256 pinneado (sha512 cotejado con Alpine). farm-worker-loop añade
recipes/incoming-kde a QUEUES.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 14:05:23 -04:00
sergio f1ae579ff4 producto E2E: hidratación no-clobber (clobber ciego de /usr/lib rompe el sshd musl)
Revierte el experimento de shadow-por-clobber: pisar /usr/lib con libs del base-system deja
arje-zero+hammerd arrancando pero sshd/login mudo (ABI musl del producto disturbado). No-clobber
preserva el producto entero y añade los binarios nuevos (probado VERDE). La sombra de applets busybox
(sed/ps/ip→full) es política del ensamblado del producto (mecanismo 'adelgazar busybox' de coreutils),
que re-linkea el NOMBRE sin tocar /usr/lib — follow-up de empaque documentado en el script.
2026-07-11 06:23:03 -04:00
sergio d9bd5220f0 producto: E2E del base-system integrado al producto, booteado in-VM (front c productionizado)
product-base-system-boot-test.sh: hidrata los 26 paquetes del base-system sobre el product-rootfs
sellado (cp -an, preserva /etc/passwd/shadow/ssh del producto), lo bootea en QEMU y verifica DENTRO
del guest por SSH que corren. VERDE: arje-zero PID1 + sshd + bash 5.3/git 2.54/gpg 2.4.9/useradd/
vim 9.2/119 CA certs. Nota: MEM=6144 (rootfs aumentado ~1.1G en tmpfs). Caveat conocido: ps/ip/sed
resuelven a busybox por precedencia de PATH (los binarios full están, a sus rutas) — mismo patrón
'adelgazar busybox' que el producto ya aplica a coreutils; refinamiento de empaque pendiente.
2026-07-11 06:16:30 -04:00
sergio 0a03e1c579 producto: base-system en el userland curado del producto (integración front c)
product-userland-from-repo.sh ahora hidrata el userland foundational C (bash/git/sudo/util-linux/
shadow/red/disco/TLS/gpg/…) además de la capa CLI Rust, todo desde el repo firmado con
--require-signed (verifica firma → reproduce del .swm → hidrata FHS). BASE_SYSTEM_PKGS + CLI_RUST_PKGS.
2026-07-11 00:43:26 -04:00
sergioandClaude Opus 4.8 9305bb16e9 instalador: TUI interactivo (disco/identidad/locale/tamaños) sobre el autoinstalador
hammer-install crece una cara humana sin tocar la mecánica EFI/BIOS validada:
- sin device + TTY ⇒ interactive_setup: detecta discos (/sys/block, marca el
  montado como posible medio live), el usuario elige + confirma escribiendo el
  nombre del disco, y recoge hostname / credencial de root (contraseña vía
  cryptpw o authorized_keys) / zona horaria (best-effort si hay tzdata) /
  teclado / tamaños de / y /store.
- apply_post_install_config escribe hostname+hosts, reemplaza el hash de root en
  /etc/shadow, instala authorized_keys, symlinkea localtime y deja install.conf;
  se llama tras la copia en AMBAS ramas (EFI y BIOS).
- con device ⇒ autoinstalador de siempre (iso/efi-install-test intactos); la
  config sale de env (HAMMER_HOSTNAME/ROOT_PW/ROOT_AUTHKEYS/TZ/KEYMAP).
- iso-image.sh: ISO instalador sin AUTO_INSTALL ahora recibe con la TUI en la
  consola (INSTALLER_INTERACTIVE, default on) y ofrece reiniciar/caer al live.

Verificado: scripts/install-tui-test.sh (4/4, dry-run con sysfs+rootfs falsos)
+ iso-install-test.sh VERDE end-to-end en QEMU (autoinstalador con la config
nueva bajo busybox real → disco bootea solo y sirve SSH).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 22:22:21 -04:00
sergioandClaude Opus 4.8 a5be781ef6 arranque-grafo: hammer boot menu — orquestador del menú + wiring en el init (ADR 0010)
hammer boot menu ata las tres piezas del contrato: emite el grafo → lanza el
compositor (mirada, --compositor configurable) → activa el nodo que el usuario
dejó en boot-select. Graceful: sin compositor (servidor headless) emite el grafo
y sigue el arranque. Refactor: activate_and_report compartido con boot activate;
--out/--select configurables (testeable sin /run/hammer root-only).

Wiring: iso-image INSTALLER=1 + install-image-efi bundlean el CLI hammer (static
musl) al sistema instalado (el producto trae arje-zero/hammerd pero no el CLI);
el wrapper /sbin/init lo invoca tras hammer-recover, salida al serial (no pinta
tty0 ⇒ respeta cero-parpadeo). Cierra la pieza #3 del handoff mirada (quién
lanza el menú en el boot): lo ownea hammer, desde el hook de init.

Tests: boot_menu.rs (3 caminos del glue: graceful/sin-selección/selección→activate)
+ efi-disk-boot-test asevera que el menú corre. Validado en OVMF: pivote →
INIT-OK → menú (emite boot-graph.json + saltea sin mirada) → arje-zero.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:30:30 -04:00
sergioandClaude Opus 4.8 3ac329ec8f arranque-grafo: cero-parpadeo VERDE + fix marcador INIT-OK tras switch_root
efi-flicker-test valida por CONTRIBUCIÓN del kernel al framebuffer (2 capturas:
handoff-firmware vs post-boot; Δ≈0 ⇒ el kernel no tocó el FB). Con el kernel
metal cero-parpadeo: Δ=0.000 VERDE — el splash de la firmware sobrevive intacto,
sin texto de boot ni cursor (el kernel viejo saltaba de ~3 a ~11). No mide negro
absoluto: el splash de OVMF (TianoCore) daría falso-positivo y no existe en metal.

Fix: busybox switch_root NO mueve /dev ⇒ los wrappers /sbin/init montan devtmpfs
antes de tee'ar HAMMER-EFI-INIT-OK a /dev/ttyS0 (si no, el nodo no existe y el
marcador se perdía). efi-disk-boot-test VERDE con el kernel quiet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:04:05 -04:00
sergioandClaude Opus 4.8 fd033fb920 efi-flicker-test: media de brillo vía %[fx:mean] normalizado (0..1)
El 1er número de identify -verbose varía por quantum (10.99 en PPM vs 0.129 en
PNG para la misma imagen); el normalizado 0..1 es fiable. Validado: negro→0,
texto→11, umbral 1.5 los separa.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:21:48 -04:00
sergioandClaude Opus 4.8 e80f15b6bc arranque-grafo: harness EFI robustos a quiet + efi-flicker-test (ADR 0010 paso 4)
Con el kernel metal cero-parpadeo (quiet), los marcadores serie kernel-side
(EFI-stub/Linux-version/EXT4) desaparecen. Los /init de pivote + /sbin/init
real ahora tee'an marcadores a /dev/ttyS0 (escritura al puerto directo, sortea
el printk ⇒ sobreviven quiet): HAMMER-EFI-DISK-PIVOT-OK + HAMMER-EFI-INIT-OK.
efi-disk-boot-test y efi-install-test pasan a apoyarse en ésos (kernel-side =
informativos). Compatible con el kernel viejo (verbose) también.

efi-flicker-test.sh: valida cero-parpadeo por captura de framebuffer OVMF-GOP
(media de brillo < umbral ⇒ pantalla negra, sin texto de boot). El seamless
i915 queda para metal Intel real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:13:45 -04:00
sergioandClaude Opus 4.8 6921dfead3 arranque-grafo: validación 2-stage del instalador live EFI en OVMF (ADR 0010 paso 5)
efi-install-test.sh cierra el lazo completo bajo UEFI (hermano de
iso-install-test.sh que es BIOS): (1) ISO live EFI=1 INSTALLER=1 AUTO_INSTALL
en OVMF con disco en blanco → hammer-install detecta /sys/firmware/efi y toma
la rama EFI (MBR+ESP-0xEF) desatendido → HAMMER-INSTALL-OK; (2) el disco
instalado bootea SOLO en OVMF → firmware → BOOTX64.EFI → pivote → arje-zero
PID1, sin GRUB. VERDE end-to-end.

Prueba el instalador live REAL corriendo dentro del live, no sólo sus
artefactos. ADR 0010: paso 5 cerrado salvo metal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:32:13 -04:00
sergioandClaude Opus 4.8 4e00178fc5 arranque-grafo: rama EFI-stub en el instalador live (ADR 0010 paso 5)
hammer-live-install.sh detecta /sys/firmware/efi y ramifica a EFI-stub soberano:
MBR con ESP tipo 0xEF (UEFI arranca una ESP MBR igual que GPT ⇒ sólo busybox
fdisk/mkfs.vfat/mount, sin GPT-tool ni mtools en el live). Arma el mismo
initramfs de pivote (findfs LABEL=hammer-root → switch_root) que el builder
host-side; /sbin/init = wrapper hammer-recover→arje-zero (el pivote ya montó
store/estado por LABEL). La rama BIOS+GRUB queda intacta tras la detección.

iso-image.sh INSTALLER=1 bundlea el kernel metal EFI-stub (bzImage-efi) en el
payload; el genérico no sirve (no hornea initrd=/rdinit= en la cmdline).

MBR+ESP-EF spot-checked en OVMF (firmware → BOOTX64.EFI → pivote → arje-zero).
ADR 0010 actualizado: pasos 2 y 5 .

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:11:06 -04:00
sergioandClaude Opus 4.8 11ff41d614 arranque-grafo: install-to-disk EFI-stub soberano (ADR 0010 paso 5)
install-image-efi.sh arma una imagen GPT+ESP donde el bzImage metal ES el
binario EFI (\EFI\BOOT\BOOTX64.EFI, ruta fallback removible) — sin GRUB ni
systemd-boot. La cmdline horneada del kernel (initrd=/initramfs.cpio.gz
rdinit=/init) se activa al no haber LoadOptions; un initramfs mínimo de pivote
resuelve hammer-root por LABEL (findfs) y hace switch_root a la ext4 real.
Layout: ESP + hammer-root/store/state ext4 (mke2fs -d bajo unshare -r, ESP con
mtools de hammer). Cierra el paso 2 (initrd chico destraba EFI-stub) y el 5.

efi-disk-boot-test.sh valida en OVMF (sin -kernel): VERDE — firmware →
BOOTX64.EFI → pivote → arje-zero PID1. Marcadores serie deterministas (los dos
primeros bytes del handoff firmware→kernel son informativos; el veredicto se
apoya en el montaje/re-mount aguas abajo, prueba concluyente de la cadena).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:03:47 -04:00
sergioandClaude Opus 4.8 cf2e8bf44d mirada-usb: modo hardware nouveau para GTX 1060 (Pascal/GP106)
- Hornea firmware nvidia/gp106 (ctxsw/acr/sec2) descomprimido a .bin (nouveau da GL 3D).
- init: modo HARDWARE por defecto (WGPU_BACKEND=gl sobre gallium-nouveau, que da float16
  vía unpackHalf2x16; tapa lavapipe). Pascal no tiene NVK ⇒ greeter va por GL, no Vulkan.
- cmdline default = hardware; 'mirada.sw nouveau.modeset=0' = fallback software.
- CHIP/FW_SRC parametrizables para otras GPUs.

Regresión: el fallback software sigue levantando el compositor en la imagen final.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 17:05:23 -04:00
sergioandClaude Opus 4.8 c82588ced8 mirada-usb: imagen USB de prueba de mirada en GPU ajena (NVIDIA)
- recipes/mesa-swrast.toml: mesa softpipe hammer-nativo (sin LLVM) para render software.
- scripts/mirada-usb.sh: ensambla rootfs (dev-fs musl + hydrate mirada/seatd/libinput/
  mesa + overlay Alpine llvmpipe/lavapipe/nouveau + XKB + PAM + init seatd+compositor) y
  empaqueta la USB con linux-generic vía systemd-boot.
- docs/mirada-usb-nvidia.md: uso + estado.

Validado en QEMU virtio-gpu: el COMPOSITOR arranca entero (libseat→card0→GBM+EGL+
GlesRenderer→[8/8]→escritorio, acepta clientes, dibuja la ventana del greeter). El
GREETER (Vello) exige shaders float16 que llvmpipe/lavapipe NO dan ⇒ su login sólo
pinta con GPU real (nouveau+firmware, v2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 14:20:46 -04:00
sergioandClaude Opus 4.8 d9d891a64a granja: tanda VPS efímero 2026-07-06 — 7 promovidos al catálogo firmado (714)
dalfox/templ/errcheck/ineffassign/unconvert (Go) + dprint (Rust) + kyverno (Go),
construidos en un worker efímero hcloud, cosechados y firmados. Binarios musl-static
verificados: dalfox 3.1.2, templ v0.3.1020, dprint 0.55.1, ineffassign, y los
analizadores Go corren. feroxbuster/jless/mdcat/mise quedan staged (frontera *-sys:
openssl-sys/xcb desde fuente).

Fix farm-down: el promote final ahora recorre TODAS las colas del worker
(incoming/incoming-go/incoming-clib), no sólo recipes/incoming — los artefactos de
las otras colas se cosechaban pero no se firmaban.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 07:31:05 -04:00
sergioandClaude Opus 4.8 e2e5bc6f04 granja: fix host-key en workers efímeros — known_hosts a /dev/null
Los workers efímeros reciclan IPs de Hetzner. accept-new RECHAZA una clave de host
cambiada ⇒ el 'until ssh true' de farm-up colgaba para siempre en una IP reusada.
Como el modelo es hub-and-spoke (worker sin secretos, compute descartable) no hay
superficie MITM: saltamos verificación de host y no ensuciamos known_hosts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 06:56:25 -04:00
sergioandClaude Opus 4.8 b90855dc30 granja: farm-run.sh — el ciclo efímero desatendido (up→esperar-ciclo→cosecha+destruye)
Encadena farm-up + farm-down con detección de fin-de-ciclo por el marcador 'ciclo
terminado' del worker-loop (cuenta ocurrencias en el journal, robusto a skew de reloj
y builds largos). 'Subí la cola, corré esto, se apaga solo al terminar.'

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 06:47:11 -04:00
sergioandClaude Opus 4.8 5658e9337c granja: ciclo de vida EFÍMERO por hcloud API (farm-up/farm-down) + baseline €0
Migración del worker pet-24/7 a workers efímeros on-demand. farm1 (ccx23 persistente que
idleaba quemando plata) → snapshot golden 'hammer-golden-2026-07-05' (img 405120842: toolchain
+ store sellado horneados) → destruido. Baseline ahora 0 cajas / €0.

- farm-up.sh [N]: crea N workers desde el snapshot (cache-hit instantáneo del catálogo baked),
  los alinea con la cola actual del laptop, registra la flota en scripts/farm/.fleet (gitignored).
- farm-down.sh [name...]: cosecha el store (CAS, merge seguro) al laptop y DESTRUYE; promueve+firma.
  Orden seguro: sólo destruye si el pull de store salió bien.
- Validado punta a punta: up 1 → boot+cache+toolchain OK → down (cosecha+destruye) OK.
- Cron laptop harvest-go contra farm1 removido (la cosecha ahora la hace farm-down).

El worker sigue sin secretos (hub-and-spoke): compute puro y descartable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 08:23:06 -04:00
sergioandClaude Fable 5 e4ef80b76e Etapa G (go): cosecha 20 + syft/traefik promovidos a mano (pack fallaba: patches no viajaban a recipes/ — fix en harvest-go) + pre-check por name interno del TOML (exporters) + re-cola crossplane-cli/fabric-ai/oh-my-posh con fixes (alias crossplane, ./cmd/fabric, -o oh-my-posh) + logs por-cola en build-farm
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 05:31:58 -04:00
sergioandClaude Fable 5 46a2d777d3 Etapa G (go): re-alimenta la granja — tanda 2026-07-05 (15 recetas: flyctl/kubescape/seaweedfs/melange/step-ca/scorecard/krew/…, 11 a mano por fetchgit-NAR + 4 import nix), aliases de gate (weed/migrate/jb/fabric/crank) y descarte flux=misimport DirectFB
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 00:47:09 -04:00
sergioandClaude Opus 4.8 0b04c90d5b Etapa G (go): re-encola temporal-cli con el main correcto + alias de cosecha
El repo temporalio/cli tiene 3 mains bajo cmd/ (gen-commands, gen-docs,
temporal); detect_go_main elegía gen-commands ⇒ binario equivocado, quedó
en needs-review. Fix: flags=["./cmd/temporal"] apunta al CLI real (verificado
vía API de GitHub en el commit fijado). El binario se llama `temporal`, así
que agrego el alias temporal-cli→temporal al gate de harvest-go.sh (mismo
patrón que opentofu→tofu). Vuelve a recipes/incoming-go para que el worker
lo selle y la cosecha lo promueva.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 06:53:25 -04:00
sergioandClaude Opus 4.8 823c7e1171 Etapa G (granja): concilia la colisión de concurrencia — reintento serial de fallos por dep compartida
build-farm.sh asumía 'sin colisión entre recetas distintas', falso para deps transitivas
compartidas no selladas: dos consumidores (p.ej. libadwaita/gtksourceview) construyen gtk4 a
la vez en el mismo sources/gtk4-<sha>/output ⇒ 'Some other Meson process is already using this
build directory'. Fase 1b: tras el pool paralelo, reintenta EN SERIE los fallos con firma de
colisión — la dep ya la selló el ganador ⇒ cache-hit y compila. Un pase basta (cada build
arrastra sus deps). Sólo reintenta colisiones, no MSRV/dep-faltante reales.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 11:25:19 -04:00
sergioandClaude Opus 4.8 114a02b597 Etapa G (granja): watchdog protege árboles calientes — cura corrupción de deps transitivas
El watchdog de disco purgaba work/sources/* protegiendo solo árboles bind-montados
por bwrap (prot.1) o cuyo nombre coincide con la receta en vuelo (prot.2). Una dep
transitiva (cairo bajo pango/gtk4) se extrae host-side ANTES del bwrap y con nombre
que no coincide con la receta ⇒ el rm -rf competía con el tar y dejaba el árbol a
medias: 'Cannot mkdir' durante la extracción, luego 'Directory not empty' para
siempre (falla rápido antes de bwrap, nunca se recupera). Prot.3: no purgar árboles
modificados hace <2 min (extrayéndose ahora); los fríos se purgan y re-extraen limpio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 06:30:29 -04:00
sergioandClaude Opus 4.8 4517a985c1 Etapa G (granja): promote más seguro — patches viajan con la receta + guarda de colisión
Dos bugs del promote de build-farm.sh, hallados al cosechar incoming-clib:
1. mv movía el .toml pero NO sus .patch (quedaban en la cola) ⇒ toda receta
   parcheada fallaba el pack ("leyendo patch ...: No such file or directory").
   Ahora mueve los patches referenciados junto al .toml.
2. mv sobrescribía a ciegas una receta canónica de recipes/ con una variante
   homónima de la cola (p.ej. curl 8.11 mínimo-para-appstream pisando el
   curl 8.20 full). Se agrega guarda: si ya existe recipes/<n>.toml, NO se
   promueve la variante (queda staged para triage) ni se re-publica.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 06:11:36 -04:00
sergio 27fb9d4812 Etapa G: worker muele 3ª cola recipes/incoming-clib (libs C toolkit; el cron-go la ignora) 2026-06-29 22:56:01 -04:00
sergio 199ce9b9dd Etapa G: harvest lock STALE-AWARE (PID; roba si el dueño murió) — un lock huérfano bloqueó el cron 16h
+ dolt: corregido, necesita ICU4C (go-icu-regex), no oniguruma. oniguruma queda en el corpus (útil p/ otros regex).
2026-06-29 22:52:24 -04:00
sergio 4bb5e67e82 Etapa G: harvest-go sale temprano si la cola está vacía (evita rsync del store de GB en balde) 2026-06-29 10:35:19 -04:00
sergio efd670a666 Etapa G: git-town PROMOVIDO (go.work, Git Town 23.0.3) + kustomize flags=./kustomize + gate alias go-mockery→mockery 2026-06-29 10:13:16 -04:00
sergio 237f9796e7 Etapa G: gate alias soft-serve→soft (charmbracelet) + re-encola soft-serve (falso-rechazo) 2026-06-29 09:12:45 -04:00
sergio 254c5a9cc7 Etapa G: ronda 2 pre-siembra finde (+18 Go) + alias gate argo-rollouts/step-cli
terrascan/tfsec/tflint/tparse/richgo/curlie/dockle/vendir/kubefwd/kubeshark/ktunnel/duplicacy/
go-junit-report/argo-rollouts/gowitness/shuffledns/dnscrypt-proxy/step-cli. Dropeados ssh-vault
(sin marca Go) y skopeo (CGO gpgme). Gate: argo-rollouts→kubectl-argo-rollouts, step-cli→step.
2026-06-27 07:04:38 -04:00
sergio b1525ec203 Etapa G: harvest-go fija GIT_SSH_COMMAND (clave github5/tawasuyu) p/ push desde cron sin agente 2026-06-27 07:00:23 -04:00
sergio b544ad3d59 Etapa G: harvest gate exige binario == nombre esperado (no solo que 'corra')
La 1ª corrida promovió+FIRMÓ binarios equivocados que pasaban el smoke por solo 'correr':
katana/naabu→functional-test, gosec→gosecutil, buf→protoc-gen-buf-lint (detect_go_main eligió un
main helper). El gate ahora localiza el binario cuyo nombre == receta (o alias conocido tofu/mc/
nats/dlv/flux/ct/kubeseal/node_exporter/...); si instaló otro → a needs-review-weekend con el motivo,
NO se firma. Lección eksctl aplicada al gate.
2026-06-27 06:50:03 -04:00
sergio c381e1b0c7 Etapa G: modo finde desatendido — worker muele incoming-go/ + harvest-go.sh (cosecha-only gated)
- farm-worker-loop.sh: construye QUEUES='recipes/incoming recipes/incoming-go' (en serie por vuelta;
  la cola Go aislada se muele 24/7 sin pisar el incoming/ del otro agente).
- scripts/farm/harvest-go.sh: cosecha determinista sin IA (cron del laptop). Baja el store sellado,
  y por cada receta SELLADA (cache-hit bajo timeout, NO compila en el hub) hace SMOKE-TEST del binario
  (existe + corre version/--help sin panic/segfault) antes de promover+firmar. Lo que falla el smoke va
  a tandas/needs-review-weekend/ para el lunes. add explícito (nunca -A), push con reintento.
2026-06-27 06:41:28 -04:00
sergio c270edade7 Etapa G: watchdog no purga caches Go con CUALQUIER hammer build en vuelo (no solo vendor)
vault (go-15) falló en 'go mod vendor' con '~/.cache/go-build/...: no such file': durante el compile
de telegraf el disco cruzó DISK_HIGH, el watchdog corrió 'go clean -cache', y el vendor de vault (que
usa esa cache) arrancó en la ventana siguiente sin ficheros. El guard anterior solo miraba 'go mod
vendor' activo en ese instante; ahora difiere la purga si hay cualquier 'hammer build' en vuelo.
2026-06-27 03:30:50 -04:00
sergio ad7ec4aea4 Etapa G: watchdog protege árboles con 'hammer build' en vuelo (fase host vendor/resolve)
go-13 (dnscontrol/lazysql, árboles de deps Go enormes) destapó otra race del watchdog: durante el
fetch/'go mod vendor'/resolve_phases (host-side, antes del bwrap) el árbol no está bind-montado ⇒ el
watchdog lo borraba a mitad del vendor → go.mod desaparecía → 'receta sin compile, heurística no
encontró build system'. Ahora además protege work/sources/<name>-* si <name> tiene un proceso
'hammer build' activo (cubre toda la vida del build, no solo la fase sandbox).
2026-06-27 01:07:09 -04:00
sergio 370e7b7a20 Etapa G: limpia cola go-12 — parquea batch gráfico C a hold-nongo + difiere syncthing
- mesa/wayland/wayland-protocols/libdrm/seatd/samurai/meson + patches: batch C de gráficos previo
  que jamás se mandó al worker, arrastrado en incoming/. Parqueado en tandas/hold-nongo/.
- syncthing: build especial (genera la GUI embebida 'auto.Assets' vía go generate/build.go) ⇒
  diferida a staged-fallidos con el motivo. Quedan 18 go-12 limpias en la cola.
2026-06-26 23:51:05 -04:00