gnome: añade seed-gnome.py + los mapas del subtree (faltaron en 72de19c)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
# seed-gnome.py — siembra el SUBTREE transitivo de GNOME desde metadata de nixpkgs (NO construye con
|
||||
# nix, ADR 0004: sólo lee deps). Corre `sembrar_cierre` de seed-graph sobre las raíces de una sesión
|
||||
# GNOME y clasifica el cierre:
|
||||
# conocida → ya hay receta en el corpus (cache-hit potencial)
|
||||
# frontera → nixpkgs lo pide y hammer NO tiene receta → HAY QUE AUTORAR (esto es el trabajo real)
|
||||
# nix-ismo/lab → ruido de nixpkgs o lo provee el sandbox (se descarta)
|
||||
#
|
||||
# Cada `frontera` es una HIPÓTESIS a clasificar/autorar por un humano (o un subagente-por-receta), NO
|
||||
# se promueve a receta automáticamente. Salida durable a docs/state/seed-gnome.json.
|
||||
import json, sys, pathlib, importlib.util
|
||||
# el guion en `seed-graph.py` impide `import seed_graph`: lo cargo por ruta.
|
||||
_spec = importlib.util.spec_from_file_location(
|
||||
"seed_graph", str(pathlib.Path(__file__).parent / "seed-graph.py"))
|
||||
sg = importlib.util.module_from_spec(_spec); _spec.loader.exec_module(sg)
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
||||
OUT = ROOT / "docs/state/seed-gnome.json"
|
||||
|
||||
# Raíces de una sesión GNOME usable: el compositor (mutter), el shell y su runtime JS (gjs), la
|
||||
# sesión y sus daemons, el display manager, el portal, y las apps mínimas (files, terminal, ajustes).
|
||||
# El cierre transitivo trae el resto (mozjs bajo gjs, gcr/libsecret bajo el keyring, etc.).
|
||||
RAICES = [
|
||||
"mutter", "gnome-shell", "gjs", "gnome-session", "gnome-settings-daemon",
|
||||
"gsettings-desktop-schemas", "gnome-desktop", "gnome-menus", "gnome-keyring",
|
||||
"gdm", "xdg-desktop-portal", "xdg-desktop-portal-gnome", "libadwaita",
|
||||
"nautilus", "gnome-console", "gnome-control-center", "gnome-text-editor",
|
||||
]
|
||||
|
||||
MINIMA = [ # lo que una sesión GNOME necesita para BOOTEAR a un shell usable (sin apps)
|
||||
"mutter", "gnome-shell", "gjs", "gnome-session", "gnome-settings-daemon",
|
||||
"gsettings-desktop-schemas", "gnome-desktop", "gdm", "xdg-desktop-portal-gnome",
|
||||
]
|
||||
|
||||
def main():
|
||||
recs = sg.recetas()
|
||||
raices = MINIMA if (len(sys.argv) > 1 and sys.argv[1] == "--minima") else RAICES
|
||||
print(f"== raíces GNOME: {len(raices)}", file=sys.stderr)
|
||||
grafo = sg.sembrar_cierre(raices, recs, prof_max=6, tope=4000)
|
||||
out_path = ROOT / ("docs/state/seed-gnome-minima.json" if raices is MINIMA else "docs/state/seed-gnome.json")
|
||||
# clasificar TODO el cierre
|
||||
clases = {"conocida": [], "frontera": [], "nix-ismo": [], "lab": [], "sin-attr": []}
|
||||
for n, aristas in grafo.items():
|
||||
if aristas is None:
|
||||
clases["sin-attr"].append(n); continue
|
||||
# nodos del cierre = todo lo referido como dep, clasificado por su presencia
|
||||
todos_deps = {}
|
||||
for n, aristas in grafo.items():
|
||||
for a in (aristas or []):
|
||||
d = a["dep"]
|
||||
# el nodo se clasifica por su MEJOR evidencia (conocida > frontera)
|
||||
prev = todos_deps.get(d)
|
||||
rank = {"conocida": 3, "lab": 2, "nix-ismo": 1, "frontera": 0}
|
||||
if prev is None or rank[a["clase"]] > rank[prev["clase"]]:
|
||||
todos_deps[d] = a
|
||||
conocidas = sorted(d for d, a in todos_deps.items() if a["clase"] == "conocida")
|
||||
frontera = sorted(d for d, a in todos_deps.items() if a["clase"] == "frontera")
|
||||
nixismos = sorted(d for d, a in todos_deps.items() if a["clase"] == "nix-ismo")
|
||||
lab = sorted(d for d, a in todos_deps.items() if a["clase"] == "lab")
|
||||
sin_attr = sorted(clases["sin-attr"])
|
||||
|
||||
# ¿cuántas veces piden cada frontera? (prioridad de autoría)
|
||||
demanda = {}
|
||||
for n, aristas in grafo.items():
|
||||
for a in (aristas or []):
|
||||
if a["clase"] == "frontera":
|
||||
demanda.setdefault(a["dep"], []).append(n)
|
||||
|
||||
print(f"\n== SUBTREE GNOME (cierre transitivo, {len(grafo)} nodos visitados)")
|
||||
print(f" ya tenemos receta (conocida): {len(conocidas)}")
|
||||
print(f" FRONTERA a autorar: {len(frontera)}")
|
||||
print(f" nix-ismos (ruido): {len(nixismos)}")
|
||||
print(f" provisto por el lab: {len(lab)}")
|
||||
print(f" sin attr en nixpkgs: {len(sin_attr)}"
|
||||
+ (f" ({' '.join(sin_attr[:8])}…)" if sin_attr else ""))
|
||||
print(f"\n== frontera por demanda (cuántas recetas la piden) — top 40:")
|
||||
for dep, quienes in sorted(demanda.items(), key=lambda kv: (-len(kv[1]), kv[0]))[:40]:
|
||||
print(f" {len(quienes):3}× {dep:30} ← {' '.join(sorted(set(quienes))[:4])}"
|
||||
+ (" …" if len(set(quienes)) > 4 else ""))
|
||||
|
||||
doc = dict(
|
||||
schema="hammer-seed-gnome/1",
|
||||
fuente="nixpkgs metadata (NO se construye con nix — ADR 0004)",
|
||||
advertencia="HIPÓTESIS. Cada frontera es dep-opcional / nix-ismo / hueco real. Autorar a mano.",
|
||||
raices=raices,
|
||||
resumen=dict(visitados=len(grafo), conocida=len(conocidas), frontera=len(frontera),
|
||||
nix_ismo=len(nixismos), lab=len(lab), sin_attr=len(sin_attr)),
|
||||
conocida=conocidas, frontera=frontera, nix_ismo=nixismos, lab=lab, sin_attr=sin_attr,
|
||||
demanda={d: sorted(set(q)) for d, q in sorted(demanda.items(), key=lambda kv:(-len(kv[1]),kv[0]))},
|
||||
)
|
||||
out_path.write_text(json.dumps(doc, indent=1, ensure_ascii=False) + "\n")
|
||||
print(f"\n → {out_path.relative_to(ROOT)}")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user