Commit Graph
137 Commits
Author SHA1 Message Date
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 9478f4c065 docs: SDD 16 harkaq — Draft 2 reescrito contra la realidad del builder (bwrap, no nix)
El Draft 1 estaba escrito contra el sandbox de nix. hammer no construye con
nix: construye con bubblewrap (ADR 0004, hammer-build/src/sandbox.rs). Eso
invalidaba por irrelevancia el argumento anti-nix (§0), las FOD y su red
abierta (§6 + D8), Q5, y la Fase 3 del fetcher mediado — que el propio doc
marcaba como el mayor riesgo de cronograma, de "meses".

Fase 0 ejecutada (5 minutos, no días):
  - ABI Landlock = 10 en el laptop (techo: audit/7, TSYNC/8, quiet/10).
  - Kernel de hammer 6.16.12-metal: CONFIG_SECURITY_LANDLOCK ausente, pero
    CONFIG_LSM ya lista landlock ⇒ falta un flag, no una versión. Q2 cerrada.
  - Cero FODs: download.rs baja con curl en el HOST y --unshare-all incluye
    --unshare-net ⇒ el fetcher mediado de D8 ya está construido. Fase 3 se
    elimina.

La brecha real es otra y paga mejor: el sandbox monta un rootfs Alpine ENTERO
como capa base ⇒ política ⊋ clausura ⇒ una receta usa Alpine sin declararlo y
pasa en verde. Es el bug que la campaña de de-Alpinización caza a mano. D1 +
audit de ABI 7 lo vuelve mecánico (path/dev/ino de lo no declarado).

Encaje en el modelo de confianza (recipe.rs:229): H1 garantiza que lo
declarado PASA; harkaq que lo declarado BASTA. Complementos simétricos.

Sobreviven intactos D1 (política derivada), D2 (evidencia negativa) y D3
(cero quieting). Nuevo Q1 = el riesgo técnico real: cómo llegan los registros
AUDIT_LANDLOCK_* al lector (CAP_AUDIT_READ, auditd, userns, flags de exec).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 12:18:19 -04:00
sergio c3042b3102 kde/Plasma: handoff — estado final plasma-desktop + bug busybox-grep + blocker feature_summary 2026-07-14 01:54:13 -04:00
sergio f6f0385297 kde/Plasma: handoff — cadena de blockers de plasma-desktop + recomendación shell-only 2026-07-14 01:35:01 -04:00
sergio 87511eeab9 kde/Plasma: handoff — caveat cascada de rebuild total en plasma-desktop + alternativas (farm-up snapshot) 2026-07-14 01:14:26 -04:00
sergio 2a8bab70c8 kde/Plasma: handoff nocturno — plasma-desktop en construcción + comandos de mañana para H-shell 2026-07-14 00:38:16 -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 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 8eb168e168 kde/H-Qt: ADR 0011 → gate PASADO; lecciones durables + snapshot para reanudar
Registra el resultado (qtbase sella b3:7c7c747d, app Qt rc=0 offscreen), las 3
lecciones de-Alpinización (wrapper zig/CMake, tensión estático↔dinámico = deuda
Capa 0, hidratación runtime musl) y el snapshot hammer-kde-qtbase-2026-07-11
(img 407438750) para arrancar futuras farm-up sin re-pagar el build. Próximo:
qtdeclarative/QML (H-QML) + saldar deuda Capa 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 16:10:40 -04:00
sergioandClaude Opus 4.8 5447c175f9 docs: ADR 0011 — roadmap campaña escritorio KDE Plasma 6
Fija la política (capa GUI adopta linking DINÁMICO: Qt carga plugins .so en
runtime, incompatible con el static-musl del userland CLI), el orden topológico
en 5 capas (sustrato→Qt6→KF6→Plasma→apps), 6 hitos verificables (gate = H-Qt:
qtbase + una ventana Qt bajo el régimen dinámico) y la estrategia de granja
(cola aislada incoming-kde/, cadencia por capa, qtwebengine diferido).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 06:53:40 -04:00
sergioandClaude Opus 4.8 c7d1d9cf5c arranque-grafo: paso 4 (cero-parpadeo) cerrado en el ADR 0010 (pasos 1–5 )
Validado por captura de framebuffer OVMF-GOP: el kernel metal con deferred-
takeover + quiet no toca el framebuffer (Δ=0). Falta sólo el seamless i915 y el
metal real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:10:39 -04:00
sergioandClaude Opus 4.8 72af9a802f arranque-grafo: diagnóstico preciso del cero-parpadeo (ADR 0010 paso 4)
Evidencia por captura de framebuffer en OVMF-GOP: el kernel metal pinta todo
el log de boot sobre el FB gráfico (simpledrm 160x50). Quitar console=tty0 no
alcanza (VT_CONSOLE=y auto-registra); quiet/loglevel por LoadOptions no frena
(fbcon redibuja el ring buffer + ignore_loglevel horneado fuerza salida).

