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>
This commit is contained in:
2026-07-22 19:53:53 -04:00
co-authored by Claude Opus 4.8
parent 42f198f97e
commit e4a0237b6d
3 changed files with 27 additions and 23 deletions
+6 -6
View File
@@ -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, ()))
@@ -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
+16 -12
View File
@@ -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"],