Files
takana/docs/state/kernel-bundles.toml
T
SergioandClaude Opus 5 ca9bde0251 kernel: la clausura contrastada contra un olddefconfig de verdad — 65/68 con 0 falsos positivos
Hasta acá el armador era análisis puro: la clausura decía qué debía morir y nadie lo había
contrastado con el resolvedor real. NO hace falta construir un kernel para hacerlo: lo caro
es la fase compile (35-60 min); toda la cadena del armador vive en configure y corre en
segundos.

Método: árbol 6.16.12 entero, `make defconfig` de base (el config de linux.toml NO sirve de
base: ya apaga wifi/audio/fs a mano, así que el lado disable no apagaría nada y la
predicción no se pondría a prueba — fue mi primer error), el fragmento del plan, y
olddefconfig. Verdad de campo = los símbolos que pasaron de encendidos a apagados.

  sólo depends on ....... clausura 1775  aciertos 64/68  SOBRA 0  falta 4
  + huérfanos select .... clausura 1794  aciertos 65/68  SOBRA 0  falta 3
  + comparaciones ....... clausura 1795  aciertos 65/68  SOBRA 0  falta 3

SOBRA 0 en las tres: el predictor nunca dice que muere algo que sobrevive, que es la única
dirección en la que puede equivocarse sin fabricar un ladrillo.

Dos refinamientos que salieron de la medición, cada uno con su test:
  · HUÉRFANOS DE SELECT. Un símbolo sin prompt no se marca a mano: sólo entra por select.
    Si caen todos sus selectores, cae él, aunque nadie dependa de él (caso ACPI_NHLT). Se
    exige >=1 selector: sin ninguno entra por un default, y darlo por muerto mataría media
    tabla.
  · `X = y` SÍ ES DEPENDENCIA DURA. Medio drivers/video/fbdev declara su dependencia de FB
    como `depends on (FB = y) && ARM`. Tratar toda comparación como opaca dejaba esos
    drivers fuera. `X = n` sigue fuera a propósito: con X en n es VERDADERA. De regalo, las
    fugas select sin declarar de sin-graficos cayeron de 8+ a 1.

Los 3 que faltan NO son un fallo, son otra pregunta: CRYPTO_LIB_ARC4, REGMAP y
SYSTEM_DATA_VERIFICATION tienen selectores FUERA de la clausura (PPP_MPPE, 111 usuarios más
de REGMAP…). Se quedaron sin usuarios en ESE config; encendés PPP y ARC4 vuelve.
«Inalcanzable» y «apagado ahora» no son lo mismo, y la clausura contesta la primera.

Y un bug que sólo aparece corriendo el resolvedor: el diff-back contaba como promesa
incumplida todo símbolo pedido ausente del .config. Pero Kconfig NO EMITE un símbolo cuyas
dependencias no se cumplen ⇒ un `-d WLAN` cuya raíz ya cayó simplemente no sale. Con esa
cuenta un plan perfecto se reportaba roto (2 falsos incumplidos de 16). Ahora: ausente +
se pedía apagar = éxito; ausente + se pedía encender = fallo. La corrida real sale 14
cumplidos, 0 incumplidos.

GUARDIÁN NUEVO, y hacía falta: las cuatro recetas de kernel NO son el mismo kernel — linux
y linux-metal van por 6.16.12, linux-metal-dual y linux-generic por 7.1.2. Planear una
contra el árbol de la otra calcularía clausuras sobre símbolos que ahí no existen, y
saldría SIN RUIDO. KconfigTree lee ahora su versión del Makefile de arriba y `plan` FALLA
si no coincide con la de la receta (los diagnósticos sólo avisan). Aviso de la sesión de
granja/store, verificado antes de implementarlo.

Catálogo: las dos fugas que destapó la clausura más grande quedan declaradas con motivo
(FB_SYSMEM_HELPERS_DEFERRED por HID_PICOLCD_FB; DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG por
DRM_I915_DEBUG), y las notas sobre THUNDERBOLT/REISERFS_FS pasan a pasado: ya se
corrigieron en 2602218.

Runbook §4.bis: cómo probar un plan entero en 30 s en vez de 40 min.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 14:20:52 +00:00

311 lines
14 KiB
TOML

