Arquitectura y evidencia

El que propone, el que verifica, y la capa de en medio

Escribes una pregunta de matemáticas en castellano o en inglés. Metamatemático la convierte en un enunciado de Lean 4 y deja que el kernel decida. Lo que devuelve no es una respuesta: es un veredicto —de ocho estados, no de dos— junto al código exacto que Lean aceptó o rechazó. Cuando no puede verificar, dice qué falló.

La forma del sistema es un lazo, no una tubería. El modelo de lenguaje propone un paso formal; Lean lo evalúa; y lo que Lean contesta condiciona el paso siguiente. Los dos extremos ya existían y no se hablaban: un modelo escribe con la misma seguridad un lema que existe y uno que ha inventado, y un verificador sólo sabe decir sí o no a un texto que ya le llega escrito. Lo que este proyecto construye es la capa de en medio: prepara lo que el modelo ve antes de escribir, y lee lo que Lean dice después de compilar, para que el lazo se cierre sobre evidencia y no sobre confianza.

Esa capa tiene dos mitades que no se parecen, y la distinción no se postuló: se descubrió midiendo. Antes de que exista un enunciado formal se trabaja con palabras humanas —ahí el grafo de conceptos gana, y por mucho—. Después, el objeto ya es un tipo, y quien busca bien sobre tipos es Lean. Ésa es la frontera de formalización, y de ella salen las cinco capas: tres antes (lengua, concepto, territorio), dos después (evidencia, emergencia).

Sirve a quien estudia —un veredicto sobre lo que uno mismo escribió, no sobre lo que dice el libro—, a quien enseña —comprobar que un enunciado dice lo que uno cree que dice— y a quien investiga —vocabulario de Mathlib verificado en un área que no domina—. Esta página describe cada pieza y la evidencia que la sostiene, incluida la que no la sostiene.

Leonardo Jiménez Martínez · BIOMAT, Centro de Biomatemáticas · Licencia MIT

353
nodos en el grafo
183 433
hechos de Mathlib
217 419
nombres indexados
387
teoremas Lean, 0 sorry
1312
tests en verde
01

El planteamiento

Qué es. Un traductor con verificador: convierte una pregunta en lenguaje natural en un enunciado de Lean 4 y somete ese enunciado al kernel. Lo que devuelve no es una respuesta sino un veredicto, y el código que lo sostiene.

Por qué hace falta. Un modelo de lenguaje que responde matemáticas produce texto plausible. La plausibilidad no es una demostración, y el modelo no distingue entre las dos: escribe con la misma seguridad un lema que existe y uno que ha inventado. De 28 identificadores que propuso de memoria, 21 no existían —y los 21 eran lemas, con la convención de nombres de Mathlib seguida al dedillo—. Por eso la decisión sobre qué es cierto se saca del modelo y se entrega al kernel de Lean 4, que sólo acepta lo que puede comprobar.

Eso reparte el trabajo en tres papeles que no se solapan:

El modelo de lenguaje

Traduce del castellano a Lean 4 y de vuelta. Escribe el enunciado formal y la explicación. No emite ningún juicio de verdad que llegue al alumno sin pasar por Lean.

nucleo/llm/

El núcleo, en cinco capas

Antes de la frontera lee la pregunta y ofrece vocabulario de Mathlib comprobado con #check. Después ordena las tácticas por la forma del objetivo y explica el resultado. No decide qué es cierto en ningún punto.

nucleo/graph/ · nucleo/lean/

Lean y Mathlib

Comprueba. Su veredicto es inapelable y va delante del texto de la respuesta, para que el alumno lea primero qué se ha comprobado y sólo después la prosa.

lake build · Mathlib
La regla que gobierna todo lo demás

Ninguna afirmación llega al alumno con sello de verificada si Lean no la ha comprobado, y el sello dice exactamente qué se comprobó. Compilar sin errores no es lo mismo que demostrar lo que se preguntó: por eso el veredicto tiene ocho estados y no dos, y tres de ellos existen justamente para nombrar los casos en que Lean acepta un archivo que no demuestra lo pedido.

Las tres vueltas del lazo, y dónde se cierra cada una

«El modelo propone y Lean evalúa» es la forma; lo que la hace funcionar es qué vuelve, y hasta dónde. El sistema cierra tres lazos de radio distinto, y ninguno de los tres es el modelo hablando consigo mismo:

lazoqué vuelve al que proponecuántas vueltasevidencia
el encabezadofalta un móduloel import que Lean echa en falta, resuelto contra el índice de nombres reales1rescata 4, rompe 0
el errorerror semánticoel error estructurado de Lean —su campo kind, no una subcadena— con el código que lo produjo2 como máximo4 de 15 · p = 0,125
la tácticaqueda un sorryno vuelve al modelo: entran las 12 tácticas en un solo compilado, ordenadas por la forma del objetivo1 compilado1,57 vs 2,44 posiciones
Un reintento sólo se acepta si mejora

Es la condición que separa un lazo de una deriva. Sin ella, un reintento que rompe lo que ya compilaba sería indistinguible de uno que arregla, y el sistema iría hacia atrás sin que nadie lo notara. Por eso el número de vueltas es pequeño y está declarado: lo que se devuelve al modelo es el veredicto de Lean, no una opinión sobre él.

Las tres vueltas operan sobre un objeto que el grafo de conceptos no contiene: el estado de prueba. Ese objeto tiene su propia categoría, construida y medida (§8) — objetos los estados, morfismos las tácticas, no goals el objeto terminal. Y el sistema enseña las tres vueltas al alumno en vez de resumírselas: el panel de explicabilidad dice qué se entendió, qué se activó, qué capacidades corrieron y cuáles no —con su motivo—, y qué contestó Lean en cada ronda.

Y una segunda regla, sobre la evidencia

Cada componente del núcleo lleva una medición con su modelo nulo al lado. Un porcentaje solo no dice nada: un clasificador que acierta el 61 % parece bueno hasta que se comprueba que responder siempre lo mismo acierta el 89 %. Comparar dos versiones de la propia idea tampoco es medir — es preferir.

La consecuencia es que este documento contiene componentes que no baten a su nulo, y lo dice. Tres de ellos están apagados en producción por esa razón, mediante una regla explícita (§12), no por criterio de nadie.

02

El flujo, de la entrada a la salida

Todo pasa por Nucleo.process(texto). Son seis pasos entre dos fronteras de idioma. El núcleo interviene en tres de los seis; en ninguno decide si algo es cierto.

NUCLEO.PROCESS(TEXTO) consulta del alumno castellano o inglés · interfaz web o REPL FRONTERA DEL IDIOMA · entrada traductor local de 74 M de parámetros, sin API — la notación se extrae, se sustituye por marcas y se restituye. El inglés pasa directo. Helsinki-NLP/opus-mt-es-en REVISIÓN DE SINTAXIS árbol por precedencia · avisa de delimitadores descasados · nunca bloquea ¿es matemática? forma, símbolos y vocabulario modelo conversacional no formaliza · sin veredicto formal no sí 1 · EL GRAFO PREPARA EL PROMPT conceptos activados · nombres de Mathlib comprobados con #check · ejemplos few-shot de miniF2F · definiciones de los pilares · declaración de la lectura elegida APORTA — 23,9 % precisión contra un nulo de 1,45 % · 16,5x 2 · EL MODELO FORMALIZA escribe Lean 4 — no juzga si es correcto. El prompt del sistema va en inglés, que es el idioma de Lean, de Mathlib y de los ejemplos. 3 · EL GRAFO DA EL MÓDULO DE CADA NOMBRE OFRECIDO va siempre, no se negocia sin esto, 282 de 284 reciben un nombre que Lean no resuelve proponer módulos VECINOS además de ésos se quitó empataba con un conjunto fijo de tres: 18 de 20 contra 18 reusa el emparejamiento del paso 1 4 · LEAN VERIFICA la fuente de verdad del sistema · su veredicto es inapelable CUATRO CAMINOS falta un módulo repara y reintenta ×1 error semántico vuelve al modelo ×2 queda un `sorry` entra la cascada acepta el archivo pasa al veredicto 5 · L3 ORDENA LAS TÁCTICAS las 12 tácticas en un `first |` con `done` · en la sesión viva (paso 2, §18) APORTA — 1,57 posiciones frente a 2,44 del nulo por frecuencia · 3,7x menos compilados EL VEREDICTO — ocho estados, no dos verificado parcial refutado sin_teorema vacuo no_verificado timeout sin_entorno los tres del centro: Lean acepta y aun así no demuestra lo que se preguntó 6 · EL MODELO TRADUCE EL VEREDICTO explica el código que Lean aceptó, no lo que el modelo creía cierto: se le pasa el código compilado y el estado de Lean, así que no puede fingir comprobación FRONTERA DEL IDIOMA · salida si preguntó en castellano, la respuesta sale en castellano — se fija en el prompt y la «pregunta original» que ve el modelo es la del alumno, no la traducción respuesta el veredicto de Lean va SIEMPRE delante del texto Lo que el diagrama no muestra Los co-reguladores deciden antes y la memoria evolutiva registra después. Ninguno formaliza ni verifica. Los dos reintentos sólo se aceptan si MEJORAN el resultado. Nunca se sustituye un veredicto por otro peor. Los 183 433 hechos de Mathlib no tocan este prompt: alimentan el índice de premisas del paso 5, y se alcanzan por classify_query, no por el grafo. Antes de compilar, el código pasa por un reparador de nombres que cualifica identificadores contra el índice de 217 419 nombres reales. Hubo un reconocedor de área por la FORMA del enunciado. En el camino real ofrecía nombres en 11 casos más y no se usaba ninguno: se quitó. Cuando la formalización admite varias lecturas clásicas, el modelo debe declarar cuál toma, y esa declaración encabeza la respuesta. El agente neuronal (GNN + PPO) daba la MISMA acción a las cuatro entradas de la sonda: aprendió una constante. Se quitó; queda data/descartado.json. Con METAMAT_GRABAR=1, el paso 2 se graba antes de que Lean lo vea, y todo lo posterior se puede reejecutar sin volver a llamar al modelo.
Fig. 1 — El recorrido completo. En morado, los tres puntos donde actúa el grafo, cada uno con su veredicto medido; en ámbar, el modelo de lenguaje; en verde, Lean. La flecha discontinua marca una dependencia real: el paso 3 no consulta el grafo por su cuenta, reusa el contexto que produjo el paso 1, así que si el emparejamiento falla, el 3 hereda el fallo.
pasoquiénqué haceevidencia
1grafoinyecta nombres de Mathlib verificados en el prompt_find_relevant_contextaporta · 16,5×
2modeloescribe Lean 4 — no juzga si es correctoLEAN_SYSTEM_PROMPT—
3grafoda el módulo de cada nombre que el paso 1 ofreció_modulos_de_los_nombres · va siempreimprescindible · 282 de 284
4Leanverifica · veredicto inapelablelean/client.py—
5L3ordena las 12 tácticas ante un sorry y las prueba sobre la sesión vivasolver_cascade.py::TacticRanker · cascada_sesion.pyaporta · 3,7× · 276 s → 40,4 s
6modelotraduce el código que Lean aceptóEXPLICACION_SYSTEM_PROMPT—

La última columna es el resultado de medir cada punto por separado. No hay un veredicto único sobre «el núcleo»: aporta en el paso 1 y en el paso 5 —y por razones distintas, a un lado y a otro de la frontera de formalización (§5)—, y en el 3 lo que va siempre es el módulo del nombre que se ofreció. Resumirlo en una sola cifra sería mentir por agregación.

Esta tabla tenía dos filas más. Proponer módulos vecinos además de los del nombre ofrecido empataba con un conjunto fijo de tres —18 de 20 enunciados elaboran, los mismos— y la regla por área que ordenaba la cascada perdía contra «probar simp primero» —1,262 contra 1,091—. Las dos estaban apagadas por el decisor y el 21 de septiembre de 2026 se quitaron del código; su cifra queda en §16. Lo que ordena la cascada hoy es un clasificador sobre la forma del objetivo, que es otra cosa y se mide aparte.

