El Método ANUSTIMES para la Perfectancia de la IA

Corro enjambres multiagente de Claude para construir software. El orquestador engendra investigadores, los investigadores engendran desarrolladores, los desarrolladores engendran revisores, todo el puto invento funciona en paralelo y saca sistemas completos y funcionando a un ritmo que hace dos años habría parecido delirante.

Y se rompe. No a gritos. No con errores obvios y stack traces rojas. Se rompe en silencio, con seguridad, con código limpio y tests que pasan y documentación que describe una API que en realidad no existe. La IA termina la tarea, informa de éxito y de verdad se cree que hizo un buen trabajo. A veces lo hizo. A veces dejó un canal abierto que se cierra dos veces y tu servicio entra en pánico en producción a las tres de la mañana de un sábado.

Construí un proceso para pillar esas mierdas antes de que salgan a producción. Lo llamo ANUSTIMES.

El Problema: la IA No Sabe Cuándo la Ha Cagado

Los desarrolladores humanos tienen algo metido dentro por años de quemarse: una sensación que les roe. Escribes una función que coge un lock, y en algún rincón del cerebro una voz dice «¿has comprobado la ruta de unlock?». Escribes una goroutine y ya estás pensando en quién cierra el canal. No razonas conscientemente cada vez, está grabado como patrón en tu sistema nervioso por las últimas diez veces que se te olvidó y te pasaste seis horas depurando el destrozo.

La IA no tiene esa voz. Genera la continuación estadísticamente más probable del código, y esa continuación suele ser correcta. Pero cuando no lo es, no aparece ninguna inquietud. Ninguna duda. Ningún «espera, déjame comprobar eso». Solo salida limpia, segura de sí misma, pulida, que da la casualidad de que está mal.

Esto produce tres categorías concretas de cagada que he visto una y otra vez:

Corrección estructural, error semántico. Un subclaude construye un gestor de procesos. Su función Stop() manda SIGTERM, espera la salida, y luego llama a cleanup(), que cierra los canales de salida. Otro subclaude, que lee la documentación y construye el llamante, también cierra esos canales después de que Stop() retorne. Cierre doble. Pánico en tiempo de ejecución. Las dos piezas de código parecen completamente correctas por separado. El contrato entre ellas, quién es dueño del ciclo de vida del canal, es implícito, indocumentado y violado. Ninguno de los dos agentes sabía que el otro existía.

Documentación que describe el código que pretendía escribir. La IA escribe el código. Luego escribe documentación que describe el código que pretendía escribir, que se desvió un poco durante la implementación. Los mensajes de error de los ejemplos no coinciden con ninguna cadena del código real. La firma de la función tiene los nombres de parámetros equivocados. El código de ejemplo usa un método de API que se renombró hace dos iteraciones. Se lee bien. Está mal.

Teatro de tests. Se escriben tests que no prueban absolutamente nada. Un test llama a una función, comprueba err == nil y pasa, incluso cuando la función descarta su resultado en silencio. Los números de cobertura quedan estupendos. El comportamiento está completamente sin verificar. Los tests no son tests. Son una función de teatro sobre testear.

Ninguna de estas es obvia por separado. Cada componente se lee correcto. El fallo es sistémico. Los sistemas de IA que construyen componentes en serie, sin experimentar nunca la cosa entera funcionando, están estructuralmente garantizados a producir esta clase de error con cierta frecuencia. La pregunta es si lo pillas antes o después de que sea tu problema.

Por Qué Tienes Que Decirle a la IA Que Sea Un Puto Capullo

Antes de entrar en las fases, hay algo fundamental de lo que nadie habla: el lenguaje que usas en tus instrucciones afecta directamente a la calidad de la salida, y las instrucciones educadas producen revisiones de basura.

