1.000 Pull Requests en un Proyecto: Lo Que Aprendi Construyendo Solo un Sistema Que un Centro de Servicio Usa Todos los Dias
Abri el pull request numero 1.000 de un sistema que un centro de servicio de motos usa todos los dias, construido solo en 278 dias. No es una celebracion del numero: el flujo detras de cada PR, las pruebas que vigilan decisiones, cinco bugs que rompieron en produccion y lo que haria distinto.

1.000 Pull Requests en un Proyecto: Lo Que Aprendi Construyendo Solo un Sistema Que un Centro de Servicio Usa Todos los Dias
En mis proyectos personales un pull request era un evento. Abria dos o tres por mes, los mergeaba yo mismo sin que nadie los mirara, y la rama main era mas una costumbre que una regla. Esta semana abri el PR numero 1.000 del mismo repositorio. No es un proyecto de juguete: es el sistema con el que un centro de servicio de motos en Antioquia recibe motos, cotiza, cobra, factura y liquida comisiones. Lo construi solo, de enero a octubre de 2026.
Este post no es una celebracion del numero. Es lo que el numero me obligo a aprender: como se trabaja cuando cada cambio lo va a usar alguien a las ocho de la mañana con una moto al frente y el cliente mirando por encima del hombro.
Que es el sistema
Empezo como una tienda en linea de repuestos y accesorios. Hoy son tres cosas que comparten una sola base de datos:
- La tienda: catalogo, carrito, pagos con pasarela y contra entrega, feed para Google Merchant, reseñas.
- El centro de servicio: la parte grande. Ordenes de servicio con fotos y videos desde el telefono, marcas de daño sobre la foto, cotizaciones que el cliente aprueba desde un enlace, citas, inventario con canastas fisicas, repuestos pedidos por el tecnico, comisiones por tecnico con tramos, garantias de la marca, procesos escritos, una bandeja de pendientes por persona y un agente de IA que sabe que hay en cada modulo.
- La contabilidad: plan de cuentas, asientos automaticos por cada venta y compra, kardex, facturacion electronica ante la DIAN, estados financieros.
Todo eso lo usa un equipo de quince personas desde una PWA instalada en el telefono, con datos moviles, en un centro de servicio donde la señal no siempre acompaña.
Las cifras, porque un «listo» sin cifras no se puede contradecir
Saque estos numeros del repositorio el dia que abri el PR 999.
| Dato | Valor |
|---|---|
| Primer commit | 11 de enero de 2026 |
| Dias transcurridos | 278 |
| Pull requests mergeados | 985 |
Commits en main | 3.052 |
| Lineas de TypeScript | 466.645 |
| De ellas, en pruebas | 150.578 (un tercio) |
| Pruebas automaticas | 9.968 (backend 5.521, frontend 4.447) |
| Migraciones de base de datos | 287 |
El ritmo no fue parejo. Nueve PRs en enero, cincuenta en marzo, ciento y pico en abril, julio y agosto, y 340 en septiembre, el mes en que el centro de servicio empezo a operar con el sistema y cada dia traia tres o cuatro cosas que arreglar antes de la tarde. Octubre va en 183 y no ha terminado.
Ese salto de septiembre es la parte que mas me gusta del grafico, y la que mas me costo. Un sistema en produccion no se mide por lo que construiste, sino por que tan rapido puedes corregir lo que el uso real te muestra.
Como es un pull request en este proyecto
La regla que mas cambio mi forma de trabajar fue esta: un cambio, una rama, un PR. Nada de «ya que estoy aqui arreglo esto otro». Si en medio de un arreglo aparece otro problema, se anota y se abre otra rama. Suena obvio. No lo era para mi.
El flujo de cada PR es el mismo desde hace meses:
- La rama sale de
uat, nunca de la rama local que tenga a mano. - Antes de empujar, corren las suites completas de backend y frontend como las corre el CI: lint, tipos, pruebas unitarias, pruebas de integracion contra una base real y el build. Si algo falla, no se empuja. No «despues lo arreglo».
- El PR va a
uat, un ambiente identico a produccion con su propia base y su propio servidor. Ahi pruebo con el mismo telefono que usa el equipo, con datos moviles. - Cuando lo que se ve en el telefono es lo que se queria, abro un segundo PR de
uatamain. Ese es el que llega a produccion. - La tarea del tablero pasa a «hecho» solo cuando el commit esta de verdad en
main. No cuando el PR dice «merged», que no es lo mismo, y eso lo aprendi perdiendo dos modulos completos.
Y una regla que parece de paranoico hasta que te pasa: abierto el PR, esa rama se cierra para mi. Si sale otro arreglo, va en otra rama. Porque el PR se mergea en minutos, y lo que empuje despues del merge se queda huerfano fuera de main mientras yo creo que ya esta desplegado.
Las pruebas que vigilan, no las que decoran
Un tercio del codigo son pruebas. Pero el numero esconde lo importante: que tipo de pruebas.
Hay 139 pruebas que no ejecutan nada. Leen el archivo fuente y comprueban que una decision siga escrita ahi. Por ejemplo: que el boton de la camara nunca se apague mientras una foto sube, que la pantalla de marcar daños sea el mismo componente en la ficha de la orden y en el ingreso, que ninguna consulta compare un timestamp sin zona contra la hora de Bogota sin el doble AT TIME ZONE. Cada una nacio de un bug que el equipo reporto por WhatsApp. Son guardianes: no prueban que algo funcione, prueban que nadie deshaga a proposito o por descuido una decision que costo cara.
Lo que aprendi diseñandolas: un guardian que enumera no vigila. Una prueba que lista los seis estados esperados se rompe el dia que agregas el septimo y te obliga a editarla, y editarla es la oportunidad de dejar pasar el error. Un guardian que barre la lista real y exige que cada elemento cumpla una regla envejece bien.
Cinco cosas que me rompieron en produccion
Esto es lo que de verdad vale de 1.000 PRs. Cada una tiene su prueba hoy.
1. Un consecutivo se mira, no se cuenta. Los numeros de orden se generaban contando filas: ORD-2026- mas la cantidad de ordenes mas uno. Dos personas recibiendo motos a la misma hora crearon dos ordenes con el mismo numero. El consecutivo vive en una secuencia de la base de datos, y la aplicacion lo lee; nunca lo calcula.
2. Una prueba con la fecha de hoy es una bomba de tiempo. Una prueba del cierre de mes usaba new Date(). Paso durante tres semanas y fallo el primer dia del mes siguiente, en el CI, bloqueando un arreglo urgente que no tenia nada que ver. Las fechas en las pruebas se escriben a mano, y las pruebas corren en UTC aunque el portatil este en Bogota.
3. Dos relojes no se comparan. La fecha de entrega de una orden se guardaba como timestamp sin zona. Al convertirla a hora de Bogota de la forma obvia, las entregas de despues de las dos de la tarde saltaban al dia siguiente. Septiembre perdio el dia 30 completo en el reporte de ventas, y el dueño del centro de servicio tenia razon cuando decia que los numeros no cuadraban.
4. «Merged» no significa «esta en main». Abri tres PRs apilados, uno sobre la rama del otro, y le dije al dueño que GitHub los reapuntaria solos. Falso. Los tres aparecieron como mergeados y solo el primero llego a main. Faltaban dos modulos completos y dos migraciones, y nada fallaba porque el codigo no estaba y sus pruebas tampoco. Desde entonces, despues de cada merge, compruebo el arbol de main, no la lista de PRs.
5. Esconder las dos puntas de una anulacion mueve el mes cerrado. Al anular una venta de un mes ya cerrado, lo facil era esconder la venta y su anulacion. Eso cambia el total de un mes que el contador ya reporto. Las dos puntas se ven: la venta queda en su mes y la anulacion en el suyo.
Ninguna de estas es un bug exotico. Son los errores de alguien que construye solo y rapido. El PR numero 1.000 no es la prueba de que ya no los cometo; es la prueba de que cada uno dejo una regla escrita para no repetirlo.
Construir solo no es construir sin equipo
No habria llegado a este ritmo sin agentes de IA trabajando como par de programacion. Pero la palabra importante es par, no autocompletar. Un modelo sin contexto refactoriza lo que no pediste, inventa features y hace commits por su cuenta. Lo escribi largo en el post sobre el harness; aqui va la version corta de lo que hace que funcione en este proyecto:
- Reglas que no se negocian, escritas en un archivo que el agente lee en cada sesion: no hacer commits solos, no refactorizar fuera del alcance, nunca empujar a
main, los merges los hago yo, cada cambio es un spec y una rama. - Una memoria de lecciones: hoy son 68 archivos, uno por cada correccion que le hice o que el uso real me hizo a mi. «Un consecutivo se mira, no se cuenta» es uno de ellos. El agente los consulta antes de tocar una zona del codigo que ya mordio.
- Puntos de parada obligatorios: antes de implementar se declara el alcance, antes de mover una tarea del tablero se pregunta, y un «ya esta arreglado» no se dice hasta comprobar el commit en
main. - Un tablero de tareas con spec: cada PR nace de una tarea con un spec tecnico escrito antes del codigo. El spec dice que se construye, que queda por fuera y como se prueba. Eso es lo que convierte 1.000 PRs en un historial que se puede leer, y no en 1.000 parches.
La IA pone velocidad. El criterio sobre que construir, en que orden y bajo que estandar sigue siendo mio, y es lo que el harness hace portable.
El flujo agentico, de punta a punta
Nada de lo anterior funciona si cada PR nace de un chat suelto. Lo que sostiene el ritmo es un flujo donde los agentes, el tablero de tareas y el repositorio hablan entre si, y yo estoy en los puntos donde se decide.
Asi se lee:
- Yo describo la mejora en una frase, y el Spec Writer no se pone a escribir codigo: lee el codigo real del proyecto, hace las preguntas que haga falta y escribe un spec tecnico, con alcance, lo que queda por fuera y como se prueba. Ese spec se convierte en una tarea del kanban interno de WillDevp a traves de su API. El tablero es la unica fuente de verdad de que hay por hacer.
- Cuando pregunto que sigue, el Tech Lead lee el tablero por la misma API, cruza prioridades y me recomienda. No decide por mi: me da el mapa.
- Con el id de la tarea, el Implementer trae el spec, lo compara con el codigo que existe hoy (lo que yo llamo el gap analysis) y construye. Con paradas obligatorias: declara el alcance antes de tocar nada y no mueve la tarea de columna sin que yo lo confirme. Sale una rama desde
uaty un PR. - El agente de QA corre las pruebas de navegador contra un ambiente levantado antes de que yo pruebe a mano.
- Los merges los hago yo, los dos: a
uaty, despues de probar con el telefono, amain. Cuando digo «ya hice merge», la tarea pasa a hecho por la API, y solo despues de comprobar que el commit esta en el arbol demain. - Todo lo que me corrige o me corrige el uso real vuelve a la memoria del harness como una leccion con su porque y su como aplicarla. La siguiente sesion arranca sabiendola.
El kanban es el mismo tablero con el que llevo todos los proyectos de WillDevp, asi que el flujo no es un invento para este sistema: es como trabajo. Lo que cambio en 1.000 PRs es que ya no hay un paso que dependa de que yo me acuerde.
Lo que haria distinto
Tres cosas, con honestidad.
Pruebas de extremo a extremo desde el primer mes. Las pruebas unitarias y de integracion llegaron temprano; las de navegador llegaron tarde y hoy son 19 contra 10.000 de las otras. El bug de las fotos que se perdian con datos moviles no lo habria cazado ninguna prueba unitaria. Lo cazo el dueño del centro de servicio con su telefono.
Medir antes de optimizar. Pase dos dias convencido de que la subida de fotos era lenta por el servidor. Cuando por fin puse medicion en cada tramo, el servidor gastaba 650 milisegundos y el telefono gastaba tres segundos achicando cada foto. La respuesta estaba en el lado que no estaba mirando.
Un cambio de regla obliga a barrer. Agregar un rol o un estado nuevo parece una linea. Es una linea mas todos los sitios que enumeran los roles o los estados, y se descubren uno por uno en produccion. Hoy hay una prueba que falla si aparece un valor nuevo del enum y algun lector no lo contempla. Debio existir desde el principio.
El PR 1.000
Sera un cambio pequeño, como la mayoria. Probablemente un ajuste de algo que el equipo vio en el telefono esta mañana. Y eso es exactamente lo que quiero que sea: la prueba de que el sistema ya no se construye en grandes entregas, sino en pasos cortos que alguien usa esa misma tarde.
Si estas construyendo algo solo, lo unico que te diria es esto: el numero no importa, pero el habito que lo produce si. Un cambio, una rama, una prueba que lo vigile, y un ambiente donde lo veas con el mismo telefono que lo va a usar tu cliente.
Comentarios
Inicia sesión para dejar un comentario
Sin comentarios aún. Sé el primero en compartir tu opinión.
Escrito por
Wilmar Garcia Valderrama
Líder Técnico de Desarrollo en QUIND y Fundador de WillDevp. Apasionado por la arquitectura limpia, microservicios y buenas prácticas de ingeniería.
