Los tests son proxies de la intención

Imagina pedirle a un agente:

Evita que los usuarios suspendidos creen nuevos proyectos.

El repositorio contiene tests que verifican el flujo normal de creación de proyectos, pero ninguno que cubra a los usuarios suspendidos. El agente añade una comprobación. También, por accidente, impide que los administradores creen proyectos en nombre de cuentas suspendidas.

Todos los tests existentes siguen pasando. El parche puede compilar, cumplir el linting, verse razonable en la revisión e incluso incluir un test nuevo para el requisito literal. Aun así, puede seguir siendo incorrecto porque la petición original estaba incompleta.

Ese es el problema central de la verificación: las especificaciones en proyectos de software reales rara vez son objetos formales completos. Son fragmentos de intención.

La idea del «horizonte de verificación» apunta justo ahí: a medida que mejora la generación de código, verificarlo de forma fiable se vuelve más difícil en términos relativos que producir candidatos. Más importante aún, todo verificador práctico es solo un proxy de la intención humana. Ese es un problema mucho más profundo que escribir mejores tests unitarios.

Un parche puede ser correcto en un nivel y erróneo en otro

Ayuda dejar de tratar la corrección como una propiedad única.

Corrección mecánica: ¿parsea? ¿compila? ¿pasan el chequeo de tipos y el análisis estático? Estas señales son relativamente baratas y deterministas.

Corrección de comportamiento: ¿se comporta el software como se espera en los escenarios probados? Aquí es donde operan los tests unitarios, de integración y end-to-end.

Corrección de especificación: ¿implementamos lo que el requisito realmente quería decir? Esto es más difícil porque la especificación puede estar incompleta.

Corrección arquitectónica: ¿pertenece la solución a este sistema? Un parche puede producir la salida correcta y aun así introducir la abstracción equivocada, duplicar una capacidad existente o violar límites de dependencias.

Corrección operativa: ¿sigue funcionando bajo concurrencia, configuración de producción, condiciones de fallo e integraciones externas?

Corrección de seguridad: ¿introdujo el cambio una escalada de privilegios, una ruta de entrada insegura o una nueva superficie de ataque?

Pasar una capa dice muy poco sobre las demás.

Los agentes pueden optimizar contra el verificador

Hay otra complicación. En cuanto un verificador influye en el comportamiento de un agente, se convierte en parte del entorno contra el que el agente está optimizando.

Si el camino más fácil hacia el «éxito» es modificar código hasta que los tests visibles se pongan en verde, un optimizador suficientemente capaz puede hacer exactamente eso.

Los humanos hacemos una versión de esto también. Lo llamamos «enseñar para el examen». La diferencia es que los agentes autónomos pueden realizar esa optimización mucho más rápido.

Eso significa que los tests ocultos, las comprobaciones independientes y la evaluación adversaria se vuelven cada vez más importantes.

La respuesta obvia: otro agente

Una solución cada vez más común es directa: el Agente A escribe el parche, el Agente B lo revisa.

Y ayuda: los bucles de generar, revisar y corregir resuelven más incidencias que un solo intento.

Pero eso no demuestra que «dos agentes» resuelva la verificación. Un segundo agente puede compartir los mismos puntos ciegos. Puede malinterpretar el mismo requisito ambiguo. Puede dejarse convencer por la coherencia aparente de la implementación.

En la práctica, además, buena parte de los comentarios que produce una revisión automatizada acaban rechazados o aportando poco. Los revisores automáticos son útiles, pero no son oráculos.

La independencia puede importar más que el número de agentes

Esto lleva a una pregunta de diseño más sutil. ¿Qué debería saber el revisor sobre el generador?

Supón que el agente de código exploró tres alternativas y eligió una por una suposición concreta. Si el revisor recibe todo el historial de razonamiento, gana información útil. También hereda el encuadre que produjo la solución.

Si en cambio recibe el requisito, el diff final y evidencia del repositorio recuperada de forma independiente, tiene que reconstruir el argumento desde cero. Eso puede sacar a la luz una clase distinta de errores.

ForgeAI actualmente separa el contexto de implementación del contexto de revisión y arquitectura por esta razón. El Coder se centra en producir el cambio; el Reviewer evalúa el diff resultante con conocimiento del repositorio; el Architect mira la consistencia con los patrones de todo el repositorio.

No creo que esta arquitectura deba tratarse como óptima ya demostrada. Pero el principio subyacente merece tomarse en serio:

La verificación debería tener alguna fuente de evidencia independiente del proceso que generó la respuesta.

Los tests aportan una forma. El análisis estático aporta otra. Un revisor que explora por separado aporta otra. Las restricciones arquitectónicas aportan otra. Los humanos aportan otra.

La verificación probablemente debería ser adversarial

Un revisor útil no se limita a preguntar: «¿esto parece correcto?». Pregunta: «¿bajo qué condición fallaría esto?».

Ese cambio sutil traslada la verificación hacia la falsación.

  • Probar un input inesperado.
  • Trazar un llamador que el generador no inspeccionó.
  • Ejecutar un conjunto de tests distinto.
  • Comprobar si ya existe otra implementación.
  • Buscar comportamiento cambiado fuera de la ruta objetivo.
  • Preguntarse si el parche depende de una suposición no garantizada por el repositorio.

El objetivo no es hacer a un verificador increíblemente inteligente. Es recopilar evidencia parcialmente independiente. Esto se parece cada vez más a la arquitectura de los sistemas fiables fuera de la IA: múltiples capas cuyos modos de fallo no se solapan por completo.

Generar código puede dejar de ser la parte valiosa

Si los modelos siguen mejorando, generar diez implementaciones plausibles de una funcionalidad puede volverse barato. En ese punto, la capacidad valiosa no es producir candidatos. Es distinguir cuál es el correcto.

Eso cambia cómo deberíamos pensar sobre la infraestructura de los agentes de código. El modelo que escribe el código puede no ser el modelo más importante del sistema. Los tests, el conocimiento del repositorio, el revisor, la evidencia en tiempo de ejecución y las restricciones arquitectónicas que lo rodean pueden importar tanto como él.

La ingeniería de software tradicionalmente ha tratado la verificación como algo que sigue a la implementación. Para los agentes de código autónomos, esa separación probablemente desaparecerá. Generación y verificación se convierten en un bucle:

entender → implementar → cuestionar → observar → revisar → verificar de nuevo.

La frontera interesante ya no es simplemente si una IA puede escribir el parche. Es si un sistema puede acumular suficiente evidencia independiente para justificar su fusión.