tawasuyu

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…

un solo NetworkManager (y KDE recupera WiFi) + upower al corpus sin arrastrar polkit

── 1. Se RETIRA incoming-kde/networkmanager.toml ───────────────────────────────────────────────
  networkmanager-qt  b3:78bbdcda00d758fb3cc3a0be7da6a67395dfbe0e4d55c5d8e5cf8afaf728ff72
  plasma-nm          b3:496a9ff7794ae5d89ac2842bdfbca38c25c91df37465a049db7cf75ee0041b82

Ayer se promovió NetworkManager al corpus CON WiFi porque la variante de KDE iba con -Dwifi=false,
y quedaron dos. Esto cierra el arco: retirada la de la cola, `networkmanager-qt` resuelve al PADRE
y la distro tiene UNO solo. Consecuencia concreta: **KDE pasa a tener WiFi**, porque su applet
hablaba con un demonio construido sin soporte inalámbrico.

Medido con `yupana radio` antes de borrar: 2 rebuilds (networkmanager-qt, plasma-nm), los dos en
la cola KDE. Y comprobado sobre el ARTEFACTO del corpus que publica lo que nm-qt pide —`libnm.pc`
y `usr/include/libnm`— antes de quitarle el suelo. Los dos sellan.

── 2. upower al corpus: COSMIC dibujaba una batería sin nadie que se la contara ────────────────
  libgudev  b3:87ca5e73…  ·  udev-pc  b3:fa880b5c…   (hash IDÉNTICO desde las dos partes ⇒ cache-hit)
  upower    b3:c82e655ff7011150f21f9413433c518f12c827c52ecf6f9fc3484f75d85c155c

Ayer escribí que esta cadena eran «3 promociones, una de ellas polkit, decisión de arquitectura».
Fui a mirar y polkit SALE de la ecuación con una perilla: la variante de KDE va `-Dpolkit=enabled`
«porque polkit YA está sellada» —cierto EN ESA COLA y falso desde el corpus—, y apagarlo cuesta
poco medido en FUNCIÓN: polkit en upower sólo gobierna las acciones privilegiadas (suspender e
hibernar por org.freedesktop.UPower, además deprecadas: hoy eso lo hace logind). Reportar batería,
carga, tiempo restante y línea de corriente NO pasa por polkit, que es justo lo que COSMIC quiere.

Se corrigió además la frase del comentario heredado que decía `-Dpolkit=enabled` al lado de un flag
que ahora dice `disabled`: una nota que desmiente al código de al lado es peor que no tener nota.
Y se le añadió su [[service]] (el corpus no lo traía; el label/id son los mismos que en GNOME a
propósito: el ULID identifica al SERVICIO, no al artefacto). No mueve el hash.

Comprobadas las NEEDED de upowerd con provee.py: libupower-glib, libffi.so.8, libz.so.1,
libudev.so.1 — las cuatro las publica el corpus y ya estaban en [deps]. Sin NEEDED colgante.

── 3. targets.toml ─────────────────────────────────────────────────────────────────────────────
  escritorio-kde     servicios += NetworkManager  (llegaba por clausura de plasma-nm y NADIE lo
                                                   arrancaba: el applet sobre un demonio apagado)
  escritorio-cosmic  paquetes  += upower · servicios += upowerd

⚠ Y se CORRIGE la nota de ayer que decía «NO declarar networkmanager en escritorio-kde porque
plasma-nm ya arrastra la variante de la cola». Ya no hay variante de cola.

0e35652fb1a5ffed39cf6b2ba4f4fb693b7f1b21 · ruwaq Sergio · (1 killa ñawpaq) · tayta ddfcdc7ab · kay commitpi sach'ata qhaway

Semántico sayk'uy

Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.

5 qillqakuna · +175 −57

diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index af33cc81..ae1ad81f 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -440,6 +440,10 @@ servicios = [
   "pipewire", "pipewire-pulse",
   # 2026-09-13: con `wireplumber` declarado arriba, el audio pasa de «acepta clientes» a «encamina».
   "wireplumber",
+  # `NetworkManager` llega por la clausura de `plasma-nm` y hasta hoy NADIE lo arrancaba: el applet
+  # de red de Plasma se dibujaba sobre un demonio apagado. Con la cola retirada es el del corpus,
+  # o sea el que sí maneja WiFi.
+  "NetworkManager",
 ]
 
 [perfil.escritorio-gnome]