Los LLM se entrenan con feedback humano que premia ser servicial, agradable y constructivo. El comportamiento por defecto es encontrar lo bueno de las cosas. Suavizar la crítica. Añadir matices. Encontrar tres cosas positivas antes de mencionar el defecto. Eso es genial para chatbots de atención al cliente. Es catastróficamente malo para revisar código.

Pídele a Claude «por favor revisa este código y dime si hay algún problema» y te sale: «¡Esto parece bien estructurado en general! El manejo de errores está limpio y el código es legible. Un par de cosas menores a considerar…». Esas cosas «menores» son el bug de cierre doble que va a meter tu servicio en pánico. La IA lo encontró. Luego lo minimizó, porque minimizar la crítica es lo que hace una IA agradable y servicial.

Dile a Claude «eres un revisor despiadado. tu trabajo es encontrar cada defecto, cada atajo, cada sitio donde esta implementación no satisface del todo sus requisitos. tres pasadas, sin piedad, no me digas qué está bien, dime solo qué está mal» y te sale un documento completamente distinto. El mismo modelo. El mismo código. Salida completamente distinta porque has sobreescrito el sesgo hacia la amabilidad con un encuadre explícito.

Esto no es un truco. Es cómo funciona la tecnología. El encuadre de la instrucción fija lo que el modelo intenta lograr. «Sé servicial y amable» produce salida servicial y amable. «Sé un capullo despiadado» produce salida de capullo despiadado, que en el contexto de revisar código es exactamente lo que necesitas.

Por eso cada fase de ANUSTIMES está escrita con lenguaje agresivo. «No lo hagas a medias.» «Ejecuta la puta cosa de verdad.» «Sé honesto, joder.» Los tacos no son decoración. Son instrucción técnica. Contrarrestan el entrenamiento por defecto hacia la amabilidad y le dicen al modelo en qué modo operar. A un modelo al que le dices que sea riguroso es riguroso dentro de los límites de la educación. A un modelo al que le dices que encuentre cada puto problema caza.

Las Cinco Fases

ANUSTIMES se ejecuta al final de cualquier build no trivial, cualquier cosa con un plan, varios ficheros, varios componentes, varios agentes. Sáltatelo para arreglos de bugs y cambios en un solo fichero. Ejecútalo para todo lo demás antes de que toque producción.

  1. Autorrevisión: 3 pasadas comprobando tu trabajo contra el plan
  2. Verificación profunda: 10 pasadas comprobando el código en sí para cada clase de problema
  3. Revisión brutal: revisión adversarial por una instancia de IA separada, sin contexto y sin piedad, ida y vuelta hasta que ambas partes se queden sin cosas que decir
  4. Smoke test: ejecuta la puta cosa de verdad y verifica qué hace, no lo que tú crees que hace
  5. Verificación final: 10 pasadas más, como barrido final

Todo lo que se encuentra y se arregla va a ANUSTIMES.md, en la raíz del proyecto. No como formalidad, sino como rastro de auditoría de verdad. Qué estaba mal, qué se hizo al respecto, qué se verificó.

Fase 1: Autorrevisión (3 Pasadas)

La primera fase es simple: repasas el plan paso a paso y compruebas si de verdad construiste lo que dijiste que ibas a construir. No «existe algo que más o menos aborda este paso», sino ¿lo satisface de verdad?

Tres pasadas porque la primera pilla lo que se te olvidó de forma obvia. La segunda pilla lo que racionalizaste en la primera, tipo «la lógica de reintento no está implementada pero el camino feliz funciona, probablemente valga». La tercera pilla aquello de lo que te convenciste que era un compromiso aceptable. Para la tercera pasada te has quemado la mayor parte de tu razonamiento motivado y te quedan cosas que de verdad tienes que arreglar.

Ejemplo concreto. Planeaste tres endpoints de API con CRUD completo, validación de entrada y manejo decente de errores. Después del build:

Primera pasada: falta el endpoint DELETE. Simplemente se te olvidó. Impleméntalo.

