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 1184Shell 70Rust 62Markdown 501503 Definitions

servidor: el archivo único trae el mínimo, el USB trae el entero

Entra `[perfil.servidor-minimo]` y el generador de variantes elige perfil POR MEDIO. La razón es
física, no una opinión sobre qué debe llevar un servidor: el fichero único carga el sistema ENTERO
en memoria —es lo que le permite soltar el disco para poder formatearlo— así que cada MiB del
rootfs es RAM exigida en la máquina de quien instala. El USB corre desde el propio medio y no
tiene ese límite.

La diferencia NO es «menos servidor», es menos HERRAMIENTA. Las raíces de servicio son las mismas
una por una —sshd, caddy, gitea, cron, hora, cortafuegos, los nueve daemons propios con sus mismas
advertencias—; lo que sale es la cadena con la que se COMPILA y el toolbox de trabajar EN la caja:

  · no hereda `cli` (54 raíces: difftastic 117 MiB, rclone 105, mise 74, dwarves 66, zellij 48,
    nushell 43, mold 41, syncthing 39, helix, yazi, btop, atuin…)
  · sin `rust` (364 MiB) ni `lld21` (109)

Medido: 99 nodos contra 166, rootfs 1456 MiB contra 2925, y el fichero pasa de 1201 a 580 MiB.
Con eso la RAM que pide el salto baja de ~7,6 GiB a ~3,6.

Si algún día el instalador deja de cargar el sistema en RAM, este perfil deja de tener motivo, y
eso queda escrito en su `descripcion` para que se borre en vez de heredarse.

El generador compone AHORA por medio (`perfiles_de <variante> <medio>`), así que las dos salidas
de una misma variante pueden llevar sistemas distintos sin que eso sea un accidente.

f268baec7c5b18304dd699c7814b7e0baa84c3aa · by Sergio · (29 d ago) · parent 2dc44ae55 · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

4 files · +92 −28

diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index e4002f03..1a3181ef 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -2042,6 +2042,41 @@ servicios = ["sshd", "gitea", "caddy", "minga", "squid", "crond", "ntpd-rs", "sh
              "matilda", "tupu", "pacha", "pacha-secretos", "willay-daemon"]
 
 # ════════════════════════════════════════════════════════════════════════════════════════════════
+[perfil.servidor-minimo]
+descripcion = "el mismo servidor, sin la cadena de desarrollo ni el toolbox: lo que se instala cuando el medio tiene que caber en RAM"
+hereda = ["base"]
+# Nace el 2026-09-23 de una pregunta del usuario mirando el tamaño del instalador: **el archivo
+# único carga el sistema entero en memoria** —es lo que le permite soltar el disco para poder
+# formatearlo— así que cada MiB del rootfs es RAM exigida en la máquina de quien instala. Con
+# `servidor` (3,0 GiB) eso pide ~7,6 GiB y el generador se niega en las máquinas chicas.
+#
+# ⚠ **La diferencia con `servidor` NO es «menos servidor»: es menos HERRAMIENTA.** Las raíces de
+# servicio son las mismas una por una —sshd, caddy, gitea, cron, hora, cortafuegos, los daemons
+# propios—; lo que sale es la cadena con la que se COMPILA y el toolbox interactivo:
+#
+#   · no hereda `cli` (54 raíces: difftastic 117 MiB, rclone 105, mise 74, dwarves 66, zellij 48,
+#     nushell 43, mold 41, syncthing 39, helix, yazi, btop, atuin… herramientas de trabajar EN la
+#     caja, no de que la caja sirva).
+#   · sin `rust` (364 MiB) ni `lld21` (109): un compilador en una imagen de servidor es una
+#     decisión, y acá se decide que no. El que lo necesite instala `servidor` por USB, o los pone
+#     después desde el repo — que es justamente para lo que el repo existe.
+#
+# ⚠ Y NO es «el servidor de verdad». `servidor` sigue siendo el destino completo y es el que va en
+# la imagen USB, donde no hay límite de memoria. Éste existe por una restricción del MEDIO, no por
+# una opinión sobre qué debe llevar un servidor. Si algún día el instalador deja de cargar el
+# sistema en RAM, este perfil deja de tener motivo.
+paquetes = [
+  # ── el acceso y la red ────────────────────────────────────────────────────────────────────────
+  "openssh", "curl", "wget", "wireguard-tools", "nftables", "netup", "tmux",
+  # ── lo que sirve ──────────────────────────────────────────────────────────────────────────────
+  "caddy", "gitea", "squid",
+  # ── operar la caja ────────────────────────────────────────────────────────────────────────────
+  "takana", "arjectl", "cronie", "logrotate", "ntpd-rs",
+  # ── los daemons propios (los mismos que `servidor`, con sus mismas advertencias) ───────────────
+  "pacha", "pacha-secretos", "minga", "tejido", "thasnuna", "tupu", "matilda",
+  "shuma-daemon", "shuma-gateway", "sandokan-watch", "willay-daemon", "willay-crosscheck",
+]
+
 [perfil.metal-tigerlake]
 descripcion = "capa de HARDWARE de la laptop del usuario: firmware y microcódigo del metal real"
 cola = "corpus"