@@ -735,8 +739,13 @@ paquetes = [
   # porque allá se escribió para dar `libnm.so` a plasma-nm y nada más. La variante del CORPUS va
   # con `-Dwifi=true` y con `nmcli` (el artefacto de KDE no lo trae, comprobado sobre el store), y
   # delega el handshake WPA2 en el `wpa_supplicant` que `base` declara desde hoy.
-  # ⚠ NO declarar esto en `escritorio-kde`: allá `plasma-nm` ya arrastra la variante de la cola, y
-  # dos NetworkManager distintos en la misma ruta es la enfermedad de las dos glib.
+  # ⚠ CORREGIDO EL MISMO DÍA: esta nota decía «NO declarar esto en escritorio-kde, allá plasma-nm ya
+  # arrastra la variante de la cola». **Ya no hay variante de cola**: `incoming-kde/networkmanager`
+  # se retiró y `networkmanager-qt` resuelve al padre, así que la distro tiene UN solo
+  # NetworkManager y KDE pasó a tener WiFi (la suya iba con `-Dwifi=false`). Costó 2 rebuilds
+  # —networkmanager-qt y plasma-nm—, medidos con `yupana radio` antes de tocar nada.
+  # KDE sigue sin listarlo entre sus `paquetes` porque no hace falta: `plasma-nm` lo arrastra por
+  # clausura. Lo que sí hacía falta era arrancarlo, y está en su lista de `servicios`.
   "networkmanager",
 ]
 
@@ -975,6 +984,12 @@ paquetes = [
   # ⚠ NO declarar esto en `escritorio-kde`: allá `plasma-nm` ya arrastra la variante de la cola, y
   # dos NetworkManager distintos en la misma ruta es la enfermedad de las dos glib.
   "networkmanager",
+  # `upower` (2026-09-13): **COSMIC dibujaba un indicador de batería sin nadie que se la contara.**
+  # El demonio no estaba en la clausura: la receta vivía en `incoming-kde` y en `incoming-gnome`,
+  # las dos inalcanzables desde acá. La variante del corpus va con `-Dpolkit=disabled` —polkit en
+  # upower sólo gobierna suspender/hibernar, que además está deprecado; reportar carga y tiempo
+  # restante no pasa por ahí— y con eso la cadena cierra sin meter un polkit de verdad al corpus.
+  "upower",
 ]
 
 # ── QUÉ ARRANCA (el «enable»; SDD 30 §3) ────────────────────────────────────────────────────────
@@ -998,6 +1013,7 @@ servicios = [
   "dbus-system", "logind-compat", "cupsd", "bluetoothd",
   "pipewire", "pipewire-pulse", "wireplumber",
   "NetworkManager",   # 2026-09-13
+  "upowerd",          # 2026-09-13: el indicador de batería deja de mirar al vacío
 ]
 
 [perfil.escritorio-sway]
