Serie: Aprender a programar con IA

Gemini revisó el PR de Claude. Treinta y seis comentarios después, era mejor.

Revisión multi-proveedor detectando dos bugs de thread-safety antes de llegar a producción.

Modelo distinto, puntos ciegos distintos Revisión entre proveedores a través de ocho subsistemas Claude escribe Gemini revisa 36 comentarios 2 bugs reales detectados thread-safety, habrían llegado a producción El humano decide — ni Gemini, ni Claude
Claude escribe. Gemini revisa. El humano fusiona. Los bugs pierden.

Un revisor que siempre está de acuerdo con el autor no es un revisor. Somete el código de tu IA a una IA rival y los puntos ciegos se iluminan, incluidos los bugs de thread-safety que habrían llegado a producción.

El patrón al que sigo volviendo es aquel en el que Claude escribe el código y Gemini lo revisa. Entrenamiento distinto. Puntos ciegos distintos. Opiniones distintas sobre qué es un patrón defendible y qué es un mal olor. Este sábado fue la demostración más concreta de por qué creo que este patrón es el correcto.

Un lote de PRs de expansión de endpoints de Fase 2 había aterrizado en toda la superficie de la API durante la semana anterior. Ocho subsistemas separados tuvieron su superficie pública expandida. Claude había escrito la mayor parte de la implementación. Antes de fusionar cualquiera de ellos, los pasé por Gemini como pase de revisión. Gemini regresó con treinta y seis comentarios específicos a lo largo del lote.

Trabajé en cada uno de ellos. Este es el post sobre lo que Gemini detectó y qué significa que las detecciones fueran del tipo de detecciones que fueron.

Cuáles eran los ocho subsistemas

Los PRs cubrían los ocho módulos de router de API que necesitaban expansión de Fase 2: animación, red, audio, percepción de IA, geometría sólida constructiva de escena, bindings de acción de entrada y gamepad, tipos de pose de anclaje XR, y ciclo de vida de la VM de Lua de scripting. Cada PR añadió entre una docena y cuarenta endpoints, con esquemas completos de solicitud/respuesta, helpers y pruebas.

Los PRs no eran sutiles. Cada uno fue una expansión sustancial de la superficie pública. Juntos representaban varias semanas de trabajo de diseño que los agentes implementaron a lo largo de aproximadamente dos fines de semana.

Qué detectó Gemini

Quiero ser específico porque las categorías importan.

Animación y red: referencias de blend tree y helpers. Gemini notó que los helpers de blend tree en la API de animación y los helpers de topología en la API de red tenían convenciones sutilmente distintas para manejar referencias faltantes. Animación devolvía un equivalente a None y dejaba que el llamador decidiera. Red lanzaba una excepción. Ambos son patrones válidos. Eran inconsistentes entre dos PRs que aterrizaron con un día de diferencia. La solución fue alinearlos; elegimos el camino de excepción explícita porque expone la referencia faltante en el límite de la API en lugar de dejar que se propague como un nulo silencioso.

Audio: valores por defecto de modelos de respuesta y helpers. Gemini encontró que varios modelos de respuesta de audio tenían valores por defecto inconsistentes para campos opcionales. Algunos usaban por defecto cadenas vacías, otros None, otros un null explícito. La inconsistencia habría producido comportamiento confuso en la capa de bindings de cliente (donde distintos lenguajes serializan cada opción de forma diferente). La solución fue elegir una única convención (None en los tipos de Python, null en el cable) y aplicarla de forma consistente.

Percepción de IA: mapas de handles y bindings. Gemini señaló una preocupación de thread-safety en el mapa de handles del subsistema de percepción: el mapa se mutaba desde un hilo en segundo plano mientras se leía desde el hilo de solicitud de la API, sin un lock. Bajo carga, esto produciría bugs intermitentes de corrupción de mapa muy difíciles de diagnosticar. La solución fue un lock de lector-escritor con la ruta de lectura optimizada para el caso común (las búsquedas superan ampliamente en número a las inserciones).

Escena: mapas de handles y respuestas de CSG. Misma familia de bug que el hallazgo de percepción de IA. Gemini detectó la misma preocupación de thread-safety en el mapa de handles de CSG del subsistema de escena. La solución tuvo la misma forma: un lock de lector-escritor. Este es el tipo de bug que un conjunto de ojos entrenados señala en todas partes porque ha visto el patrón; Claude había escrito el mismo patrón en dos lugares y no lo había notado.

Entrada: bindings de acción y gamepad. Gemini encontró que la API de binding de acción usaba una convención de número mágico para IDs de acción inválidos (-1), mientras que la API de binding de gamepad usaba un valor centinela de struct. La inconsistencia produciría bugs sutiles cuando un desarrollador trabajando en ambas APIs usara accidentalmente el marcador de inválido equivocado. La solución fue introducir una constante tipada ActionId::Invalid en ambas APIs y migrar todos los números mágicos a ella.

