gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1389Shell 137Markdown 80Rust 802602 Definiciones

gnome: el perfil y el hidratador decían cosas distintas — 21 paquetes no llegaban a la imagen

Verificando que las extensiones de la tanda anterior llegaran al rootfs apareció algo bastante peor
que lo que fui a buscar: **`scripts/gnome/hydrate-gnome.sh` no lee `targets.toml`**. Arma el rootfs
desde una lista de 14 raíces escrita a mano dentro del propio script, y de las 28 raíces que el
perfil declaraba sólo DOS coincidían.

MEDIDO recorriendo la clausura de esa lista (123 recetas) contra la membresía del perfil: **21
paquetes declarados en `escritorio-gnome` no llegaban al rootfs hidratado**. No son accesorios —
son las hojas, que es justo lo que un perfil declara porque no es dep de build de nadie:

  atuq (el navegador) · foot (la terminal) · helix (el editor) · mpv · swayimg (el visor)
  zathura + zathura-pdf-poppler (el lector de PDF) · dejavu-fonts y dejavu-fonts-nerd (las FUENTES)
  xdg-desktop-portal-gnome · libnotify · desktop-file-utils
  bzip2-shared, expat-shared, libffi-shared, ncurses-shared, xz-shared (las .so que se cazaron el
  2026-09-03 recorriendo NEEDED, justamente para que el rootfs no resolviera contra el lab)
  y las cuatro de ayer: las tres extensiones y gnome-tweaks

O sea que el trabajo de descubrir que la imagen no tenía terminal, ni editor, ni una sola fuente
—con su análisis largo escrito en este mismo fichero— estaba DECLARADO y no llegaba.

Y la divergencia iba en los dos sentidos: 11 raíces de RUNTIME vivían sólo dentro del script y el
perfil no las conocía (accountsservice, geoclue, libgdm, libgweather, upower, librsvg, ibus, los dos
gi-*-typelibs, gsd-schemas y wireplumber). Sin ellas el shell no arranca: las carga por
`imports.gi.*`, que es invisible para la clausura de deps.

ARREGLO: las 11 se mueven a `targets.toml` con la justificación que el script ya traía bien escrita,
y el script queda marcado como SUPERADO por `scripts/hydrate-profile.py`, que hidrata desde el
perfil — la única declaración que existe. Su propia cabecera ya advertía de este modo de fallo
(«DOS fuentes de verdad para lo mismo, y divergen sin que nada lo diga»); esto es esa advertencia
cumpliéndose. El perfil pasa de 28 a 39 raíces y de 190 a 204 nodos, deuda 0.

VERIFICADO HIDRATANDO DE VERDAD, no leyendo: `hydrate-profile.py escritorio-gnome` proyecta
210/210 nodos (27993 ficheros, 3,5 G) y ahí están las tres extensiones, `gnome-tweaks` con su
módulo `gtweak`, y los tres gschemas en el directorio GLOBAL. Después se corrió el bloque nuevo del
lanzador contra ESE árbol: enumeró las tres, escribió el override y `glib-compile-schemas` salió 0
con stderr vacío.

⚠ DOS COSAS QUE APRENDÍ MIDIENDO Y CONVIENE QUE ESTÉN DICHAS:

1. **El hub NO puede hidratar GNOME hoy.** `gjs`, `gnome-shell` y `spidermonkey` salen «no sellado»
   localmente. No es deriva ni un grafo mintiendo: sus hashes vigentes SÍ están en
   `work/farm-sellados.txt` — o sea sellados EN EL WORKER — y la cosecha baja el manifiesto y no el
   store, a propósito (bajarlo deshacía la poda). `build-state` los cuenta bien porque mira también
   el manifiesto; `hydrate-profile.py` mira sólo el disco local. Los dos tienen razón.
2. **EXDEV entre bind-mounts, otra vez.** Hidratar a `work/` o a `work/out` falla con «Invalid
   cross-device link» AUNQUE `work/out` esté en el mismo /dev/sdb que el store: son bind-mounts
   distintos y `linkat()` no cruza montajes. Hay que hidratar accediendo al store por su montaje
   raíz (`--store /mnt/cosecha/store --into /mnt/cosecha/escritorios/…`). El mensaje de error del
   script lo dice y aun así me costó dos intentos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCt3ettR4Z7b6wPCBmbvEV

eb8f2172451d7b52c97efabea933a3ae686a507b · por Sergio · (hace 1 mes) · padre 9bd95cd30 · ver el árbol en este commit

Delta semántico

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

4 archivos · +82 −19

diff --git a/docs/state/build-state-gnome.json b/docs/state/build-state-gnome.json
index 73246257..fa4ad40c 100644
--- a/docs/state/build-state-gnome.json
+++ b/docs/state/build-state-gnome.json
@@ -36,9 +36,9 @@
    "sealed": 80
   },
   "escritorio-gnome": {
-   "raices": 28,
-   "clausura": 190,
-   "sealed": 190
+   "raices": 39,
+   "clausura": 204,
+   "sealed": 204
   },
   "escritorio-mirada": {
    "raices": 17,
@@ -46,7 +46,7 @@
    "sealed": 41
   }
  },