diff --git a/scripts/instalador-variantes.sh b/scripts/instalador-variantes.sh
index b9518bcb..db0820d5 100755
--- a/scripts/instalador-variantes.sh
+++ b/scripts/instalador-variantes.sh
@@ -35,11 +35,26 @@ SALIDA="${SALIDA:-work/variantes}"
 COMPOSICION="$STORE/.perfiles"
 LOCAL="work/.rootfs-local"
 
+# ── perfiles_de <variante> <medio> ────────────────────────────────────────────────────────────
+# ⚠ **El medio manda sobre el contenido, y `servidor` es el caso donde se nota.** El fichero único
+# carga el sistema ENTERO en memoria —es lo que le permite soltar el disco para poder formatearlo—
+# así que cada MiB del rootfs es RAM exigida en la máquina de quien instala. El USB no tiene ese
+# límite: corre desde el propio medio.
+#
+# Por eso `servidor` no es la misma cosa en los dos:
+#   · por el archivo único va `servidor-minimo` — los mismos servicios, sin la cadena de compilar
+#     (`rust` 364 MiB, `lld21` 109) ni el toolbox de `cli` (54 raíces). 1,6 GiB contra 3,2.
+#   · por USB va `servidor` entero, que es el destino de verdad.
+#
+# No es una opinión sobre qué debe llevar un servidor: es una restricción física del medio, y está
+# escrita en los dos sitios —acá y en el `descripcion` del perfil— para que nadie la lea como un
+# recorte arbitrario.
 perfiles_de() {
-    case "$1" in
-        servidor) echo "base servidor" ;;
-        mirada)   echo "base escritorio-mirada" ;;
-        full)     echo "base cli escritorio-mirada servidor" ;;
+    case "$1:${2:-usb}" in
+        servidor:run) echo "base servidor-minimo" ;;
+        servidor:*)   echo "base servidor" ;;
+        mirada:*)     echo "base escritorio-mirada" ;;
+        full:*)       echo "base cli escritorio-mirada servidor" ;;
         *) echo "variante desconocida: $1 (servidor|mirada|full)" >&2; return 1 ;;
     esac
 }
@@ -63,7 +78,7 @@ medios_de() {
 }
 
 VARIANTES="${*:-servidor mirada full}"
-for v in $VARIANTES; do perfiles_de "$v" >/dev/null || exit 2; done
+for v in $VARIANTES; do perfiles_de "$v" usb >/dev/null || exit 2; done
 
 KERNEL="${KERNEL:-$(ls -dt "$STORE"/*-linux-metal/boot/bzImage 2>/dev/null | head -1)}"
 [ -n "${KERNEL:-}" ] && [ -r "$KERNEL" ] || { echo "no encuentro un bzImage de linux-metal (set KERNEL=)" >&2; exit 1; }
@@ -73,10 +88,9 @@ echo "==> piso de arranque: $PISO"
 echo "==> kernel: $KERNEL"
 mkdir -p "$SALIDA" "$COMPOSICION" "$LOCAL"
 
