
La IA tradujo 30 años de COBOL a la perfección. Luego corrompió la base de datos.
Era un martes por la noche, y estaba mirando fijamente un stack trace que no tenía ningún sentido.
Habíamos estado trabajando con un equipo de servicios financieros que intentaba migrar un módulo de transacciones central de COBOL a Java. La IA había hecho su trabajo — o eso creíamos. El código Java generado era limpio, estaba bien estructurado, compilaba sin un solo error. Las pruebas unitarias pasaban. Todos en la llamada estaban cautelosamente optimistas. Luego lo desplegaron en el entorno de pruebas, y la primera transferencia bancaria corrompió la base de datos.
El error no estaba en el Java. El Java era sintácticamente perfecto. El error estaba en lo que la IA nunca vio.
Una variable llamada TRN-LIMIT — definida no en el archivo fuente que la IA tradujo, sino en un COPYBOOK incluido miles de líneas antes en la cadena de ejecución — contenía una cláusula REDEFINES. Es una construcción de COBOL donde la misma dirección de memoria se interpreta como dos tipos de datos diferentes según una bandera establecida en un módulo completamente distinto. La IA vio TRN-LIMIT como un simple campo numérico. No lo era. Era un decimal empaquetado que se hacía pasar por un entero según el contexto de ejecución. La IA alucinó una definición estándar, y la aplicación Java escribió datos binarios corruptos en una columna de la base de datos.
Esa noche, sentado en una sala de conferencias con mi equipo desmenuzando lo que había salido mal, me di cuenta de algo que reformaría todo lo que construimos en Veriprajna: la IA no falló porque fuera estúpida. Falló porque estaba ciega.
El problema de 1,52 billones de dólares del que nadie quiere hablar
Esta es la incómoda realidad de la economía global en 2025: el 43% de los sistemas bancarios todavía funcionan con COBOL, y esos sistemas procesan el 95% de todas las transacciones de cajeros automáticos. ¿El software que hace funcionar a las empresas de la lista Fortune 500? Aproximadamente el 70% se escribió hace más de dos décadas. Solo en EE. UU., la deuda técnica se ha disparado hasta un estimado de 1,52 billones de dólares.
Y las personas que escribieron este código se están jubilando. No "podrían jubilarse algún día" — se están yendo ahora, llevándose consigo décadas de conocimiento institucional. Mientras tanto, el 80% de los presupuestos federales de TI se destina a mantener vivos los sistemas heredados, dejando apenas un 20% para cualquier cosa nueva.
Me he sentado frente a CTO que describen su situación de modernización como describirías una casa con los cimientos desmoronándose: sabes que necesitas arreglarla, sabes que esperar la empeora, pero cada contratista que lo ha intentado ha encarecido las cosas sin resolver realmente el problema.
Los números lo respaldan. Entre el 70% y el 80% de los proyectos de modernización de sistemas heredados no logran cumplir sus objetivos. Eso era cierto antes de que la IA generativa entrara en escena.
¿Por qué todo el mundo pensó que GPT podía arreglar esto?
Lo entiendo. De verdad que sí. Cuando salió GPT-4, el mercado de las consultorías de software se aceleró al máximo. De repente cada firma tenía un "acelerador de migración de COBOL" — que, si mirabas bajo el capó, era un fino envoltorio alrededor de un modelo fundacional. Pegas tu párrafo de COBOL, recibes de vuelta un método de Java. Magia.
Mi cofundador y yo pasamos semanas evaluando estas herramientas. Les dábamos código heredado real de entornos de clientes y comprobábamos el resultado. La sintaxis era casi siempre correcta. El código compilaba. Y luego fallaba de maneras increíblemente difíciles de diagnosticar, porque la forma del código parecía correcta incluso cuando el significado era incorrecto.
El error más peligroso no es el que colapsa tu sistema. Es el que corrompe silenciosamente tus datos durante seis meses antes de que alguien se dé cuenta.
El problema es arquitectónico, y se reduce a cómo los grandes modelos de lenguaje procesan la información. Los LLM usan un mecanismo de atención para ponderar la importancia de las diferentes partes de su entrada. Los modelos modernos presumen de ventanas de contexto de hasta un millón de tokens. Pero la investigación ha demostrado un fenómeno llamado el efecto "Perdido en el medio": los LLM exhiben una curva de rendimiento en forma de U, recordando bien la información al principio y al final de un prompt pero degradándose significativamente con cualquier cosa en el medio.
En un proyecto de modernización, un solo programa COBOL puede tener miles de líneas, haciendo referencia a copybooks que a su vez tienen miles de líneas. Si la definición de MAX-TRANSACTION-LIMIT se encuentra en el medio de ese contexto masivo, es estadísticamente probable que la IA la pase por alto. Y cuando pasa algo por alto, no se detiene a preguntar. Alucina. Inventa una definición plausible y sigue adelante.
¿Qué ocurre cuando tratas el código como texto?