# Catálogo del armador de kernel (SDD 22) — bundles de nivel 1 y perillas de nivel 2.
#
# UN BUNDLE NO ES UNA LISTA DE SÍMBOLOS. Es una raíz y su clausura sobre el grafo de Kconfig:
# `disable = ["WIRELESS"]` son ~400 CONFIG_* que hammer calcula, no que alguien mantiene a mano.
# Por eso se auto-cura: el driver wifi que entre en 6.17 cae dentro sin que nadie lo toque.
#
# LO QUE LA CLAUSURA NO CIERRA SOLA. `select` fuerza su destino IGNORANDO los `depends on` de éste,
# así que un símbolo de fuera del bundle puede reencender lo que el bundle apagó. Cada fuga se
# declara, una vez, de una de dos formas:
# · `close_leaks` — se apaga también al que la provoca.
# · `accept_leaks` — se deja abierta A SABIENDAS, con el motivo escrito.
# `hammer kernel bundles --check` falla si aparece una fuga que no esté en ninguna de las dos: eso
# es el catálogo envejeciendo, y es la mitad barata de la curación del delta entre versiones.
#
# CONTRADICTED_BY VA EN UN SOLO SENTIDO. Sirve para decirle al usuario «marcaste "no necesito wifi"
# y tenés un AX211 activo ahora mismo». NUNCA para podar el config solo: no se puede detectar el
# dock que se enchufa el mes que viene ni el fs del USB de rescate, y un kernel podado por
# autodetección es cómo se fabrica un ladrillo.
#
# Regenerar los números / revisar las fugas:
# hammer kernel bundles --kconfig <árbol> --check
# hammer kernel closure --kconfig <árbol> WIRELESS --fixpoint
version = 1
reviewed_against = "linux-6.16.12"
# =================================================================================================
# NIVEL 1 — aserciones del dueño de la máquina. No son categorías de Kconfig: son decisiones de
# vida. «No necesito wifi», «esta máquina nunca tuvo batería».
# =================================================================================================
[[bundle]]
id = "sin-wifi"
title = "No necesito wifi"
help = """
Apaga el stack 802.11 entero: cfg80211, mac80211 y todos los drivers de tarjeta. La máquina sigue
teniendo ethernet. NO apaga el interruptor de radio (RFKILL): eso es «sin-radios», porque lo
comparten bluetooth y NFC."""
disable = ["WIRELESS"]
# WLAN no DEPENDE de WIRELESS: lo SELECCIONA. Sin cerrarlo, apagar WIRELESS es un no-op — el
# olddefconfig lo reenciende y no lo dice. Fue el hallazgo que validó el diseño (SDD 22 §9).
close_leaks = ["WLAN", "IWLEGACY", "GELIC_WIRELESS"]
notes = "406 símbolos en 6.16.12; el bundle a mano de recipes/linux.toml da 421, y los 15 de diferencia son todos de sin-radios."
[bundle.contradicted_by]
pci_class = ["0280"]
[[bundle]]
id = "sin-bluetooth"
title = "No necesito bluetooth"
disable = ["BT"]
# Tarjeta combo wifi+BT: entra por select desde el lado wifi.
close_leaks = ["RSI_91X"]
[bundle.contradicted_by]
driver = ["btusb", "btintel", "btrtl"]
[[bundle]]
id = "sin-nfc"
title = "No necesito NFC"
disable = ["NFC"]
[[bundle]]
id = "sin-radios"
title = "No necesito el interruptor de radio (rfkill)"
help = """
RFKILL es el conmutador compartido de todas las radios: wifi, bluetooth y NFC lo declaran igual.
Apagarlo sólo tiene sentido si ninguna de las tres se usa — y se lleva por delante los botones de
radio de portátil (Dell, Lenovo, MSI…), que dependen de él."""
disable = ["RFKILL"]
notes = "Es un bundle propio, no parte de sin-wifi: el config a mano de linux.toml los escribía en la misma línea y por eso parecían uno solo."
[[bundle]]
id = "sin-audio"
title = "No necesito audio"
help = "Apaga ALSA y todo el stack de sonido, incluido el códec HDMI."
disable = ["SOUND"]
notes = """
No cierra: los drivers de GPU hacen `select` de los helpers de audio HDMI. Cerrarlo obligaría a
apagar la GPU, que es un precio que un escritorio no puede pagar — así que las fugas se aceptan y
quedan escritas. En recipes/linux.toml sale gratis sólo porque ahí los gráficos TAMBIÉN están
apagados."""
[bundle.accept_leaks]
SND_HDA_COMPONENT = "lo selecciona DRM_AMD_DC / DRM_NOUVEAU / DRM_RADEON: cerrarlo = quedarse sin GPU"
SND_HDA_I915 = "lo seleccionan DRM_I915 y DRM_XE: ídem para gráficos Intel"
SND_SOC_HDMI_CODEC = "lo seleccionan diez drivers DRM (casi todos SoC ARM, inertes en x86_64)"
SND_AUDIO_GRAPH_CARD = "DRM_TEGRA, inerte en x86_64"
SND_SIMPLE_CARD = "DRM_TEGRA, inerte en x86_64"
SND_UMP = "USB_F_MIDI2, gadget USB: sólo entra si la máquina hace de dispositivo USB"
SND_UMP_LEGACY_RAWMIDI = "USB_F_MIDI2, ídem"
[bundle.contradicted_by]
pci_class = ["0403"]
driver = ["snd_hda_intel"]
[[bundle]]
id = "sin-graficos"
title = "No necesito salida gráfica"
help = """
Kernel de servidor o de consola serie: sin DRM, sin framebuffer, sin retroiluminación. Si esta
máquina tiene pantalla, este bundle la deja negra — es la aserción más peligrosa del catálogo."""
disable = ["DRM", "FB", "AGP", "BACKLIGHT_CLASS_DEVICE"]
# Framebuffers de PowerMac y de SoC ARM: no existen en x86_64, cerrarlos no cuesta nada.
close_leaks = [
"FB_CONTROL", "FB_IMSTT", "FB_MAC", "FB_PLATINUM", "FB_VALKYRIE",
"FB_VT8500", "FB_WM8505", "PMAC_BACKLIGHT",
]
[bundle.accept_leaks]
DRM_AUX_BRIDGE = "lo seleccionan los muxes USB-C (TYPEC_MUX_*): apagarlos rompería el USB-C de un portátil real"
DRM_AUX_HPD_BRIDGE = "ídem, TYPEC_QCOM_PMIC / UCSI_HUAWEI_GAOKUN"
BACKLIGHT_CLASS_DEVICE = "lo seleccionan drivers de plataforma (ACPI_CMPC, SAMSUNG_Q10, USB_APPLEDISPLAY)"
DRM_DW_HDMI_I2S_AUDIO = "SND_SOC_RK3288_HDMI_ANALOG, SoC Rockchip: inerte en x86_64"
FB_SYSMEM_HELPERS_DEFERRED = "lo selecciona HID_PICOLCD_FB, una pantallita USB que es un dispositivo HID: decir «no quiero salida gráfica» no debe apagar un HID"
[bundle.contradicted_by]
pci_class = ["0300", "0380"]
[[bundle]]
id = "solo-ext4"
title = "Sólo uso ext4"
help = "Apaga los demás sistemas de ficheros locales. Ojo con el USB de rescate: lo que no está no se monta."
disable = ["XFS_FS", "BTRFS_FS", "F2FS_FS", "JFS_FS", "GFS2_FS", "NTFS3_FS"]
close_leaks = ["NTFS_FS"]
notes = "REISERFS_FS NO va acá: upstream lo retiró y 6.16.12 ya no lo tiene. Las cuatro recetas lo apagaban en vano hasta `2602218`, que quitó el flag."
[[bundle]]
id = "sin-usb"
title = "No necesito USB"
help = "Kernel de VM con consola serie o de servidor sin puertos accesibles. En metal deja la máquina sin teclado."
disable = ["USB_SUPPORT"]
[bundle.contradicted_by]
driver = ["usbhid", "usb_storage", "xhci_hcd"]
[[bundle]]
id = "sin-entrada-humana"
title = "No necesito teclado ni ratón"
help = """
La aserción de un kernel de QEMU con consola serie: nadie va a tocar esta máquina. Es exactamente
lo que hace recipes/linux.toml, y por eso el gate de no-regresión tiene que ser POR OBJETIVO — un
gate global rechazaría esa receta, que está sana."""
disable = ["HID_SUPPORT", "INPUT_MOUSE", "INPUT_JOYSTICK", "INPUT_TABLET", "INPUT_TOUCHSCREEN"]
[bundle.contradicted_by]
driver = ["usbhid", "hid_generic", "i8042"]
[[bundle]]
id = "sin-camaras-tv"
title = "No necesito cámara ni sintonizador"
disable = ["MEDIA_SUPPORT"]
close_leaks = ["USB_F_UVC"]
[bundle.accept_leaks]
VIDEOBUF2_VMALLOC = "lo seleccionan pantallas táctiles (RMI4_F54, TOUCHSCREEN_ATMEL_MXT_T37) para sus modos de diagnóstico: decir «no quiero cámara» no debe matar el táctil"
[bundle.contradicted_by]
driver = ["uvcvideo"]
[[bundle]]
id = "sin-infiniband"
title = "No necesito InfiniBand / RDMA"
disable = ["INFINIBAND"]
[[bundle]]
id = "sin-bus-industrial"
title = "No necesito buses industriales (CAN)"
disable = ["CAN"]
[[bundle]]
id = "sin-thunderbolt-firewire"
title = "No necesito Thunderbolt ni FireWire"
help = "El símbolo se llama USB4 desde que upstream fundió Thunderbolt y USB4 en un solo driver."
disable = ["USB4", "FIREWIRE"]
notes = """
Hasta el 2026-08-10 las cuatro recetas de kernel apagaban `THUNDERBOLT`, que 6.16.12 ya no tiene, y
ese `-d` era un no-op silencioso. Corregido a `USB4` en `2602218`, que lo convierte en un guardián
de verdad: si mañana la base o un `select` lo encienden, ahora sí lo apaga."""
[bundle.accept_leaks]
DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG = "lo selecciona DRM_I915_DEBUG: es una perilla de depuración del driver gráfico, no hardware Thunderbolt"
[bundle.contradicted_by]
driver = ["thunderbolt"]
[[bundle]]
id = "sin-lector-de-tarjetas"
title = "No necesito lector de tarjetas SD/MMC"
disable = ["MMC", "MEMSTICK"]
[bundle.contradicted_by]
driver = ["sdhci_pci", "rtsx_pci_sdmmc"]
[[bundle]]
id = "sin-virtualizacion"
title = "No voy a virtualizar en esta máquina"
help = "Apaga KVM. No afecta a correr DENTRO de una VM — sólo a hospedar una."
disable = ["VIRTUALIZATION"]
[bundle.contradicted_by]
cpu_flag = ["vmx", "svm"]
# =================================================================================================
# NIVEL 2 — política y rendimiento. El campo `side` NO es decorativo: la mitad de N2 no es Kconfig
# sino variables de receta. Las dos mitades mueven el ArtifactHash igual, pero se aplican en fases
# distintas y fallan distinto; una UI que no lo sepa prometerá diffs que no puede explicar.
# =================================================================================================
[[knob]]
id = "jaula-y-eio-moderna"
title = "Jaula (Landlock + audit) y E/S moderna (io_uring, BPF)"
help = """
El contrato de PLAN-KIKIN §4.bis. Sin SECURITY_LANDLOCK+AUDIT, harkaq (SDD 16) certifica TODO como
hermético en silencio: sin auditoría no se emite un solo registro de denegación, y la evidencia
negativa se vuelve vacía."""
side = "kconfig"
enable = ["SECURITY_LANDLOCK", "AUDIT", "IO_URING", "BPF_SYSCALL"]
notes = "linux-metal y linux-generic ya los declaran; linux (el de QEMU) deja IO_URING y BPF_SYSCALL al defconfig."
[[knob]]
id = "sin-info-de-depuracion"
title = "Kernel sin información de depuración"
help = "Baja mucho el tamaño de la imagen. DEBUG_INFO_BTF además exige pahole, que el toolchain de hammer no trae."
side = "kconfig"
disable = ["DEBUG_INFO", "DEBUG_INFO_BTF"]
[[knob]]
id = "unwinder-frame-pointer"
title = "Desenrollado por frame pointer en vez de ORC"
help = """
Reduce el trabajo de objtool, pero NO lo elimina: en x86_64 las mitigaciones (retpoline,
RETHUNK) seleccionan CONFIG_OBJTOOL igual, y objtool necesita libelf."""
side = "kconfig"
enable = ["UNWINDER_FRAME_POINTER"]
disable = ["UNWINDER_ORC"]
[[knob]]
id = "preempcion-escritorio"
title = "Preempción de escritorio (menos latencia, algo menos de rendimiento bruto)"
side = "kconfig"
enable = ["PREEMPT"]
[[knob]]
id = "tick-1000"
title = "Reloj del sistema a 1000 Hz"
side = "kconfig"
enable = ["HZ_1000"]
disable = ["HZ_250"]
[[knob]]
id = "compilador-lto"
title = "LTO (optimización al enlazar)"
help = """
EL EJEMPLO DE PERILLA MIXTA. Su mitad Kconfig (LTO_CLANG_FULL) sólo se vuelve seleccionable si el
kernel se compila con clang, que es una decisión de RECETA. Hoy recipes/linux.toml compila con gcc
por decisión formal (la capa de traducción de flags de `zig cc` choca con el kbuild de x86_64), así
que esta perilla está declarada y NO es aplicable todavía."""
side = "recipe"
recipe_field = "build.compiler + build.phases.compile (make LLVM=1)"
notes = "Ver la cabecera de recipes/linux.toml: el kernel se queda en el gueto gcc hasta que se exponga el clang que zig empaqueta."
[[knob]]
id = "march-nativo"
title = "Compilar para esta CPU exacta"
help = "Mata la reproducibilidad ENTRE máquinas distintas, no la de una misma máquina: el artefacto sigue siendo bit a bit el mismo para la misma huella."
side = "recipe"
recipe_field = "build.flags"
[[knob]]
id = "debug-aparte"
title = "Separar los símbolos de depuración del artefacto"
side = "recipe"
recipe_field = "build.strip_debug"
notes = "SDD 23. Entra en hash_inputs sólo si está fijado, así que se puede activar receta a receta."
# =================================================================================================
# OBJETIVOS — para qué es este kernel. EL GATE DE NO-REGRESIÓN NO CORRE SIN UNO.
#
# La regla del gate es «todo dispositivo en uso debe seguir teniendo driver». Aplicada global,
# rechazaría recipes/linux.toml, que apaga USB, HID e INPUT A PROPÓSITO por ser el kernel de QEMU
# con consola serie. El objetivo declara qué pérdidas son legítimas para este uso; todo lo demás
# bloquea. El portón se queda — sólo que en el sitio correcto.
# =================================================================================================
[[objective]]
id = "qemu-serial"
title = "VM con consola serie"
help = """
Nadie va a tocar esta máquina: entra por ttyS0 y sale por ttyS0. Es exactamente lo que hace
recipes/linux.toml, y es una receta sana."""
allow_bundles = [
"sin-wifi", "sin-bluetooth", "sin-nfc", "sin-radios",
"sin-audio", "sin-graficos", "sin-usb", "sin-entrada-humana",
"sin-camaras-tv", "sin-infiniband", "sin-bus-industrial",
"sin-thunderbolt-firewire", "sin-lector-de-tarjetas", "solo-ext4",
]
[[objective]]
id = "servidor"
title = "Servidor sin pantalla"
help = """
Sin monitor ni sonido, pero CON teclado y USB: alguien va a enchufar un rescate el día que la red
falle. Ésa es justo la clase de pérdida que el gate existe para no dejar pasar en silencio."""
allow_bundles = [
"sin-audio", "sin-graficos", "sin-camaras-tv",
"sin-bluetooth", "sin-nfc", "sin-lector-de-tarjetas",
"sin-thunderbolt-firewire", "sin-bus-industrial",
]
[[objective]]
id = "metal-escritorio"
title = "Escritorio en metal"
help = """
El objetivo más estricto del catálogo, y a propósito: en un escritorio casi nada de lo que hoy
funciona puede desaparecer sin que el dueño se entere. Sólo se autoriza lo que un escritorio
demostrablemente no usa."""
allow_bundles = ["sin-infiniband", "sin-bus-industrial"]
[[objective]]
id = "portatil"
title = "Portátil"
help = "Como el escritorio pero además con radios y lector de tarjetas: en un portátil eso se usa."
allow_bundles = ["sin-infiniband", "sin-bus-industrial", "sin-nfc"]