Cola de revisión con triage automático
PR Review Console
Por cada pull request que te espera, decide qué hacer con él y después hace la parte segura.
- Rol
- Autor principal, junto a dos compañeros
- Período
- ago. 2026 – hoy
- Estado
- En uso diario
- Código
- Privado, hecho en Enara Health
- de 420 commits son míos
- 330
- funciones de prueba
- 2.827
- filas de la cola decididas solo por reglas
- 47 de 49
- veredictos publicados coincidieron con el modelo en modo sombra
- 8 de 8
- Python
- FastAPI
- htmx
- SQLite
- Claude Code
- GitHub
- Bitbucket
01 Contexto
Por qué existe
La cola de revisión de un tech lead puede llegar a setenta y tantos pull requests abiertos entre GitHub y Bitbucket, y la mayoría no necesita la revisión de esa persona. El costo real es decidir, cada mañana, qué código leer. Una migración de 30 líneas tiene más prioridad que un refactor de interfaz de 900. Un pull request apilado sobre un padre sin revisar no se puede revisar hasta que el padre avance. Uno que aprobaste la semana pasada sigue apareciendo como si te necesitara.
Reemplazó a un clasificador basado en un modelo que producía una foto del momento y la olvidaba. Lo que el revisor necesita, en cambio, son tres cosas: en qué estado está cada pull request, cuánta atención merece y qué cambió desde la última vez que miró.
02 En uso
Qué hace
La app real, llena de pull requests de una empresa inventada y corriendo con todos los workers apagados. La cola la clasificó el propio motor de reglas.
03 Arquitectura
Cómo funciona
Una app FastAPI local recolecta la cola periódicamente, decide cada fila con un motor de reglas puro y le pregunta a un modelo solo por las pocas filas que las reglas no logran resolver. Las revisiones corren como sesiones headless de Claude Code y se transmiten al navegador. Solo la propia consola publica en GitHub o Bitbucket.
-
Recolectar por niveles
Un solo ciclo hace toda la recolección. Cada tres minutos corre una búsqueda y enriquece solo los pull requests cuya hora de actualización cambió; una pasada más liviana y un barrido completo corren con menos frecuencia. Las observaciones van a SQLite.
-
Tres tipos de estado, un escritor para cada uno
Lo que dijo la forja, lo que hizo la persona y lo que decidieron las reglas viven en familias de columnas separadas. El upsert del recolector nunca nombra una columna de usuario, y una prueba lo verifica byte por byte.
-
Primero las reglas
Una función pura, sin I/O y sin reloj, clasifica cada fila en actuar, revisar, delegar, bloqueado, observar o borrador, y le asigna una prioridad. Cada decisión lleva un id de regla, un motivo hecho con plantilla y la versión de las reglas. Para dos decisiones que requieren criterio, lee el diff real.
-
Un modelo para la franja ambigua
Solo las filas que las reglas no logran resolver, y cuya señal cambió, van al modelo, en una sola llamada en lote con presupuesto y timeout. La respuesta se revisa contra overrides estrictos, y se descarta si rompe alguno.
-
Revisiones como sesiones headless
Una revisión es una ejecución headless de Claude Code: un orquestador con un modelo potente reparte el trabajo entre especialistas elegidos según lo que toca el cambio, como seguridad, rendimiento o datos. La salida se guarda antes de transmitirse al navegador, y el veredicto vuelve en un archivo estructurado, no extraído de la prosa.
-
Publicar sin un modelo
Una persona envía desde el diálogo, o la consola publica sin supervisión si una política revisada por repositorio permite ese veredicto y pasan cinco controles: el head no se movió, todavía no respondiste, ninguna revisión está esperando tu respuesta, una solicitud de cambios no se envía sin supervisión (salvo dos excepciones acotadas) y sale una sola publicación por ciclo.
04 Decisiones
Las decisiones que le dieron forma
-
Decisión 01
Triage determinista, con el modelo solo para una franja ambigua
- Elegí
- Un motor de reglas, con el modelo como asesor dentro de una zona acotada.
- En vez de
- El enfoque anterior, en el que un modelo clasificaba toda la cola.
- Porque
- Se midió. En una cola congelada de 49 pull requests, el modelo y las reglas coincidieron en 45, y las reglas acertaron en los cuatro desacuerdos. Además, las reglas son reproducibles, no cuestan nada y dan motivos estables; un motivo redactado de otra forma inundaría el feed de cambios.
- Costo
- Las reglas tienen que seguir la política a mano: subir el tope de tamaño cambió una fila fijada en la prueba golden. Parte de la ventaja vino de calcular hechos que el pipeline anterior nunca tuvo, como si ya lo aprobaste.
-
Decisión 02
Ningún modelo en la ruta de publicación; ampliar la autonomía midiendo
- Elegí
- Una revisión propone; un archivo de políticas revisado decide si ese veredicto puede salir sin supervisión. La publicación sin supervisión viene apagada por defecto y corrió primero en modo sombra.
- En vez de
- Dejar que el skill de revisión publique, y publicar solicitudes de cambios sin supervisión, lo que iniciaría un ciclo de nuevas revisiones que el interruptor de pausa no alcanza a detener.
- Porque
- En modo sombra, de los ocho veredictos que una persona publicó de verdad, la persona coincidió con el modelo en los ocho y dejó el texto sin cambios en los ocho.
- Costo
- Pierdes la mirada de último segundo, y se necesitan varios controles para que publicar sin supervisión sea seguro.
-
Decisión 03
Control de admisión que cuenta la máquina entera
- Elegí
- Una revisión empieza solo si la CPU y la memoria de toda la máquina están bajo sus topes, contando también las revisiones que iniciaron otras sesiones.
- En vez de
- Una cola de tareas como Celery o RQ, o un límite de concurrencia dentro de la app.
- Porque
- Varias sesiones abrieron cada una unos ocho subagentes y la máquina se quedó sin CPU ni memoria. Un límite por app no sirve cuando nada de la carga es de la app.
- Costo
- Las revisiones ajenas se reconocen por su línea de comandos, lo que es frágil y está fijado con pruebas.
-
Decisión 04
Supervisar como OTP, no como cron
- Elegí
- Un supervisor dentro del proceso con hijos permanentes, transitorios y temporales, backoff exponencial y escalamiento después de cinco reinicios en un minuto.
- En vez de
- Tareas de cron o una biblioteca de planificación.
- Porque
- Una vez un ciclo de monitoreo se detuvo en silencio, y una instancia de respaldo sirvió una cola desactualizada durante 67 horas.
- Costo
- Un supervisor propio y una elección de líder que mantener.
-
Decisión 05
Revisores independientes en distintas cuentas de Claude
- Elegí
- Varias cuentas con asignación lineal, round-robin o balanceada por carga, y una regla estricta: una cuenta que escribió código en un pull request no puede revisarlo.
- En vez de
- Roles fijos por cuenta, con lo que una cuenta de revisión agotada se volvía un callejón sin salida.
- Porque
- Las revisiones siguen saliendo cuando se acaba el plan de una cuenta, y nada evalúa su propio trabajo.
- Costo
- Las sesiones quedan fijadas a la cuenta que las creó.
05 Lo interesante
Vale la pena mirarlo de cerca
-
El resultado de reglas contra modelo es una prueba
La prueba golden corre el motor sobre la cola congelada de 49 filas y compara el resultado con lo que dijo el modelo. Nombra cada desacuerdo, así que un cambio a las reglas tiene que discutir con evidencia registrada.
-
Honesto sobre dónde se filtra el límite
La documentación enumera dónde «el modelo nunca publica» no es hermético: un panel de asistente puede publicar si se le pide, y autorizar un comando de la CLI autorizaba escrituras. Restringir las escrituras terminó siendo un hook fail-closed, porque los flags de permisos documentados no las restringían.
-
Aprendido corriendo la CLI
Un flag de presupuesto es un cortacircuitos, no un tope: se revisa entre turnos, y una ejecución medida gastó unas 3,8 veces un límite pequeño. La señal de salud resultó ser la cuenta de permisos denegados, no el flag de error.
-
Escalar el hallazgo, no el agente
Los especialistas corren en un modelo más barato y el orquestador mantiene el potente. Un hallazgo que necesita pensarse más va a un asesor con el modelo más potente, como máximo tres veces por revisión.
06 Hecho con agentes
Cómo encajan los agentes
La mayor parte del código se escribió con Claude Code: 332 de los 420 commits llevan el trailer de coautor de Claude, 247 de ellos entre mis 330. Escribí el motor, el nivel del modelo, la supervisión, la admisión, el balanceo de cuentas, la revisión y la publicación sin supervisión, y el servidor MCP; un compañero construyó gran parte del diálogo de revisión y de las páginas.
Este repositorio no tiene archivo de reglas. Lo que hace de contrato es una guía corta para pull requests: decir lo que se midió, y nunca más que eso. Cada falla que enumera es una exageración típica de un agente, y los pull requests los revisa un agente de Claude además de personas. Dos veces, ese agente corrigió una afirmación hecha en un mensaje de commit.
La app también usa agentes intensivamente: revisiones completas con carriles de especialistas, chequeos rápidos, predicciones antes de una revisión, correcciones de comentarios de revisión en una cuenta aparte y conversaciones que se pueden retomar cuando una persona tiene que decidir.