Este es el error fundamental que veo cometer a todo el ecosistema de los "envoltorios de IA", y es el argumento que discutía una y otra vez con un posible inversor al principio. Miró nuestro enfoque — construir grafos de conocimiento de repositorios de código — y dijo: "¿Por qué no usar simplemente una ventana de contexto más grande? GPT-5 lo arreglará."
Abrí un programa COBOL en mi portátil. "Encuéntrame la definición de ACCOUNT-BALANCE", dije.
Buscó en el archivo. No pudo encontrarla. Porque no estaba en ese archivo. Estaba en un copybook, incluido mediante una instrucción en la línea 47, que a su vez hacía referencia a una división de datos compartida mantenida por un equipo completamente diferente.
"Ahora imagina que eres un LLM", dije. "Estás haciendo una búsqueda de similitud vectorial para código relacionado con 'procesamiento de pagos'. Encontrarás cinco fragmentos que mencionan la palabra 'pago'. Te perderás por completo el archivo llamado GlobalVarDef.cbl que define la tasa impositiva utilizada por la lógica de pagos — porque ese archivo no menciona la palabra 'pago' en ninguna parte."
La generación aumentada por recuperación estándar, o RAG — la técnica que la mayoría de las herramientas de programación con IA usan para añadir conocimiento a los LLM — recupera contexto basándose en la similitud textual. Convierte el código en vectores y encuentra vectores similares. Esto funciona de maravilla para chatbots de preguntas frecuentes. Es catastróficamente insuficiente para el código.
El código no es lenguaje natural. "El gato se sentó en la alfombra" significa más o menos lo mismo independientemente de lo que hayas leído cincuenta páginas atrás. Pero x = y + 1 no significa nada a menos que conozcas las definiciones, los tipos y los estados actuales de x e y — que podrían estar definidas en un archivo diferente, un módulo diferente, o heredadas de una clase padre.
Escribí sobre este problema estructural en profundidad en la versión interactiva de nuestra investigación. La versión corta: el software no es texto. El software es un grafo.
La noche que dejamos de construir un envoltorio mejor
Hubo un momento — lo recuerdo con claridad — en que mi equipo estaba debatiendo nuestra arquitectura. Teníamos dos caminos. Camino uno: construir un pipeline de RAG más inteligente. Mejor fragmentación, mejores embeddings, mejores prompts. Iterar sobre el enfoque del envoltorio hasta que funcionara lo suficientemente bien. Camino dos: descartar por completo el paradigma basado en texto y tratar el código como lo que realmente es — un sistema relacional de lógica.
El camino uno era más rápido. El camino uno era lo que los inversores entendían. El camino uno ya tenía una docena de competidores demostrando la demanda del mercado.
Mi ingeniera principal sacó una pizarra y dibujó un programa COBOL como un grafo. Nodos para variables, funciones, copybooks, tablas de base de datos. Aristas para CALLS, READS, UPDATES_TABLE, IMPORTS_COPYBOOK. Luego trazó una cadena de dependencias: el Módulo A llama al Módulo B, que modifica la Variable X, que es leída por el Módulo C en un directorio completamente diferente.
"Pídele a una búsqueda vectorial que encuentre esa cadena", dijo.
Nadie pudo.
Esa fue la noche en que nos comprometimos a construir lo que ahora llamamos un Grafo de Conocimiento Consciente del Repositorio — una base de datos de grafos unificada que combina la estructura estática del código (árboles de sintaxis abstracta, grafos de llamadas) con el significado semántico de la lógica de negocio (documentación, comentarios, intención de las variables). No íbamos a construir un traductor mejor. Íbamos a construir un mapa.
¿Cómo conviertes treinta años de COBOL en un mapa?