diff --git a/recipes/incoming-kde/networkmanager.toml b/recipes/incoming-kde/networkmanager.toml
deleted file mode 100644
index 5ee13593..00000000
--- a/recipes/incoming-kde/networkmanager.toml
+++ /dev/null
@@ -1,55 +0,0 @@
-# NetworkManager 1.52.0 — libnm (libnm.so + libnm.pc + headers NetworkManager.h/nm-*.h). Campaña KDE
-# (ADR 0011): destraba networkmanager-qt (KF6NetworkManagerQt) → plasma-nm, el applet de red. Era el
-# "rabbit-hole libnm→glib" que plasma-workspace esquivó parcheando NetworkManagerQt a opcional.
-#
-# El tarball NO está en download.gnome.org (sólo llega a 1.9.x; NM migró) ⇒ git-archive de
-# gitlab.freedesktop.org.
-#
-# **-Dcrypto=null es la clave**: NM ofrece crypto ∈ {nss, gnutls, null}; 'null' evita nss (→nspr/sqlite) y
-# gnutls (→nettle/libtasn1/p11-kit), dos cadenas enormes. Sin cripto no valida certificados 802.1X, pero
-# libnm compila y la API D-Bus que usa networkmanager-qt es completa.
-#
-# Deps DURAS de NM (dependency() sin required:false): libudev (→ libudev-zero YA sellado, da libudev.so.1
-# + libudev.pc), libndp (receta nueva), gio-unix-2.0 (→ glib-shared, la deuda Capa 0 recién saldada).
-# jansson/libpsl son required:false. Todo lo demás se apaga: sin daemon-extras (ovs/ppp/modem/wifi/nmtui/
-# teamdctl/ofono/cloud-setup), sin systemd (session_tracking=no, journal off), sin polkit/selinux/audit,
-# sin introspection/docs/tests/ebpf/firewalld.
-name    = "networkmanager"
-version = "1.52.0"
-license = "GPL-2.0-or-later"
-
-[source]
-tarball = "https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/archive/1.52.0/NetworkManager-1.52.0.tar.gz"
-sha256  = "2ebe60a1497a9650d58336b73413d838189b04543365b3dbc22e1eb8023d205f"
-
-[build]
-compiler = "zig-cc"
-target   = "x86_64-linux-musl"
-link     = "dynamic"
-flags    = []
-
-[build.phases]
-configure = '''
-# meson.build:92 hace `find_program('xsltproc')` INCONDICIONAL (required por defecto), pero xsltproc sólo
-# se usa en man/meson.build (páginas de manual), que no se construye con -Ddocs=false. Se degrada a
-# required:false y así se evita la receta libxslt entera. (sed DIRECTO: el sandbox usa busybox grep, que
-# no soporta --include.)
-sed -i "s/xsltproc = find_program('xsltproc')/xsltproc = find_program('xsltproc', required: false)/" meson.build
-PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release \
-  -Ddefault_library=shared \
-  -Dld_gc=false -Dconcheck=false -Dnmcli=false -Dreadline=none \
-  -Dcrypto=null \
-  -Dsystemdsystemunitdir=no \
-  -Dsession_tracking=no -Dsession_tracking_consolekit=false -Dsuspend_resume=consolekit \
-  -Dpolkit=false -Dselinux=false -Dsystemd_journal=false -Dlibaudit=no \
-  -Dwifi=false -Dppp=false -Dmodem_manager=false -Dovs=false -Dnmtui=false -Dnm_cloud_setup=false \
-  -Dteamdctl=false -Dofono=false -Debpf=false -Dfirewalld_zone=false -Dlibpsl=false \
-  -Dintrospection=false -Ddocs=false -Dtests=no -Dvapi=false \
-  -Dconfig_dhcp_default=internal -Dqt=false
-'''
-compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
-install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
-
-[deps]
-build = ["meson", "samurai", "python3", "pkgconf", "glib-shared", "pcre2-shared", "libffi",
-  "libudev-zero", "libndp", "libnl", "zlib-shared", "gettext-tiny", "libxml2", "util-linux", "perl", "dbus", "expat"]
diff --git a/recipes/libgudev.toml b/recipes/libgudev.toml
new file mode 100644
index 00000000..e59e8af2
--- /dev/null
+++ b/recipes/libgudev.toml
@@ -0,0 +1,39 @@
+# ⚠ COPIA EN LA COLA KDE (2026-09-09), y NO es lo mismo que la de GNOME aunque el texto sea igual.
+# Las colas no se ven entre sí (HERMANO→corpus), así que `upower` en KDE necesita una acá.
+# ⚠ Y el ARTEFACTO ES DISTINTO a propósito: `glib` existe en las DOS colas y son recetas distintas.
+# Desde `incoming-gnome/` esto se construye contra la glib de GNOME; desde acá, contra la del
+# corpus (KDE no tiene glib hermana). Medido: promoverla al corpus le cambiaba el hash y habría
+# arrastrado a GNOME a la glib del corpus — el cuadro de las «dos glib» que este repo ya pagó.
+# Por eso se COPIA y no se promueve.
+# libgudev 238 — envoltorio GObject sobre libudev (GUdevClient/GUdevDevice: enumerar dispositivos y
+# escuchar uevents con el bucle de GLib en vez de a mano).
+#
+# La piden DOS de la onda 3, y por eso va antes que colord: mutter por su opción `udev`, que es la
+# que necesita el backend NATIVO (KMS/DRM) —o sea, la que hace que mutter sea un compositor de
+# verdad y no sólo un cliente anidado— y colord, que la exige incondicionalmente (gudev-1.0).
+#
+# libudev lo provee libudev-zero, ya en el corpus y sellado (libudev.pc + libudev.a). Ojo con el
+# gotcha ya conocido de este frente: eudev y libudev-zero PISAN el mismo .pc y el mismo .so — acá se
+# declara libudev-zero explícitamente para que no haya duda de cuál entra en el cierre.
+#
+# Feature-minimal: introspection/vapi/tests disabled (tests piden umockdev), gtk_doc off.
+name    = "libgudev"
+version = "238"
+license = "LGPL-2.1-or-later"
+
+[source]
+tarball = "https://download.gnome.org/sources/libgudev/238/libgudev-238.tar.xz"
+sha256  = "61266ab1afc9d73dbc60a8b2af73e99d2fdff47d99544d085760e4fa667b5dd1"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dintrospection=disabled -Dvapi=disabled -Dtests=disabled -Dgtk_doc=false -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "glib", "libudev-zero", "libffi", "pcre2", "zlib"]
diff --git a/recipes/udev-pc.toml b/recipes/udev-pc.toml
new file mode 100644
index 00000000..65fbcfa6
--- /dev/null
+++ b/recipes/udev-pc.toml
@@ -0,0 +1,53 @@
+# ⚠ COPIA EN LA COLA KDE (2026-09-09). El original vive en `incoming-gnome/`, y las colas NO se ven
+# entre sí: una receta resuelve HERMANO→corpus y nunca de reojo a otra cola. `upower` la necesita
+# para que KDE tenga batería y perfiles de energía (powerdevil habla con upower por D-Bus).
+# Sus deps son sólo `pkgconf`, que está en el corpus ⇒ **el ArtifactHash es el MISMO que el de la
+# copia de GNOME** (verificado): un solo artefacto en el store, cero builds nuevos.
+# udev-pc — el `udev.pc` que falta, y nada más.
+#
+# QUÉ ES: mutter pide DOS pkg-config distintos para su backend nativo (meson.build:262-264):
+# `libudev` (la librería, que da libudev-zero) y `udev` (metadata: la variable `udevdir`, dónde van
+# las reglas). libudev-zero provee el primero y no el segundo — no tiene por qué: es una libudev sin
+# udevd. En distros con systemd el `udev.pc` lo pone systemd; en las que no, lo pone eudev.
+#
+# POR QUÉ UNA RECETA APARTE Y NO AGREGARLO A libudev-zero: `yupana radio libudev-zero` da **51
+# sellados cayendo a deuda**, en las cinco imágenes (base, cli y los tres escritorios). Un fichero de
+# 4 líneas no justifica reconstruir medio catálogo. Esta receta instala SÓLO el .pc, así que no pisa
+# nada de libudev-zero y las dos conviven en el mismo cierre.
+#
+# LA FUENTE es el tarball de libudev-zero a propósito, aunque no se compile nada de él: `[source]` es
+# obligatorio en el esquema de receta, y atarla a su upstream natural deja claro de quién es
+# compañera. El .pc se escribe acá porque libudev-zero no lo trae.
+#
+# udevdir=/usr/lib/udev es la ruta real de esta distro: la Semilla de arje arranca /usr/bin/udevd y
+# ahí busca sus reglas. mutter sólo usa el valor para saber dónde instalar las suyas.
+name    = "udev-pc"
+version = "1.0.4"
+license = "ISC"
+
+[source]
+tarball = "https://github.com/illiliti/libudev-zero/archive/refs/tags/1.0.4.tar.gz"
+sha256  = "10148cfd6047d387bf71eca72cd19c177084224d96434a118d8def6e0a3d6316"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+compile = 'true'
+install = '''
+set -e
+mkdir -p /out/usr/share/pkgconfig
+cat > /out/usr/share/pkgconfig/udev.pc <<'PC'
+prefix=/usr
+udevdir=${prefix}/lib/udev
+
+Name: udev
+Description: udev device manager (metadata; la libreria la provee libudev-zero)
+Version: 252
+PC
+'''
+
+[deps]
+build = ["pkgconf"]
diff --git a/recipes/upower.toml b/recipes/upower.toml
new file mode 100644
index 00000000..c0ec9fad
--- /dev/null
+++ b/recipes/upower.toml
@@ -0,0 +1,65 @@
+# upower 1.90.10 — **la variante del CORPUS**: el demonio que reporta batería, carga y estado de
+# energía por D-Bus. Es lo que alimenta el indicador de batería de un escritorio.
+#
+# ══ POR QUÉ EXISTE ESTA COPIA (2026-09-13) ═════════════════════════════════════════════════════
+# El barrido de servicios midió que **`escritorio-cosmic` dibuja un indicador de batería y NO tiene
+# `upowerd`** en su clausura: el applet existe y no tiene de dónde leer. La receta vivía en
+# `incoming-kde` y en `incoming-gnome` —las dos inalcanzables desde COSMIC, que es una cola
+# hermana— así que la copia va al corpus, el único sitio desde el que las cuatro imágenes la ven.
+#
+# ══ EL CAMBIO QUE HACE QUE LA CADENA CIERRE: `-Dpolkit=disabled` ═══════════════════════════════
+# La variante de KDE va con `-Dpolkit=enabled` «porque polkit YA está sellada» — cierto **en esa
+# cola**. Desde el corpus, `polkit` NO se alcanza, y promoverlo sería meter un polkit de verdad al
+# lado de `arje-polkit-compat`: una decisión de arquitectura, no un paso de este barrido.
+#
+# Apagarlo cuesta poco y conviene saber QUÉ cuesta: polkit en upower sólo gobierna las acciones
+# PRIVILEGIADAS (suspender/hibernar por `org.freedesktop.UPower`), que además están deprecadas —
+# hoy eso lo hace logind. **Reportar batería, carga, tiempo restante y estado de la línea de
+# corriente no pasa por polkit**, y es exactamente para lo que COSMIC lo quiere. Con esto la cadena
+# es `libgudev` + `udev-pc` + `upower`, y las dos primeras sellan con hash IDÉNTICO desde las dos
+# partes ⇒ entran por cache-hit.
+#
+# ⚠ Hay tres variantes vivas (corpus, kde, gnome) y no colisionan: ninguna imagen hidrata dos.
+# La de GNOME va con introspección (gjs dlopea `libupower-glib.so.3`); ésta no la necesita.
+#
+# Lo que sigue es la documentación de la variante de KDE, de la que ésta es copia.
+name    = "upower"
+version = "1.90.10"
+license = "GPL-2.0-or-later"
+
+[source]
+tarball = "https://gitlab.freedesktop.org/upower/upower/-/archive/v1.90.10/upower-v1.90.10.tar.gz"
+sha256  = "7fcd51bece2526dbee5170feb3ffd1adab5b0cd023575f1fd119d969b73f4b90"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+configure = '''
+set -e
+PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/share/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output \
+  --prefix=/usr --buildtype=release --wrap-mode=nodownload \
+  -Ddefault_library=both -Dos_backend=linux -Dintrospection=disabled \
+  -Didevice=disabled -Dpolkit=disabled -Dman=false -Dgtk-doc=false \
+  -Dudevrulesdir=/usr/lib/udev/rules.d -Dudevhwdbdir=/usr/lib/udev/hwdb.d \
+  -Dsystemdsystemunitdir=no -Dc_args=-Wno-error=date-time
+'''
+compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+# Sin las cuatro de introspección: las saca `-Dintrospection=disabled` (ver cabecera).
+build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "glib", "libgudev", "udev-pc", "libudev-zero", "libffi", "pcre2", "zlib-shared", "expat", "dbus-shared"]
+
+# El demonio. Mismo `label` e `id` que la variante de GNOME a propósito: es EL MISMO servicio
+# lógico, y el id (ULID) del SDD 30 identifica al servicio, no al artefacto que lo trae. Ninguna
+# imagen hidrata dos upower, así que no hay ambigüedad.
+# ⚠ Declararlo NO lo enciende: falta que el perfil lo habilite. Ver `escritorio-cosmic`.
+[[service]]
+label   = "upowerd"
+id      = "01HQAR53D4M2NBV8KZTYXFQA24"
+exec    = "/usr/libexec/upowerd"
+scope   = "system"
+restart = { initial_ms = 500, max_ms = 20000 }