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…

terminfo: la base de datos entra al corpus — sin ella el backspace de zsh no borra

El anfitrión `takana` no tiene NINGUNA entrada terminfo: `/usr/share/terminfo` no
existe y `${#terminfo}` da 0 incluso con TERM=xterm-256color. Las tres recetas de
ncurses instalan `install.libs`/`install.includes`/`install.progs` y ninguna corre
`install.data`.

Medido en un pty real contra el zsh del anfitrión: sin `cub1`, zle no sabe mover el
cursor a la izquierda y el backspace emite un espacio suelto en vez de `\b \b` — el
carácter no se borra y el hueco se corre a la derecha. El prompt sale además con un
`?` espurio delante de cada glifo del tema, y flechas/Home/TAB quedan inertes.

    sin base    echo hola + ' '     ·  \x1b[01;32m ? \xe2\x9e\x9c
    con base    echo hola + \b \b   ·  \x1b[01;32m   \xe2\x9e\x9c

El control importa: el anfitrión es musl y `LANG` viene vacío, así que «es el locale»
es la respuesta que uno quiere dar. Sólo `LANG=C.UTF-8` ⇒ sigue roto; sólo la base ⇒
arreglado. Era terminfo y sólo terminfo.

Y corrige la nota de `ncurses-tools` en targets.toml, que daba por cubierto el caso
con los `--with-fallbacks` compilados. Es una etiqueta, no un hecho: xterm-256color
es uno de los nueve pineados y daba 0 capacidades.

Va como variante y no como parche a `ncurses.toml`, que tiene 18 dependientes: así no
re-hashea nada. Mismo patrón que `ncurses-tools`, `xz-tools`, `zstd-cli`.

⚠ NO CONSTRUIDA: en este hub `takana hash` muere con `io: No such file or directory`
para cualquier receta, incluidas las ya selladas. El primer build va en el worker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

3ea48d283f55d0e75f5a756ad7a9c21b1fa31171 · ruwaq Sergio · (29 p'unchaw ñawpaq) · tayta 037a77568 · kay commitpi sach'ata qhaway

Semántico sayk'uy

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

2 qillqakuna · +154 −5

diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index 0333ac97..0700c99d 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -253,12 +253,29 @@ paquetes = [
   # `ncurses` instala `install.libs install.includes` y nada más ⇒ `clear` y `reset` en una imagen
   # de takana eran el applet de busybox. Es el mismo caso que `xz-tools` y `zstd-cli`: variante con
   # las herramientas, porque ampliar la canónica re-hashearía a sus 15 consumidores.
-  # ⚠ Instala los binarios y NO la base terminfo (~4000 entradas): `clear` y `tput` resuelven con
-  # los `--with-fallbacks` compilados dentro de la librería —linux, vt100, vt220, xterm,
-  # xterm-256color, screen, tmux, tmux-256color, ansi—, que cubren la consola del metal, QEMU y
-  # cualquier ssh moderno. Con un TERM exótico contestan «unknown terminal type» en vez de pintar
-  # basura. Corolario: `tic` e `infocmp` viajan pero no tienen base que consultar.
+  # ⚠ Instala los binarios y NO la base terminfo. La nota que había acá decía que no hacía falta
+  # porque los `--with-fallbacks` compilados dentro de la librería —linux, vt100, vt220, xterm,
+  # xterm-256color, screen, tmux, tmux-256color, ansi— cubrían «la consola del metal, QEMU y
+  # cualquier ssh moderno». **ESO ERA UNA ETIQUETA, NO UN HECHO**, y está medido en el anfitrión
+  # `takana` el 2026-09-23, con TERM que es UNO DE LOS NUEVE PINEADOS:
+  #
+  #     $ TERM=xterm-256color zsh -f -c 'zmodload zsh/terminfo; echo ${#terminfo}'
+  #     0
+  #
+  # Cero capacidades: el fallback compilado NO llega. Por eso entra `ncurses-terminfo` abajo.
+  # Corolario que SÍ se sostiene: `tic` e `infocmp` no tienen base que consultar sin esa receta.
   "ncurses-tools",
+  # `ncurses-terminfo` (2026-09-23): la BASE de datos, `/usr/share/terminfo`. Entra porque sin ella
+  # una terminal interactiva no funciona, y falla de una forma que NADIE asocia con ncurses: sin
+  # `cub1`, zle no sabe mover el cursor a la izquierda y el BACKSPACE emite un espacio suelto en vez
+  # de `\b \b` —el carácter no se borra y el hueco se corre a la derecha—; sin `kcuu1`/`khome` las
+  # flechas y Home quedan inertes; y el prompt sale con un `?` espurio pegado a cada glifo del tema.
+  # Se lee como una fuente rota y un teclado roto, no como una base de datos que falta.
+  # Control que separa la causa (el anfitrión es musl y `LANG` viene VACÍO, así que «es el locale»
+  # es la respuesta que uno quiere dar): sólo `LANG=C.UTF-8` ⇒ SIGUE ROTO; sólo la base ⇒ arreglado.
+  # Cuesta ~7,5 M y ~2900 entradas de las que una máquina usa tres: recortar ese set es su propia
+  # unidad de trabajo, pero el recorte correcto es elegir cuáles viajan, no quedarse sin ninguna.
+  "ncurses-terminfo",
   # `akllay` (2026-09-22): el `awk` del producto, takana-PROPIO. *akllay* = escoger. «awk soberano» (usuario), que era
   # la cuarta opción del ADR — las otras tres adoptaban la semántica de otro: gawk es C con
   # extensiones GNU, goawk es Go y rompe la premisa de cadena de la Etapa C, frawk es otro dialecto.
diff --git a/recipes/ncurses-terminfo.toml b/recipes/ncurses-terminfo.toml
new file mode 100644
index 00000000..edac1bc5
--- /dev/null
+++ b/recipes/ncurses-terminfo.toml
@@ -0,0 +1,132 @@
+# ncurses 6.5 — VARIANTE con la BASE DE DATOS terminfo: `/usr/share/terminfo` (~2900 entradas).
+# NO sustituye a `recipes/ncurses.toml` ni a `recipes/ncurses-tools.toml`.
+#
+# ── POR QUÉ EXISTE: la premisa de los fallbacks era una ETIQUETA, no un hecho ────────────────────
+# `ncurses-tools.toml` dice, en su propia cabecera, que omitir `install.data` es deliberado porque
+# los nueve `--with-fallbacks` COMPILADOS dentro de la librería —linux, vt100, vt220, xterm,
+# xterm-256color, screen, tmux, tmux-256color, ansi— cubren «la consola del metal, QEMU y cualquier
+# ssh desde un emulador moderno». La decisión era razonable; **la premisa es falsa, y está medida**
+# (anfitrión `takana`, 2026-09-23, antes de este cambio):
+#
+#     $ TERM=xterm-256color zsh -f -c 'zmodload zsh/terminfo; echo ${#terminfo}'
+#     0
+#
+# Cero capacidades para `xterm-256color`, que es UNO DE LOS NUEVE PINEADOS. O sea: el fallback
+# compilado NO llega. `strings /bin/zsh | grep -c '^xterm-256color$'` ⇒ **0**; la tabla de
+# fallbacks no viaja dentro del zsh estático. **La causa exacta NO está determinada** y conviene
+# decirlo así en vez de inventarla: lo medido es que la base no está y el fallback no suple.
+#
+# ── LO QUE ROMPÍA, QUE NO SE PARECE A «falta terminfo» ──────────────────────────────────────────
+# El síntoma no se lee como un problema de base de datos: se lee como una fuente rota y un teclado
+# roto. Reproducido byte a byte en un pty real contra el zsh del anfitrión:
+#
+#   · BACKSPACE. Sin `cub1`, zle no sabe mover el cursor a la izquierda. Al borrar emitía un
+#     ESPACIO SUELTO en vez de `\b \b`, así que el carácter no se borraba y el hueco se corría a
+#     la derecha:
+#
+#         hoy        echo hola + ' '        ⇒ un espacio que avanza, no borra
+#         con base   echo hola + \b \b      ⇒ borra
+#
+#   · EL PROMPT. Un `?` espurio pegado delante de cada glifo del tema (el `➜` de robbyrussell):
+#
+#         hoy        \x1b[01;32m ? \xe2\x9e\x9c     ⇒ se ve  ?➜
+#         con base   \x1b[01;32m   \xe2\x9e\x9c     ⇒ se ve   ➜
+#
+#   · Flechas, Home y TAB inertes: sin `kcuu1`/`khome` zle no tiene qué bindear.
+#
+# ⚠ **El CONTROL importa acá**, porque las dos causas plausibles se prueban a la vez y es fácil
+# acreditarle el arreglo a la equivocada (el anfitrión es musl y `LANG` viene VACÍO, así que «es el
+# locale» es la respuesta que uno quiere dar):
+#
+#     sólo LANG=C.UTF-8      ⇒ SIGUE ROTO: backspace ' ', prompt ?➜
+#     sólo la base terminfo  ⇒ ARREGLADO:  backspace \b \b, prompt ➜     ← es esto, y sólo esto
+#
+# Y el locale no era sospechoso sin motivo: musl contesta `CODESET=UTF-8` y `MULTIBYTE=on` aun con
+# `LANG` vacío, o sea que esa pista estaba bien desde el principio.
+#
+# ── POR QUÉ UNA RECETA NUEVA Y NO UN PARCHE A LA CANÓNICA ───────────────────────────────────────
+# `ncurses.toml` tiene **18 dependientes**: moverle el `install` los re-hashea a todos y a su
+# cascada, para agregar unos megas de datos que la mayoría no mira. Va como variante, que es el
+# patrón que el repo ya usa para esto mismo — `ncurses-tools` sobre `ncurses`, `xz-tools` sobre
+# `xz`, `zstd-cli` sobre `zstd`. Esta receta no re-hashea NADA.
+#
+# ── EL PESO, QUE ES EL ARGUMENTO HONESTO EN CONTRA ──────────────────────────────────────────────
+# Son ~7,5 M y ~2900 entradas, de las que cualquier máquina usa tres. Es mucho para lo que se usa, y
+# por eso la decisión original de omitirlo no era un descuido. Pero el recorte correcto es elegir
+# QUÉ entradas viajan (un `--with-fallbacks` que de verdad llegue, o instalar un subconjunto), no
+# quedarse sin ninguna: **sin base, una terminal interactiva no funciona**, y falla de una forma
+# que nadie asocia con ncurses. Recortar el set es su propia unidad de trabajo.
+
+# ── ⚠ PUNTO DE PARTIDA, NO SELLADA ────────────────────────────────────────────────
+# Escrita en el hub el 2026-09-23 y **NO CONSTRUIDA**: en este árbol `takana hash` muere con
+# `io: No such file or directory (os error 2)` para CUALQUIER receta, incluidas las ya selladas
+# (`zlib`, `bzip2`, `xz`, `ncurses-tools`), con y sin `TAKANA_LAB=/work/dev-fs`. O sea que el fallo
+# es del entorno de build del hub, no de esta receta — pero tampoco se pudo descartar por medición.
+# El primer build va en el worker, y las trampas que ya se conocen están anotadas arriba.
+#
+# Mientras tanto el anfitrión lleva la base COPIADA A MANO en `/usr/share/terminfo` (7,5 M, 2899
+# entradas, del rootfs Arch de la jaula). Eso está FUERA DEL STORE: se pierde si la imagen se
+# rehace, y nada va a fallar cuando se pierda — simplemente el backspace vuelve a romperse. Esta
+# receta existe para que ese parche deje de hacer falta.
+
+name    = "ncurses-terminfo"
+version = "6.5"
+license = "MIT"
+
+[source]
+tarball = "https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz"
+sha256  = "136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+# El artefacto son DATOS: no hay ELF que partir. Se deja en `true` igual que las hermanas porque
+# `strip_debug` entra en `hash_inputs` y divergir acá sólo agrega una diferencia sin motivo.
+strip_debug = true
+
+[deps]
+build = ["binutils"]
+
+[build.phases]
+# `configure` IDÉNTICO al de la canónica y al de `ncurses-tools`. No hace falta para los datos, pero
+# `install.data` corre el `tic` que este mismo árbol compila, y ese `tic` tiene que hablar la misma
+# librería que el resto: una perilla distinta acá haría una base compilada por un `tic` que no es el
+# que viaja en `ncurses-tools`.
+configure = "./configure --prefix=/usr --without-shared --with-normal --enable-widec --without-debug --without-ada --without-tests --enable-pc-files --with-pkg-config-libdir=/usr/lib/pkgconfig --with-fallbacks=linux,vt100,vt220,xterm,xterm-256color,screen,tmux,tmux-256color,ansi"
+compile   = "make"
+
+# `install.data` es el target que compila `misc/terminfo.src` con `tic` y lo deja en
+# `/usr/share/terminfo`, más `/usr/share/tabset`. Es lo ÚNICO que se pide: las librerías las da la
+# canónica y los binarios `ncurses-tools`; duplicarlos acá sería pisar a dos recetas selladas.
+install = '''
+_abuild_phase() {
+	set -e
+	make install.data DESTDIR=/out
+
+	# GUARDIÁN — regla 3 de CLAUDE.md, y acá es EL riesgo real de esta receta: `install.data` no
+	# compila código, ejecuta el `tic` recién construido sobre `terminfo.src`. Si ese `tic` no
+	# arranca (estático a medias, o sin la librería que espera), el target puede «terminar bien»
+	# y dejar el árbol de directorios CREADO y VACÍO. Y las fases corren con `/bin/sh -c` SIN
+	# `-e` desde el harness, así que un fallo a mitad no aborta: sólo cuenta el último comando.
+	# Un artefacto vacío no falla — llega hasta el final diciendo que todo fue bien y envenena
+	# la caché. Se pregunta por el CONTENIDO, no por el directorio.
+	n=$(find /out/usr/share/terminfo -type f 2>/dev/null | wc -l)
+	if [ "$n" -lt 1000 ]; then
+		echo "ncurses-terminfo: la base salió con $n entradas (se esperan ~2900) — ¿corrió tic? Mirar si install.data falló en silencio: el harness no usa 'sh -e'"
+		exit 1
+	fi
+
+	# Y que estén las que de verdad se usan. Una base de 2900 entradas a la que le falte
+	# `xterm-256color` es el mismo fallo con mejor disfraz: hay bulto, no hay servicio.
+	for t in x/xterm-256color x/xterm l/linux s/screen t/tmux-256color; do
+		if [ ! -f "/out/usr/share/terminfo/$t" ]; then
+			echo "ncurses-terminfo: falta la entrada $t en la base — la mayoría de las terminales reales pasan por ahí"
+			exit 1
+		fi
+	done
+	echo "ncurses-terminfo: $n entradas, con xterm-256color/xterm/linux/screen/tmux-256color presentes"
+}
+_abuild_phase
+'''