El proceso tiene cuatro fases, y te ahorraré los detalles de implementación — puedes encontrarlos en nuestro análisis técnico completo en profundidad. Pero los conceptos importan, porque explican por qué este enfoque funciona donde los envoltorios fallan.
Primero, analizamos el código de forma estructural, no textual. Los pipelines de RAG estándar usan "división ingenua" — cortan un archivo cada 500 tokens, a menudo separando la firma de una función de su cuerpo. Nosotros usamos analizadores como Tree-sitter para generar árboles de sintaxis abstracta, que respetan los límites lógicos del código. Una función se trata como una unidad de lógica completa, no como un fragmento aleatorio de texto.
Segundo, extraemos entidades y relaciones. Clases, párrafos, variables, tablas de base de datos, endpoints de API — estos se convierten en nodos. Las aristas entre ellos — CALLS, UPDATES_TABLE, DEFINES_VARIABLE — se convierten en el tejido conectivo. Ahora podemos consultar el grafo: "Muéstrame cada párrafo que actualiza el campo CUSTOMER-ID." Resultados exactos, al instante. Intenta eso con grep.
Tercero — y aquí es donde se pone interesante — resolvemos los símbolos en todo el repositorio. Un analizador estándar ve ACCT-NUM en el Archivo A y ACCT-NUM en el Archivo B como dos cadenas diferentes. Nuestro sistema determina que ambas se refieren a la misma entrada en un copybook compartido y las fusiona en un solo nodo. También fusionamos la documentación con el código: si un documento de requisitos en PDF describe la "User API" y el código contiene una clase llamada UserAPI, el sistema vincula la intención con la implementación.
Cuarto, calculamos el cierre transitivo. ¿Recuerdas el fallo del banco? A depende de B, B depende de C, y la IA vio A pero se perdió C. Nuestro grafo recorre en profundidad — de A a B a C — para identificar la definición raíz de cada variable. Cuando la IA genera código para el Módulo A, importa las definiciones correctas desde el Módulo C, incluso si el Módulo C está en un directorio o repositorio completamente diferente.
¿Por qué falla el RAG estándar en la migración de código?
La gente siempre se resiste a esto. "El RAG funciona bien para el código", dirán. "Solo usa mejores embeddings."
Déjame darte tres escenarios donde la búsqueda de similitud vectorial se desmorona por completo:
Un desarrollador renombra Account a Acct. La similitud semántica cae, aunque la lógica sea idéntica. Una función llamada FNC-001 realiza el cálculo de intereses pero no contiene comentarios — buscar "cálculo de intereses" nunca la encontrará. Y el fallo más común: el RAG vectorial recupera una prueba unitaria y un comentario de la interfaz de usuario que mencionan "pago", pero se pierde la lógica de negocio central porque los nombres de las variables no coinciden con los términos de la consulta.
La recuperación basada en grafos no pregunta "¿qué texto parece similar?". Pregunta "¿qué está lógicamente conectado?" — y esa distinción es la diferencia entre código que compila y código que funciona.
Lo que llamamos GraphRAG opera sobre la estructura, no sobre la similitud. Cuando alguien pide "refactoriza la lógica de pagos", el sistema usa la búsqueda vectorial para encontrar el punto de entrada — digamos, el párrafo ProcessPayment. Pero luego, en lugar de detenerse, recorre las aristas del grafo. Incorpora las subrutinas a través de las aristas CALLS, las definiciones de variables a través de las aristas READS, los copybooks a través de las aristas INCLUDES. Estas piezas conectadas pueden ser textualmente distintas pero son lógicamente inseparables.
Las investigaciones muestran que GraphRAG supera significativamente al RAG vectorial en el razonamiento multisalto — conectar hechos separados por varios pasos. En el software, casi todos los errores graves son un fallo del razonamiento multisalto. Si cambio la lógica de la tasa de interés en el Módulo A, ¿qué pantallas de informes del Módulo Z se rompen? El RAG vectorial no puede responder a esto. El grafo sí, porque recorre la cadena de llamadas a funciones que las conecta.
El problema del GOTO (o: por qué COBOL hace que la IA alucine bucles)

