Oficio en la era del código generado
A todos los estudios les están haciendo la misma pregunta este año: si un modelo puede escribir el código, ¿por qué cobráis exactamente? Nuestra respuesta, en forma de las cosas que nuestra propia build se niega a aceptar.
En esta página
Escribir código dejó de ser la parte cara. Leerlo no se abarató nunca, y esa única asimetría es toda la historia del año.
Un modelo produce cuatrocientas líneas de TypeScript plausible mientras tú terminas una frase. Tu capacidad de sostener cuatrocientas líneas en la cabeza y preguntar qué tendría que ser cierto para que esto estuviera mal es exactamente la misma que en 2019. El cuello de botella se mudó a la única parte del proceso que no acelera. Todos los argumentos sobre ingeniería asistida por IA que me parecen interesantes empiezan ahí; los que me aburren van en secreto sobre si teclear fue alguna vez lo importante.
El código generado además falla de una forma particular y desagradable: falla de manera plausible. Los errores escritos a mano suelen parecer errores — una variable mal nombrada, una rama que obviamente no se ejecuta nunca, un comentario que discute con la línea de debajo. Los errores de un modelo llegan bien vestidos. Los nombres son buenos, la estructura es convencional, los comentarios están de acuerdo con el código, y la segunda respuesta de DNS no se comprueba jamás.
Así que dejamos de preguntar quién escribió una línea y empezamos a preguntar qué, dentro de la build, protestaría si esa línea estuviera mal.
Comprobaciones que se ejecutan sin mí
El Orrery propaga órbitas de satélites en el navegador a partir de conjuntos de elementos publicados por CelesTrak. En desarrollo, antes de que se dibuje un solo píxel de eso, corre una autocomprobación. Dale un conjunto de elementos de clase ISS — movimiento medio de 15.495 revoluciones por día — y tiene que devolver un periodo orbital de 92.933 minutos y una velocidad de 7.660 km/s. Dale un conjunto geoestacionario y la longitud debe derivar 0.010° en seis horas. Esos números no son nuestros. Salen de la física, y eran ciertos mucho antes de que el archivo existiera.
El valor de esa comprobación está enteramente en lo que evita: un mapa de satélites que está mal en todas partes y obviamente mal en ninguna. El error orbital no se anuncia. Cada punto sigue moviéndose con suavidad, el planeta sigue girando, y nada en pantalla te dice que el solucionador de Kepler perdió una iteración en la limpieza de alguien. Las aserciones sí.
El mismo instinto, a escala de juego. Slipstream es un corredor de carriles cuyas filas de obstáculos salen de patrones generados, y un patrón que no deja ningún carril alcanzable a velocidad no es un nivel difícil: es un nivel roto. Ese defecto sobrevive de maravilla a las pruebas de juego, porque quien muere da por hecho que se le da mal. Así que los patrones se validan al cargar el módulo: se propaga hacia delante qué carriles puede alcanzar físicamente la nave en el peor caso de velocidad, 32 unidades por segundo, y se afirma que cada fila mantiene al menos uno de ellos superable. El comentario de ese archivo es toda la filosofía en nueve palabras — justo para el validador es justo para quien juega.
| Qué se ejecuta | Qué afirma | Por qué una persona no puede cubrirlo |
|---|---|---|
| Autocomprobación de propagación del Orrery | Órbita de clase ISS → periodo de 92.933 min, 7.660 km/s; deriva geoestacionaria de 0.010° en 6 h | El error orbital es invisible a simple vista: el mapa parece correcto mientras está equivocado |
| Validador de patrones de Slipstream | Cada fila de obstáculos mantiene un carril alcanzable a la peor velocidad | Las pruebas de juego pueden no encontrar la fila injusta; no pueden demostrar que no exista |
| Esquema, límites y sanitizador de Blueprint | 3–14 nodos, exactamente 3 fases, sin aristas colgantes, sin ids de opción desconocidos | La salida del modelo se lee con fluidez incluso cuando es estructuralmente imposible |
Tres comprobaciones cableadas en rutas de código que un desarrollador ya recorre. A ninguna le importa quién escribió el código que está comprobando.
Esa última propiedad importa más que las propias comprobaciones. La verificación que tienes que acordarte de lanzar es verificación que acabarás saltándote, normalmente el día en que vas más rápido — que, ahora, es casi todos los días.
El modelo propone; el motor decide
Blueprint es donde tuvimos que responder a esto comercialmente y no filosóficamente. Un visitante describe un producto, Claude redacta una arquitectura, la página la dibuja y le adjunta un precio. La catástrofe evidente es un modelo de lenguaje inventando un número que un desconocido trata después, con toda la razón, como una cotización nuestra.
Así que en ese código hay una regla, escrita como frase y no como flag de configuración: el LLM no pone precio a nada; solo propone selecciones, y hasta esas se sanean antes.
En la práctica el modelo elige de un catálogo cerrado: plataformas, funcionalidades, capacidades de IA, un nivel de diseño, un número de integraciones. Los ids desconocidos se descartan al llegar. Los campos obligatorios de opción única que vuelven vacíos se rellenan con valores por defecto. Después la aritmética ocurre en un sitio al que el modelo no llega: unidades base sumadas entre las selecciones, multiplicadas por la complejidad del producto, el nivel de QA y el alcance del lanzamiento, convertidas mediante una banda de tarifa por unidad; el calendario con las plataformas corriendo en paralelo, el resto a quince unidades por semana, más dos semanas de colchón. Es el mismo motor determinista que hay detrás de nuestra página de precios, leyendo las mismas reglas. La lista de enums del esquema de salida, el catálogo de opciones del prompt y la lista blanca del sanitizador se derivan todos de ese único objeto de reglas, así que no pueden separarse en silencio.
El modelo tiene permiso para ser imaginativo con la arquitectura. No lo tiene para acercarse a un número sobre el que un cliente pueda actuar.
Dos decisiones menores del mismo espíritu. La idea del visitante se envuelve en etiquetas y se trata como datos, no como instrucciones, porque una caja de texto en una página pública es entrada no confiable por muy conversacional que parezca. Y cuando un blueprint se convierte en una solicitud de presupuesto, la estimación se recalcula en el servidor a partir de las selecciones saneadas; los números que llegaron desde el navegador se ignoran por completo. El precio de un cliente no debería ser nunca un valor que pasó por un sitio que un desconocido puede editar.
Saber contra qué no te defendiste
Un servidor que descarga URLs escritas por desconocidos es un arma cargada apuntando a tu propia red, y eso es exactamente el Reliquary: pegas un enlace, nuestro servidor descarga la página, la analiza y devuelve una pieza. Las direcciones que vale la pena atacar no están en la internet pública. 169.254.169.254 es donde los proveedores de nube aparcan los metadatos de instancia; los rangos privados son donde vive el resto de tu infraestructura. Escribimos sobre esa construcción en junio; la protección es la parte menos glamurosa de todo aquello y la primera que defendería.
Solo http y https, solo los puertos 80 y 443, sin credenciales coladas en el campo userinfo. Una lista de bloqueo que cubre los rangos privados, reservados, link-local y de NAT a escala de operador. DNS resuelto con todas las direcciones devueltas y la exigencia de que cada una sea pública, porque validar solo la primera respuesta es el clásico casi-acierto. Cada salto de redirección se vuelve a analizar y a validar desde cero: una URL pública que redirige a una dirección de loopback es el ataque entero. Los prefijos IPv6 se clasifican antes que la cola en cuartetos decimales, en ese orden, ya que al revés se dejaría pasar una dirección mapeada con un cuarteto de aspecto público.
Y luego la parte de la que estoy más orgulloso. Un comentario en ese archivo nombra el ataque que no paramos: el rebinding de DNS. Entre el momento en que validamos un nombre de host y el momento en que el socket conecta, la respuesta puede cambiar a algo privado. Cerrar eso como es debido significa fijar la conexión a la dirección ya validada, lo que significa un dispatcher HTTP propio y una nueva superficie de dependencias, y juzgamos que no compensaba para una función que descarga anuncios de subastas. Puede que el juicio sea erróneo. Al menos está escrito, de modo que quien lea el archivo después hereda el razonamiento en lugar de la impresión de que todo está resuelto.
Esta es la parte que ningún generador hace por ti. Un modelo escribirá encantado un validador de URLs, y hasta puede que escriba uno bueno. Lo que no puede hacer es decidir qué riesgo residual está dispuesto a asumir tu negocio y luego decirlo en voz alta en un sitio donde se le pueda discutir. El criterio no es la capacidad de producir la versión defendida. Es conocer la forma de lo que queda sin defender, elegirlo a conciencia y ponerle tu nombre a esa elección.
Otras dos cosas siguen aquí tercamente humanas. Una es el invariante — la frase que un sistema no tiene permitido violar — porque los invariantes codifican lo que te importa, y nada en un corpus de entrenamiento sabe lo que a ti te importa. La otra es decidir qué no construir. El Reliquary guarda cada pieza en el almacenamiento local de tu navegador y absolutamente nada en nuestros servidores. Eso costó funcionalidades reales: sin compartir, sin sincronización entre el portátil y el móvil, un tope duro de sesenta piezas y ni idea de qué hace nadie con la cosa. Ningún sistema entrenado con la última década de software habría propuesto renunciar a los datos. Fue una decisión de gusto, y el gusto es exactamente lo que el estándar del conjuro se escribió para proteger.
Lo que me lleva a la palabra que todo el mundo usa este año. El slop no es una propiedad de la IA; es una propiedad de la revisión. El código sobre el que nadie puede decir qué tendría que ser cierto para que esto estuviera mal es slop, venga de un modelo, de un proveedor externo o de mí a la una de la madrugada. Nuestro sector publicó océanos de eso antes de que nada supiera autocompletar una función. Los modelos no inventaron ese fallo. Abarataron su producción, que es el argumento para tomarse la revisión más en serio, no menos.
La parte incómoda de esta postura es que escala mal, y creo que quienes venden el futuro lo saben. Generar es casi gratis y cada vez lo es más. Verificar es trabajo, es tercamente lineal, y es lo que estamos cobrando en realidad. Cuando un cliente pregunta qué le está pagando a un ingeniero en 2026, la respuesta honesta es: no el tecleo. Las negativas. El número que tenía que salir de la calculadora, la fila que tenía que seguir siendo superable, el riesgo que había que nombrar en un comentario donde alguien pudiera estar en desacuerdo.