gnome: integra el frente a yupana — perfil escritorio-gnome + reckoning honesto

1. targets.toml: [perfil.escritorio-gnome] (9 raíces de sesión, cola incoming-gnome)
   ⇒ `yupana objetivo` ya lo ve; fluye por targets.py. build-state lo SALTA hasta
   que la cola se cargue (--gnome), así declararlo no reporta raíces fantasma.
2. seed-gnome.py OPTIMIZADO: hornea la triage (sustitución/tooling/opcional/espinazo)
   como HIPÓTESIS con el caveat "el cierre de nixpkgs sobreestima ~5-10×", marca el
   keystone (spidermonkey→gjs→gnome-shell), y deja de mentir con el 465 crudo. El
   espinazo (353) se reporta como COTA ALTA, no como lista de build.

Falta (se activa al autorar): grafo build-state-gnome + flag --gnome ⇒ keystones/
drenar nativos sobre GNOME. Hoy la capa OBJETIVO del yupana-gnome está; la GRAFO no.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-23 15:58:23 -04:00
co-authored by Claude Opus 4.8
parent 224b15f231
commit 0b333b4c9e
3 changed files with 922 additions and 12 deletions
+842 -4
View File
@@ -1,7 +1,7 @@
{
"schema": "hammer-seed-gnome/1",
"schema": "hammer-seed-gnome/2",
"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.",
"advertencia": "El cierre de metadata SOBREESTIMA ~5-10× la frontera real de hammer (buildInputs de features máximas). Las cubetas son HIPÓTESIS, no verdad: la frontera real emerge autorando TOP-DOWN feature-minimal. NO promover a receta automáticamente.",
"raices": [
"mutter",
"gnome-shell",
@@ -16,10 +16,848 @@
"resumen": {
"visitados": 613,
"conocida": 155,
"frontera": 465,
"frontera_cruda": 465,
"nix_ismo": 61,
"lab": 2,
"sin_attr": 95
"sin_attr": 95,
"sustitucion": 4,
"tooling": 33,
"opcional": 75,
"espinazo": 353
},
"palo_largo": [
"spidermonkey",
"gjs"
],
"espinazo": [
"gtk+3",
"json-glib",
"gsettings-desktop-schemas",
"libxcrypt",
"polkit",
"libgudev",
"libglvnd",
"gnutls",
"libselinux",
"libsoup",
"gst-plugins-base",
"libunwind",
"libxrandr",
"fuse",
"gnome-desktop",
"gstreamer",
"libtasn1",
"libxkbfile",
"acl",
"audit",
"avahi",
"gcr",
"iso-codes",
"libidn2",
"libmnl",
"librsvg",
"libseccomp",
"libxt",
"p11-kit",
"shared-mime-info",
"at-spi2-core",
"fftw-single",
"flac",
"keyutils",
"libcap-ng",
"libgweather",
"libopus",
"libplist",
"libsecret",
"libxinerama",
"libxshmfence",
"mesa-gl-headers",
"popt",
"pygobject",
"unzip",
"accountsservice",
"db",
"dbus-python",
"dconf",
"dri-pkgconfig-stub",
"font-util",
"gdbm",
"geocode-glib",
"gjs",
"glib-networking",
"glu",
"gnome-settings-daemon",
"gst-plugins-good",
"jansson",
"jinja2",
"libbpf",
"libedit",
"libical",
"libimobiledevice-glue",
"libjack2",
"libnotify",
"libraw1394",
"libsysprof-capture",
"libunistring",
"libxfont_2",
"libxpm",
"llvm",
"net-tools",
"nettle",
"numactl",
"protobuf",
"pygments",
"serd",
"setuptools",
"umockdev",
"upower",
"v4l-utils",
"xvfb-run",
"SPIRV-LLVM-Translator",
"abseil-cpp",
"adwaita-icon-theme",
"attr",
"boehm-gc",
"bubblewrap",
"clang",
"duktape",
"egl-wayland",
"flit-core",
"fmt",
"gd",
"getopt",
"glslang",
"gpgme",
"iptables",
"kmod",
"lame",
"libao",
"libapparmor",
"libatasmart",
"libbluray",
"libcdio",
"libconfig",
"libdatrie",
"libei",
"libev",
"libfido2",
"libfontenc",
"libgphoto2",
"libimobiledevice",
"libmbim",
"libmicrohttpd",
"libnetfilter_conntrack",
"libnfnetlink",
"libnftnl",
"libpciaccess",
"libpq",
"libproxy",
"libpsl",
"libsepol",
"libstemmer",
"libthai",
"libtirpc",
"liburing",
"libva-minimal",
"libwacom",
"libxcomposite",
"libxdamage",
"libxft",
"libxmu",
"libxxf86vm",
"lttng-ust",
"lv2",
"lzo",
"mobile-broadband-provider-info",
"nghttp3",
"nspr",
"nss",
"opencl-headers",
"ply",
"ppp",
"procps",
"pyyaml",
"scons",
"sord",
"sox",
"soxr",
"speex",
"spirv-tools",
"xkbcomp",
"xxhash",
"CUnit",
"JSON",
"Module-Build",
"Parse-Yapp",
"Pod-Parser",
"SGMLSpm",
"Syntax-Keyword-Try",
"Text-WrapI18N",
"Unicode-LineBreak",
"YAML-Tiny",
"adns",
"alabaster",
"amf-headers",
"argcomplete",
"audiofile",
"autogen",
"babel",
"boost-build",
"bpftools",
"c-ares",
"cargo-c",
"catch2",
"check",
"cjson",
"clang-only",
"cpio",
"cracklib",
"cython",
"dbus-cplusplus",
"dbus-glib",
"defusedxml",
"directx-headers",
"distutils",
"dnsmasq",
"double-conversion",
"eglexternalplatform",
"ell",
"ffado",
"fftw-double",
"gdm",
"glib-testing",
"glibmm",
"gnome-autoar",
"gnome-bluetooth",
"gnome-keyring",
"gpm",
"gptfdisk",
"graphite2",
"gsound",
"gts",
"guile",
"gusb",
"gweather-locations",
"hicolor-icon-theme",
"hwloc",
"ibus",
"imagesize",
"imlib2",
"jam",
"jasper",
"jbigkit",
"kexec-tools",
"kpsewhich",
"ldns",
"lerc",
"libaio",
"libargon2",
"libavc1394",
"libavif",
"libb2",
"libblake3",
"libblockdev",
"libbsd",
"libbytesize",
"libcbor",
"libcddb",
"libcdio-paranoia",
"libclc",
"libdaemon",
"libdbusmenu-gtk3",
"libdecor",
"libdeflate",
"libdex",
"libeatmydata",
"libebur128",
"libelf",
"libexif",
"libfreeaptx",
"libfyaml",
"libglycin",
"libgnomekbd",
"libid3tag",
"libiec61883",
"libieee1284",
"libipt",
"libmd",
"libmng",
"libmtp",
"libmysofa",
"libnma",
"libopenmpt",
"libpanel",
"libpaper",
"libpfm",
"libphonenumber",
"libpipeline",
"libpwquality",
"libqmi",
"libqrtr-glib",
"librest",
"librist",
"libsamplerate",
"libsigc++",
"libssh",
"libstartup-notification",
"libsystemtap",
"libtatsu",
"liburcu",
"libusbmuxd",
"libvmaf",
"libxaw",
"libxfont_1",
"libxklavier",
"libxml++",
"libxres",
"libxscrnsaver",
"libyuv",
"lilv",
"lksctp-tools",
"lmdb",
"lzip",
"malcontent",
"markdown",
"mbedtls",
"md4c",
"mpdecimal",
"mutest",
"mutter",
"netpbm",
"newt",
"nftables",
"nghttp2",
"ngtcp2",
"nv-codec-headers",
"ocl-icd",
"onetbb",
"openapv",
"openfec",
"openjpeg",
"opensp",
"pcsclite",
"plymouth",
"portaudio",
"protobuf-c",
"pth",
"publicsuffix-list",
"pybind11",
"pycparser",
"pytest-xdist",
"python-dbusmock",
"requests",
"rhash",
"roman-numerals",
"rpcsvc-proto",
"rust-bindgen",
"rust-cbindgen",
"sandbox-dbus-launch",
"setxkbmap",
"shaderc",
"slang",
"snowballstemmer",
"source-highlight",
"spandsp",
"spdlog",
"sphinxygen",
"spidermonkey",
"spirv-headers",
"sqlite-connector-odbc",
"sratom",
"sysprof",
"systemtap",
"tinysparql",
"typing-extensions",
"typogrify",
"udisks",
"uthash",
"volume_key",
"w3m",
"webrtc-audio-processing",
"xapian",
"xdg-desktop-portal",
"xorg-server",
"xvfb",
"xvidcore",
"xwayland",
"xxd",
"zip",
"zix"
],
"triage": {
"sustitucion": [
"libpulseaudio",
"systemd",
"systemd-minimal",
"systemd-minimal-libs"
],
"tooling": [
"autoconf",
"autoconf-archive",
"automake",
"bash-completion",
"byacc",
"cmocka",
"dejagnu",
"desktop-file-utils",
"docbook-sgml",
"docbook5",
"docutils",
"doxygen",
"expect",
"gdb",
"gengetopt",
"gi-docgen",
"graphviz",
"groff",
"gtest",
"help2man",
"man-db",
"nasm",
"po4a",
"prune-libtool-files",
"ragel",
"sphinx",
"swig",
"texinfo",
"vala",
"valgrind",
"validate-pkg-config",
"xmlto",
"yasm"
],
"opcional": [
"argyllcms",
"bluez",
"bluez-headers",
"colord",
"cryptsetup",
"cups",
"cyrus-sasl",
"dav1d",
"evolution-data-server",
"fdk-aac",
"ffmpeg-headless",
"flatpak",
"geoclue",
"gnome-clocks",
"gnome-online-accounts",
"gst-plugins-bad",
"gvfs",
"krb5",
"ldacbt",
"ldb",
"libaom",
"libass",
"libcamera",
"libiscsi",
"liblc3",
"libmad",
"libmpg123",
"libndctl",
"libnfs",
"libnvme",
"libtheora",
"libtpms",
"libvpx",
"lua",
"lvm2",
"mariadb-connector-c",
"mariadb-connector-odbc",
"mpg123",
"net-snmp",
"openjdk",
"openldap",
"opusfile",
"ostree",
"poppler-glib",
"psqlodbc",
"roc-toolkit",
"ruby",
"samba",
"sane-backends",
"sbc",
"sphinxcontrib-applehelp",
"sphinxcontrib-devhelp",
"sphinxcontrib-htmlhelp",
"sphinxcontrib-jsmath",
"sphinxcontrib-qthelp",
"sphinxcontrib-serializinghtml",
"sphinxcontrib-websupport",
"srt",
"svt-av1",
"swtpm",
"talloc",
"tcl",
"tdb",
"tevent",
"tpm2-tss",
"unbound",
"unixodbc",
"vid.stab",
"vorbis-tools",
"wavpack",
"webkitgtk",
"x264",
"x265",
"zimg",
"zvbi"
],
"espinazo": [
"CUnit",
"JSON",
"Module-Build",
"Parse-Yapp",
"Pod-Parser",
"SGMLSpm",
"SPIRV-LLVM-Translator",
"Syntax-Keyword-Try",
"Text-WrapI18N",
"Unicode-LineBreak",
"YAML-Tiny",
"abseil-cpp",
"accountsservice",
"acl",
"adns",
"adwaita-icon-theme",
"alabaster",
"amf-headers",
"argcomplete",
"at-spi2-core",
"attr",
"audiofile",
"audit",
"autogen",
"avahi",
"babel",
"boehm-gc",
"boost-build",
"bpftools",
"bubblewrap",
"c-ares",
"cargo-c",
"catch2",
"check",
"cjson",
"clang",
"clang-only",
"cpio",
"cracklib",
"cython",
"db",
"dbus-cplusplus",
"dbus-glib",
"dbus-python",
"dconf",
"defusedxml",
"directx-headers",
"distutils",
"dnsmasq",
"double-conversion",
"dri-pkgconfig-stub",
"duktape",
"egl-wayland",
"eglexternalplatform",
"ell",
"ffado",
"fftw-double",
"fftw-single",
"flac",
"flit-core",
"fmt",
"font-util",
"fuse",
"gcr",
"gd",
"gdbm",
"gdm",
"geocode-glib",
"getopt",
"gjs",
"glib-networking",
"glib-testing",
"glibmm",
"glslang",
"glu",
"gnome-autoar",
"gnome-bluetooth",
"gnome-desktop",
"gnome-keyring",
"gnome-settings-daemon",
"gnutls",
"gpgme",
"gpm",
"gptfdisk",
"graphite2",
"gsettings-desktop-schemas",
"gsound",
"gst-plugins-base",
"gst-plugins-good",
"gstreamer",
"gtk+3",
"gts",
"guile",
"gusb",
"gweather-locations",
"hicolor-icon-theme",
"hwloc",
"ibus",
"imagesize",
"imlib2",
"iptables",
"iso-codes",
"jam",
"jansson",
"jasper",
"jbigkit",
"jinja2",
"json-glib",
"kexec-tools",
"keyutils",
"kmod",
"kpsewhich",
"lame",
"ldns",
"lerc",
"libaio",
"libao",
"libapparmor",
"libargon2",
"libatasmart",
"libavc1394",
"libavif",
"libb2",
"libblake3",
"libblockdev",
"libbluray",
"libbpf",
"libbsd",
"libbytesize",
"libcap-ng",
"libcbor",
"libcddb",
"libcdio",
"libcdio-paranoia",
"libclc",
"libconfig",
"libdaemon",
"libdatrie",
"libdbusmenu-gtk3",
"libdecor",
"libdeflate",
"libdex",
"libeatmydata",
"libebur128",
"libedit",
"libei",
"libelf",
"libev",
"libexif",
"libfido2",
"libfontenc",
"libfreeaptx",
"libfyaml",
"libglvnd",
"libglycin",
"libgnomekbd",
"libgphoto2",
"libgudev",
"libgweather",
"libical",
"libid3tag",
"libidn2",
"libiec61883",
"libieee1284",
"libimobiledevice",
"libimobiledevice-glue",
"libipt",
"libjack2",
"libmbim",
"libmd",
"libmicrohttpd",
"libmng",
"libmnl",
"libmtp",
"libmysofa",
"libnetfilter_conntrack",
"libnfnetlink",
"libnftnl",
"libnma",
"libnotify",
"libopenmpt",
"libopus",
"libpanel",
"libpaper",
"libpciaccess",
"libpfm",
"libphonenumber",
"libpipeline",
"libplist",
"libpq",
"libproxy",
"libpsl",
"libpwquality",
"libqmi",
"libqrtr-glib",
"libraw1394",
"librest",
"librist",
"librsvg",
"libsamplerate",
"libseccomp",
"libsecret",
"libselinux",
"libsepol",
"libsigc++",
"libsoup",
"libssh",
"libstartup-notification",
"libstemmer",
"libsysprof-capture",
"libsystemtap",
"libtasn1",
"libtatsu",
"libthai",
"libtirpc",
"libunistring",
"libunwind",
"liburcu",
"liburing",
"libusbmuxd",
"libva-minimal",
"libvmaf",
"libwacom",
"libxaw",
"libxcomposite",
"libxcrypt",
"libxdamage",
"libxfont_1",
"libxfont_2",
"libxft",
"libxinerama",
"libxkbfile",
"libxklavier",
"libxml++",
"libxmu",
"libxpm",
"libxrandr",
"libxres",
"libxscrnsaver",
"libxshmfence",
"libxt",
"libxxf86vm",
"libyuv",
"lilv",
"lksctp-tools",
"llvm",
"lmdb",
"lttng-ust",
"lv2",
"lzip",
"lzo",
"malcontent",
"markdown",
"mbedtls",
"md4c",
"mesa-gl-headers",
"mobile-broadband-provider-info",
"mpdecimal",
"mutest",
"mutter",
"net-tools",
"netpbm",
"nettle",
"newt",
"nftables",
"nghttp2",
"nghttp3",
"ngtcp2",
"nspr",
"nss",
"numactl",
"nv-codec-headers",
"ocl-icd",
"onetbb",
"openapv",
"opencl-headers",
"openfec",
"openjpeg",
"opensp",
"p11-kit",
"pcsclite",
"ply",
"plymouth",
"polkit",
"popt",
"portaudio",
"ppp",
"procps",
"protobuf",
"protobuf-c",
"pth",
"publicsuffix-list",
"pybind11",
"pycparser",
"pygments",
"pygobject",
"pytest-xdist",
"python-dbusmock",
"pyyaml",
"requests",
"rhash",
"roman-numerals",
"rpcsvc-proto",
"rust-bindgen",
"rust-cbindgen",
"sandbox-dbus-launch",
"scons",
"serd",
"setuptools",
"setxkbmap",
"shaderc",
"shared-mime-info",
"slang",
"snowballstemmer",
"sord",
"source-highlight",
"sox",
"soxr",
"spandsp",
"spdlog",
"speex",
"sphinxygen",
"spidermonkey",
"spirv-headers",
"spirv-tools",
"sqlite-connector-odbc",
"sratom",
"sysprof",
"systemtap",
"tinysparql",
"typing-extensions",
"typogrify",
"udisks",
"umockdev",
"unzip",
"upower",
"uthash",
"v4l-utils",
"volume_key",
"w3m",
"webrtc-audio-processing",
"xapian",
"xdg-desktop-portal",
"xkbcomp",
"xorg-server",
"xvfb",
"xvfb-run",
"xvidcore",
"xwayland",
"xxd",
"xxhash",
"zip",
"zix"
]
},
"conocida": [
"alsa-lib",
+14
View File
@@ -64,3 +64,17 @@ paquetes = [
# en un estilo genérico. Ver docs/state/frontera-triaje.toml para el porqué de cada uno.
"shared-mime-info", "xwayland", "polkit-qt-1", "qqc2-breeze-style",
]
[perfil.escritorio-gnome]
descripcion = "escritorio GNOME (Wayland-nativo) desde fuente — 3er escritorio, X11 al tacho"
cola = "incoming-gnome"
# Raíces de una sesión GNOME que bootea a un shell usable. El resto es CLAUSURA. Hoy son HUECOS
# (cero recetas en incoming-gnome): build-state SALTA este perfil hasta que su cola se cargue
# (--gnome), así que declararlo NO reporta raíces fantasma — sólo lo hace un objetivo de primera
# clase que el sistema conoce. La frontera de autoría se descubre con `seed-gnome.py` (bootstrap por
# metadata mientras no haya recetas); OJO: ese cierre SOBREESTIMA ~5-10× (ver docs/state/seed-gnome.json
# y la memoria frente-gnome). El palo largo / keystone es spidermonkey(mozjs) → gjs → gnome-shell.
paquetes = [
"mutter", "gnome-shell", "gjs", "gnome-session", "gnome-settings-daemon",
"gsettings-desktop-schemas", "gnome-desktop", "gdm", "xdg-desktop-portal-gnome",
]
+66 -8
View File
@@ -32,6 +32,45 @@ MINIMA = [ # lo que una sesión GNOME necesita para BOOTEAR a un shell usable (
"gsettings-desktop-schemas", "gnome-desktop", "gdm", "xdg-desktop-portal-gnome",
]
# ── LA OPTIMIZACIÓN (el "yupana de gnome", no un sembrador crudo). El cierre de metadata de nixpkgs
# SOBREESTIMA ~5-10× la frontera real de hammer, porque declara buildInputs de features MÁXIMAS. Estas
# tablas son HIPÓTESIS de triage (NO verdad — la verdad emerge autorando feature-minimal), para que el
# reporte no mienta con "465 recetas". Cada una vuelve legible por qué un candidato probablemente NO es
# hueco. Clasificar a mano al autorar; mover entre cubetas es esperable.
SUSTITUCION = { # hammer YA tiene equivalente → mapeo, no hueco
"systemd", "systemd-minimal", "systemd-minimal-libs", # → elogind
"libpulseaudio", # → pipewire (libpulse compat)
"networkmanager", # → iwd / systemd-networkd (a elegir)
}
TOOLING = { # generadores de docs / build-glue: el lab los provee o se deshabilitan
"vala", "gi-docgen", "gtk-doc", "docutils", "doxygen", "texinfo", "autoconf", "automake",
"autoconf-archive", "xmlto", "nasm", "yasm", "cmocka", "gtest", "bash-completion",
"desktop-file-utils", "gettext", "itstool", "sassc", "meson", "ninja", "help2man", "gperf",
"appstream", "appstream-glib", "asciidoc", "docbook-xsl", "docbook-xml", "docbook-sgml",
"docbook5", "perl", "python3", "gobject-introspection", "sphinx", "graphviz", "groff", "swig",
"dejagnu", "expect", "valgrind", "gdb", "man-db", "po4a", "ragel", "byacc", "gengetopt",
"validate-pkg-config", "prune-libtool-files",
}
# subárboles de features/apps que una sesión mínima NO necesita (defer): media, impresión, red,
# almacenamiento, TPM, escáner, runtimes de scripting arrastrados por deps opcionales.
OPCIONAL_PREF = (
"ffmpeg", "gst-plugins-bad", "gst-plugins-ugly", "gst-libav", "x264", "x265", "svt-av1",
"dav1d", "libaom", "libvpx", "fdk-aac", "libmad", "libmpg123", "mpg123", "opusfile", "wavpack",
"libtheora", "vorbis", "zimg", "vid.stab", "libass", "srt", "zvbi", "sbc", "ldacbt", "liblc3",
"samba", "talloc", "tevent", "tdb", "ldb", "libnfs", "libiscsi", "cyrus-sasl", "net-snmp",
"unbound", "cups", "sane", "colord", "argyllcms", "bluez", "freerdp", "evolution",
"gnome-online-accounts", "gnome-remote-desktop", "webkitgtk", "gnome-clocks", "flatpak",
"ostree", "gvfs", "openjdk", "ruby", "lua", "tcl", "tpm2", "swtpm", "libtpms", "cryptsetup",
"lvm2", "libnvme", "libndctl", "mariadb", "psqlodbc", "unixodbc", "openldap", "krb5",
"sphinxcontrib", "geoclue", "libcamera", "roc-toolkit", "exiv2", "poppler",
)
def _cubeta(dep):
if dep in SUSTITUCION: return "sustitucion"
if dep in TOOLING: return "tooling"
if any(t in dep for t in OPCIONAL_PREF): return "opcional"
return "espinazo"
def main():
recs = sg.recetas()
raices = MINIMA if (len(sys.argv) > 1 and sys.argv[1] == "--minima") else RAICES
@@ -73,18 +112,37 @@ def main():
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 ""))
# ── TRIAGE (hipótesis): parte la frontera cruda en cubetas para no mentir con el conteo bruto.
cubetas = {"sustitucion": [], "tooling": [], "opcional": [], "espinazo": []}
for d in frontera:
cubetas[_cubeta(d)].append(d)
espinazo = sorted(cubetas["espinazo"], key=lambda k: (-len(demanda.get(k, [])), k))
# keystone / palo largo: gjs bloquea gnome-shell, y gjs cuelga de spidermonkey(mozjs).
palo_largo = [d for d in ("spidermonkey", "gjs", "mozjs") if d in frontera]
print(f"\n== TRIAGE de la frontera cruda (HIPÓTESIS — el cierre de nixpkgs sobreestima ~5-10×):")
print(f" sustitución (systemd→elogind…): {len(cubetas['sustitucion'])}")
print(f" tooling/docs (lab o disable): {len(cubetas['tooling'])}")
print(f" opcional (media/print/red/…): {len(cubetas['opcional'])}")
print(f" ⇒ ESPINAZO candidato a autorar: {len(espinazo)} (SIGUE siendo cota ALTA)")
print(f" ⚠ palo largo / keystone: {''.join(palo_largo) or ''} (bloquea gnome-shell)")
print(f"\n== espinazo por demanda — top 30 (hipótesis, clasificar al autorar):")
for d in espinazo[:30]:
print(f" {len(demanda.get(d, [])):3}× {d}")
doc = dict(
schema="hammer-seed-gnome/1",
schema="hammer-seed-gnome/2",
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.",
advertencia=("El cierre de metadata SOBREESTIMA ~5-10× la frontera real de hammer (buildInputs "
"de features máximas). Las cubetas son HIPÓTESIS, no verdad: la frontera real "
"emerge autorando TOP-DOWN feature-minimal. NO promover a receta automáticamente."),
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)),
resumen=dict(visitados=len(grafo), conocida=len(conocidas), frontera_cruda=len(frontera),
nix_ismo=len(nixismos), lab=len(lab), sin_attr=len(sin_attr),
sustitucion=len(cubetas["sustitucion"]), tooling=len(cubetas["tooling"]),
opcional=len(cubetas["opcional"]), espinazo=len(espinazo)),
palo_largo=palo_largo,
espinazo=espinazo, triage=cubetas,
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]))},
)