Quiero hablarte de un desafío técnico específico que casi nos rompe, porque ilustra por qué este trabajo es mucho más difícil de lo que la gente supone.
COBOL tiene una instrucción GOTO. Java no. GOTO permite que la ejecución del programa salte a cualquier parte — hacia adelante, hacia atrás, hacia el medio de otro bloque. Crea el "código espagueti" del que te advierte todo profesor de informática. Traducir GOTO no es un problema de sintaxis. Es un problema de topología.
Vimos a tres herramientas comerciales de IA diferentes intentar traducir un módulo COBOL con un uso intensivo de GOTO. Una generó una llamada a función recursiva que habría causado un StackOverflowError en producción. Otra produjo un bucle while(true) sin condición de salida. La tercera — mi favorita personal — simplemente inventó un flujo de control que no existía en el código original. Parecía plausible. Estaba completamente equivocado.
Nuestro enfoque: mapear los destinos de GOTO como aristas en un Grafo de Flujo de Control. Luego usar el reconocimiento de patrones en el grafo. ¿Un GOTO que salta de vuelta a una etiqueta anterior? Eso es un bucle. ¿Un GOTO que se salta un bloque? Eso es un condicional. ¿Un GOTO a un párrafo de salida? Eso es una instrucción de retorno. La IA, guiada por la estructura del grafo, refactoriza estos saltos en bucles while, bloques if/else, o instrucciones break/continue.
Sin el grafo, la IA está adivinando. Con el grafo, está haciendo ingeniería.
La diferencia entre un chatbot y un agente
No construimos chatbots. Necesito dejar esto claro, porque el mercado está inundado de herramientas que te permiten "chatear con tu base de código", y no son lo mismo.
Un chatbot toma tu pregunta, la envía a GPT-4, y devuelve lo que sea que salga. Si el resultado es incorrecto, lo depuras manualmente. Ese es el flujo de trabajo de todos los envoltorios de IA del mercado.
Lo que desplegamos son agentes autónomos que planifican, ejecutan y se autocorrigen. El agente analiza el AST del archivo COBOL objetivo, identifica dependencias, consulta el grafo de conocimiento, genera código Java, y luego lo compila en un entorno aislado. Si el compilador arroja un error — "variable no encontrada" — el agente lee el error, consulta el grafo en busca de la dependencia que falta, y regenera. Luego ejecuta pruebas unitarias derivadas de las trazas de ejecución del COBOL original para verificar la equivalencia de comportamiento.
Este bucle de compilar y corregir traslada la carga de validación del humano al sistema. Pero — y esto importa enormemente en las industrias reguladas — el grafo de conocimiento proporciona una interpretabilidad total. Un desarrollador puede ver exactamente por qué la IA tomó cada decisión: "La IA importó com.bank.logic porque encontró una dependencia en COPYBOOK-X." No "confía en mí, soy IA". Sino: aquí está la cadena de citas de esta lógica.
En la banca, cada línea de código debe ser auditable. No puedes desplegar una caja negra que "probablemente" lo hizo bien. Necesitas un sistema que pueda mostrar su trabajo.
¿Y el código muerto?
Una cosa que me sorprendió: los sistemas heredados están llenos de código que ya nadie usa. Viejas promociones, productos retirados, rutinas de depuración de 1997. Una IA basada en texto migra todo lo que se le da — no puede distinguir el código activo del código muerto.
Nuestro grafo de llamadas identifica los nodos inalcanzables — párrafos o archivos sin aristas entrantes, lo que significa que nada los llama. Marcamos este código muerto para su eliminación antes de que comience la migración. En nuestra experiencia, esto normalmente reduce la base de código en un 20-30%. Eso no es una optimización menor. Eso es eliminar una cuarta parte del trabajo y una cuarta parte de la superficie de ataque.
"¿No resolverán esto las ventanas de contexto más grandes?"
Sigo recibiendo esta pregunta constantemente. La suposición es que si GPT-5 o Claude 4 pueden manejar diez millones de tokens, el problema de "Perdido en el medio" desaparece.
No lo hará. Y aquí está el porqué.
Incluso si la degradación de la atención mejora — y lo hará — sigues haciendo recuperación de texto. Sigues buscando cadenas similares en lugar de recorrer conexiones lógicas. Una ventana de contexto de un millón de tokens no ayuda si la variable que necesitas está definida en un archivo que no comparte ninguna palabra clave con el archivo que estás traduciendo. El problema no es el tamaño de la ventana. El problema es que la ventana está mirando lo que no debe.
La otra objeción que escucho: "Los grafos de conocimiento son caros de construir". Lo son. Analizar un repositorio entero, resolver símbolos, calcular el cierre transitivo — es una inversión inicial significativa. Pero considera la alternativa. La migración manual de un gran sistema COBOL cuesta decenas de millones de dólares y lleva años. La migración con IA basada en envoltorios cuesta menos por adelantado pero genera un flujo constante de errores inducidos por alucinaciones que requieren una costosa depuración humana. El enfoque basado en grafos tiene un coste de configuración más alto y un coste de retrabajo drásticamente más bajo. Los datos de McKinsey sugieren que la IA generativa puede reducir las tareas de programación en un 50%, pero solo si se despliega correctamente. Hemos visto mejoras de 2x a 3x en la productividad de los desarrolladores en comparación con las herramientas de IA estándar, específicamente porque los desarrolladores dejan de pasar horas buscando dónde está definida una variable.
El mapa es el activo
Esto es lo que ojalá hubiera entendido al principio: el grafo de conocimiento no es solo una herramienta para la migración. Es un activo permanente.
Una vez que tu base de código existe como un grafo, permanece como una representación viva de tu sistema. A medida que el nuevo código Java evoluciona, el grafo se actualiza. Obtienes documentación automatizada que siempre está actualizada. Obtienes detección de deriva arquitectónica — el sistema te alerta si el nuevo código viola las reglas de modularidad que definiste. Obtienes análisis de impacto bajo demanda: "Si cambio este método, ¿qué se rompe?"
La modernización no es un evento único. Es un ciclo de vida. Las organizaciones que la tratan como un proyecto — con una fecha de inicio y una fecha de fin — son las que acaban de vuelta donde empezaron en cinco años, ahogándose en una nueva generación de deuda técnica.
El código no es texto
La lección a la que sigo volviendo — la de aquel martes por la noche mirando fijamente un stack trace — es engañosamente simple: el código no es texto, y las herramientas que lo tratan como texto producirán resultados que parecen correctos y se comportan de forma incorrecta.
Toda la economía del "envoltorio de IA" está construida sobre un error de categoría. Asume que, como los LLM son extraordinarios procesando lenguaje, deben ser extraordinarios procesando código. Pero el código no es lenguaje. El código es un grafo — un sistema denso e interconectado de dependencias, flujos de datos y cambios de estado que existe en múltiples dimensiones simultáneamente. Intentar modernizarlo con herramientas basadas en texto es como navegar por una ciudad usando una lista de nombres de calles pero sin mapa. Acabarás "perdido en el medio".
Nosotros construimos el mapa. Y funciona — no porque seamos más inteligentes que los equipos que construyen modelos fundacionales, sino porque hicimos una pregunta diferente. Ellos preguntaron: "¿Cómo hacemos que la IA entienda mejor el texto?" Nosotros preguntamos: "¿Y si el problema no es el texto en absoluto?"
El futuro de la modernización de sistemas heredados no es un modelo de lenguaje más grande. Es un sistema que entiende el software de la forma en que el software realmente funciona — como estructura, no como cadenas de texto.
Esa es la apuesta que hicimos en Veriprajna. Cada día, otra organización descubre que su Java generado por IA compila de maravilla y falla catastróficamente. Cada día, la brecha entre la traducción sintáctica y la comprensión semántica se vuelve más cara de ignorar. Las organizaciones que cierren esa brecha no solo modernizarán su código. Finalmente lo entenderán — muchas de ellas por primera vez.