XR: tipos de pose de anclaje y reutilización de handlers. Gemini detectó que la API de XR exponía dos tipos de pose sutilmente distintos en diferentes endpoints: uno en coordenadas de mundo y otro en coordenadas locales al anclaje. La diferencia es real e importa al consumidor, pero los endpoints no documentaban la diferencia con claridad. Gemini sugirió dividir los tipos para que el sistema de tipos haga cumplir la distinción. La solución fue introducir WorldPose y AnchorPose como tipos distintos sin conversión implícita entre ellos.

Scripting: ciclo de vida de la VM de Lua y fugas. Gemini encontró que la VM de Lua se asignaba por solicitud sin una ruta de desmontaje clara. Bajo carga sostenida, esto filtraría estado de VM en el espacio de direcciones hasta que el servidor de la API colapsara. La solución fue introducir un pool de VMs por hilo de servidor con semántica explícita de adquisición y liberación, y añadir una ruta de desmontaje que se ejecuta al completarse la solicitud, sin importar éxito o fallo.

Lo que noté sobre las detecciones como categoría

Tres observaciones.

La mayoría de las detecciones fueron detecciones de consistencia. Dos tercios de los comentarios de Gemini eran “esta convención difiere de la convención usada en otro subsistema que acabas de aterrizar.” Este es exactamente el tipo de detección en el que un solo modelo es malo, porque cada PR aterrizó de forma aislada y el modelo que lo escribió no tenía los otros PRs en su contexto. Un revisor que trabaja a través del lote ve las inconsistencias que el autor no tenía presentes.

Algunas detecciones fueron bugs genuinos. Los hallazgos de thread-safety en los mapas de handles fueron bugs reales. Habrían llegado a producción. Habrían sido intermitentes y difíciles de diagnosticar. Gemini detectó ambas instancias en el lote (una en percepción de IA, otra en CSG de escena) porque tenía el reconocimiento de patrones para “mapa mutable compartido sin lock = preocupación de thread-safety.” Modelo distinto, entrenamiento distinto, cosas distintas para las que ha sido calibrado a señalar.

Algunas fueron estilísticas y se debatieron. No todos los comentarios de Gemini eran correctos. Un puñado fueron preferencias estilísticas a las que o bien me opuse o pedí juicio humano. El hecho de que algunos comentarios fueran rechazados no debilita el patrón; lo refuerza. Un revisor que siempre está de acuerdo con el autor no es un revisor.

Qué hace esto y qué no hace

Lo que hace: detectar una clase de bugs que la revisión de un solo modelo pasa por alto. Específicamente los bugs de consistencia entre PRs y las detecciones por reconocimiento de patrones donde un revisor entrenado con datos distintos señala algo que el entrenamiento del autor no vio.

Lo que no hace: reemplazar la revisión humana. Los comentarios de Gemini fueron un primer pase. Leí cada uno. Rechacé algunos. Acepté la mayoría. La decisión final de fusión fue mía. El patrón es “Claude escribe, Gemini revisa, el humano decide.” No “Gemini decide.”

Lo que sugiere para los laboratorios de IA: la métrica a optimizar no es “el código propio del modelo pasa su propia revisión.” Es “el código del modelo pasa la revisión de un modelo de otro proveedor.” Los agentes que rinden bien en la métrica entre proveedores son en los que confío para trabajo serio.

Qué deberían llevarse los socios y constructores de esto

Si estás ejecutando un flujo de trabajo impulsado por agentes y aún no estás pasando la revisión de PR por el modelo de un proveedor distinto, pruébalo en el próximo lote. El costo de configuración es bajo. La tasa de detección de bugs es no trivial. El lote de hoy detectó dos bugs reales de thread-safety que habrían llegado a producción.

Si eres un laboratorio de IA y no has optimizado tu agente de codificación para “revisión de PR contra el modelo de otro proveedor” como objetivo, considéralo. La métrica es honesta. La señal es real. Los agentes que puntúan bien en ella son los que los equipos serios adoptarán.

Si estás evaluando un motor para una asociación, el patrón de revisión multi-proveedor es una de las señales de disciplina que preguntaría. Un equipo que ejecuta revisión entre proveedores en cada PR significativo es un equipo distinto de uno que no lo hace. La base de código refleja la diferencia.

Treinta y seis comentarios, ocho subsistemas, un sábado. El lote es mejor de lo que era esta mañana. El patrón demuestra su valor, otra vez.

De vuelta a construir.

El runtime con el que revisan los laboratorios de IA, y sobre el que construyen

RakuAI es el runtime espacial contra el que los creadores de LLM distribuyen. Revisión entre proveedores, métricas honestas, disciplina de nivel socio. Descubre dónde encajan tus modelos en el mundo real.

← Todas las entradas