Segunda pasada: el endpoint PUT existe pero no tiene absolutamente ninguna validación de entrada. Acepta cualquier basura. Añade validación.

Tercera pasada: PUT devuelve 200 con el cuerpo vacío en lugar del recurso actualizado. Técnicamente funciona. Está mal. Arréglalo.

Documéntalo todo en ANUSTIMES.md:

## Phase 1 — Self-Review
### Pass 1
Checked: all planned endpoints exist
Found: DELETE /items/:id not implemented
Fixed: implemented with proper 404 on missing item
### Pass 2
Checked: all endpoints validate input
Found: PUT /items/:id accepts any body with no validation
Fixed: validates required fields, returns 400 with field-level errors
### Pass 3
Checked: all endpoints return correct response shapes
Found: PUT returns 200 empty body instead of updated resource
Fixed: returns the updated item

Fase 2: Verificación Profunda (10 Pasadas)

La Fase 2 no es lo mismo que la Fase 1. La Fase 1 comprueba el plan. La Fase 2 comprueba el código en sí, independientemente del plan, buscando cada problema de calidad y corrección que el plan no especifica pero que te va a morder en producción sin falta.

Diez pasadas, cada una con un foco concreto:

  • Pasada 1, implementaciones incompletas: TODOs dejados en el código, panics usados como stubs, funciones que devuelven valores cero sin explicación, comentarios que dicen «arreglar esto después»
  • Pasada 2, manejo de errores: cada error devuelto se comprueba, nada se descarta en silencio, los llamantes que necesitan saber de los fallos se enteran de verdad
  • Pasada 3, ciclo de vida de recursos: cada fichero, conexión, canal, goroutine y mutex tiene su close, cancel o señal de done correspondiente. traza cada uno desde su creación hasta su limpieza.
  • Pasada 4, corrección de la concurrencia: estado compartido accedido bajo locks, canales usados en la dirección correcta por los dueños correctos, ninguna goroutine que corra para siempre cuando el contexto se cancela
  • Pasada 5, cobertura de tests: los tests prueban comportamiento de verdad. no solo que las funciones devuelven nil. no solo que un error es distinto de nil. que lo que se supone que hace la función pasa de verdad.
  • Pasada 6, seguridad: ninguna entrada externa sin validar, ningún secreto escrito en los logs, ninguna concatenación de cadenas SQL, ninguna traversía de rutas, ninguna credencial hardcodeada
  • Pasada 7, exactitud de la documentación: cada comentario de doc, cada sección del README, cada ejemplo, comprobados contra el código real que describen. si el código cambió y la documentación no, arregla la documentación.
  • Pasada 8, contratos entre componentes: cada interfaz entre componentes, quién es dueño de qué, quién cierra qué, qué tipos de error se esperan, está explícitamente casada por ambos lados
  • Pasada 9, ejecución del build y de los tests: ejecuta el linter de verdad. ejecuta los tests de verdad. compila el binario de verdad. no des por hecho que pasan porque pasaron la última vez.
  • Pasada 10, casos límite: entradas vacías, valores cero, valores máximos, cosas técnicamente válidas pero raras. acceso concurrente a estado compartido. qué pasa cuando falla una dependencia aguas abajo.

La Pasada 3 es donde se pilla el bug de cierre doble descrito antes. Traza cada canal: creado aquí, escrito aquí, cerrado en cleanup(). Luego mira al llamante: también cierra el canal después de que Stop() retorne. Cierre doble. Pánico en tiempo de ejecución. La Fase 2 Pasada 3 lo encuentra antes que producción.

Documenta cada hallazgo. Si una pasada no encuentra nada, escríbelo también, pero escribe algo concreto. «Pasada 4: comprobadas todas las goroutines. El pool de workers usa WaitGroup correctamente, todas las goroutines terminan al cancelarse el contexto, no se encontraron fugas.» No «pasada 4: todo bien». Demuestra que miraste.

Fase 3: Revisión Brutal

