> 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…
yupana: rename khipu→yupana — el registro es el khipu, la yupana es el ábaco que reckona sobre él
`khipu` colisionaba con una app de tawasuyu. En vez de un nombre a dedo, el
significado más profundo RESUELVE la colisión: en los Andes el khipu GUARDABA
(el registro de nudos) y la yupana CALCULABA sobre él (el ábaco). Acá igual, y
la distinción es arquitectura:
docs/state/build-state.json = el KHIPU (el registro firme: nudos y cuerdas)
scripts/yupana.py = la YUPANA (el motor que reckona: radio, ondas, clausura)
Nunca fue del todo un khipu lo que construimos; era la yupana. La colisión
empujó al nombre más exacto.
git mv preserva historia. Verificado tras el rename: `yupana radio libdrm` da
126/132/[kde,mirada]; el guardián de regresión pasa; build-state importa yupana
y --check sigue en 0. Cero referencias `khipu` colgadas en código.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
diff --git a/scripts/build-state.py b/scripts/build-state.py
index 02118fbd..95ccfcc2 100755
--- a/scripts/build-state.py
+++ b/scripts/build-state.py
@@ -40,7 +40,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import targets as targets_mod
-import khipu # el motor de dependencias INVERSAS: cruza TODAS las colas (ver por qué en su cabecera)
+import yupana # la YUPANA: el motor de dependencias INVERSAS que cruza TODAS las colas (ver su cabecera)
ROOT = Path(__file__).resolve().parent.parent
os.chdir(ROOT)
@@ -224,11 +224,11 @@ def main():
# MEMBRESÍA DE PERFIL y DEPENDIENTES INVERSOS: los dos se calculan sobre el GRAFO ENTERO (todas
# las colas del disco), NO sobre los nodos que esta vista cargó. Es la corrección del bug de
# libdrm: en la corrida del corpus, `perfiles` llegaba a decir `['escritorio-mirada']` sobre un
- # paquete que sostiene KDE entero, porque no veía las recetas de incoming-kde. khipu las ve
- # siempre y resuelve sibling-first ⇒ el nodo se identifica por (cola, nombre). Ver khipu.py.
- todas = khipu.cargar_colas()
- memb = khipu.membresia(todas, cargar_perfiles({q for q in todas})) # TODOS los perfiles, no sólo los de esta vista
- rev = khipu.dependientes(todas)
+ # paquete que sostiene KDE entero, porque no veía las recetas de incoming-kde. yupana las ve
+ # siempre y resuelve sibling-first ⇒ el nodo se identifica por (cola, nombre). Ver yupana.py.
+ todas = yupana.cargar_colas()
+ memb = yupana.membresia(todas, cargar_perfiles({q for q in todas})) # TODOS los perfiles, no sólo los de esta vista
+ rev = yupana.dependientes(todas)
for n, r in recs.items():
clave = (r.get("queue", "corpus"), n)
r["perfiles"] = sorted(memb.get(clave, ()))
diff --git a/scripts/test-khipu-radio.py b/scripts/test-yupana-radio.py
similarity index 91%
rename from scripts/test-khipu-radio.py
rename to scripts/test-yupana-radio.py
index 934a87c9..bd9c6509 100755
--- a/scripts/test-khipu-radio.py
+++ b/scripts/test-yupana-radio.py
@@ -1,17 +1,17 @@
#!/usr/bin/env python3
-# test-khipu-radio.py — REGRESIÓN del bug de libdrm (2026-07-22). No es un test cualquiera: es la
+# test-yupana-radio.py — REGRESIÓN del bug de libdrm (2026-07-22). No es un test cualquiera: es la
# cicatriz. Si el radio de un paquete compartido entre colas vuelve a medirse sobre una sola cola,
# esto falla. La propiedad que blinda: el radio SIEMPRE cruza todas las colas del disco.
import sys, subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "scripts"))
-import khipu
+import yupana
def main():
- colas = khipu.cargar_colas()
- rev = khipu.dependientes(colas)
- memb = khipu.membresia(colas)
+ colas = yupana.cargar_colas()
+ rev = yupana.dependientes(colas)
+ memb = yupana.membresia(colas)
fallos = []
# 1) libdrm lo consumen recetas de MÁS de una cola (corpus + incoming-kde). Medirlo sobre una
diff --git a/scripts/khipu.py b/scripts/yupana.py
similarity index 87%
rename from scripts/khipu.py
rename to scripts/yupana.py
index f76c7891..c195d567 100755
--- a/scripts/khipu.py
+++ b/scripts/yupana.py
@@ -1,12 +1,16 @@
#!/usr/bin/env python3
-# khipu.py — el KHIPU del build: el registro vivo del estado de la distro y el motor de consultas
-# sobre su grafo. Es la BASE metodológica; el resto de los scripts de estado son sus órganos.
+# yupana.py — la YUPANA del build: el ábaco que RECKONA sobre el estado de la distro.
#
-# QUÉ ES UN KHIPU. El dispositivo andino de contabilidad: cuerdas anudadas que registran cantidades
-# y relaciones. Este es el khipu del build — cada receta es un nudo, cada dep una cuerda, y el
-# conjunto es la única fuente de verdad sobre QUÉ hay, QUÉ falta, QUIÉN depende de quién y A QUIÉN
-# rompo si toco algo. Antes ese saber vivía disperso (en la cabeza, en `grep`, en docs que
-# envejecen) y cada medición a mano mentía distinto.
+# DOS OBJETOS ANDINOS, DOS ROLES. En los Andes el khipu GUARDABA (cuerdas anudadas que registran
+# cantidades y relaciones) y la yupana CALCULABA sobre ese registro (el ábaco inca). Acá es igual y
+# la distinción es la arquitectura, no adorno:
+# · `docs/state/build-state.json` es el KHIPU — el registro firme y versionado: los nudos
+# (recetas) y las cuerdas (deps), la única fuente de verdad de QUÉ hay y QUÉ falta.
+# · este módulo es la YUPANA — el motor que reckona sobre el khipu: a QUIÉN rompo si toco algo
+# (radio), qué imágenes dependen de un nudo (perfiles), en qué orden masticar (ondas).
+# Es la BASE metodológica y la PUERTA ÚNICA; el resto de los scripts de estado son sus órganos.
+# Antes este saber vivía disperso (en la cabeza, en `grep`, en docs que envejecen) y cada medición
+# a mano mentía distinto.
#
# POR QUÉ EXISTE ESTE FICHERO Y NO SÓLO build-state.py. El 2026-07-22 un cambio a `libdrm`
# (default_library=both, para gtk4) invalidó 118 recetas KDE. El radio se midió contra
@@ -24,7 +28,7 @@
# capas). Por eso los nodos se identifican por PAR `(cola, nombre)`, no por nombre: `corpus/fontconfig`
# y `incoming-kde/fontconfig` son nudos distintos y romper uno no rompe a los consumidores del otro.
#
-# khipu es la PUERTA ÚNICA de la metodología. Sus verbos son los órganos del ciclo, en el orden en
+# yupana es la PUERTA ÚNICA de la metodología. Sus verbos son los órganos del ciclo, en el orden en
# que se usan (el mismo que la cadena del plan docs/plan-catalogo-objetivo.md):
#
# radio <receta> ¿a QUIÉN rompo si toco esto? (nativo; cruza TODAS las colas) ← ANTES de cambiar nada
@@ -35,9 +39,9 @@
# triaje clasificar la frontera → triaje.py
# drenar [--perfil] el orden de masticado, en ondas → drenar.py
#
-# Uso: scripts/khipu.py radio <receta> [--json]
-# scripts/khipu.py estado [--kde] | drenar [--todos] | triaje | frontera <perfil> | objetivo
-# Como módulo: from khipu import cargar_colas, membresia, dependientes, resolver
+# Uso: scripts/yupana.py radio <receta> [--json]
+# scripts/yupana.py estado [--kde] | drenar [--todos] | triaje | frontera <perfil> | objetivo
+# Como módulo: from yupana import cargar_colas, membresia, dependientes, resolver
import glob, json, os, subprocess, sys, tomllib
from pathlib import Path
@@ -189,7 +193,7 @@ def _por_cola(nodos):
return dict(Counter(q for q, _ in nodos))
-# Delegación a los órganos: khipu es la puerta, cada script sigue siendo el músculo. Se delega por
+# Delegación a los órganos: yupana es la puerta, cada script sigue siendo el músculo. Se delega por
# subproceso (no import) para no acoplar sus ciclos de vida ni sus flags — cada uno evoluciona solo.
ORGANOS = {
"estado": ["build-state.py"],