Fix identificado (requiere rebuild del kernel metal, cambia hash firmado):
CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y + cmdline horneada quiet
loglevel=3 vt.global_cursor_default=0 sin earlyprintk/ignore_loglevel
(CONFIG_LOGO ya off). Seamless i915 sólo validable en metal Intel real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:02:17 -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 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 3c343bee9a arranque-grafo: paso 3 del ADR 0010 — grafo de estados + hammer boot
El menú de arranque como navegación del grafo content-addressed de estados
(no una lista de kernels). Sube el modelo de generaciones in-place a un grafo
navegable y define el contrato de datos con mirada.

- hammer_upgrade::boot_graph: BootGraph/BootNode (formato exacto del contrato),
  build() arma el DAG desde las generaciones (id = of_tree sin b3:, parents =
  of_tree del padre, Base para la raíz del linaje), nodo Recovery sintético
  colgando de la viva, emit() atómico a /run/hammer/boot-graph.json.
- activate(): resuelve el id content-addressed a una generación y deja el
  sistema en ese nodo — no-op si ya viva, rollback paso a paso a un ancestro
  (reusa el rollback E4), recovery = un rollback, error honesto ante un "redo"
  hacia una generación huérfana (pide re-aplicar el árbol).
- CLI `hammer boot graph [--out|--stdout]` y `hammer boot activate <id>
  [--from-select]` (lee el id que mirada deja en /run/hammer/boot-select).
- Tests: DAG + activate a ancestro + recovery + redo-falla; rfc3339 sin deps.
  Validado e2e por el binario (3 generaciones → grafo → activar → recovery).