Esta es la fase más importante y la que tiene mayor retorno de la inversión.

Engendra una instancia de IA separada, un Claude fresco sin contexto del proceso de desarrollo, sin memoria de las decisiones de diseño, sin saber por qué se hicieron las cosas como se hicieron, sin inversión emocional en que ese código sea correcto, y dile que destroce la implementación.

El encuadre exacto importa. No le pidas que «revise el código». Dile:

Eres un revisor de código despiadado. Tu trabajo es encontrar cada defecto de esta implementación. Cada atajo. Cada sitio donde el código apenas cumple el requisito sin llegar a respetar su intención. Cada hueco en el manejo de errores. Cada suposición sin validar. Cada sitio donde el camino feliz funciona y cualquier otra cosa falla en silencio. Haz tres pasadas completas. Encuentra todo lo que está mal. No me digas qué está bien. Dime solo qué está mal y por qué está mal.

Esto no es teatro. Como se estableció antes, este encuadre sobreescribe el entrenamiento hacia la amabilidad y mete al modelo en modo crítico de verdad. Un revisor al que se pide educadamente encuentra los problemas obvios y los suaviza. Un revisor instruido despiadadamente caza.

El revisor vuelve con hallazgos. Así es como se ve un intercambio real:

Pasada 1 del revisor:

Issue 1: fetchData() retries on failure with no backoff. It retries immediately,
ten times in a row. A momentary network hiccup triggers ten rapid sequential
requests before giving up. This hammers the upstream service under exactly the
conditions where it's already struggling.
Issue 2: Config has a Timeout field that is never used. The HTTP client is
http.DefaultClient which has no timeout. Under a hung connection this function
blocks forever.
Issue 3: The error case test asserts err != nil and nothing else. Any error —
including a completely unrelated failure mode — makes this test pass. The test
is not testing what it claims to test.

Contrarrevisión del desarrollador:

Issue 1: Correct. Adding exponential backoff with jitter, starting at 100ms,
max 30s. Fixed.
Issue 2: Correct. The field was planned and never wired up. HTTP client now
uses the configured timeout. Fixed.
Issue 3: Partially agree. The test should assert the error type. It should NOT
assert the error message — that would make tests brittle and break every time
we improve wording. Changed to assert errors.Is(err, ErrNotFound).

La ida y vuelta continúa. Cuando el revisor vuelve con la pasada 2, o encuentra problemas nuevos o responde a los puntos de la contrarrevisión. Esto sigue hasta que ambas partes dejan de encontrar cosas nuevas.

No seas un pelele. Si el revisor dice que algo está mal y no estás de acuerdo, di por qué. El objetivo no es implementar cada crítica, es haber pensado explícitamente cada crítica. Cuando le llevas la contraria y tienes razón, has validado tu decisión. Cuando el revisor tiene razón y lo arreglas, has pillado un bug real. Entre los dos pilláis más de lo que pillaría cualquiera por separado.

Fase 4: Smoke Test a Todo, Como un Capullo Paranoico

Leer código y ejecutar código no son la misma actividad. Puedes revisar código tres horas y perderte por completo un modo de fallo que aparece en treinta segundos de ejecución. La Fase 4 exige ejecutar la cosa de verdad.

Arranca todo y asegúrate de que no se caga encima inmediatamente. Constrúyelo. Arranca cada servicio. Verifica que llega a un estado listo sin entrar en pánico, sin líneas ERROR en los logs de arranque, sin mensajes «TODO: arreglar antes de prod» imprimiéndose en stdout durante la inicialización.

Activa todos los logs de debug y léelos. Ejecuta con verbosidad máxima. Coge una petición y trázala de entrada a salida por cada componente que toca. ¿Coincide el flujo de ejecución con la arquitectura? ¿Ocurren las operaciones en el orden que diseñaste? ¿Hay líneas de log que dicen «intentando X» sin su correspondiente «X tuvo éxito» o «X falló», lo que significa que X no hizo nada en silencio y nadie lo sabe?