-for v in $VARIANTES; do
-    echo
-    echo "════ $v ════════════════════════════════════════════════════════════════════════"
-    C="$COMPOSICION/$v"
+compone() {   # <variante> <medio> → deja el árbol local en $LOCAL/<variante>-<medio>
+    _cv="$1"; _cm="$2"
+    C="$COMPOSICION/$_cv-$_cm"
     # `cp -al`: el piso entra por hardlinks, que en el mismo filesystem es gratis. Un `cp -a` de
     # 265 MiB por variante es tiempo y disco que no hacen falta.
     rm -rf "$C"; cp -al "$PISO" "$C"
@@ -87,13 +101,13 @@ for v in $VARIANTES; do
     # encima de `base`, veía el `doas` 4755 que dejó `base` —declarado, legítimo— y lo denunciaba
     # como «un bit que nadie declaró». La auditoría tiene razón en lo suyo; el que estaba mal era
     # el método. Medido el 2026-09-23.
-    for p in $(perfiles_de "$v"); do
+    for p in $(perfiles_de "$_cv" "$_cm"); do
         echo "  ── perfil $p"
-        H="$COMPOSICION/$v-$p"; rm -rf "$H"
+        H="$COMPOSICION/$_cv-$_cm-$p"; rm -rf "$H"
         python3 scripts/hydrate-profile.py "$p" --into "$H" --store "$STORE" \
-            > "work/.variante-$v-$p.log" 2>&1 || {
-            echo "     ✗ falló la hidratación de $p — ver work/.variante-$v-$p.log" >&2
-            grep -A6 'SIN artefacto\|✗' "work/.variante-$v-$p.log" | head -14 >&2
+            > "work/.variante-$_cv-$p.log" 2>&1 || {
+            echo "     ✗ falló la hidratación de $p — ver work/.variante-$_cv-$p.log" >&2
+            grep -A6 'SIN artefacto\|✗' "work/.variante-$_cv-$p.log" | head -14 >&2
             exit 1; }
         # `-n` (no pisar): si dos perfiles traen el mismo fichero es el mismo artefacto, así que
         # gana el primero y da igual cuál sea. Pisar daría el mismo resultado y un error si el
@@ -102,16 +116,22 @@ for v in $VARIANTES; do
         ( cd "$H" && find . -type d -exec mkdir -p "$C/{}" \; ) 2>/dev/null || true
         ( cd "$H" && find . ! -type d -exec cp -a -l -n {} "$C/{}" \; ) 2>/dev/null || true
         rm -rf "$H"
-        echo "     $(grep -oE '[0-9]+/[0-9]+' "work/.variante-$v-$p.log" | tail -1) artefactos · acumulado $(du -sm "$C" | cut -f1) MiB"
+        echo "     $(grep -oE '[0-9]+/[0-9]+' "work/.variante-$_cv-$p.log" | tail -1) artefactos · acumulado $(du -sm "$C" | cut -f1) MiB"
     done
-
     # ── el árbol tiene que quedar en el MISMO montaje que el stage del ensamblado ─────────────
-    L="$LOCAL/$v"
+    L="$LOCAL/$_cv-$_cm"
     rm -rf "$L"; cp -a "$C" "$L"
-    echo "  ── árbol local: $(du -sm "$L" | cut -f1) MiB"
+    rm -rf "$C"
+    echo "     árbol local: $(du -sm "$L" | cut -f1) MiB"
+}
+
+for v in $VARIANTES; do
+    echo
+    echo "════ $v ════════════════════════════════════════════════════════════════════════"
 
   if echo " $(medios_de "$v") " | grep -q ' run '; then
-    echo "  ── el fichero que se baja (.run)"
+    echo "  ── el fichero que se baja (.run) — perfiles: $(perfiles_de "$v" run)"
+    compone "$v" run
     ROOTFS="$L" KERNEL="$KERNEL" SALIDA="$SALIDA/paquete-$v" ./scripts/instalador-paquete.sh \
         > "work/.variante-$v-paquete.log" 2>&1 || {
         echo "     ✗ falló el paquete — ver work/.variante-$v-paquete.log" >&2; tail -6 "work/.variante-$v-paquete.log" >&2; exit 1; }
@@ -119,20 +139,19 @@ for v in $VARIANTES; do
         > "work/.variante-$v-run.log" 2>&1 || {
         echo "     ✗ falló el autoextraíble — ver work/.variante-$v-run.log" >&2; tail -6 "work/.variante-$v-run.log" >&2; exit 1; }
     echo "     $SALIDA/takana-instalador-$v.run  $(( $(wc -c < "$SALIDA/takana-instalador-$v.run") / 1048576 )) MiB"
+    rm -rf "$L"
   else
     echo "  ── sin .run: este rootfs no entra en RAM en una máquina normal (sólo USB)"
   fi
 
-    echo "  ── la imagen USB"
+    echo "  ── la imagen USB — perfiles: $(perfiles_de "$v" usb)"
+    compone "$v" usb
     ROOTFS="$L" KERNEL="$KERNEL" IRD_TREE="work/.arbol-$v" \
         IMG="$SALIDA/takana-instalador-usb-$v.img" ./scripts/instalador-usb.sh \
         > "work/.variante-$v-usb.log" 2>&1 || {
         echo "     ✗ falló el USB — ver work/.variante-$v-usb.log" >&2; tail -6 "work/.variante-$v-usb.log" >&2; exit 1; }
     echo "     $SALIDA/takana-instalador-usb-$v.img  $(( $(wc -c < "$SALIDA/takana-instalador-usb-$v.img") / 1048576 )) MiB"
-
-    # La composición bajo el store se borra: es un árbol de trabajo, no un artefacto, y dejarlo ahí
-    # es invitar a que alguien lo confunda con uno.
-    rm -rf "$C" "$L"
+    rm -rf "$L"
 done
 
 echo
diff --git a/web/takana-os.net/README.md b/web/takana-os.net/README.md
index 677016a2..12410bb7 100644
--- a/web/takana-os.net/README.md
+++ b/web/takana-os.net/README.md
@@ -69,7 +69,7 @@ La diferencia es **qué rootfs se copia al disco**, no cómo: el instalador y el
 |---|---|---|---|
 | `base` | sólo el piso de arranque | 137 MiB | 519 MiB |
 | `mirada` | + `[perfil.base]` + `[perfil.escritorio-mirada]` | 524 MiB | 1,6 GiB |
-| `servidor` | + `[perfil.base]` + `[perfil.servidor]` | 1,2 GiB | 3,3 GiB |
+| `servidor` | `.run`: `base` + `servidor-minimo` · USB: `base` + `servidor` | 580 MiB | 3,2 GiB |
 | `full` | + `base` + `cli` + `escritorio-mirada` + `servidor` | **no hay** | 3,5 GiB |
 
 ⚠ **«base» son DOS cosas con el mismo nombre y confundirlas da un rootfs que no arranca.** El
@@ -84,6 +84,16 @@ auditoría del bit de privilegio corre contra las declaraciones `[[setuid]]` del
 hidratando, así que al poner `escritorio-mirada` sobre `base` veía el `doas` 4755 que dejó `base`
 —declarado y legítimo— y lo denunciaba como un bit que nadie declaró.
 
+⚠ **`servidor` NO es la misma cosa en los dos medios, y es la misma física.** El `.run` carga el
+sistema entero en memoria —es lo que le permite soltar el disco— así que cada MiB del rootfs es RAM
+exigida en la máquina de quien instala. Por ahí va `servidor-minimo`: **los mismos servicios uno por
+uno** (sshd, caddy, gitea, cron, hora, cortafuegos, los daemons propios), sin la cadena de compilar
+(`rust` 364 MiB, `lld21` 109) y sin heredar `cli` (54 raíces de toolbox interactivo). **1456 MiB
+contra 2925**, y el fichero baja de 1,2 GiB a 580 MiB. Por USB va `servidor` entero, que es el
+destino de verdad. No es una opinión sobre qué debe llevar un servidor: es una restricción del
+MEDIO, y está escrita en los dos sitios —acá y en el `descripcion` del perfil— para que nadie la
+lea como un recorte arbitrario.
+
 ⚠ **`full` no tiene `.run`, y es física.** El fichero único carga el instalador entero en memoria
 —es lo que le permite soltar el disco— y ahí viven a la vez el initramfs comprimido y su contenido
 desempaquetado. Con 3,2 GiB de rootfs eso pide ~8 GiB de RAM en la máquina donde se instale. El USB
diff --git a/web/takana-os.net/index.html b/web/takana-os.net/index.html
index 48047ed4..6b637886 100644
--- a/web/takana-os.net/index.html
+++ b/web/takana-os.net/index.html
@@ -283,9 +283,9 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
   </tr>
   <tr>
    <td><code>servidor</code></td>
-   <td><span data-l="es">+ el userland completo + el perfil de servidor</span><span data-l="en">+ the full userland + the server profile</span></td>
-   <td><a href="/descargas/takana-instalador-servidor.run">1,2 GiB</a></td>
-   <td><a href="/descargas/takana-instalador-usb-servidor.img">3,3 GiB</a></td>
+   <td><span data-l="es">+ el userland completo + los servicios. <strong>El archivo único trae el servidor mínimo</strong> —los mismos servicios, sin compilador ni toolbox— porque carga el sistema en memoria; <strong>el USB trae el servidor entero</strong>, que no tiene ese límite.</span><span data-l="en">+ the full userland + the services. <strong>The single file carries the minimal server</strong> — same services, no compiler and no toolbox — because it loads the system into memory; <strong>the USB carries the full server</strong>, which has no such limit.</span></td>
+   <td><a href="/descargas/takana-instalador-servidor.run">580 MiB</a></td>
+   <td><a href="/descargas/takana-instalador-usb-servidor.img">3,2 GiB</a></td>
   </tr>
   <tr>
    <td><code>full</code></td>