Cierra el lado `proceso` de SDD 15 §H4 (arrancar = activar un nodo del DAG).
mirada ya puede maquetar contra el grafo real (HANDOFF-arranque-grafo.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 20:36:04 -04:00
sergioandClaude Opus 4.8 7e21b0184b docs: ADR 0010 — arranque por grafo (menú de boot = navegación del grafo de estados, mirada+hammer)
El menú de arranque soberano (sin systemd-boot, sin GRUB) no es un port de GRUB: es la
navegación del grafo content-addressed de estados del sistema, renderizado por mirada
sobre KMS y respaldado por las generaciones/DAG de hammer. Cierra el lado 'proceso' de
SDD 15 §H4 (arrancar = activar un nodo). Fija la división de labores, el contrato de
datos (/run/hammer/boot-graph.json + hammer boot activate), el invariante cero-parpadeo
(simpledrm→i915 seamless) y la vía del loader (squashfs+overlay → initrd chico → EFI-stub
directo viable). Espejo en tawasuyu/HANDOFF-arranque-grafo.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 20:23:25 -04:00
sergioandClaude Opus 4.8 3e520d4477 H4e: requires OBSERVADOS — dep de runtime divergida = incompatible (SDD 15 §H4)
Cierra la simetría de la vía observada: además de observar lo que un paquete escribe (H4c),
observa de qué depende A UNA VERSIÓN. Fuente observable sin declaración: el paquete se
construyó contra la versión de sus deps que hay en el repo (deps.runtime del .swm +
expected_hash de cada dep en el índice); si el usuario tiene esa dep instalada a OTRO hash,
la divergió -> rechazo duro. Es el caso wayland DERIVADO (el que H4b captura cuando el autor
declara requires, ahora leído del cierre).

- compat::observed_requires(swm, index) + version_conflicts(db, req) — reusan deps del .swm,
  expected_hash del índice e InstalledDb.hash (cero declaración nueva).
- Cableado en install (rechazo duro, no lo salva --force-slots) y en `hammer compat`.
- Verificado e2e real: `hammer compat` marca app INCOMPATIBLE por su dep wayland-protocol
  instalada a un hash divergido del repo (read-only, ve el source_patch sin construirlo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 06:29:22 -04:00
sergioandClaude Opus 4.8 bbf4411af0 H4d: hammer compat <repo> — la búsqueda que particiona un repo contra lo instalado (SDD 15 §H4)
Responde la pregunta que arrancó §H4 ("cuando busco, ¿cuáles puedo adoptar?"): es el `filtrar`
del prototipo wawa-memo, ahora sobre el repo real y READ-ONLY (no construye ni toca nada).
Evalúa cada paquete contra el estado instalado y lo parte en {compatibles, requieren-elección,
incompatibles}, combinando la vía declarada (slots, H4b) con la observada (paths, H4c):
incompatible domina, colisión (de slot o fichero) -> elección, si no compatible.

Verificado e2e real (tests/compat_gate.rs): un repo de dos paquetes se parte correctamente
(uno choca de fichero con lo instalado -> elección; otro limpio -> compatible).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:23:19 -04:00
sergioandClaude Opus 4.8 9be7bdd707 H4c: superficies OBSERVADAS — colisión de fichero en install sin declarar slots (SDD 15 §H4)
La misma subida de H1 (prometer -> verificar), ahora sobre topología: la superficie más
común de un paquete es el conjunto de paths que escribe, y esos paths ya están declarados
en el .swm (target_bin + file_drop.path), conocidos ANTES de hidratar.

- compat::output_paths(swm) lee esos paths; compat::path_collisions(db, name, paths) detecta
  cuáles ya posee OTRO paquete instalado (reusa InstalledDb.files + owner_of, cero declaración
  nueva). Reinstalar el mismo paquete sobre sus propios paths NO colisiona (upgrade).
- Gate en `install` corre el chequeo observado JUNTO al declarado (H4b): pisar el fichero de
  otro paquete = caso logo a nivel de fichero (elección) -> aborta salvo --force-slots.
- Verificado e2e REAL (tests/compat_gate.rs, shell-ea al binario hammer): dos paquetes
  escriben /share/logo.png; el 2do aborta con "COLISIÓN de fichero" sin escribir nada; con
  --force-slots la elección se respeta y el fichero se escribe.

Un paquete SIN declarar slots ya participa del gate por lo que de verdad toca.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:17:17 -04:00
sergioandClaude Opus 4.8 27066776b3 H4b: gate de compatibilidad de configs en la receta real + hammer install (SDD 15 §H4)
Sube el modelo de slots de wawa-memo (prototipo host) a hammer:
- Recipe + source_patch del .swm llevan bloque `slots` {claims, requires} (slot->b3:…),
  FUERA de hash_inputs (topología ≠ identidad, no mueve el artifact_hash). Viaja intacto
  por los dos sentidos del puente (Recipe->.swm->Recipe): test de round-trip.
- InstalledDb registra claims por paquete + system_state() -> slot->hash (el Estado del gate).
- hammer-core::compat::evaluar(estado, slots) -> Veredicto {Compatible, Colision, Incompatible}
  (el álgebra probada en wawa-memo, sobre tipos de hammer).
- Gate en `hammer install`: antes de tocar nada evalúa el paquete contra el estado instalado.
  Incompatible (requisito sin resolver, caso wayland) -> aborta; Colisión (caso logo) ->
  aborta pidiendo elección salvo --force-slots; Compatible -> procede y registra los claims.

Plumbing propagado por los 5 sitios de Mutation::SourcePatch (from_recipe, swm_bridge,
export, bus, orchestrator). Tests: compat (4) + slots-no-en-hash/round-trip (2) +
system_state (1) + puente receta<->swm (1). Workspace compila y verde.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:10:02 -04:00
sergioandClaude Opus 4.8 66241c31a4 docs: SDD 15 §H4 — configs compartidas (compatible/completa/segura) + la ambición hasta config=paquete=función=proceso
Aterriza H2/H3 sobre el caso de uso real del usuario: compartir configuraciones
por la malla y, al buscar, saber que son compatibles/completas/seguras.
- H4a  (prototipo en wawa-memo): el modelo de slots reclama/requiere; compatible
  = colisión sobre la misma superficie (logo=elección, wayland=rechazo); completa y
  segura reusan H3c/H2c.
- H4b: subir slots a la receta/.swm real (InstalledDb como slot->Id).
- Sección "la ambición hasta el final": config y programa son el mismo objeto (hash);
  el último lado abierto es el proceso (replay del MonotonicLog, plan OS-CRDT).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:57:12 -04:00
sergioandClaude Fable 5 e72a630d31 docs: SDD 15 §H3c — formato de viaje canónico del Paquete + wawa-verifica (el puente concreto paquete↔función)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 10:31:28 -04:00
sergioandClaude Fable 5 3ff1823e38 docs: SDD 15 §H3c hecho — el linker de contenido (grano intra-función por hash, Merkle-DAG de código)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 06:20:07 -04:00
sergioandClaude Opus 4.8 aad80ca519 docs: SDD 15 §H3b — puente H3b↔H2c (compartir programas por la malla, seguros por construcción)
Cierra la tesis de §H3: un programa entero viaja como Paquete verificable
en dos capas — integridad del código por el hash (tamper-evident sin firmar)
+ verdad del resultado por reproducción (H2c). Implementación en tawasuyu
wawa-memo/src/programa.rs (8 tests, total wawa-memo 30).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 06:45:48 -04:00
sergioandClaude Opus 4.8 fdfaab5151 docs: SDD 15 §H3b hecho — código por contenido estilo Unison sobre el grano wasm de H2
El núcleo del modelo Unison (definir por hash, nombres como metadata,
actualizar sin romper, componer por hash) se sostiene sobre el runtime
de wawa. Implementación en tawasuyu wawa-memo/src/base.rs (8 tests verdes).
Frontera: es el subconjunto que wasm+BLAKE3+H2 sostienen, no el colapso
total paquete=función=proceso (sigue ambición, no promesa).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 06:31:57 -04:00
sergioandClaude Opus 4.8 efe1dfcc46 docs: SDD 15 §H2c — núcleo de confianza hecho (sellado + verificar-reproduciendo)
En wawa-memo: sellado de portabilidad (Portable/SoloLocal, sella el vector
NaN cross-arch) + modelo de confianza (ingerir_ajeno verifica reproduciendo,
rechaza envenenamiento). Transporte de malla diferido al otro agente
(PLAN-OS-CRDT E3). Tests h2c.rs verdes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 20:17:29 -04:00
sergioandClaude Opus 4.8 ea2dface82 docs: SDD 15 §H2b hecho — memoización de ejecución wasm (cómputo como dato)
El prototipo vive en tawasuyu/03_ukupacha/wawa/wawa-memo (crate host/std):
reproduce la vía pura del kernel y monta la clave del contrato §4 sobre un
LwwMap. Test §5 verde (72 casos byte-idénticos, Hit/Miss, fallas cacheadas,
E-invalidación, merge de malla). Desbloquea H2c.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 20:07:33 -04:00
sergioandClaude Opus 4.8 b173630e81 query: exports:<elf> — procedencia por-símbolo (puente barato de ADR 0009)
Extiende el parser ELF (parse_elf_needed→parse_elf_info): además de DT_NEEDED,
recorre .dynsym (DT_SYMTAB) y extrae los símbolos EXPORTADOS (defined +
global/weak). Nuevo término `exports:<path>` en el mini-lenguaje de queries;
fluye por el bus (query expr) sin cambios. Metadata descriptiva, fuera de
hash_inputs (misma disciplina que la evidencia de H1). Refactor: helper
vaddr_to_file_off compartido por strtab/symtab + cstr_at.

nsyms vía layout convencional (strtab sigue a symtab); best-effort → [] si no
se puede acotar con seguridad. Validado end-to-end: 2873 símbolos reales de
/lib/libc.so.6 (aguanta glibc y musl). Tests: term-parse + missing-file +
host-gated real-.so. Workspace verde (33 suites).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 06:10:59 -04:00
sergioandClaude Opus 4.8 236aac7c7f docs: ADR 0009 código direccionado por contenido (H3a) — registrar visión Unison
Design-doc de la idea 3 (SDD 15 §H3): decide NO reescribir la unidad de
compilación. Puente barato = procedencia por-símbolo como metadata (extender
el parser ELF parse_elf_needed para emitir exports de .dynsym), fuera de
hash_inputs — misma disciplina que la evidencia de H1. El grano fino real
(función-por-hash) se difiere a H3b sobre wasm, gateado por el determinismo H2.
Marca §H3a  en la frontera.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 06:03:48 -04:00
sergioandClaude Opus 4.8 7a708aa282 docs: SDD 15 §H2a hecho — auditoría de determinismo wasm de wawa
El subconjunto puro ya existe (ejecutar_dinamico/_v2, linker vacío); H2a lo
sella con un contrato de clave de caché + hash-de-entorno. Deliverable en
tawasuyu/03_ukupacha/wawa/SDD-determinismo.md. Desbloquea H2b (prototipo de
memoización local blake3(módulo)⊕blake3(entrada)→salida).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 01:11:21 -04:00
sergioandClaude Opus 4.8 6ac6438c00 H1c (proof-carrying recipes): cablea la evidencia al Orchestrator VERIFY
La evidencia corre del lado del BUILD (hammer-agent no depende de hammer-build:
separación PROPONE/CONSTRUYE). Piezas:

- proto: RecipeInline lleva `evidence`; Event::BuildReady lleva
  `verdict: Option<EvidenceVerdict>` (+ EvidenceCheckVerdict). Ambos con
  skip_serializing_if ⇒ wire compatible con clientes pre-H1c.
- hammerd/bus: run_compile ejecuta la evidencia declarada tras sellar el
  artefacto (run_evidence vía swm_bridge::recipe_from_source_patch) y adjunta
  el veredicto en BuildReady. Si ni se pudo ejecutar ⇒ veredicto fallido
  sintético (no pasa en silencio). El lab reporta; el gate vive en el agente.
- client: compile() devuelve CompileOutcome { artifact, verdict }.
- orchestrator: VERIFY lee el veredicto; si all_passed=false empuja
  VerifyCheck::fail y ABORTA antes de hidratar (artefacto sellado, no toca el
  sistema). Nuevo constructor VerifyCheck::fail.

Tests: roundtrip del veredicto en proto; stub-bus refleja evidencia→verdict;
nueva prueba de integración orchestrator_evidence_gate (veredicto fallido ⇒
run() aborta con "no se propone" y no hidrata). Suite completa verde (33 suites).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:33:25 -04:00
sergioandClaude Opus 4.8 d3da07fb3e docs: SDD 15 frontera AI-nativa — proof-carrying recipes, computo como dato, codigo por contenido
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:00:08 -04:00
sergioandClaude Opus 4.8 673bdde69f Etapa G: mirada-compositor CONSTRUIDO — stack de sesión gráfica COMPLETO
mirada-compositor sellado (store/d8fd9ca…): el compositor Wayland teselante sobre smithay 0.7,
que maneja DRM/GBM/EGL/libseat/libinput directo y hospeda a mirada-greeter como cliente.
Compila ~255 crates incl. smithay para musl; PIE dinámico.

Cierra la cadena de sesión gráfica de tawasuyu sobre hammer: Mesa(iris) + wayland + stack de
entrada + compositor + greeter, todo sellado.

smithay (default features) enlaza por -sys: drm-sys→libdrm, gbm-sys→mesa, libseat-sys→seatd,
input-sys→libinput, libudev-sys→libudev-zero, + xkbcommon→libxkbcommon y pixman (link directo).
Dos libs nuevas para cerrar el link:
- libxkbcommon 1.7.0 (meson, sin x11/wayland/docs/tools): smithay la enlaza, no sólo dlopen.
- pixman 0.44.2 (meson, sin tests/demos): composición CPU de smithay.

foreign-av NO enlaza ffmpeg (spawnea el binario en runtime) ⇒ no hizo falta construir ffmpeg.
NEEDED del binario: libgbm/libseat/libudev/libinput/libpixman-1/libxkbcommon + musl (libdrm/EGL/
wayland se dlopen-ean).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 07:06:41 -04:00
sergioandClaude Opus 4.8 11386c0a59 Etapa G: mirada-greeter CONSTRUIDO — primera app gráfica tawasuyu sobre el stack
mirada-greeter sellado (store/41fdd015…): el greeter/login de mirada (runtime Elm Llimphi
sobre winit + wgpu) compila ENTERO para musl — 314 crates incl. wgpu/winit/naga/smithay/
llimphi-* — y enlaza dinámico. Valida la cadena completa: stack gráfico (wayland+mesa) →
app GUI tawasuyu real.

Binario: PIE dinámico, DT_NEEDED = sólo libpam.so.0 + musl; EGL/GLES/GBM/wayland/iris se
dlopen-ean en runtime (wgpu/winit), así que el rootfs debe tenerlas (mesa+wayland ya selladas).

Dos blockers resueltos en el camino:
- atspi/accesskit (a11y, vía accesskit_winit): zbus-lockstep-macros #[validate] PANICA
  («File has no extension.») al escanear xml/ de atspi-common y hacer .extension().expect()
  sobre el SUBDIR xml/schemas/ (lib.rs:147). Fix: fase compile custom (réplica de la fase
  Cargo de hammer) que setea LOCKSTEP_XML_PATH a un dir con sólo los .xml.
- PAM: auth-core → pam/pam-sys hace bindgen sobre security/pam_appl.h ⇒ nueva receta
  linux-pam 1.6.1 (libpam.so + headers; build limpio en musl con gcc de Alpine).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 03:45:48 -04:00
sergioandClaude Opus 4.8 7131cd4269 Etapa G: MESA iris-only CONSTRUIDA (24.0.9, sin LLVM) — stack gráfico COMPLETO
Mesa sellada: store/607a513c…-mesa con dri/iris_dri.so + libEGL/libgbm/libGLESv2/
libglapi + egl/gbm/glesv2.pc. El stack gráfico para el escritorio tawasuyu (Iris Xe)
queda completo: libdrm✓ wayland✓ wayland-protocols✓ seatd✓ mesa✓.

Decisiones/fixes clave:
- PIN 24.0.9 (no 26.1.1): desde Mesa 24.1 iris REQUIERE intel-clc (kernels OpenCL-C
  internos) ⇒ libclc + clang/LLVM, lo que rompe el plan iris-sin-LLVM. Bisección: 24.0.9
  es el último donde with_clc=FALSE con iris-only sin Vulkan/rusticl. (Decisión del usuario:
  pinear Mesa viejo en vez de construir LLVM.)
- recorte iris-only: -Dllvm=disabled -Dintel-clc=disabled, sin Vulkan/glx/rusticl/codecs/tools.
- packaging (módulo Python puro): el chequeo de versión de mako usa packaging.version y
  Python 3.12 ya no trae distutils ⇒ sin packaging fallaba con el engañoso «mako required».
- PYTHONPATH al site-packages en configure Y compile (el codegen mako corre en ninja).
- libffi en deps: lo pide wayland-client.pc (Requires: libffi) al resolver cflags.
- mesa-version-script-comma.patch: el target DRI emitía «-Wl,--version-script dri.sym»
  (token separado) que zig cc reordena ⇒ «cannot find version script --end-group» al ligar
  libgallium_dri.so. La forma coma «-Wl,--version-script,dri.sym» (un token) lo arregla.

Runtime pendiente (ensamblado de rootfs): iris_dri.so/libEGL necesitan libz.so.1, libzstd.so.1
(de la base), libdrm.so.2, wayland .so. mirada-greeter (Cargo, link dinámico a Mesa) ya desbloqueado.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 02:13:23 -04:00
sergioandClaude Opus 4.8 6fb7fd36d0 Etapa G: wayland + wayland-protocols CONSTRUIDAS (scanner desbloqueado)
Root cause real del bloqueo de wayland: NO era bug del wayland-scanner ni del XML
(ambos verificados OK). En el sandbox el scanner in-tree se compila ENLAZADO DINÁMICO
contra la musl (zig cc nativo no produce estático acá), y bajo musl-dinámico
`freopen(@OUTPUT@,"w",stdout)` queda roto por la copy-relocation de `stdout`: trunca el
archivo de salida pero manda el header generado a stdout → @OUTPUT@ vacío → `WL_SHM_FORMAT_*`
/ `wl_*` «undeclared» al compilar libwayland.

Fix: wayland-scanner-dup2-output.patch redirige la salida con `dup2(fd, STDOUT_FILENO)`
(nivel descriptor) en vez de `freopen` → robusto al modo de enlace. Verificado byte-a-byte:
salida idéntica a la del scanner estático (217484 B al archivo).

Segundo blocker (libwayland-server.so): libffi.a era no-PIC → `R_X86_64_PC32 ... recompile
with -fPIC` al ligarlo dentro de una .so. libffi ahora con --with-pic (superset; sigue
sirviendo para enlace estático). Mesa necesitará lo mismo en zlib/zstd/expat.

Restaura recipes/samurai.toml (lo necesita el stack adaptado de recipes/: libdrm/seatd/
wayland; las otras build-deps —meson/pkgconf/python3/expat/libffi— ya viven en recipes/).

Sellados: wayland (libwayland-{client,server,cursor,egl}.so + scanner + .pc),
wayland-protocols (XML + .pc). Queda mesa (iris-only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 00:52:16 -04:00
sergioandClaude Opus 4.8 93e3ea28d2 Etapa G: wayland root cause CONFIRMADO — scanner musl lee input vacío
Verificado que la fuente extraída protocol/wayland.xml está completa (165075 B) y
expat OK ⇒ el wayland-scanner compilado static-musl recibe el XML completo pero
emite headers vacíos y sale 0 (bug de runtime, falla con zig default y 0.13.0). FIX
recomendado: construir el scanner NATIVO (build-time only, no se shippea) y apuntar
libwayland al scanner externo; libwayland-{client,server} sí con musl/zig.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 00:14:03 -04:00
sergioandClaude Opus 4.8 060e24e564 Etapa G: debug wayland-scanner — genera headers vacíos (input vacío a expat)
El build de libwayland falla: wayland-scanner produce headers de protocolo vacíos
→ wl_*/WL_SHM_FORMAT_* undeclared. Diagnóstico documentado en la receta y en
docs/14-mesa-stack.md §Estado: el scanner sale 0 sin emitir; por stdin expat dice
'no element found at line 1 col 0' (input vacío). Descartado samurai-ordering (-j1
falla igual) y libexpat (estático, sin símbolos glibc-only). Resultados
inconsistentes entre corridas (wayland.xml 165KB vs vacío) → sospecha de extracción
.tar.xz no determinista, lectura de input miscompilada, o estado tocado por el farm.
Siguiente: corrida aislada que verifique el tamaño del wayland.xml extraído.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 00:12:14 -04:00
sergio 66ed94d4e0 Etapa G: corrige nota wayland (no es libexpat — es estático en hammer) 2026-06-26 23:59:37 -04:00
sergioandClaude Opus 4.8 99bbeac54a Etapa G: stack Mesa — 4/7 construidas (samurai, meson, libdrm, seatd)
Adapta las recetas importadas a fases hammer (meson/samurai directos, link=dynamic)
y construye+sella la base del stack gráfico para el escritorio tawasuyu:

- samurai: zig 0.13.0 (el default miscompila musl → reallocarray falla en runtime)
- meson:   Python puro, copia mesonbuild/+wrapper (sin wheel/gpep517 que hammer no tiene)
- libdrm:  core-only (GPU helpers disabled) → sin libpciaccess; iris usa libdrm core
- seatd:   libseat.so.1, -Dwerror=false (CMSG_NXTHDR de musl dispara -Wsign-compare)

Pendiente (docs/14-mesa-stack.md §Estado): wayland (los headers de wayland-scanner
no aparecen, prob. libexpat.so en el scanner), wayland-protocols (bloqueada por
wayland) y mesa (la grande, recortada iris-only). meson validado con zig cc sobre
proyectos meson reales (libdrm, seatd).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 23:58:37 -04:00
sergioandClaude Opus 4.8 00339b625e Etapa G: cola del stack gráfico Mesa (iris) para el escritorio tawasuyu
Importa de Alpine aports (con parches musl) las recetas del stack que el greeter
real de mirada necesita en el rootfs de producto: libdrm 2.4.134, wayland 1.25.0,
wayland-protocols 1.48, seatd, mesa 26.1.1, + build-tools meson 1.11.1 y samurai
(ninja). Quedan en recipes/incoming/ como puntos de partida: traen los parches
musl de Alpine pero usan helpers de abuild — falta adaptarlas a fases hammer
(meson/samurai directos, link=dynamic), como elfutils.

docs/14-mesa-stack.md fija el plan: iris-only ⇒ SIN LLVM/Vulkan/X11 (el driver
gallium iris no necesita LLVM), lo que recorta clang/llvm/libclc/spirv/bindgen.
DAG de build (hojas→raíz) + estado por receta + el lado tawasuyu (recetas Cargo
arje-splash/net-bring-up estáticas ya construibles; mirada-greeter dinámico,
bloqueado por mesa). Contraparte de la seed arje-tawasuyu del monorepo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 23:41:34 -04:00
sergioandClaude Opus 4.8 b979d9e550 Etapa G: importador nix→receta (hammer import-nix + scripts/nix-import.sh)
Poblar el catálogo no es opcional: 34 recetas a mano = userland desierto. nixpkgs es el mayor set
de recetas DESDE FUENTE ⇒ semilla natural. Importamos la RECETA (source+hash+deps), nunca el
binario del cache de nix — hammer reconstruye desde fuente ("verificar, no confiar").

- crates/hammer-cli/nix_import.rs: consume el JSON normalizado de nix y emite una receta hammer.
  Clasifica el origen: fetchurl flat → tarball+sha256 (convierte el hash nix SRI/base32/hex → hex);
  fetchFromGitHub → repo+commit (hammer pinea por commit, no necesita el hash NAR). Filtra el ruido
  de stdenv (setup-hooks, wrappers). nix_base32 decode portado. 11 tests.
- `hammer import-nix [FILE|-]` (stdin) → receta .toml; valida que parsee como Recipe.
- scripts/nix-import.sh <attr>: `nix eval --apply` produce el JSON normalizado y lo pipea al
  importador. NIX_STORE= para store local si /nix/store no es escribible.
- VALIDADO contra nixpkgs REAL (nix 2.34): import hello (tarball, sha256→hex) + ripgrep (github→
  repo+commit); pipeline completo nix→import→pack→.swm probado con hello. 31 suites verde.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:41:50 -04:00
sergioandClaude Opus 4.8 f94ef01139 Etapa F refinamientos: uninstall poda dirs vacíos + install --require-signed
Dos bordes ásperos de la paquetería:
- uninstall ahora retira los directorios que quedaron VACÍOS por el borrado (rmdir de abajo
  arriba; remove_dir sólo borra dirs vacíos ⇒ se detiene solo al toparse con contenido de otro
  paquete). Antes dejaba /usr/bin, etc. huérfanos.
- `install --require-signed`: modo estricto que ABORTA si el release no está firmado por una
  clave confiada (Unsigned o UnknownKey ⇒ error). No basta con que el .swm reproduzca: exige
  autoría verificada del catálogo. Default off (no rompe flujos sin firma).

Validado E2E: uninstall bwrap poda 4 dirs; --require-signed aborta sin firma y procede con
release trusted. 31 suites verde.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 07:12:58 -04:00