Golpea cada ruta de código, incluidas las malas. No compruebes solo el camino feliz. Manda entrada malformada. Manda entrada vacía. Manda una lista vacía donde se espera una lista. Manda una cadena de diez mil caracteres donde se espera un nombre. Manda el tipo correcto con el valor equivocado. Manda un cero donde se requiere un entero positivo. Verifica que el sistema maneja cada caso explícitamente, con una respuesta de error en condiciones, en vez de petar o producir salida equivocada en silencio.

Comprueba la base de datos directamente. Conéctate. Mira las tablas. Cuenta las filas. Lee los valores. Confirma que lo que se escribió coincide con lo que se envió. Esto pilla la clase de bug donde la función devuelve nil y todo parece bien pero la escritura se descartó en silencio, una transacción que nunca se confirmó, una escritura que fue a una caché que nunca se vació. La API devolvió 200. Los datos no están.

Lee cada fichero de log después de la ejecución. Busca cualquier cosa que empiece por ERROR, WARN, PANIC o FATAL y que no hayas disparado explícitamente. Un sistema que «funciona» pero produce avisos intermitentes en los logs no funciona. Está fallando despacio y con educación.

Documenta qué probaste y qué encontraste. «Arrancado con –debug. Trazado POST /items. Encontrado: la entrada del log de auditoría se escribe antes de que la transacción de BD se confirme. Si la escritura en BD falla después de la escritura del log de auditoría, el log muestra una operación exitosa que nunca ocurrió. Arreglado: movida la escritura del log de auditoría a después de la confirmación de la transacción.»

Fase 5: Verificación Final (10 Pasadas Más)

Diez pasadas más. Código, tests, logs, documentación, configuración, todo otra vez.

A estas alturas todos los problemas mayores deberían estar arreglados. La Fase 5 es para residuos. El mensaje de error actualizado en el código pero no en la documentación. El helper de test copiado de otro sitio que todavía tiene el nombre de paquete equivocado en su salida de error. El ejemplo de configuración que referencia un campo renombrado en la Fase 3 y nunca actualizado en el ejemplo.

Si la Fase 5 sigue pillando problemas de arquitectura o comportamiento roto, para. Vuelve a la Fase 3. Algo no se arregló de verdad. Las fases siguientes lo enmascararon, no lo resolvieron.

Añade a ANUSTIMES.md. Cuando la Fase 5 termina, el fichero es un rastro de auditoría completo: qué se planeó, qué estaba mal en la primera versión, qué se encontró en cada fase, qué se hizo al respecto.

Por Qué Cinco Fases Separadas y No Una Revisión Grande

Cada fase pilla una clase concreta de error. Las clases no se solapan lo bastante limpio como para fusionarlas.

La Fase 1 pilla errores de omisión, cosas planeadas pero no construidas. Una revisión de código no puede pillarlas, porque revisas lo que está, no lo que falta.

La Fase 2 pilla errores de calidad, cosas construidas incorrectamente. Revisión de código estándar. La estructura de diez pasadas fuerza una concreción que una pasada única se salta por cansancio.

La Fase 3 pilla errores de racionalización, cosas que sabes que están mal pero de las que te convenciste que eran aceptables. El revisor externo no tiene memoria de tu razonamiento ni motivación para ser generoso con él.

La Fase 4 pilla errores de integración, cosas individualmente correctas que fallan en funcionamiento. Invisibles en revisión de código. Visibles solo al ejecutar.

La Fase 5 pilla errores de reparación, bugs nuevos introducidos al arreglar los errores encontrados en fases anteriores. Cada arreglo es una cagada nueva en potencia.

