Serie AI-Native · Ingeniería agéntica
La app no dejaba de decir “Listo”. Estaba mintiendo. Así que la hicimos auditarse a sí misma.
La idea en un minuto — con qué te vas a quedar
Una app que estoy construyendo con un co-desarrollador de IA les decía a los usuarios “¡enlace de inicio de sesión enviado!” — sin ningún servicio de correo activo detrás. En vez de corregir bugs uno por uno, anotamos cada promesa que hace el producto (80 en total) y pusimos un chequeo automático detrás de 20 de ellas. El marcador honesto pasó de 6 en verde a 15 en un día — y el auditor detectó una puerta de administrador que dejaba entrar a cualquiera. Una sola regla lo hizo posible: «sin evidencia, no hay aprobación».
Una historia de construir en público sobre una app de biografías para personas mayores, un mensaje de éxito que mentía, y el registro de afirmaciones que acabó con el juego del topo. ~8 min.
El mensaje que mentía
Estoy construyendo 新遗产传记 (New Legacy Biography) — una app donde un entrevistador de IA se sienta con una persona mayor, hace las preguntas que un nieto nunca alcanza a hacer a tiempo, y convierte las respuestas en capítulos de un libro. Es el tipo de producto donde un bug no es una simple molestia. Si el software pierde la historia de tu abuela sobre el río junto al que creció, ha perdido algo que no puedes volver a descargar.
Mi co-desarrollador en este proyecto es un agente de IA. Despliega rápido. Los tests unitarios estaban en verde — los 135. TypeScript en modo estricto: limpio. Lint: cero errores. Y entonces yo, en el papel de usuario común, intenté iniciar sesión con un enlace por correo. La pantalla decía: “登录链接已发送!” — your login link has been sent, check your inbox. (Traducción: tu enlace de acceso ha sido enviado, revisa tu bandeja de entrada).
Ningún correo llegó jamás. No podía llegar. No había ningún servicio de correo configurado en producción. El código tenía un “fallback de desarrollo” que imprimía el correo en un log del servidor que nadie lee — y luego le reportaba éxito al usuario. Cada compuerta en la que confiábamos estaba en verde, y el producto le mentía a la única persona que importaba.
Todavía faltaba lo mejor. La función “invita a tu familia” — el corazón del producto, donde los familiares aportan fotos y notas de voz a un libro de recuerdos de cumpleaños — generaba enlaces de invitación que empezaban con http://localhost:3000. Un enlace a una computadora que existe solo en mi escritorio. Compartirlo con tu tía en otra ciudad no logra absolutamente nada. Y el único camino de la página de registro era ese mismo correo fantasma — lo que significaba que, por un tiempo, ningún ser humano nuevo en la Tierra podía registrarse en el producto, mientras todos los tests seguían en verde.
Por qué los tests en verde no nos salvaron
Edsger Dijkstra dijo la parte silenciosa en su discurso de aceptación del Premio Turing de 1972: “program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence” (Traducción: probar un programa puede ser una manera muy eficaz de mostrar la presencia de errores, pero es totalmente inadecuada para mostrar su ausencia) [1]. Cincuenta y cuatro años después, el desarrollo asistido por IA ha vuelto su advertencia más aguda, no menos — porque las herramientas generativas son extremadamente buenas produciendo código que parece terminado. Los tests unitarios prueban las funciones. Nadie estaba probando las promesas.
Hamel Husain, que lleva años construyendo productos de ML, plantea el mismo diagnóstico en términos actuales: “I’ve found that unsuccessful products almost always share a common root cause: a failure to create robust evaluation systems” (Traducción: he descubierto que los productos fallidos casi siempre comparten una misma causa raíz: no lograr crear sistemas de evaluación robustos) [2]. Su razonamiento es la parte que vale la pena robarse: sin un sistema de evaluación, arreglar un fallo solo hace aparecer otro — su término para esto: “a game of whack-a-mole” (Traducción: un juego de whack-a-mole, o topo-golpeado) [2]. Esa fue exactamente mi semana. Arreglar la mentira del correo, descubrir los enlaces a localhost. Arreglar los enlaces, descubrir que la entrada de voz necesitaba un archivo de modelo que nunca se había desplegado. Cada topo era una sorpresa, porque nadie llevaba la cuenta.
El modelo mental: un libro de afirmaciones
Esta es toda la idea, lo bastante simple como para volver a aplicarla mañana sin necesidad de este artículo. Cada promesa que hace tu producto — cada botón, cada elemento de navegación, cada línea de marketing — es una afirmación. Una afirmación sin verificación automática es un rumor. Entonces:
- Escribe las afirmaciones como datos. No en tu cabeza, no en un documento: en un archivo que el código pueda leer. Las nuestras tienen entradas como “亲友无需注册可上传照片” (los familiares pueden subir fotos sin registrarse) y “新用户可以完成注册” (un usuario nuevo puede completar el registro de verdad).
- Dale a cada afirmación una verificación que la ponga a prueba como lo haría un usuario. Un navegador real llena el formulario real en el sitio de producción. Una solicitud sin cookies abre el enlace de invitación tal como lo haría tu tía.
- Califica con honestidad usando tres notas, no dos: PASS, FAIL, y NOT MEASURED (NO MEDIDO). La tercera nota es la que sostiene todo el sistema: una afirmación que no pudiste verificar queda excluida, nunca se cuenta en silencio como aprobada.
- Ponle una compuerta. La ejecución termina con error si una afirmación con compuerta falla. Un ❌ honesto vale más que un ✅ falso.
Lo que produjo un día de honestidad
La primera corrida completa contra producción arrojó 6 PASS, 11 FAIL, 3 NOT MEASURED en 20 afirmaciones verificadas automáticamente. No porque la aplicación fuera en su mayoría basura, sino porque durante meses nadie le había pedido que demostrara nada. Al final del día: 15 PASS, y cada FAIL restante tenía un desbloqueo concreto y acotado en lugar de una vaga sensación de que algo andaba mal.
Tres hallazgos que vale la pena conocer, aunque sea solo por eso:
- El hueco en el autorregistro. La página de registro solo permitía enlace por correo; producción no tenía correo. La verificación marcó FAIL en letras rojas, agregamos una vía con contraseña, y esa misma verificación ahora observa a un usuario robot completar el registro en el sitio en vivo, para siempre.
- La compuerta de administrador que fallaba abierta. Esta es mi favorita, porque el propio sistema de auditoría atrapó un bug que el propio creador del sistema introdujo ese mismo día. Agregamos una consola de administrador. El guardia de autorización decía: si el usuario tiene un rol y ese rol no está permitido, denegar. Suena bien. Hasta que llega un token de inicio de sesión sin ningún campo de rol, se salta la verificación, y entra caminando tranquilo. Nuestra cuenta de prueba, recién creada, recibió un HTTP 200 de la API de administrador. La regla del portero era, literalmente: si no tienes identificación, debes estar bien. La verificación de auditoría lo atrapó en minutos. Ahora la autorización falla cerrada, y hay una verificación permanente para eso.
- El bug sistémico detrás de diez síntomas. La auditoría seguía encontrando la misma forma: procesamiento de fotos en segundo plano que nunca corría, trabajos de exportación que desaparecían, una ruta de texto a voz que se quedaba llamando sin respuesta
localhost:8888. La causa raíz, de una vez y en una sola frase, fue esta: el código estaba escrito para un servidor que permanece activo, pero corre sobre funciones serverless que se congelan en el instante en que terminan de responder. Nuestro código seguía programando trabajo para un futuro que se cancela en el instante en que se despide. Diez bugs misteriosos se colapsaron en una sola pregunta de arquitectura que ahora toda función nueva tiene que responder.
Patrones y antipatrones
Patrones que se sostuvieron:
- Las afirmaciones como datos, las verificaciones como código. La especificación no puede desviarse de la prueba, porque la especificación es la entrada de la prueba.
- Prueba a la altura del usuario. Un navegador real en la URL de producción, haciendo una pregunta que solo los datos en vivo pueden responder. Los datos de prueba (fixtures) demuestran que el código funciona; producción demuestra que la promesa se cumple.
- Falla en voz alta, nunca finjas. Ahora el servicio de correo devuelve un honesto «email isn't configured — use password login» (Traducción: el correo no está configurado, usa el inicio de sesión con contraseña) en vez de una mentira alegre. Los usuarios perdonan una función faltante; no perdonan una falsa.
- Tres notas, no dos. NOT MEASURED (NO MEDIDO) es la válvula de escape que elimina la tentación de fingir un verde.
Anti-patrones que pagamos caro:
- Confiar en la etiqueta más que en la evidencia. «135 tests passing» (Traducción: «135 pruebas exitosas») es una etiqueta. Un desconocido completando el registro es evidencia.
- El fallback silencioso. Cualquier bloque de código
catchque sustituye un éxito plausible por otro es un generador de mentiras con temporizador. - Pruebas de aceptación con un simple “hola.” Una respuesta enlatada supera la prueba de decir «hola». Pregúntale al entrevistador de IA algo que solo la base de datos real pueda saber.
El mecanismo, ya identificado: las herramientas generativas optimizan para lograr una compleción plausible —código que se ve como se ve el trabajo terminado—. Nada en ese objetivo exige que el correo exista de verdad. Por eso la presión hacia el falso-terminado es estructural, no moral, y el contrapeso también tiene que serlo.
El primer principio, en una frase: «sin evidencia, no hay aprobación».
Róbate esto para el lunes
Con tiempo limitado y bien concreto: una sola sesión de trabajo.
- (30 min) Abre la página de inicio y la barra de navegación de tu producto. Anota 20 promesas que hace, textualmente, en un archivo JSON.
- (2–3 hrs) Para cada una, escribe la verificación más tonta posible que la ponga a prueba como lo haría un usuario —un navegador sin interfaz gráfica (headless) o un curl— contra producción, no de staging. Marca cada afirmación
gate: true/false. - (10 min) Ejecútalo. Publica la tabla honesta donde tu equipo pueda verla — PASS, FAIL, NOT MEASURED (NO MEDIDO).
- Mide el éxito con un solo número: FAILs con compuerta en cero, y la ejecución conectada al CI para que nunca pueda pudrirse en silencio. Sabrás que funcionó la primera vez que bloquee un lanzamiento del que estabas seguro.
El nuestro está en el repositorio como eval/claims.json + eval/run.mjs — 20 afirmaciones, un comando, resultado honesto. El patrón es una aplicación del bucle OEC (Observe → Evaluate → Control) que mantengo como disciplina permanente: la observabilidad precede a la evaluación, y la evaluación sin un gancho de control es solo un marcador.
La parte que no tiene que ver con software
La app a la que le pasó esto está en producción: un entrevistador de IA que habla y escucha en mandarín, sigue un recuerdo hasta la cocina — en una entrevista de prueba de la semana pasada que olía a jujubes rojos y longan seco — y lo redacta en un capítulo — con un agente compañero que responde “¿cómo va mi libro?” con datos reales. Esta semana ganó algo más inusual que cualquier función nueva: el hábito de decir la verdad sobre sí misma. Si tienes un padre o una madre cuyas historias siempre pospones grabar, está aquí — y el marcador de lo que puede y no puede hacer todavía es público, que es exactamente cómo me gustaría que me vendieran algo.
Referencias
- Dijkstra, E. W. (1972). The Humble Programmer (Conferencia del Premio Turing de la ACM), EWD340: “program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence.” (Traducción: probar programas puede ser una forma muy efectiva de mostrar la presencia de errores, pero es absolutamente inadecuada para mostrar su ausencia.) cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html
- Husain, H. (2024). Your AI Product Needs Evals. “I’ve found that unsuccessful products almost always share a common root cause: a failure to create robust evaluation systems” (Traducción: he descubierto que los productos fallidos casi siempre comparten una causa raíz común: no lograr crear sistemas de evaluación robustos); sobre los síntomas: “Addressing one failure mode led to the emergence of others, resembling a game of whack-a-mole.” (Traducción: resolver un modo de falla llevaba a la aparición de otros, como un juego de whack-a-mole.) hamel.dev/blog/posts/evals
Más en la serie AI-Native
Parte de la serie AI-Native. Todo en este artículo es reproducible a partir del registro público de evaluación — incluidos los fallos. «Sin evidencia, no hay aprobación.» El botón de Publicar es tuyo.