- "sin_perfil": 660,
+ "sin_perfil": 647,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -81,7 +81,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 1
   },
   "act": {
@@ -5301,7 +5303,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "geocode-glib": {
@@ -5337,7 +5341,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 1
   },
   "gettext-tiny": {
@@ -5474,7 +5480,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "gi-girepository-typelib": {
@@ -5501,7 +5509,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "giflib": {
@@ -7419,7 +7429,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "gsettings-desktop-schemas": {
@@ -8360,7 +8372,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "icu4c": {
@@ -10317,7 +10331,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "libglvnd": {
@@ -10479,7 +10495,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "libical": {
@@ -10827,7 +10845,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "libsass": {
@@ -11620,7 +11640,8 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-cosmic"
+    "escritorio-cosmic",
+    "escritorio-gnome"
    ],
    "dependientes_total": 2
   },
@@ -17522,7 +17543,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "usbutils": {
@@ -18354,7 +18377,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 0
   },
   "wishlist": {
@@ -18503,7 +18528,9 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
+   "perfiles": [
+    "escritorio-gnome"
+   ],
    "dependientes_total": 1
   },
   "x264": {
diff --git a/docs/state/drenaje.json b/docs/state/drenaje.json
index 6ba8f2ce..6e483641 100644
--- a/docs/state/drenaje.json
+++ b/docs/state/drenaje.json
@@ -31,7 +31,7 @@
   },
   "escritorio-gnome": {
    "grafo": "docs/state/build-state-gnome.json",
-   "nodos": 190,
+   "nodos": 204,
    "en_deuda": 0,
    "ondas": 0,
    "profundidad": 0,
diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index bf141439..89585898 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -458,6 +458,32 @@ paquetes = [
   # `python3` y `py3-gobject` como deps de RUNTIME: sin ellas en la imagen se instala y no arranca,
   # y ningún build puede delatarlo.
   "gnome-tweaks",
+  # ── RAÍCES DE RUNTIME QUE EL GRAFO NO PUEDE VER (traídas acá el 2026-09-09) ───────────────────
+  # ⚠ Estas once vivían SÓLO dentro de `scripts/gnome/hydrate-gnome.sh`, en una lista escrita a
+  # mano. O sea DOS fuentes de verdad para «qué lleva la imagen de GNOME», y habían divergido en
+  # los DOS sentidos: el script no conocía 21 paquetes que este perfil declara —entre ellos el
+  # navegador, la terminal, el editor, el visor de PDF, las fuentes y las tres extensiones— y este
+  # perfil no conocía estas once, sin las cuales el shell no arranca. Es exactamente el modo de
+  # fallo que la cabecera de `scripts/hydrate-profile.py` describe y que `vigia-imagen.py` existe
+  # para cazar.
+  # Ninguna es dep de BUILD de nadie: el shell las carga por `imports.gi.*` al arrancar, y eso es
+  # invisible para la clausura de deps. La justificación de cada una la traía el script:
+  "accountsservice",           # imports.gi.AccountsService
+  "gi-foreign-typelibs",       # DBus-1.0 / cairo-1.0, que Gdk y Atspi incluyen
+  "gi-girepository-typelib",   # lo pide el propio gjs desde su JS embebido
+  "libgdm",                    # imports.gi.Gdm — el shell lo importa SIN condición al arrancar
+  "geoclue",                   # imports.gi.Geoclue
+  "libgweather",               # imports.gi.GWeather
+  "upower",                    # imports.gi.UPowerGlib
+  "librsvg",                   # imports.gi.Rsvg
+  "ibus",                      # imports.gi.IBus
+  # Ni typelib ni librería: los GSCHEMAS de gnome-settings-daemon. El demonio está aparcado
+  # (GTK3/X11) pero el shell lee sus esquemas al armar los quick settings, y si faltan la excepción
+  # ocurre DENTRO de Main.start() ⇒ el panel no se arma y la pantalla queda NEGRA.
+  "gsd-schemas",
+  # `wireplumber` es lo que le da DISPOSITIVOS a PipeWire (que ya entra por la clausura): sin él hay
+  # socket de audio y nada que suene.
+  "wireplumber",
 ]
 
 [perfil.escritorio-cosmic]
diff --git a/scripts/gnome/hydrate-gnome.sh b/scripts/gnome/hydrate-gnome.sh
index ca66734b..089d7b71 100755
--- a/scripts/gnome/hydrate-gnome.sh
+++ b/scripts/gnome/hydrate-gnome.sh
@@ -10,6 +10,16 @@
 # calcula el ArtifactHash de la receta de HOY sin construir. O sea: cero ambigüedad, y si falta algo
 # el reporte dice exactamente qué receta y con qué hash lo buscaba.
 #
+# ⚠ SUPERADO POR `scripts/hydrate-profile.py` (2026-09-09). Sus raíces eran una lista ESCRITA A
+# MANO acá adentro, o sea una segunda fuente de verdad frente a `docs/state/targets.toml`, y habían
+# divergido en los DOS sentidos: este script no conocía 21 paquetes que el perfil declara —el
+# navegador, la terminal, el editor, el visor de PDF, las fuentes, las tres extensiones y
+# gnome-tweaks— y el perfil no conocía las 11 raíces de RUNTIME que sólo estaban acá. Las 11 se
+# movieron a `targets.toml` con su justificación, así que hoy
+#     scripts/hydrate-profile.py escritorio-gnome --into <dir>
+# arma el rootfs COMPLETO desde la única declaración que existe. Este script se deja porque su
+# cabecera documenta por qué cada raíz de runtime hace falta, pero su lista ya no es la verdad.
+#
 # Uso:   scripts/gnome/hydrate-gnome.sh [receta.toml ...]
 # Env:   RFS   (def work/gnome-rootfs)   destino
 #        STORE (def ./store)