03

La frontera del idioma

El alumno pregunta en castellano y todo el aparato del sistema es inglés: las palabras clave del grafo, los 183 433 hechos de Mathlib, los ejemplos few-shot de miniF2F y el propio Lean. Quien escribe «¿Es 17 un número primo?» no toca ninguna de esas palabras.

La consulta se traduce una sola vez, al entrar, con un modelo local de 74 M de parámetros (Helsinki-NLP/opus-mt-es-en): sin API y sin coste por consulta. El inglés pasa directo.

La notación se protege, y no es opcional

Un traductor general no distingue notación de prosa. Medido sobre el modelo desnudo:

$x^2 - 5x + 6$          →  $x^2 - 5x + $6
\mathbb{R}$             →  \mathbb{R$
\int_0^\infty ... dx$   →  int_0=infty ... dx$    (destruido)
\sin x                  →  \without x

El último lo explica todo: \sin es el seno, y «sin» en castellano es una preposición. Así que la notación se extrae, se sustituye por marcas que sobreviven al tokenizador y se restituye en su sitio. Medido sobre 200 enunciados con notación: 15 014 caracteres de notación protegidos y 653 expuestos, con hueco en 21 de los 200.

Los dos lados se normalizan con la misma función

Traducir no basta, porque el emparejador comparaba dos alfabetos. La puntuación —primo? no es primo— y los acentos, porque las palabras clave se escribieron sin acentuar y el alumno escribe con ellos. Normalizar sólo la consulta empeoraría las cosas: una palabra clave acentuada dejaría de casar.

La ñ se conserva: es una letra del alfabeto, no una n con tilde — año → ano cambia la palabra. Sobre 3 000 consultas etiquetadas, el grafo guarda silencio total en el 7,7 % de los casos y activa 7,00 conceptos por consulta de media.

Y la frontera se cruza de vuelta. Si preguntó en castellano, la respuesta sale en castellano, y eso hay que fijarlo explícitamente en el prompt: el enunciado que el modelo tiene delante ya está en inglés, así que una instrucción como «responde en el idioma del usuario» le haría contestar en inglés. Lo que se le enseña como «pregunta original» es la del alumno, no la traducción, y el historial guarda lo que él escribió.

04

La sintaxis de la consulta

Una expresión matemática es un árbol, no una cadena. El módulo nucleo/sintaxis/ la analiza por precedencia —lexer, parser tipo Pratt, extractor de rasgos y revisor— y produce dos cosas que conviene no mezclar: rasgos estructurales que alimentan al emparejador, y un aviso para el alumno que sólo se emite cuando merece la pena.

consulta tal cual la escribió léxico piezas con su posición lexico.py árbol por precedencia arbol.py 68 RASGOS ESTRUCTURALES relación principal, cuantificadores, tipos, qué es hipótesis y qué es tesis. Van al emparejador y no se le muestran a nadie. EL REVISOR — qué se avisa y qué no medido sobre 23 243 enunciados correctos delimitadores descasados → SÍ se avisa 0,6 % falsos positivos · 99 % de caza los otros cuatro motivos → a metadatos 2,3 % falsos positivos · ~50 % de caza sirven para depurar, no para gritarle a nadie POR QUÉ EL DELIMITADOR ES EL ERROR CARO Un paréntesis sin cerrar hace que el modelo formalice OTRA fórmula. Lean verifica esa otra tan contento, y la respuesta sale con el sello de «verificado» puesto sobre un enunciado que nadie pidió. EL AVISO ACOMPAÑA A LA RESPUESTA — NUNCA LA SUSTITUYE NI LA BLOQUEA
Fig. 2 — El módulo de sintaxis. El corte por motivos no es cosmético: avisar del 3,6 % global enseñaría a uno de cada veintiocho alumnos a ignorar los avisos. Los delimitadores casi nunca se equivocan, casi nunca fallan, y son el único error que puede producir un sello de verificado sobre la pregunta equivocada.

Los rasgos predicen qué hechos harán falta

La relación entre sintaxis y semántica se puede medir aquí sin metáforas, porque están las dos mitades: el enunciado en Lean es un objeto puramente simbólico, y los lemas que su prueba usó son lo que hizo falta en el universo matemático. Sobre 22 117 pares y los 100 lemas con suficientes ejemplos:

representaciónrasgoscoberturaacierta alguno
modelo nulo los 6 lemas más citados—56,6 %80,3 %
n-gramas de caracteres40 00076,8 %94,7 %
estructura sintáctica6876,3 %94,9 %
las dos juntas40 06880,9 %96,8 %

Sesenta y ocho rasgos igualan a cuarenta mil, y juntos suman cuatro puntos: no son la misma información. Y lo que aprende la estructura se puede leer, que es lo que una bolsa de n-gramas no da nunca:

lemael rasgo que lo predicequé significa
sq_nonnegrelación principal ≤ (+2,92)en contra: = (−2,54)los cuadrados sirven para desigualdades, no para igualdades
mul_pos< o > en las hipótesis (+2,90)hace falta cuando el signo viene supuesto
Real.sqrt_nonneg√ en la conclusión (+1,67)en contra: tipo ℤ (−1,92)no hay raíces sobre los enteros
mul_commtipo ℂ y relación =en contra: ¬ y %no es lo que se usa en aritmética modular
El alcance de esta medida

El corpus es lean_workbook y está dominado por desigualdades: sq_nonneg aparece en el 72 % de las pruebas, y por eso el modelo nulo ya llega al 56,6 %. Mide recuperar premisas, no cerrar pruebas, y son 100 lemas de los 809 que aparecen — los que tienen al menos 30 ejemplos. Los rasgos corren sobre enunciados de Lean, que sólo existen después del paso 2.

05

La arquitectura: cinco capas y una frontera

El sistema y Lean hacen búsquedas distintas, y durante mucho tiempo compitieron sin saberlo. La diferencia no es de calidad: es de tipo de entrada. Eso parte el trabajo en dos mitades con dueños distintos, y la frontera es el momento en que existe un enunciado formal.

quién buscaindexa pornecesita
el grafopalabras humanas, ES/ENprosa
Lean exact? · apply? · aesop estructura del tipo, sobre ~200 000 declaraciones un objetivo formal

La evidencia del reparto

Antes de formalizar, con la consulta todavía en prosa, buscar sobre el índice completo no supera al azar; el vocabulario curado lo bate trece veces:

antes de la fronteraprecisiónveredicto
grafo curado 353 nodos23,9 %16,5× · aporta
índice completo de Mathlib 217 419 nombres1,53 %empata con el azar
modelo nulo1,45 %—

Después de formalizar, con un objetivo formal delante, la búsqueda del grafo pierde por dos órdenes de magnitud:

después de la fronteracoberturaveredicto
recuperación de lemas, método léxico0,64 %muy por debajo
recuperación de lemas, método semántico0,37 %muy por debajo
modelo nulo los lemas más citados77,05 %—
La frontera no se decidió: se descubrió midiendo

El decisor (§12) había separado estas capacidades una a una, cada cual contra su propio nulo, antes de que nadie nombrara la frontera. Al ponerlas en fila apareció la regla: toda capacidad del grafo que actúa antes de formalizar gana, y toda la que actúa después pierde o empata. No es una tesis previa con datos buscados a posteriori; es lo que quedó cuando se apagó lo que no batía a su nulo.

Las cinco capas

                consulta (ES/EN)
                       │
  L0  LENGUA       palabras clave ES/EN → concepto      ANTES
  L1  CONCEPTO     189 curados · vocabulario #check       DE
  L2  TERRITORIO   147 generados · dónde vive        FORMALIZAR
                       │
             ENUNCIADO FORMAL   ←── la frontera
                       │
                  LEAN VERIFICA
                       │
  L3  EVIDENCIA    forma del objetivo → qué cierra     DESPUÉS
  L4  EMERGENCIA   colímites sobre teoremas aceptados
                       │
                  LA RESPUESTA   veredicto delante del texto
Describir, medir y cablear son tres cosas distintas

Hasta el 10 de septiembre de 2026 L3 y L4 estaban descritas y medidas, y no estaban enchufadas. El rankeador estaba entrenado, guardado en disco y con su cifra publicada, y set_tactic_ranker no lo llamaba nadie: el getattr de la cascada devolvía None en todas las consultas y se ordenaba solo con la heurística. L4 igual — cargar_coocurrencia_verificada existía en CR_org y en la fachada, y el paisaje se seguía sembrando con lo que el emparejador léxico adivinaba.

Ninguna de las dos cosas daba error. Los tests pasaban, las mediciones eran ciertas, y el sistema que corría no era el que este documento describía. Es la misma familia de fallo que la §16 persigue: afirmar con más autoridad de la que se tiene. Ahora las dos corren, y hay un guardián —tests/test_capas_cableadas.py— que falla si alguna vuelve a quedarse desconectada.

Qué está cableado hoy

capaen el caminoquién la gobiernaevidencia
L0 lenguasíclasificacion_por_palabras_clave62,1 % vs 33,3 %
L1 conceptosínombres_de_mathlib_en_el_prompt23,9 % vs 1,45 %
L2 territorioalcance, sin nombres— por diseñono transfiere
Leansíverificacion_con_leanla excepción declarada: no pasa por la reglael veredicto
L3 evidenciasí · desde hoymodelo_de_orden_de_cascada0,621 vs 0,318
1,57 vs 2,44 posiciones
L4 emergenciasí · desde hoysiembra al arrancar28 pares con exceso ≥ 1,5exceso hasta +6,74
bloque estructuralla explicabilidad en el promptnocontexto_estructural_en_el_promptsin evidencia — el decisor lo deja fuera
sesión de Leanla cascada, sobre la sesión vivasí · desde el 21-09cascada_por_estadomismos 9 cierres
fallos: 276 s → 40,4 s
lazo por pasosmediador, proponentes, φnolazo_por_pasosconstruido; su puerta con modelo no se ha corrido (§18)
EL CAMINO SERVIDO LA FRONTERA ↓ consulta ES / EN el grafo · L0–L2 nombres #check · módulos formalizador · LLM enunciado + prueba Lean · el fichero check_code · repara ≤ 2 veredicto 8 estados respuesta su idioma cascada por estado 12 tácticas · sesión viva ENCENDIDA · paso 2 queda sorry la ganadora, al fichero el decisor · 23 capacidades lee data/ · corre lo que bate a su nulo gobierna las dos mitades si no verifica (apagado) EL LAZO POR PASOS · CONSTRUIDO, APAGADO HASTA SU PUERTA CON MODELO PROPONENTES · MEDIDOS SIN API SOBRE 60 ESTADOS D0 · la cascada el suelo: 40 D1v · los vecinos +8 −0 · entra D3 · el modelo gasta API · sin medir D2 · apply? de sonda medido · quitado D1d · el denso medido · quitado el mediador lo mejor primero · fallos por estado · presupuesto la sesión · busca una táctica: centésimas el fichero · decide la prueba ensamblada el registro → L4 cada intento, y cada teorema verificado φ · la explicación por paso qué conceptos toca cada estado · exactitud sin revisar
La arquitectura de hoy. Arriba corre lo que el decisor tiene encendido; la única pieza nueva en ese camino es la sesión de Lean bajo la cascada. Abajo está el lazo por pasos de §18: construido y medido sin API pieza a pieza, y fuera del camino hasta que su puerta con modelo diga que verifica más que lo servido. En las dos mitades la regla es la misma: la sesión busca, el fichero decide.
Lo que sigue fuera, y por qué

El bloque estructural —prerrequisitos, tácticas sugeridas, competencia emergente y skills que suelen acompañar, que es lo que el grafo sabe por sus aristas— está escrito y apagado. Su efecto sólo se ve en lo que el modelo escribe, y eso cuesta una llamada. Este repositorio ya ha medido dos veces que añadir contenido correcto al prompt puede empeorar el resultado, así que encenderlo sin medirlo sería justo el error contra el que existe el decisor.

L0 — Lengua

Por qué. Es lo único que Lean no puede hacer: leer una frase. Un índice de 217 419 nombres formales no contiene la correspondencia «grupo → Group, Subgroup, MonoidHom»; ésa la escribió una persona.
Qué muestra. 62,1 % de acierto de área equilibrado, frente al 33,3 % de responder siempre la clase mayoritaria.

L1 — Concepto

Por qué. El modelo inventa 21 de cada 28 identificadores cuando tira de memoria.
Qué muestra. 180 de 186 nombres existen; los seis restantes son espacios de nombres y están filtrados antes del prompt, así que la etiqueta «verificado» es cierta para todo lo que se ofrece.
Lo que NO muestra: que eso haga verificar más a Lean. Se midió — rescata 3, rompe 2, p = 1,0. Es puntería, no resultado.

L2 — Territorio

Por qué. El curado nombra 189 conceptos; la taxonomía de Mathlib tiene 1 139. Los generados dan alcance para reconocer temas.
Qué muestra. Que su vocabulario no transfiere, por tres vías medidas: sin criba 17,45 %, criba por uso 20,77 % y cuota separada 20,18 %, frente al 21,64 % de la base. El módulo de un objeto generado es un rincón de su área, no su centro.

L3 — Evidencia

Por qué. Pasada la frontera la pregunta ya no es «de qué trata» sino «qué cierra esto», y eso lo decide la forma del objetivo. Cada intento fallido cuesta una compilación de 12 a 30 segundos.
Qué hace. Un clasificador ordena la cascada combinando n-gramas —que ven los símbolos— con 74 rasgos estructurales, que ven la forma. No son redundantes: 60,53 % y 61,14 % por separado, 67,11 % juntos, sobre un nulo de 23,77 % —responder siempre nlinarith—.
Qué muestra. Medido con el modelo de producción contra el orden fijo real, sobre 1 530 casos que no vio:

ordenposición media1er intentoen los 3
fijo SOLVER_CASCADE5,790,0 %36,0 %
modelo nulo por frecuencia2,4442,5 %78,5 %
el rankeador1,5771,0 %93,5 %

3,7 veces menos invocaciones de Lean que el orden fijo, y bate al nulo fuerte por 0,87 posiciones. Es la pieza que más mejora la búsqueda de todo el sistema.

L4 — Emergencia

Por qué. El paisaje de CR_org, de donde salen los patrones que se ligan en colímites, se alimentaba de lo que el emparejador léxico adivinaba: el grafo llevaba la cuenta de sus propias conjeturas.
Qué hace. Dos conceptos coocurren si un teorema que Lean aceptó habla de los dos — 40 025 teoremas de Mathlib, corregido por frecuencia.
Qué muestra. Que los pares que emergen son relaciones genuinas, medidas por el exceso sobre lo esperado:

excesopar de conceptosjuntasesperadas
+6,74derived-category + homological-algebra60,1
+6,23measure-theory + random-variables90,1
+5,03hilbert-spaces + inner-product-spaces220,7
+4,95ideals-quotient-rings + ring-theory491,6
+4,61commutative-algebra + ideals-quotient-rings492,0
Por qué hace falta corregir por frecuencia

En crudo, el cuarto par más frecuente es cic + linear-algebra con 134 coocurrencias, y su exceso es +0,11: azar puro, porque cic declara Type y eso sale en todos los enunciados. Contar coocurrencias sin corregir mide qué palabras son comunes, no qué conceptos se relacionan.

Qué parte busca y qué parte explica

Las capas no hacen todas lo mismo, y confundirlo lleva a pedirle a una lo que sólo puede dar otra.

piezabuscaexplicaevidencia
L0 lenguasípoco62,1 % vs 33,3 %
L1 vocabulariosí, y no llega al finalmucho23,9 % vs 1,45 %p = 1,0 en verificación
L2 territorioreconoce temaspocono transfiere
L3 rankeadorla más efectivapoco3,7× menos compilaciones
L4 coocurrencianomuchoexceso hasta +6,74
la reparaciónsínorescata 4, rompe 0
387 teoremas Leannoel fundamento62 de 63 operaciones

La pieza que más mejora la búsqueda no es el grafo de conceptos: es L3, el rankeador del estado de prueba, que trabaja del lado formal de la frontera. L1 busca bien y no llega al resultado. Y L4 no busca nada y es de lo más valioso para explicar: no entra en el prompt ni ordena tácticas; lo que aporta es poder decirle a un alumno que group-theory y subgroups-cosets aparecen juntos en 206 teoremas que Lean aceptó, veinte veces más de lo que cabría esperar por azar (exceso +4,32).

06

Las dos capas de conocimiento

Hay dos almacenes con trabajos distintos, y se miden distinto. Uno dice de qué habla algo; el otro dice qué es cierto.

la consulta emparejamiento léxico classify_query() → un nombre de área EL GRAFO — conceptos «de qué habla» · lleva veredicto categórico 353 nodos · 1 586 morfismos curado a mano (173) y leído de Mathlib (125 + 22 de área) estructura categórica: colímites, orden, pilares, fibras PUEDE EQUIVOCARSE — es curación humana alimenta el prompt de formalización (paso 1) y la elección de módulos (paso 3) y de tácticas (paso 5) LA LISTA — hechos «qué es cierto» · extraída del fuente, entera 183 433 hechos · 1 102 conceptos 121 756 theorem · 50 835 lemma · 10 842 instance plana e indexada · sin estructura categórica NO PUEDE EQUIVOCARSE SOBRE SÍ MISMA alimenta el índice de premisas que se consulta cuando la táctica desnuda no cierra el objetivo EL PUENTE EXISTE EN LOS DATOS Cada hecho lleva su concepto —Algebra.Order, Data.Set— y ésos son exactamente los identificadores de los 125 nodos generados. La correspondencia no hay que inventarla: está escrita en la ruta del módulo. Y EN TIEMPO DE EJECUCIÓN NO SE TIENDE — POR MEDICIÓN, NO POR OLVIDO `premisas.py` tiene CERO menciones del grafo. El área se la da classify_query, y con exactitud equilibrada eso acierta 62,1 % frente al 38,9 % del grafo, sobre un azar del 33,3 %. Tender el cable cambiaría lo bueno por lo malo.
Fig. 3 — Las dos capas, y las dos vías por las que se alcanzan. Que el puente no esté tendido no es una deuda pendiente: está medido que tenderlo empeoraría la elección de área.

Por qué hacen falta las dos

De los 169 nombres que el grafo inyecta hoy, 3 son teoremas o lemas y 166 son tipos, estructuras y clases: el grafo aporta los sustantivos. Y ahí no es donde el modelo falla. De 28 nombres que el modelo propuso de memoria, los 21 inexistentes eran todos lemas — tsum_geometric_two, Subgroup.isCyclic, isOpen_union: siguen la convención de nombres al dedillo y no existen.

El modelo acierta razonablemente los sustantivos e inventa los hechos. La lista existe para cubrir esa mitad, y el índice de nombres (§9) para desmentir la otra.

07

El grafo: anatomía

Una categoría finita: 353 objetos y 1 586 morfismos, con identidad en cada objeto y composición por transitividad. Cada nodo lleva un sort que dice qué clase de objeto es, y ese tipado lo hace cumplir el constructor: una dependencia mal tipada se rechaza.

zfc-axioms ordinals cat-basics functors nat-trans limits fol-deduction fol-metatheory cic lean-kernel algebra algebraicgeometry algebraictopology analysis categorytheory combinatorics computability dynamics fieldtheory geometry grouptheory linearalgebra logic measuretheory modeltheory numbertheory ordertheory probability representationtheory ringtheory settheory topology las 9 tácticas, aparte 552 entran · 11 salen, todas a estrategias aesop apply calc exact induction omega rewrite ring simp SET 274 CAT 31 LOG 22 TYPE 16 147 sin interpretar 22 de área, que cosen 353 nodos · 1586 morfismos se dibujan 655 dependencias
Fig. 4 — El grafo real, dibujado desde el propio runtime. Cuatro sectores, uno por pilar fundacional: las bases al centro y las sub-ramas fuera, con el ángulo repartido por tamaño de subárbol para que ningún nodo tape a otro. En tono claro, los nodos que no llevan veredicto categórico. Las nueve tácticas van aparte porque son sumideros. Se dibujan 659 dependencias de las 688: las 1 586 aristas completas darían una maraña que esconde la estructura.
El grafo entero, nodo a nodo

Un dibujo estático no puede mostrar 353 nodos con sus nombres ni 1 586 flechas a la vez. El explorador interactivo sí: lleva el grafo completo dentro, con filtro por sort y por área, búsqueda por identificador, nombre o palabra clave, y la ficha de cada nodo — qué vocabulario lo alcanza desde una consulta, qué identificadores de Mathlib aporta al prompt, de qué depende y qué le apunta.

Se regenera desde el grafo del runtime con scripts/exportar_grafo_web.py y scripts/incrustar_grafo_web.py, así que no puede quedarse desfasado en silencio.

LOS 353 NODOS, POR SORT CONCEPTO · 189 curados a mano, con veredicto categórico: «un objeto es un grupo, las flechas son homomorfismos» MODULO · 125 leídos de la taxonomía de Mathlib. Dicen dónde vive algo, no qué es. Van marcados interpretado=False AREA · 24 22 áreas + zfc-axioms y lean-kernel la base de la proyección π. Entrar por una poda el grafo a 10 nodos de mediana TACTICA · 9 ESTRATEGIA · 6 sort=TACTICA lleva area=None: no es que le falte el área, es que la pregunta no se le aplica LOS 1 586 MORFISMOS, POR TIPO DEPENDENCY · 688 prerrequisitos. Acíclicas entre los 206 curados; de las curadas, 73,7 % confirmadas por el DAG de imports TRANSLATION · 538 entre pilares: Curry-Howard, conjuntos ↔ categorías tipos ↔ proposiciones IDENTITY · 353 una por objeto, como exige la definición de categoría — no son decorativas: la ley las necesita ANALOGY · 7 correspondencias débiles, marcadas como tales Las 9 tácticas reciben 552 aristas y sólo emiten 11, todas hacia las 6 estrategias. Una táctica no es una cosa, es una transformación de estado de prueba — como flecha compondría y tendría dominio y codominio.
Fig. 5 — Composición del grafo. Sólo los 189 nodos CONCEPTO pueden aportar nombres de Mathlib al prompt —y 147 lo hacen—: los MODULO y los AREA aportan estructura, y por eso la política de ranking los sitúa detrás — un acierto de área es más grueso que uno de concepto.

Un solo grafo, cosido por el anidamiento de módulos

Los nodos generados (125) y los curados (173) están cosidos por la jerarquía que Mathlib ya tiene escrita en el anidamiento de sus módulos, que va de lo general a lo especial — la misma dirección que el grafo curado sigue con group-theory → ring-theory → field-theory. Un cuerpo es un anillo con más axiomas: la teoría general se inyecta en la especializada.

aristas que cruzan curado ↔ generado    125
generados con ancestro curado común    109 de 125
nodos que alcanza la lógica            278 de 320
Una arista curada que vale por trescientas

fol-deduction → zfc-axioms. ZFC es una teoría de primer orden: sus axiomas son fórmulas de primer orden con igualdad, el ejemplo canónico. Sin esa arista la lógica alcanzaba 158 de 353 nodos, o sea media matemática del grafo sin la lógica detrás.

Es curada, no derivada: Mathlib no construye ZFC sobre Logic.Basic, así que el DAG de imports no la contiene. Sale de un juicio matemático y va marcada como tal.

Lo que el esqueleto de módulos no da: los generados y los curados son hermanos bajo un área, no descendientes, porque la profundidad del módulo no ordena la generalidad — LinearAlgebra.Basis está a profundidad 2 y LinearAlgebra.Matrix.Defs a 3, y sin embargo el álgebra lineal es más general que la noción de base. Eso requiere un juicio que Mathlib no contiene.

Los ciclos son de la agregación, no de la matemática

Hay 134 ciclos, todos entre nodos generados; entre los 173 curados hay cero. El DAG oficial de imports es acíclico —Lean prohíbe imports circulares— pero al colapsar 7 747 módulos en conceptos de dos niveles aparecen:

Topology.Instances → Analysis.Asymptotics → Analysis.Complex → Topology.Instances

Son tres desarrollos distintos: los espacios vectoriales topológicos necesitan la topología de ℝ≥0∞, el análisis asintótico complejo necesita la notación Θ, y la topología de ℂ necesita su estructura normada. Nadie dio la vuelta. El ciclo marca dónde la división en ramas deja de funcionar, no un recorrido.

Resultado negativo: las áreas no son recuperables de la estructura

Se intentó definir las áreas por componentes fuertemente conexas, para que el corte lo dictara la estructura y no una elección de profundidad. Da una mega-área con 918 de los 1 358 conceptos — Algebra, Data, Order, Topology y Analysis en el mismo saco— más dos residuos.

A nivel de fichero Mathlib es un DAG limpio; en cuanto se agrupa por ramas, casi todo queda entrelazado. El orden en que se construye la matemática formalizada no respeta la frontera entre álgebra, topología y análisis. Las ramas son una capa humana, útil y no derivable.

08

La base y las fibras

El grafo tiene dos preguntas distintas sobre cada nodo, y separarlas es lo que le da estructura: area dice de qué rama habla —y es la base— y sort dice qué clase de objeto es —y determina la fibra—.

LAS FIBRAS — CADA UNA CON SU SEMÁNTICA C · conceptos 158 · sort CONCEPTO «qué es una cosa» lleva veredicto categórico M · módulos 125 · sort MODULO «dónde vive el código» interpretado=False L · hechos 183 433 · lista plana «qué es cierto» HOY NO ES UNA FIBRA × loc_C loc_M loc_L NO EXISTE B · las 22 áreas una sola taxonomía · 389 palabras clave ES + EN poset por construcción — no puede tener ciclos LA BASE CATEGORÍA APARTE T · estados de prueba objetos = 24 752 estados morfismos = 25 206 tácticas CONSTRUIDA · graph/estados.py `no goals` es el objeto terminal Aquí la táctica ES la flecha, y compone: el 46,4 % de ellas lo hace. En el grafo de skills no. 16 pares paralelos · 72 ramifican 13 511 flechas al terminal (53,6 %) no enseña a ELEGIR — ver §18 EL FUNTOR ESTÁ VERIFICADO — Y UN FUNTOR NO BASTA Que π : Skills → Áreas cumpla las dos leyes está comprobado. Pero un funtor que manda todo a un punto también las cumple. La condición que dice que la base SIRVE es la de fibración: que toda flecha de abajo se levante de forma cartesiana. MEDIDO SOBRE EL GRAFO REAL — NO ES UNA FIBRACIÓN 10 de 6753 pares admiten levantamiento cartesiano: 0,1 %, frente al 4,3 % que da barajar las áreas al azar. Peor que el azar. La causa está medida: sólo 105 de 688 morfismos de orden cruzan de área, y esos 105 generan 462 relaciones entre áreas al cerrar transitivamente. La base afirma de más: el 93 % de los objetos no tiene ni un skill del área de abajo por debajo.
Fig. 6 — La estructura fibrada. La definición de fibración y las propiedades de los levantamientos cartesianos están demostradas en Lean sin ningún sorry (CategoryFoundations/Fibracion.lean); lo que no se cumple es la hipótesis sobre el grafo real. No falta formalización: faltan morfismos que crucen de área.
Por qué el tipado abarata las pruebas de Lean, y no sólo ordena

ColimitVerifier.lean y JoinColimit.lean exigen que la alcanzabilidad sea un preorden. Con un solo conjunto plano eso hay que pedirlo sobre los 353 nodos. En una estructura fibrada la delgadez se pide por fibra, y la base es un poset por construcción: la obligación de prueba se hace más pequeña y más honesta.

Y interpretado=False deja de ser un booleano que hay que acordarse de respetar: como sort, una arista de dependencia CONCEPTO → MODULO es sencillamente mal tipada, y el constructor la rechaza.

El claim que el sistema sostiene, y con esa precisión: I es el colímite de P en la subcategoría delgada finita Gn — no en una categoría arbitraria. La propiedad universal, la unicidad del mediador y el puente con CategoryTheory.Limits.IsColimit de Mathlib están demostrados, y el Python que los implementa está auditado contra ellos (§13).

Dos cosas distintas que Lean comprueba aquí

Los archivos de CategoryFoundations/ demuestran los teoremas generales: que ser colímite equivale a ser join en un preorden delgado, que el mediador es único, que la construcción encaja con IsColimit de Mathlib. Son enunciados sobre cualquier grafo, y se prueban una vez.

Lo que no dicen es si este nodo concreto es colímite de este patrón en el grafo de hoy. Eso es una afirmación sobre una instancia finita, y es decidible: hay 353 objetos, así que el ∀ del enunciado se recorre entero. build_colimit(…, con_lean=True) genera ese enunciado en Lean —sin import Mathlib, para que compile en segundos— y lo cierra con decide, que lo comprueba el kernel y no el compilador. El veredicto queda en Colimit.lean_verified.

Tres valores, no dos. True es «el kernel lo comprobó»; False es «el kernel lo refutó, hay un co-cono sin mediador»; y None es «no se sabe» — no había Lean, o no pudo terminar. Distinguir el tercero del segundo es lo único que impide que un fallo del verificador se lea como un resultado sobre el grafo, y no es hipotético: a escala real el kernel agotaba la profundidad de recursión y eso salía indistinguible de una refutación.

Va apagado por defecto, porque cuesta un compilado. Y cuesta asimétrico: refutar es barato —decide se para en el primer contraejemplo— mientras que confirmar obliga a reducir la conjunción entera. Medido sobre tres colímites reales del grafo: 2,6 s, 3,4 s y 15,3 s.

Al enunciado sólo viajan los morfismos que consulta —los que salen del diagrama y los que salen del ápice—, que no es una poda sino el conjunto exacto que la propiedad mira; el universo del cuantificador sigue siendo los 353 nodos. Sin ese recorte, los casos verdaderos agotaban el presupuesto del kernel a los 25 segundos.

09

La lista y los índices

Tres estructuras derivadas del fuente de Mathlib, con trabajos distintos: una dice qué es cierto, otra qué nombres existen, y la tercera qué herramienta puede usar cada lema.

La lista de hechos

Nombre, enunciado, módulo y concepto por cada teorema, lema e instancia. Alimenta el índice de premisas.

183 433 entradas · 54 MB
121 756 theorem · 50 835 lemma
10 842 instance · 1 102 conceptos

El índice de nombres

Unifica lemas y sustantivos. Se consulta para saber si un nombre existe, para cualificarlo antes de compilar y para desmentir a la respuesta cuando afirma que un nombre real no existe.

217 419 nombres
183 351 lemas + 34 084 sustantivos

El DAG oficial de imports

No hubo que reconstruirlo: Mathlib trae la herramienta hecha en .lake/packages/importGraph.

21 378 aristas · 7 747 módulos · 0 ciclos

Mathlib no etiqueta por rama — etiqueta por táctica

Se buscó una anotación de área y no existe. Lo que sí hay, en 83 111 líneas y 162 atributos distintos, es qué herramienta puede usar cada lema:

@[simp]        40 736      @[gcongr]       575      @[continuity]  255
@[norm_cast]    2 257      @[grind]        547      @[mono]        244
@[fun_prop]     1 796      @[aesop]        286      @[measurability]

Es un índice herramienta → lemas curado por los mantenedores, y sirve para algo concreto: el 42,1 % de las premisas que citan las pruebas ya llevan @[simp], y simp las conoce sin que nadie se las pase. Filtrarlas movió la selección de premisas de empatar con un prior de frecuencia (9,4 % contra 9,2 %) a superarlo: 14,0 % contra 11,7 %.

El reparador de nombres, antes de compilar

El índice de 217 419 nombres se consulta en la ruta de formalización con tres reglas deliberadamente conservadoras: un nombre con punto desconocido que tenga exactamente una terminación válida se cualifica; un nombre capitalizado suelto se resuelve por los espacios de nombres que la primera regla descubrió; y se añade el import del módulo que lo define.

Comprobado sobre las 241 pruebas de miniF2F que ya compilaban: el reparador no modifica ninguna. Sólo actúa donde hay algo roto.

Cobertura de la taxonomía

Los conceptos de nivel 2 que el grafo cubre alcanzan 137 476 de los 173 636 teoremas de Mathlib (79,2 %) con 211 conceptos de 1 139. La cobertura es muy desigual por rama —Álgebra 25 410 de 27 560, Análisis 20 178 de 21 240, Geometría algebraica 1 643 de 2 906, y Condensed 0 de 75—, y esa desigualdad es informativa: marca dónde el grafo curado tiene huecos reales.

10

Lean: cuatro caminos, ocho veredictos

Hay dos cosas que conviene no mezclar. Lo que Lean dice abre cuatro caminos, y tres de ellos siguen trabajando. El veredicto viene después, y no coincide con «compiló».

lo que dice Leanqué pasa después
falta un módulose repara el encabezado y se reintenta una vez
error semánticoel error estructurado vuelve al modelo, máximo 2 rondas
queda un sorryentra la cascada de 12 tácticas
acepta el archivopasa directo al árbol de veredicto
Los reintentos sólo se aceptan si MEJORAN

Nunca se sustituye un resultado por otro peor. Sin esa condición, un reintento que rompe lo que ya compilaba sería indistinguible de uno que arregla, y el sistema iría hacia atrás sin avisar.

La distinción entre error mecánico y error semántico se toma del campo kind del JSON que Lean emite —por ejemplo lean.unknownIdentifier— y sólo en segundo lugar de buscar subcadenas en el texto del error.

El árbol de veredicto, en el orden exacto en que se decide

resultado de Lean ¿hay entorno de Lean? no sin_entorno no es un fallo de lógica ¿aceptó el archivo? no sí ACEPTAR NO ES DEMOSTRAR — TRES FILTROS ANTES DEL SELLO ¿la conclusión es `True`? sí vacuo ¿contiene algún teorema? no sin_teorema ¿es la negación de lo pedido? sí refutado verificado LEAN NO ACEPTÓ parcial queda un `sorry` timeout no terminó a tiempo no_verificado rechazado POR QUÉ HACEN FALTA LOS TRES FILTROS `theorem t : True := trivial` compila con éxito y sin una sola línea de salida. Un archivo que sólo hace #check también. Y demostrar la negación de lo pedido es una respuesta correcta a una pregunta falsa — pero no es lo que se preguntó.
Fig. 7 — El árbol de veredicto, en el orden exacto en que lo evalúa core.py. Los tres filtros de la izquierda se aplican antes de conceder el sello, y existen porque los tres casos se dan en la práctica: un archivo que compila no es lo mismo que una demostración de lo que se preguntó.
veredictoqué significa exactamente
verificadohay teorema, Lean lo prueba, no es vacuo y no es la negación de lo pedido
parcialla estructura compila y queda un sorry; la cascada intentó cerrarlo
refutadoLean verificó la negación del enunciado — el enunciado pedido es falso
sin_teoremaLean aceptó el archivo, pero no contiene ningún teorema
vacuohay teorema y compila, pero su conclusión es exactamente True: no afirma nada
no_verificadoLean rechazó y los reintentos no lo arreglaron
timeoutLean no terminó dentro del límite
sin_entornono hay lake instalado — no es un fallo de lógica
Lo que se le muestra al alumno es lo que Lean compiló

El normalizador retira import Mathlib antes de compilar y pone una cabecera estrecha: compila en 11 s frente a los 24 s de Mathlib entera (data/coste_de_mathlib.json). Aquí decía «742 s, más que el tiempo límite»: esa cifra no tenía procedencia, y medida de nuevo el 2026-09-21 queda muy por debajo de los 360 s del límite. La razón para la cabecera estrecha es el coste, no que Mathlib entera no quepa. El resultado guarda el código que realmente se compiló, y es ése el que se muestra y el que se le pasa al modelo para que lo explique. Así, el bloque de código de la respuesta y el veredicto hablan del mismo archivo.

La detección de vacuo es deliberadamente estrecha: sólo dispara cuando la conclusión es exactamente True tras el último : de profundidad cero, de manera que ∃ (n : Nat), True —que sí afirma algo— no se marca.

11

La cascada de tácticas

Cuando Lean acepta la estructura pero queda un sorry, entran doce tácticas con su tiempo límite. El orden lo propone el grafo a partir de la forma del objetivo.

Desde el paso 2 del lazo (§18) el bloque ya no se compila como fichero en el camino servido: se elabora en la sesión viva de Lean, con el mismo orden y el mismo texto, y el fichero sólo confirma la táctica ganadora. Lo que sigue describe el bloque, que es el mismo en las dos vías.

rfl 1s   simp 2s   norm_num 2s   ring 2s   ring_nf 3s   field_simp 3s
linarith 3s   nlinarith 4s   omega 3s   exact? 5s   apply? 5s   aesop 8s
DÓNDE ESTÁ EL COSTE — Y NO ES EN LA TÁCTICA Arrancar Lean y elaborar los imports cuesta ~15 s cada vez. `first | t1 | t2 | ...` mete las doce en un compilado. dónde gana un proceso por táctica un solo compilado factor 1ª rfl 15,8 s 15,9 s — 4ª ring 63,6 s 15,9 s 4,0× 7ª linarith 111,4 s 16,5 s 6,8× agotada (12) 203,3 s 29,1 s 7,0× Veredicto idéntico en los cuatro escenarios: mismo solver ganador, mismo recuento. La ganancia está entera en la cola — el veredicto `parcial`, que es exactamente donde el alumno está esperando. `first |` NO ES EQUIVALENTE AL BUCLE POR SÍ SOLO `first` se queda con la primera rama que NO LANZA EXCEPCIÓN. El bucle se quedaba con la primera que hace COMPILAR EL FICHERO. No es lo mismo: una táctica puede progresar sin cerrar el objetivo. sobre a + b = b + a sin `done` norm_num progresa, first la acepta → UNSOLVED GOALS con `done` norm_num no cierra, se descarta → gana ring
Fig. 8 — La cascada en un solo compilado. Cada rama lleva done, que falla si quedan objetivos abiertos, y un trace con una marca distintiva para que Lean diga qué táctica ganó — sin eso, la ganancia costaría saber cuál fue, que es justo lo que la cascada tiene que devolver.
El orden que proponía el grafo no batía a su modelo nulo, y se quitó

Sobre 1 600 pruebas de una línea de Mathlib, con una partición de prueba del 20 %:

orden                 posición media   1er intento   en los 3
regla de hoy                1,26          88,4 %       94,4 %
MODELO NULO                 1,09          94,4 %       99,4 %
clasificador entrenado      1,06          95,9 %       99,4 %

El modelo nulo es «probar simp primero y no mirar nada más», y sale de mirar la distribución: simp cierra el 95,8 % de los 1 600 casos. La regla pierde contra el nulo en 24 casos y gana en 2, con diferencia media +0,172 posiciones e intervalo de confianza bootstrap del 95 % en [+0,094, +0,253] — entero por encima de cero, o sea real.

El mecanismo se ve en los casos: los patrones del objetivo desplazan a simp justo en objetivos que simp cierra.

La conclusión honesta no es «el orden de tácticas es malo», sino que este banco no puede decidirlo: con el 95,8 % en una sola clase, casi cualquier cosa que ponga simp primero da lo mismo. Por eso tampoco se cableó el clasificador entrenado: 1,06 frente a 1,09 no es nada sobre 320 casos.

La regla por área estuvo apagada por el decisor hasta que, el 21 de septiembre de 2026, se quitó del código con las otras nueve que no batían a su nulo. Quien ordena la cascada es el TacticRanker, que mira la forma del objetivo y sí bate al suyo: 1,57 posiciones contra 2,44.

12

El decisor

Una tabla de mediciones con filas que dicen «no bate al nulo» no sirve de nada si esas capacidades siguen ejecutándose. nucleo/decisor.py convierte la evidencia en control de flujo.

LA REGLA, Y ES UNA SOLA 1 · ¿su guarda aplica a esta consulta? p. ej. «sólo si el enunciado trae notación matemática» 2 · ¿su evidencia gana a su modelo nulo? ESTA NO SE NEGOCIA se ejecuta sólo si las DOS se cumplen ¿Y si no hay evidencia registrada? Sólo corre si es GRATIS. No se gasta una llamada al modelo ni un compilado de Lean en algo que nadie ha medido. EL VEREDICTO SE LEE, NO SE RECUERDA Se guarda la RUTA al número dentro del fichero de medición, no el número. Volver a medir cambia la decisión sola. Y si una ruta deja de resolver, un test lo caza. LO QUE APAGÓ — Y QUE POR ESO SE QUITÓ DEL CÓDIGO orden de cascada por área real 1,262 · nulo 1,091 estaba en producción — posición de la táctica que cierra, menos es mejor dos etapas: localizar el área y luego elegir real 0,42 · nulo 0,93 precisión de premisas contra ofrecer las más frecuentes recuperación léxica de lemas real 0,065 · nulo 7,78 `sq_nonneg` es una herramienta, no un concepto del que el problema hable emparejador semántico por embeddings 13,2 % precisión · el léxico da 23,9 % nunca se adoptó, y además costaba una llamada al modelo … y seis más, todas con su cifra en data/descartado.json Coste por consulta: el decisor 0 llamadas al modelo; su nulo, 2. LA ÚNICA EXCEPCIÓN, Y VA DECLARADA: verificar con Lean no pasa por esta regla El nulo de «verificar» sería «no verificar», que es OTRO SISTEMA — no una versión más barata de éste.
Fig. 9 — Las cuatro de la derecha, y otras seis, se quitaron del código el 21 de septiembre de 2026: lo que queda de ellas es su medición. El decisor. Su propio modelo nulo es «ejecutarlo todo», y está implementado: se puede correr la comparación completa. Una capacidad que se apagara en silencio sería peor que no tener decisor, así que hay un test que falla si alguna ruta de evidencia deja de resolver.

El catálogo tiene trece capacidades. Ante una consulta matemática con Lean disponible corren siete; 0 están apagadas porque no baten a su nulo; una bate al suyo y no está cableada, y el decisor dice por qué en cada caso; dos dependen de la consulta, porque su guarda sólo aplica a algunas; y tres no tienen medición contra un nulo —entre ellas lazo_por_pasos, el paso 3 del lazo (§18), cuya puerta con modelo no se ha corrido—.

Que ninguna capacidad esté hoy apagada por medición no es que la regla se haya relajado: las diez que no batieron a su nulo se quitaron del código el 21 de septiembre de 2026. Un candidato evaluado y descartado es información, así que no desaparece: queda en data/descartado.json —qué hacía, su cifra, su nulo y el commit donde se puede leer entero— y en §16.

13

El respaldo formal en Lean

Las construcciones categóricas del núcleo no se implementan primero en Python y se justifican después: se demuestran en Lean, y el Python se audita contra los teoremas. El corpus son 387 teoremas y lemas en 22 archivos, sin un solo sorry — y eso se comprueba preguntándole al compilador con #print axioms, no con grep: ninguna constante depende de sorryAx.

CATEGORYFOUNDATIONS · 14 ARCHIVOS · 210 TEOREMAS CoRegulatorNetwork39 Complexificacion29 EhresmannLinks25 ComplexityOrder24 MultiplicidadDelGrafo23 SimpleComplexLinks12 QuotientFunctor11 JoinColimit10 MorfismosGrupoAnillo10 ColimitVerifier8 Evolution8 Fibracion5 IsColimitBridge5 + SkillCategory · 1 TEOREMAS CLÁSICOS · 8 ARCHIVOS · 177 TEOREMAS Grupos FirstIsomorphism 25 · LatticeTheorem 32 SecondIsomorphism 10 · ThirdIsomorphism 20 Anillos FirstIsomorphism 21 · LatticeTheorem 29 SecondIsomorphism 18 · ThirdIsomorphism 22 LA AUDITORÍA: PYTHON ↔ TEOREMA Cada operación categórica del Python se mapea a un teorema Lean que afirma la propiedad que esa operación asume. 62 / 63 respaldadas (98 %) 0 mapeos rotos · 0 operaciones fantasma LO ÚNICO SIN RESPALDO, Y VA DECLARADO `patterns.py :: campos_operativos_isomorfos` es una heurística estructural, NO la homología de Ehresmann. Se llama como se llama y no se le atribuye lo que no demuestra. El resto de la auditoría comprueba además que no haya mapeos rotos —un teorema citado que no existe— ni operaciones fantasma —un teorema sin código que lo use.
Fig. 10 — El corpus formal y su auditoría. El orden de trabajo es siempre el mismo: se demuestra en Lean, se comprueba con lake build, se verifica que el grafo real satisface las hipótesis del teorema, y sólo entonces se escribe el Python — que queda registrado en el mapeo de la auditoría.
Qué se demuestra exactamente, con esa precisión

Fibracion.lean define proyección monótona, levantamiento cartesiano y fibración, y prueba la unicidad del levantamiento, la monotonía del reindexado y su composición — sin depender de ningún axioma, ni siquiera de los tres estándar. También incluye un contraejemplo finito: hay monótonas que no son fibraciones, sin el cual la condición no distinguiría nada.

JoinColimit.lean prueba que ser colímite equivale a ser co-cono con propiedad universal en un preorden delgado, con unicidad automática. IsColimitBridge.lean conecta ese resultado con CategoryTheory.Limits.IsColimit de Mathlib, que es lo que convierte una construcción propia en una instancia de la noción estándar.

14

El método de medición

Todo lo que se afirma de este sistema se afirma con una medición detrás, y toda medición cumple cuatro condiciones. No son formalidades: cada una corresponde a una forma concreta de producir una cifra creíble y falsa.

1 · Modelo nulo obligatorio

Cada cifra se compara contra la cosa más tonta que haría el mismo trabajo: responder siempre la clase mayoritaria, ofrecer los elementos más frecuentes, barajar las etiquetas.

Sin él, un 61 % de acierto parece bueno hasta que se sabe que una constante acierta el 89 %.

2 · Volumen igualado

La precisión y la cobertura no se comparan entre configuraciones que ofrecen distinto número de candidatos. Un mando de volumen disfrazado de mando de calidad produce una tabla creíble y una conclusión falsa: basta ofrecer un tercio de los nombres para que suba la precisión sin acertar más.

3 · La medida adecuada al banco

En un banco desequilibrado, la exactitud cruda mide el desequilibrio. La exactitud equilibrada —media de los aciertos dentro de cada clase— es inmune a él, y su nulo baja a 1/k clases.

4 · La alarma dentro del instrumento

Cada script de medición lleva escrita la condición que revelaría que el instrumento está roto y no el sistema: un cero perfecto que incluye al azar, una tasa de exclusión imposible, un resultado demasiado cómodo.

Un fallo de infraestructura no es un resultado

Los bancos que llaman al modelo distinguen explícitamente entre un caso que falló y uno que no se midió porque se agotó el saldo o la API devolvió un error. Un caso sin medir no cuenta ni a favor ni en contra, y mientras queden casos sin medir no hay nota: una cifra parcial presentada como total sería una medición deshonesta.

El bucle que no cuesta dinero

La formalización es el único paso que necesita el modelo. Con METAMAT_GRABAR=1 se graba el código del modelo antes de que Lean lo vea, y todo lo que el sistema hace después —reparación de imports, cascada, premisas, veredicto— se reejecuta con Lean de juez y coste cero.

La frontera está donde tiene que estar, y hay un test que lo impide mover: si el gancho de grabación se colocara detrás de la normalización, la reejecución mediría el sistema contra su propia salida y daría siempre lo mismo.

15

Lo que está medido

El resultado que ordena a los demás: ¿aporta el sistema?

Durante mucho tiempo la comparación fue «el sistema con el grafo» contra «el sistema sin el grafo». Esa pareja contesta si aporta el grafo, no si aporta el sistema: la rama sin grafo sigue llevando reparación, premisas, cascada y ejemplos. Faltaba el suelo — el mismo modelo, una llamada, sin nada.

configuraciónverificaqué es
modelo solo4 de 20 · 20 %una llamada, sin sistema
sin reparación6 de 15 · 40 %el sistema menos el bucle de reparación
sin vocabulario11 de 20 · 55 %el sistema menos el grafo
sistema completo12 de 20 · 60 %la configuración que se sirve
comparación pareadarescatarompep · McNemar exacto
el sistema frente al modelo solo800,0078
la reparación completo frente a sin reparación400,1250
el vocabulario con frente a sin321,0000
Las dos cosas son verdad a la vez

El aparato triplica al modelo aislado y es significativo. El grafo, dentro de él, no se distingue del ruido. El vocabulario cambió lo que el modelo escribió en 19 de los 20 casos, pero no movió el veredicto en una dirección consistente.

Y hay una tercera pieza medida contra el mismo suelo: la reparación —devolverle al modelo el error de Lean— rescata cuatro casos y no rompe ninguno. Con 15 pares no llega a significancia, pero es, junto al aparato entero, la única pieza que nunca estropea un caso; el vocabulario rescata tres y rompe dos.

La afirmación sostenible es, por tanto: el grafo ofrece los identificadores correctos —catorce veces mejor que su nulo— y eso es puntería, no resultado. Que haga verificar más a Lean se midió y no se ve a n=20.

Catorce mediciones, cada una con su modelo nulo. La figura las pone todas en la misma escala —cuántas veces bate a su nulo— para que se puedan comparar componentes que miden cosas distintas.

CUÁNTAS VECES BATE A SU MODELO NULO — ESCALA LOGARÍTMICA 1× · el nulo 0,1× 0,5× 2× 5× 10× Revisión de sintaxis · caza de roturas 16,9× 60,8 % vs 3,6 % Vocabulario de Mathlib · precisión 16,5× 23,9 % vs 1,45 % Vocabulario de Mathlib · cobertura 5,0× 16,5 % vs 3,3 % Reconocedor de área · no cableado 3,2× 75,4 % vs 23,8 % Dependencias curadas vs el DAG 2,35× 73,7 % vs 31,3 % Área de la consulta · equilibrada 1,76× 62,1 % vs 33,3 % N-gramas + rasgos → premisas 1,43× 80,9 % vs 56,6 % Área de la 1ª skill · equilibrada 1,23× 38,9 % vs 33,3 % Premisas, sin los @[simp] 1,20× 14,0 % vs 11,7 % Elección de módulos para Lean 1,00× 18/20 vs 18/20 Costura de cobertura vs el DAG 1,00× 9/9 vs 9/9 NO BATEN A SU NULO Orden de tácticas de la cascada 0,87× 1,26 vs 1,09 Poda por área antes de elegir 0,69× 6,8 % vs 9,8 % Fibración π : Skills → Áreas 0,04× 0,1 % vs 4,3 % Menos es mejor en «orden de tácticas» (posición de la táctica que cierra): la razón está invertida para que la lectura sea la misma en todas las filas. La escala es logarítmica, así que las distancias son razones y no diferencias. El nulo de cada fila está en la columna de la derecha.
Fig. 11 — Las catorce mediciones contra sus nulos, en una escala común. Todo lo que queda a la izquierda de la línea roja está apagado o marcado como no concluyente — no hay ningún componente activo en producción que pierda contra su nulo sin que este documento lo diga.
qué se mideresultadomodelo nuloveredicto
Vocabulario contra ProofNet371 ejercicios con formalización de oro · k=2, el valor de producción23,9 % precisión
16,5 % cobertura
1,45 %
3,3 %
16,5× · aporta
Dependencias curadas contra el DAG real152 aristas skill→skill medibles · nulo emparejado112 confirmadas
73,7 %
31,3 %2,35× · aporta
Costura de cobertura contra el DAG9 aristas skill→módulo medibles9 confirmadas
100 %
100 %1,00× · no dice nada
Vocabulario sobre Mathlib entero53 613 docstrings limpios · cubre todos los módulos, no sólo los de grado5,0 % precisión
2,2 % cobertura
0,3 %
0,5 %
19,2× · aporta
Vocabulario contra Herald43 856 enunciados reescritos por otro sistema · el control10,6 % precisión
6,6 % cobertura
1,2 %
2,2 %
9,0× · aporta
La tanda de curación, en su barrio384 y 691 filas de los temas que trajo · sin ella contra con ella3,9 → 16,9 %
4,0 → 20,6 %
0,5 %
0,2 %
×4,3 y ×5,2
Revisión de sintaxis de la consulta23 243 enunciados de LeanWorkbook, todos correctos3,6 % falsos pos.
60,8 % de caza
3,6 %
(moneda)
+57,2 puntos
Rasgos del árbol → premisas22 117 pares, bootstrap emparejado, 68 rasgos80,9 % cobertura56,6 %+24,3 · aporta
Reconocedor de área por la forma5 750 de test sobre 7 temas de MATH · medido, nunca cableado: por el camino real contra ProofNet no pagaba75,4 %
techo 84,1 %
23,8 %3,2× en su banco
quitado · §16
Área de la consulta3 000 consultas etiquetadas · banco 88,6 % algebra62,1 % equilibrada
60,3 % cruda
33,3 %
88,6 % cruda
+25,4 equilibrada
Selección de premisassin los @[simp], que simp ya conoce14,0 % cobertura11,7 %mejora pequeña
Elección de importsmódulos vecinos ADEMÁS de los del nombre ofrecido · 20 enunciados, Lean como juez18/20 elabora18/20 fijoinerte
quitado · §16
Orden de tácticas por área1 600 pruebas de Mathlib · simp cierra el 95,8 %1,26 posiciones1,09no bate al nulo
Poda por área antes de elegircon localización perfecta — es el techo, no lo real6,8 %9,8 %no llega al nulo
Fibración π : Skills → Áreas6753 pares (objeto, área por debajo)10 se levantan
0,1 %
4,3 %
(áreas al azar)
peor que el azar
Nombres de los nodos generados447 identificadores, uno a uno con #check346 existen—95 no existen
Respaldo formal Python ↔ Leanauditoría del mapeo operación → teorema62/63 · 98 %—0 mapeos rotos

El banco de fidelidad

Es el instrumento que responde a la pregunta central: ¿el teorema que Lean verifica es el que se preguntó? Verificar fielmente algo falso es tan malo como verificar infielmente algo cierto, así que un caso sólo cuenta como bueno si salen bien las tres cosas:

  1. Verificación — qué dijo Lean.
  2. Fidelidad — un juez independiente decide si el enunciado formalizado es el de la pregunta, sin ver el veredicto de Lean, para que el sello no lo contamine.
  3. Honestidad — para los enunciados falsos a propósito, el sistema debe rechazarlos o probar su negación, y la respuesta debe abrir diciéndolo.

El banco tiene 24 casos en tres grupos: 16 ciertos y formalizables, 4 falsos a propósito y 4 controles que no son matemáticas y no deberían tocar Lean. La corrida rápida es una muestra estratificada de ocho —4/2/2— para que la parte que discrimina siga estando representada.

El estado exacto de esta medición

La corrida registrada en data/banco_fidelidad.json es la muestra rápida: 8 casos medidos, 8 correctos, 0 infieles. La corrida completa de los 24 es la medición pendiente del proyecto, y es la única que necesita presupuesto de API y de Lean. Hasta que exista, la cifra que este documento sostiene es la de ocho casos.

16

Los resultados negativos

Costaron el mismo trabajo que los positivos y valen igual. Están aquí para que nadie los repita, y porque un sistema que sólo publica lo que funciona no se puede evaluar.

Y el 21 de septiembre de 2026 dejaron de ser código

Diez capacidades habían quedado apagadas por su propia medición, y el código seguía ahí. Se quitó. Lo que queda de cada una es su cifra, su nulo y el commit donde se puede leer entera, en data/descartado.json; la página de mediciones del sistema lo enseña como una tabla más. Descartar no es borrar: sin el registro, dentro de seis meses alguien vuelve a construir lo mismo.

Las diez: el orden de cascada por área, proponer módulos vecinos, el reconocedor de área, los vecinos de estado como sustituto del rankeador, apply? como sonda, el encoder denso de premisas, la localización en dos etapas, la recuperación léxica de lemas, el emparejador semántico y el enrutado neuronal.

Proponer imports por vecindad no aporta — y no es todo el paso 3

qué se midió
y qué no

Sólo la mitad b: proponer módulos por vecindad ADEMÁS de los del nombre ofrecido. La mitad a —el módulo de cada nombre que el prompt ofrece— no pasa por aquí, va siempre, y sin ella 282 de las 284 consultas de ProofNet que reciben un nombre reciben alguno que Lean no puede resolver; con ella, 0.

medido

Un conjunto fijo de tres módulos hace elaborar 18 de 20 enunciados. Añadirle lo que el grafo propone: los mismos 18, y un 11 % más de tiempo. Contra el azar sí gana —18 frente a 12, rescatando 6 casos sin romper ninguno—, o sea que hace trabajo real, pero redundante con una constante.

el margen

De los 2 fallos, ninguno es de imports: uno necesita open Real y otro usa sintaxis vieja de Mathlib.

y la cautela

El «conjunto fijo» no es pequeño: Mathlib.Tactic arrastra 2 972 módulos por transitividad, y los tres juntos cubren el 38,4 % de Mathlib. La medición es aditiva —añadir imports nunca rompe una elaboración— así que la única forma de ganar era rescatar un fallo. En 10 de 20 casos el grafo no añade ni un módulo: las dos ramas son la misma ejecución.

cómo leerlo

El test discriminante tiene n ≈ 0. «Inerte» está sostenido como no se midió beneficio, no como se demostró que no lo hay.

Las premisas no cierran pruebas, y la aritmética lo explica

medido

Añadir tácticas con premisas costó 231 invocaciones extra de Lean y cerró cero sobre 21 teoremas que la cascada desnuda no cerraba.

por qué

La cobertura de premisas es del 14 %, o sea una de cada siete, y una prueba las necesita todas — 2,1 de media. Esperado 0,14² × 21 ≈ 0,4 cierres; observado, 0.

la lección

Una métrica de recuperación no se traduce en cierres. El listón real está muy por encima del 14 % que la mejora celebraba.

Tres emparejadores fallaron, y la causa no era el emparejador

medido

Búsqueda plana 43,9 %, descenso anclado en pilares 11,8 %, embeddings 11,9 % — los tres por debajo del 79,4 % de decir siempre «álgebra».

la causa

Para (a+b)² = a²+2ab+b² no existía el nodo: las 35 skills de álgebra eran todas álgebra abstracta. Ningún emparejador recupera lo que no está.

y el juez

MATH es 79 % álgebra escolar contra una ontología de investigación. La conclusión útil no es sobre el emparejador, es sobre qué conceptos faltan en el grafo.

Podar por área no sirve, ni siquiera acertando el área

la idea

Localizar primero el área y elegir las premisas sólo dentro de ella. El orden es correcto: buscar sobre los 183 433 hechos de golpe confundiría el fallo de la búsqueda con la ausencia de poda.

medido

Con localización perfecta —el oráculo— la cobertura sube de 6,0 % a 6,8 %. El modelo nulo da 9,8 %. Aunque se acertara el área siempre, se perdería contra ofrecer las premisas más citadas.

y afinar
empeora

De 27 áreas a 1 095 sub-áreas: el espacio se divide por cuarenta y el techo sube 0,3 puntos, pero acertar la sub-área es la mitad de fácil, así que en la práctica cae de 4,6 % a 4,0 %.

una hipótesis
descartada

Se pensó que la poda fallaba porque las premisas venían de otras áreas. No: el 77,1 % está en la misma área que el teorema. La localización sí informa; lo que falla es elegir cuáles dentro.

Los sustantivos del módulo: la lista sirve, la vía no

el hueco
es real

Mathlib tiene 34 084 sustantivos —29 883 def, 2 949 abbrev, 1 845 class, 1 490 structure, 300 inductive— y el grafo inyecta 169: el 0,50 %. Y es justo la mitad del trabajo que el reparto le asigna, porque el modelo acierta los sustantivos e inventa los lemas.

la lista
es buena

Los nombres se leen de la declaración en vez de deducirse de la ruta. #check sobre una muestra: 200 de 200 existen, frente al 77,4 % de los deducidos.

y aun así
pierde

Ofrecer los sustantivos del módulo de cada nodo generado, a volumen igualado contra ProofNet: en ~1 800–2 000 nombres, 14,0 % / 17,8 % sin ellos contra 11,5 % / 16,5 % con ellos. Pierde precisión en los dos puntos de la curva: no es dilución, son peores nombres.

por qué,
sin estadística

El módulo de un nodo generado es un rincón de su área. mathlib-analysis-real ofrecía Hyperreal.Infinite y Real.ofDigits, mientras Real y Real.sqrt viven en Data/Real/Basic. La clave «módulo del nodo» no lleva a los sustantivos que hacen falta.

Buscar en los 217 419 nombres no bate al vocabulario curado

la idea

El índice de nombres se usa para comprobar y cualificar, nunca para buscar. ¿Y si se usara como buscador, con índice invertido e idf?

medido

Contra ProofNet, mismo K y mismo nulo: el índice completo da 0,0 % de precisión y el de sólo sustantivos 1,5 %, frente al 23,9 % del vocabulario curado y al 1,45 % del nulo. El mejor índice empata con el azar.

la lección

Más candidatos no es más información. Las colisiones de palabra dominan: «Banach» lleva a los espacios de Banach, no al teorema del punto fijo.

La recuperación de lemas por contenido pierde contra la moda

medido

Sobre 23 243 pruebas reales: por contenido, 0,6 % de cobertura; ofrecer siempre los 20 lemas más citados, 77 %.

por qué

sq_nonneg no aparece en el enunciado ni tiene por qué: es una herramienta que el problema necesita, no un concepto del que hable. No hay parecido que encontrar.

alcance

En Mathlib general el nulo sólo vale 9,2 % y el contenido 4,6 %: lo que cambia por dominio es la fuerza del nulo, no la del método.

95 de los 447 nombres generados no existen en Mathlib

medido

De los 447 identificadores que proponen los 125 nodos generados, comprobados uno a uno con #check: 346 existen, 95 no existen en absoluto y 6 son espacios de nombres — agrupan, pero no son un término.

por qué

Estaban deducidos de la ruta del módulo. El filtro pedía CamelCase sin guion bajo, y eso deja pasar Basic —un nombre de fichero— igual que Polynomial —un tipo—. La forma no distingue; sólo Lean lo hace.

consecuencia

Cuatro nodos se quedan sin ningún nombre válido, así que aunque se activara la inyección no podrían aportar nada. Por eso los nodos generados no inyectan vocabulario.

La red neuronal aprendió una constante

qué era

Un GNN de atención sobre el grafo más un actor-crítico entrenado con PPO —546 820 parámetros— para decidir si una consulta se responde, se reorganiza el grafo o se asiste con Lean.

medido

Una sonda de cuatro entradas deliberadamente distintas —un teorema, un saludo, un hecho no matemático y un fragmento de Lean— recibe la misma acción en las cuatro: 1 acción distinta, exactamente lo que da la política constante.

por qué

Se entrenó con el objetivo «todo problema matemático → ASSIST», que se satisface con una constante. El «100 % de precisión» del informe de entrenamiento no era un logro: era el modelo nulo con otro nombre.

la lección

Un objetivo que una constante satisface no puede evaluar un modelo. El runtime ya la detectaba degenerada y la ignoraba en cada arranque; ahora el código tampoco está.

Un encoder de premisas entrenado para Lean tampoco entra

la idea

Llevar el estado de prueba impreso a las premisas de Mathlib que su prueba usó, con el codificador de premise-selection (Zhu et al., ICLR 2026) y las 382 212 premisas ya codificadas.

medido

Dentro del lazo, con Lean de juez sobre 60 estados y el mismo presupuesto: 39 verificados contra 40 sin él, y 46 contra 48 junto a los vecinos de estado.

y lo que dice
el detalle

Ningún camino verificado usa una táctica suya. Lo que sí hace es gastar: trece plantillas por estado que Lean rechaza, y el presupuesto se agota antes de que lleguen las que cierran.

la trampa
que casi cuela

Los embeddings publicados son una matriz sin nombres. Con el modelo que enlaza el artículo, cada premisa se parecía a su propia fila casi lo mismo que a la vecina —0,33 contra 0,26—: era otro modelo. Sin comprobarlo, el experimento habría medido premisas equivocadas con toda la seguridad del mundo.

17

Tests y guardianes

1 312 tests en 67 suites, verdes en los dos intérpretes con los que se trabaja. Los que más valen no comprueban que el código funcione: comprueban que el sistema no pueda volver a afirmar más de lo que sabe.

guardiánqué impide
test_cobertura_consultasque el grafo deje de engancharse con las consultas reales sin que nadie se entere
test_auditoria_veredictoque un archivo sin teorema, vacuo o refutado reciba el sello de verificado
test_interpretacionque un nodo generado se cuele como si estuviera interpretado categóricamente
test_decisorque una capacidad se apague en silencio porque su ruta de evidencia dejó de resolver
test_idioma_de_los_promptsque las instrucciones a Lean y a Mathlib dejen de estar en inglés
test_nombres_mathlibque el reparador de nombres modifique código que ya compilaba
test_fibracionque cambie la proporción de morfismos que cruzan de área sin volver a medir la fibración
rutas absolutas en el runtimeque un except mudo degrade el sistema en silencio al mover el proyecto
cifras declaradasque la documentación anuncie números que ya no son ciertos
valores por defecto de los medidoresque un banco mida una configuración que el sistema no sirve
La categoría de guardián que este proyecto necesita más

Los tres últimos no comprueban comportamiento: comprueban que lo que se publica siga siendo verdad. Una cifra desactualizada en la portada y un banco que mide otra configuración producen exactamente el mismo daño que un fallo de lógica, y ningún test normal los ve.

18

El lazo por pasos: en construcción

Las tres vueltas de §1 son un lazo por intentos: el modelo escribe la prueba entera, Lean compila el fichero, y si falla el modelo recibe los errores y la reescribe entera. Lo que se está construyendo es un lazo por pasos: el modelo propone una táctica sobre un estado de prueba, Lean la evalúa, y lo que contesta —el estado nuevo, o por qué falló— condiciona el paso siguiente. Es la categoría de estados de §8 hecha viva: cada flecha la crea Lean en línea, no un corpus.

Se construye en cinco pasos, y cada uno termina en una medición que decide si se sigue. Ninguno entra en el camino servido por estar construido: entra si su capacidad bate a su nulo en el decisor (§12).

pasoquésigue siestado
1la sesiónnucleo/lean/sesion.pyacepta lo mismo que el fichero, y más rápidopasa · 20 de 20
2la cascada por estadonucleo/lean/cascada_sesion.pyno pierde ningún cierre y cuesta menospasa · encendida
3el mediador con el modelonucleo/lazo/verifica más que el lazo por intentosconstruido · sin medir
4la recuperaciónpremisas y tácticas por estadocada fuente bate a su nulovecinos sí · D2 no · denso no
5φ y la explicación por pasonucleo/lazo/phi.pyexplica con exactitudconstruido · exactitud sin revisar

Paso 1 · una sesión de Lean que no se apaga

Hoy cada comprobación arranca Lean y vuelve a cargar la cabecera: el coste está ahí, no en la táctica. La sesión es un proceso de Lean —el repl de leanprover-community, con el mismo toolchain que el proyecto— que carga la cabecera una vez y después recibe tácticas sobre estados. Con la cabecera estrecha del camino servido, medido en esta máquina:

quésegundos
cargar la cabecera, una vez por proceso10,2
plantar el teorema con sorry0,04
una táctica —cierra, progresa o falla—0,009 – 0,093
el mismo teorema como fichero, que es lo de hoy10,8
La sesión busca; el fichero decide

La velocidad no era la pregunta difícil. La difícil es si la sesión acepta lo mismo que el fichero: el repl tiene registrado un caso en que aceptó pruebas incorrectas. Se enviaron 20 formalizaciones reales por los dos caminos, con la misma cabecera: 20 de 20 de acuerdo, y 0 aceptadas por la sesión que el fichero rechace. Aun así, el sello de verificado sigue saliendo siempre del fichero: un buscador que se equivoca cuesta un camino perdido; un certificador que se equivoca cuesta un sello falso.

Paso 2 · la cascada, en la sesión

Cuando queda un sorry, la cascada de §11 prueba doce tácticas en un first |. Hoy eso es un compilado por sorry, cierre o no. En el paso 2 el mismo bloque, con el mismo orden y sobre el mismo texto, se elabora en la sesión viva; si cierra, el fichero confirma la prueba con la táctica ganadora. Medido sobre 30 casos, las dos vías:

fichero (hoy)sesión (paso 2)
cierran9 de 30los mismos 9
perdidos · ganados · falsos—0 · 0 · 0
en los 21 que no cierran276 s40,4 s
todo, pagando la cabecera en cada caso381 s373 s
procesos de Lean309

Es lo que se predijo antes de medir: empate en cierres y la ganancia en los fallos, que son la mayoría —la sesión no necesita compilar para saber que no cerró—. La fila con cabeceras apenas gana porque en este banco cada teorema trae la cabecera de su fichero; en el sistema servido la cabecera estrecha es casi siempre la misma y se paga una vez por proceso. El decisor lee esa fila, la peor para la sesión, y la enciende; si una medición futura pierde un solo cierre, la cifra desaparece del fichero y la apaga sola.

Los 9 cierres no son una tasa de la cascada

La cabecera estrecha alcanza cientos de módulos de Mathlib. En 11 de los 30 casos el fichero del propio teorema está entre ellos, y ahí simp o exact? pueden cerrarlo con el propio teorema: 7 de los 9 cierres son de ésos. La comparación entre las dos vías es válida —ven el mismo texto—; el porcentaje de cierre, no.

El modo importa. La primera versión aplicaba el bloque como táctica sobre el estado, y el repl no aplica ahí el límite de heartbeats: en un objetivo duro se agotaba a los 120 s. Se elabora como comando, con su límite, igual que un fichero pero sin arrancar Lean. El modo táctica queda para el paso 3, que tendrá que resolver ese límite.

Paso 3 · el mediador, construido y todavía sin su puerta

nucleo/lazo/ hace la búsqueda de la propuesta: cada sorry es una raíz, los proponentes sugieren tácticas —D0, la cascada, una a una; D3, el modelo, con la retroalimentación del estado—, la sesión evalúa cada una, y el fichero verifica la prueba ensamblada. Los estados se identifican normalizados, cada uno guarda sus fallos para el paso siguiente, y todo intento va a data/transiciones_vivas.jsonl: las alternativas que la categoría de estados construida desde LeanWorkbook no tenía.

Su puerta gasta modelo y no se ha corrido, así que el decisor lo tiene apagado. Lo que sí está medido, gratis, es un suelo: las dos ramas sobre las mismas 20 formalizaciones grabadas, A el camino servido de hoy sobre el código que escribió el modelo, B el lazo sin modelo —sólo D0— sobre su enunciado.

verifica
A · lo servido, sobre el código del modelo9 de 20
B · el lazo sin modelo, sobre el enunciado6 de 20
las dos · sólo A · sólo B5 · 4 · 1
A o B: el lazo como segunda etapa10 de 20

El caso que sólo el lazo cierra es «todo subgrupo de un grupo cíclico es cíclico»: el modelo escribió la prueba con un lema que no existe, y el lazo la cerró con exact?, que busca por el tipo sobre toda la biblioteca. Es la frontera de §5 en un solo caso. Con 20 consultas no significa nada estadísticamente, y A no incluye las rondas de reparación, que gastan modelo.

El modo táctica acepta lo que el kernel rechaza

La puerta del paso 1 midió la sesión en modo comando. El mediador trabaja en modo táctica, y ahí apareció el caso que justifica que el veredicto lo dé el fichero: linarith dejó el objetivo sin metas y el REPL informó kernel type check failed. Una lectura de «sin objetivos» como «demostrado» habría construido una flecha falsa. Ahora un cierre exige proofStatus Completed, y lo demás —apply? admitiendo con sorry, el kernel rechazando— es un fallo que va a la memoria del estado.

Paso 4 · de dónde salen las tácticas

La cascada propone nombres: «prueba nlinarith». Lo que cierra una desigualdad de competición casi nunca es el nombre desnudo, sino nlinarith [sq_nonneg (a - b), …], con los hechos que hay que citarle. Esos argumentos están escritos en las transiciones de LeanWorkbook de §8: los vecinos de estado buscan el estado más parecido y copian lo que lo cerró. La otra fuente es D2: apply? lanzado como sonda para leer sus «Try this». Todo se mide sin modelo, con el índice construido sólo con la partición de entrenamiento.

medidarankeadorvecinosfusión
posición del nombre que cierra1530 casos · la de la propuesta1,571,841,46
estados raíz cerrados con Lean150 estados · 3 intentos por rama797688

Como sustitutos del rankeador, los vecinos no ganan: 76 frente a 79. Pero son complementarios —22 estados que sólo cierran ellos, 25 que sólo cierra el rankeador—, y la prueba que decide es otra: como fuente añadida del lazo, con los mismos 60 estados y el mismo presupuesto:

el lazo converificafrente a D0pllamadas a Lean
D0 · la cascada41——14,6
D0 + vecinos48+7 −00,01613,0
D0 + D240+0 −11,00015,3
D0 + vecinos + D246+7 −20,18013,4

Los vecinos entran como fuente del lazo: rescatan sin romper, y además gastan menos Lean, porque cierran antes. D2 no entra —y su código se quitó—: no rescata ninguno y sus sondas se comen el presupuesto; con las tres fuentes juntas se pierden casos que D0 + vecinos cerraba. Las dos decisiones las tiene escritas el decisor, que lee estos ficheros. Y ninguna llega al alumno todavía: viven dentro del lazo, que sigue sin su puerta con modelo.

La tercera fuente es el índice denso: un codificador entrenado para Lean —premise-selection, Zhu et al., ICLR 2026— que acerca el estado impreso a las premisas de Mathlib que su prueba usó. Las 382 212 premisas vienen ya codificadas; cada una se prueba como exact, apply y rw, y todas juntas en simp […]. Mismo banco, mismos 60 estados, y la regla escrita antes: entra si bate a D0, y se queda junto a los vecinos sólo si les añade algo.

el lazo converificafrente apllamadas a Lean
D0 · la cascada40——14,4
D0 + vecinos48+8 −0 · D00,00813,0
D0 + denso39+1 −2 · D01,00015,4
D0 + vecinos + denso46+0 −2 · vecinos0,50013,5

El denso no entra, y su código se quitó. En ninguno de los caminos verificados aparece una táctica suya; su único «rescate» lo cerró exact?, que es de D0, en un caso en que el brazo D0 se había colgado en una sola llamada. Lo que sí hace es gastar: trece plantillas por estado que Lean rechaza y que agotan el presupuesto antes de que lleguen las que cierran. La corrida repite a los vecinos —48 otra vez—; D0 dio 40 donde el paso 4 dio 41, y ésa es la escala del ruido de un presupuesto en segundos.

El modelo correcto no era el que enlaza el artículo

Los embeddings precalculados son una matriz sin nombres; el nombre de la fila i sale de reconstruir el corpus en el mismo orden. Antes de medir se comprobó (scripts/alinear_premisas.py) re-codificando premisas al azar. Con el modelo de hanwenzhu/, el que llega a Lean v4.20, cada premisa se parecía a su propia fila casi lo mismo que a la vecina: coseno 0,33 frente a 0,26. Los embeddings los hizo l3lab/, rama v4.29.0, y con él dan 1,0000. Además, el lector del corpus, escrito en Linux, descartaba en silencio en Windows todo fichero con un α. Ninguna de las dos cosas daba un error: habría dado premisas equivocadas con toda la seguridad del mundo.

El sesgo de los vecinos queda dicho: LeanWorkbook es matemática de competición, y fuera de desigualdades y álgebra elemental propondrán tácticas que Lean rechazará en centésimas. Los dos codificadores de 7 000 millones de parámetros de la propuesta —LeanSearch-PS y Lean Finder— están descargados, pero con 4,3 GB de GPU no codifican Mathlib a una velocidad útil: no están medidos.

Paso 5 · φ, de qué conceptos habla un estado

φ lleva cada estado de prueba a los conceptos del grafo cuyos nombres verificados de Mathlib aparecen en él, por coincidencia exacta —la regla que hizo fiable a L4—. No es un funtor y no se usa para buscar: sirve para que la explicación diga «este paso pasó de hablar de subgrupos a hablar de órdenes». La propuesta predecía que leerlo del texto impreso pierde casi todo, porque Lean escribe ℝ y ∑ y no Real ni Finset.sum; la otra lectura pide a Lean las constantes que el estado usa, con una táctica propia. Sobre 168 estados raíz —las consultas de la campaña y LeanWorkbook—:

estados con al menos un conceptode 168
leyendo el texto impreso21
leyendo las constantes168
las constantes, sin los tipos de número21

La cobertura de las constantes es hueca. 145 de los 150 estados de LeanWorkbook sólo recibían la etiqueta del tipo donde viven los números —ℝ daba «análisis real», ℕ «teoría elemental de números»—, y una etiqueta que sale en todo no explica nada. Quitados los tipos portadores, las dos lecturas empatan: 21 contra 21. La predicción de la propuesta no se confirma: quitada la notación, lo que queda apunta a otro límite —que el grafo nombre las constantes que estos estados usan—, y eso no está medido.

La exactitud no la decide un guion

Que «análisis real» sea una buena etiqueta para 2ab ≤ a² + b² lo decide alguien leyendo. La muestra está en data/phi_muestra_para_revisar.json: 38 estados con sus etiquetas y pertinente: null en cada uno. Hasta que se revise, el decisor tiene φ sin evidencia. La explicación por paso (phi.explicar) está escrita y probada, y los teoremas que el lazo verifica ya se anotan para que L4 los sume a los de Mathlib; ni lo uno ni lo otro llega al alumno mientras el lazo no tenga su puerta con modelo.

Lo que construirlo destapó del sistema de antes

  • La cascada servida no cerraba nada desde el 2026-09-04. field_simp no existe bajo la cabecera estrecha, y un first | es una sola pieza de sintaxis: si una táctica no existe, Lean rechaza el bloque entero sin probar ninguna. Ni a + b = b + a. Los tests usaban un Lean de mentira y no podían verlo; ahora la cabecera trae FieldSimp y hay un test que compila de verdad. La campaña del lazo por intentos (2026-09-10) se midió con ese fallo; de las 63 formalizaciones grabadas, sólo 2 tenían un sorry, que es donde entra la cascada.
  • apply? dejaba muerto lo que iba detrás. Cuando no encuentra prueba, cierra el objetivo con sorry: dentro del first es una rama que no falla, y las tácticas posteriores no se probaban. El fichero no daba sello falso; ahora va siempre la última. No hay un caso medido en que eso costara un cierre.
  • import Mathlib no tarda 742 s. La cifra estaba en diez sitios sin procedencia, justificando la cabecera estrecha porque «siempre expira». Medido de nuevo: 24 s entera y 11 s estrecha, las dos muy por debajo del límite de 360 s. La cabecera estrecha se queda, por coste.
19

Límites y trabajo abierto

Lo que el sistema no hace

  • No demuestra teoremas por sí solo. Formaliza y verifica. La prueba la escribe el modelo o la cierra la cascada de tácticas.
  • El grafo no decide qué es cierto en ningún punto. Eso es Lean, siempre.
  • Sin API no hay formalización, ni chat, ni banco de fidelidad. Lo que sigue vivo sin ella es todo el trabajo de validar y mejorar el núcleo, que es la mayor parte de este documento.

Preguntas abiertas

  • El banco de fidelidad completo, los 24 casos con juez ciego. Es la única medida de si la respuesta responde a la pregunta, y la única que sigue necesitando presupuesto de modelo.
  • Un banco en español con premisas de oro. Sin él, todo lo que se construye para el alumno hispanohablante se mide en inglés y por analogía.
  • Subir el n de la campaña. Los tres contrastes pareados corren sobre 20 casos (15 en la rama sin reparación). Con ese tamaño, «rescata 4 y rompe 0» no llega a significancia aunque el efecto sea real.

Identificado, con el camino claro

  • La categoría de estados existe, y lo que le falta no son datos. Estaba aquí como «las tácticas deberían ser flechas» y ya está construida (nucleo/graph/estados.py): 24 752 estados, 25 206 tácticas, no goals terminal, el 46,4 % de las flechas componen. Lo que no puede dar es la parte que hacía falta: sólo 72 de los 24 752 estados registran dos tácticas distintas, porque el corpus recoge la prueba que alguien escribió y no las que descartó. Aprender a elegir exige generar esas alternativas probando tácticas contra estados reales. Eso ya no cuesta un compilado por intento: con la sesión viva una táctica cuesta centésimas de segundo (§18). Es el paso 3.
  • La base no es un orden, y por eso no hay viaje general. Esto decía que faltaban morfismos que crucen de área y que eran «lo único que puede convertir el funtor en una fibración». Es falso, y lo refuta el propio repositorio: la clausura transitiva es monótona, así que una arista nueva sólo puede añadir relaciones a la base, y las áreas ya forman una componente fuertemente conexa de 21 de 23. Añadir morfismos que crucen empeora la tasa — medido en scripts/base_no_es_un_orden.py. Los 105 de 688 que cruzan hoy generan 462 relaciones entre áreas al cerrar: la base afirma de más. La palanca no son los morfismos sino la asignación de áreas. Lo que sí se puede usar son los 105 levantamientos que existen uno a uno (data/viajes.json), al 7,3 % de lo que la base promete y sólo 1,1× sobre el azar.
  • La fibra de hechos. data/banco_lemas.jsonl son 23 243 pares (enunciado, lemas que la prueba usó): un grafo bipartito esperando a ser construido, que hoy sólo alimenta un índice plano.
  • Un índice de sustantivos consultado por la consulta, como premisas.py hace con los lemas. La lista está construida y verificada; lo que no funciona es la clave «módulo del nodo».
  • No hay lematización en el emparejador, así que primos no casa con primo. Añadirla mueve la precisión y necesita su propia medición.
  • Seis dependencias del grafo siguen bajo sospecha de ir en sentido contrario, según la comparación con el DAG oficial.