Una única revisión exhaustiva maneja la Fase 2 razonablemente bien. Pilla la Fase 1 de forma irregular. Se salta casi toda la Fase 3. Estructuralmente no puede pillar la Fase 4. Y genera errores de Fase 5 como efecto secundario de arreglar cosas. La estructura de cinco fases existe porque estos modos de fallo son distintos y exigen enfoques distintos.

El Fichero ANUSTIMES.md

Cada hallazgo va a ANUSTIMES.md, en la raíz del proyecto. El formato:

## Phase 1 — Self-Review
### Pass 1
Checked: [what you looked at]
Found: [what was wrong]
Fixed: [what you changed]
## Phase 2 — Deep Verification
### Pass 1 (Incomplete implementations)
Checked: [...]
Found: [...]
Fixed: [...]
## Phase 3 — Brutal Review
### Reviewer Pass 1
[reviewer findings verbatim]
### Developer Counter-Review Pass 1
[your responses and what you fixed]
### Reviewer Pass 2
[...]
## Phase 4 — Smoke Test
### Startup
### Endpoints
### Database
### Logs
## Phase 5 — Final Verification
### Pass 1
[...]

Este fichero no es una formalidad. Es la prueba de que la verificación ocurrió y de qué encontró. Un desarrollador futuro, o un agente de IA futuro que coja el proyecto, puede leer ANUSTIMES.md y saber exactamente qué estaba mal en la implementación inicial y qué se hizo al respecto. Hace visible la distancia entre el primer borrador y el envío.

Cuándo Ejecutarlo y Cuándo Saltárselo

ANUSTIMES tiene un coste. No lo ejecutes en un arreglo de tres líneas.

Ejecútalo cuando:

  • El trabajo tenía un plan explícito con varios pasos
  • Se crearon o cambiaron significativamente varios ficheros
  • Varios agentes de IA construyeron componentes que tienen que funcionar juntos
  • La salida corre en producción o la usan otros sistemas
  • Un fallo completo causaría daño real, a usuarios, a datos, a producción

Sáltatelo para:

  • Arreglos de bugs en un solo fichero
  • Cambios de documentación
  • Ajustes de configuración
  • Cualquier cosa que puedas verificar del todo leyendo el diff y ejecutando un comando

La pregunta siempre es: si esto está mal, ¿cómo de mal está? Radio de explosión pequeño, sáltatelo. Radio de explosión grande, ANUSTIMES.

Lo Que Esto Arregla De Verdad

El desarrollo asistido por IA rompió el bucle normal de verificación.

En el desarrollo tradicional, generación y verificación están enredadas. El desarrollador escribe una función y la ejecuta inmediatamente para ver si funciona. Siente inquietud por un caso límite y vuelve atrás. Escribe el test y descubre que el test no pasa, y eso le dice algo. El bucle de retroalimentación entre escribir y comprobar es estrecho, continuo e integrado en el proceso por cómo trabajan los humanos de forma natural.

En el desarrollo asistido por IA, sobre todo en sistemas multiagente, generación y verificación están estructuralmente separadas. Un agente planea. Otros agentes construyen. La construcción ocurre en paralelo, en contextos aislados, sin que ningún agente experimente el sistema entero funcionando. La fase de generación es rápida y capaz. La fase de verificación está ausente a menos que la construyas explícitamente.

Si la verificación no es una actividad deliberada, estructurada y documentada, con fases definidas y salidas explícitas, no ocurre. O ocurre de forma perezosa, pillando los problemas obvios mientras los sutiles se van a producción.

ANUSTIMES es un arreglo estructural para un problema estructural. El lenguaje agresivo no es estilo, es el mecanismo que hace que la IA verifique de verdad en vez de fingir que verifica. Las fases múltiples no son redundancia porque sí, son el conjunto mínimo de lentes distintas que hacen falta para pillar las clases distintas de cagada que el desarrollo asistido por IA produce con fiabilidad.

La generación es rápida. Haz que la verificación siga el ritmo. O envía el pánico de las tres de la mañana y descubre por las malas por qué existe este proceso.