Un bug tonto que tardé 15 rondas en arreglar (y lo que aprendí sobre debuggear con IA)

Quince rondas con Claude para arreglar un bug. Una hora larga de ida y vuelta. Un error que, en retrospectiva, tenía una causa clara y un fix de pocas líneas. Pero tardamos una hora en encontrarlo. 

No es la primera vez que me pasa. Pero sí es la primera vez que me paro a analizar qué salió mal en la colaboración, no solo en el código. Porque el problema no fue técnico. El problema fue cómo nos comunicamos. Y el resultado fue un nivel de frustración alto. Lo confieso: le grité varias veces a la pantalla del ordenador.


El bug

El formulario de onboarding de Savia tiene tres pasos. Rellenas tus datos, avanzas, y en el último paso le das a “Completar perfil”. Simple.

El bug: al hacer clic en “Completar perfil”, aparecía un mensaje de error en rojo. “Revisa los campos marcados en rojo antes de continuar.” Pero no había ningún campo en rojo. Y lo más raro: el perfil se creaba correctamente. Error y éxito al mismo tiempo, en un solo clic.


Lo que salió mal

Yo describí el síntoma: “aparece un error pero el perfil se crea.” Claude interpretó que era un problema de validación estándar — que el formulario bloqueaba el envío. Asumió el bug más probable, no el que yo estaba describiendo.

Y yo no le corregí lo suficientemente rápido. Pensé que me había entendido. Le di una instrucción muy vaga. No le referencié a la documentación del flujo de onboarding para que tuviera contexto.

Me propuso un fix, lo probé, no funcionó. Me propuso otro. Tampoco. Otro más. Nada. Claude no justificaba el fix que proponía y se lanzaba a implementarlo; yo entré en su bucle y no le pedía que me explicase qué estaba fallando y qué alternativa proponía.

Me quedé en un “yo no se de código, él lo arreglará”. Y pasé por alto que el error de partida había sido mío por no dar un buen prompt.

Ahí cometimos los dos el mismo error: intentar soluciones sin haber diagnosticado la causa. Claude proponía cambios de código basados en hipótesis. Yo los probaba y le decía “no funciona”. Pero ni él me preguntaba qué veía exactamente en pantalla, ni yo le daba datos concretos más allá de “sigue sin funcionar.”

Quince rondas así. Cada intento razonable por separado, pero sin un diagnóstico real, eran parches a ciegas.

Soy honesta: parte del problema fue mío. Yo había intentado explicar este bug en una sesión anterior y tampoco lo conseguí. Empecé esta segunda sesión un poco frustrada, con la sensación de “ya te lo expliqué antes.” Pero la realidad es que mi explicación seguía siendo incompleta.

El punto de inflexión

El desbloqueo llegó cuando cambié de estrategia. Dejé de probar y decir “sigue sin funcionar” y propuse algo diferente: “Ponme logs en el código y lo testeo yo. Miramos juntos qué sale en la consola.” En dos rondas teníamos la causa raíz y la solución.

  • Lo que (por fin) funcionó: Claude añadió mensajes de debug en puntos clave del formulario. Yo reproduje el bug y le envié capturas de la consola. Los logs mostraron que una función de validación interna estaba validando todos los campos del formulario (incluidos los de pasos anteriores), no solo los del paso actual. Eso generaba un error fantasma en un campo que el usuario ni veía. Y como el formulario sí enviaba los datos correctamente por otra vía, el perfil se creaba a pesar del error visual. El diagnóstico fue claro. El fix, directo. Tres cambios y resuelto.
  • ¿Qué cambió para que funcionase? Dejamos de operar con hipótesis y empezamos a operar con datos. Yo dejé de ser “la que describe” y pasé a ser “la que testea y aporta evidencia.” Claude dejó de ser “el que propone soluciones” y pasó a ser “el que instrumenta para diagnosticar.”

El aprendizaje: una guía práctica de cómo debuggear mejor con IA

Después de resolver el bug, le pedí a Claude que me ayudara a entender qué podría haber hecho yo diferente para llegar antes a la solución. Esto fue lo que le dije literalmente.

Help me learn from this bug fixing. It took too many developments and testing to understand what was broken and how to fix it. We had to try different approaches and we made several mistakes. How could I have better guided the troubleshooting to solve it more effectively and faster?

Esto lo que documenté basado en lo que habíamos hecho mal.

Esta es la guía que destilamos juntos. Son las cosas que, a partir de ahora, intento aplicar cuando algo falla.

1 Describe lo que ves, no lo que crees que pasa.

Hay una diferencia enorme entre decir “el formulario no valida bien” y “aparece un error en rojo, pero no hay campos en rojo, y el perfil sí se crea.” Lo primero es una interpretación. Lo segundo es lo que pasa de verdad. La IA trabaja mucho mejor con observaciones que con diagnósticos prematuros.

En la práctica: Describe la secuencia exacta. “Hice clic en X, apareció Y, pero también pasó Z.” Cuantos más hechos, menos ambigüedad.

2 Da todos los síntomas en el primer mensaje.

Yo fui dando la información a cuentagotas. Primero dije que había un error. Luego, cuando Claude ya estaba trabajando en una hipótesis equivocada, mencioné que el perfil sí se creaba. Después, mucho más tarde, que había pegado el texto en vez de teclearlo.

Cada pieza de información que me guardé costó rondas. Si hubiera dicho todo junto desde el principio — error + éxito + paste en vez de typing — probablemente habríamos llegado en 3 rondas, no en 15.

En la práctica: Antes de escribir, hazte la pregunta: “¿Hay algo más que sea raro o inesperado?” Si sí, inclúyelo aunque no te parezca relevante.

3. Si la segunda solución falla, para y exige diagnóstico.

Este es el patrón más peligroso: la IA te propone un fix, no funciona, te propone otro, tampoco, y te propone un tercero. Cada uno suena razonable. Pero si ninguno funciona, el problema no es el fix — es que no sabemos qué está roto.

En la práctica: Si ves que van dos intentos sin éxito, di literalmente: “Para. No propongas otra solución. Primero explícame cuál crees que es la causa raíz. Si no la sabes, ponme debug logs y lo testeo.”

4 Ofrece tus manos como herramienta de diagnóstico.

La IA no puede ver tu pantalla. No puede hacer clic en tu formulario. No puede reproducir el bug. Pero tú sí. Tú eres sus ojos y sus manos. Cuando propones “ponme logs y lo testeo”, estás cerrando el gap más grande de la colaboración: la IA tiene contexto del código, tú tienes contexto del comportamiento real.

En la práctica: Cuando un bug se resiste, propón debugging colaborativo: “Añade console.log en los puntos que necesites y dime qué buscar. Yo testeo y te mando la salida.”

5. Corrige rápido y sin diplomacia.

Cuando Claude malinterpretó mi bug, yo intenté explicar con más contexto, más detalle, más palabras. Lo que funcionó fue ser directa: “No, estás equivocado. El perfil SÍ se crea. Relee lo que dije.” La IA no se ofende. No necesita contexto emocional. Necesita claridad.

En la práctica: Si la IA va por mal camino, no elabores. Di: “No. Eso no es lo que pasa. Lo que pasa es [X].” Punto. Es más rápido y más efectivo.

6. Las capturas de pantalla valen más que las descripciones.

Cuando empezamos a trabajar con los logs de consola, dejé de describir lo que veía y pasé a enviar capturas. Cada captura eliminaba ambigüedad. La IA podía leer exactamente los mismos datos que yo.

En la práctica: Siempre que puedas, envía capturas. De la pantalla, de la consola, del error. Una imagen elimina diez rondas de “¿qué quieres decir con…?”

7. Si el bug es raro, probablemente hay una segunda causa.

Nuestro bug tenía tres causas combinadas: la validación que afectaba campos invisibles, la tecla Enter que activaba el envío desde un componente inesperado, y el texto pegado que no se registraba correctamente en el formulario. Cada causa por separado era menor. Juntas, creaban un comportamiento que parecía imposible.

En la práctica: Si un bug no tiene sentido con una sola explicación, pregunta: “¿Podría haber más de una causa? ¿Qué otros factores podrían estar contribuyendo?”


La lección

Debuggear con IA no es lo mismo que debuggear solo. Ni mejor ni peor. Es diferente. Cuando debuggeas solo, tú tienes todo el contexto: ves la pantalla, lees el código, pones los breakpoints, reproduces el bug. El cuello de botella es tu conocimiento técnico.

Cuando debuggeas con IA, el contexto está partido en dos. La IA tiene el código y el conocimiento técnico. Tú tienes la pantalla y el comportamiento real. El cuello de botella no es el conocimiento — es la comunicación entre los dos.

Y eso requiere un skill que nadie te enseña: saber guiar a alguien que ejecuta muy rápido pero no ve lo que tú ves. Darle datos, no interpretaciones. Corregirle rápido cuando se equivoca. Y, sobre todo, saber cuándo parar de describir y empezar a medir juntos.

Después de escribir estas reglas, hice algo que no había hecho antes: las añadí al manual operativo del proyecto. El archivo que Claude lee al inicio de cada conversación. Un “protocolo de debugging” con cinco reglas: escucha primero, diagnostica antes de proponer, si dos intentos fallan para y mide, explica cada fix antes de implementarlo, y considera causas múltiples.

No es garantía de que no vuelva a pasar. Pero ahora las reglas están escritas. Y cuando trabajas con IA, las reglas escritas son instrucciones — no sugerencias. La próxima vez que reporte un bug, Claude leerá ese protocolo antes de responder. Eso es lo más parecido a “aprender de los errores” que puedes tener con una IA: no confiar en que recuerde la lección, sino asegurarte de que la tiene delante.

Quince rondas. Una hora. Un fix de pocas líneas. Pero una lección que vale para cada bug que venga después.


Artículos anteriores de la serie:

Así implementé una feature crítica en 1 hora tras recibir feedback de un usuario

De un «no puedo entrar a Savia» de un usuario a una feature en producción con PRD, desarrollo y auditoría en una sola sesión con 3 roles involucrados.

Sabía que iba a pasar. Cuando lancé Savia, la recuperación de contraseña se quedó fuera del MVP deliberadamente. Prioricé el flujo core — que un mentorizado pudiera encontrar un mentor, solicitar una sesión y coordinarla — y aparqué todo lo que no fuera crítico para validar la propuesta de valor. Recuperar contraseña era importante, sí. Pero no era lo que iba a determinar si Savia despertaba algo de interés o no.

Hasta que llegó el feedback que hace daño. Un usuario real no podía entrar a Savia. Llevaba varios minutos perdidos. Me escribió contándomelo para ayudar y como sugerencia, nada enfadado. Sin embargo, me fui a PostHog y había señales de rage click que delataban una frustración evidente. Normal.

Había olvidado su contraseña y no tenía forma de recuperarla. Dead end total. Una versión del producto que dejaba a un usuario atrapado si no podía recuperar su contraseña. Error básico, vaya. No hay login con Google ni ninguna alternativa. Email y contraseña es el único método de acceso, y si la pierdes, pierdes tu cuenta.

La feature para la que pensé “bueno, ya llegará el momento de dedicarle tiempo” se convirtió en necesaria. Quería demostrar a ese usuario que era capaz de darle lo que necesitaba y convertir su feedback en una mejora de producto de manera muy rápida.

De hecho, podría haberle reseteado la contraseña manualmente. Decidí no hacerlo. Le respondí a su email con un: “Gracias por el feedback. Dame un rato, lo soluciono y lo pruebas para confirmar que funciona”.

Definir primero, codear después

Mi primer instinto fue ir directa a implementar. Tengo Claude Code, conozco el codebase, el flujo es estándar. ¿Cuánto podía costar que la IA se ponga a hacerlo directamente?

Pero frené mi instinto. Pensé que era mejor seguir el proceso natural de desarrollo de una feature pero acelerarlo exponencialmente gracias a la IA. Pero no delegarle el criterio y permitir que se pusiera a picar código con un prompt genérico de “implementa recordatorio de contraseña”.

Empecé activando dos skills que tengo configuradas en Claude — una con el rol de Product Manager y otra con el de UX/UI Designer. Les pedí que analizaran el problema antes de tocar una línea de código.

Estas no son skills genéricas. Las he ido construyendo con contexto específico de Savia: conocen la arquitectura, las decisiones de diseño, el tono de voz, las convenciones del código, los patrones de UX que uso. Son archivos markdown que viven en el repositorio del proyecto y que Claude carga cuando los invoco. Cuando los activo, no parten de cero. Parten del proyecto.Cualquiera puede hacer lo mismo: es un archivo de texto con instrucciones, contexto y protocolos. No tiene nada de mágico, pero marca una diferencia enorme en la calidad del output.

Les pedí algo sencillo: “Hay feedback de usuarios de que no tenemos recuperación de contraseña. Quiero que ambos analicéis qué habría que hacer para solucionarlo y me hagáis una propuesta”.

Y lo que salió de esa interación fue útil. El PM identificó 10 consideraciones estratégicas — impacto en retención, riesgo de email bombing, anti-enumeración de usuarios, métricas a trackear. La UX sumó 14 más — dónde colocar el link en login, copy empático, validación en tiempo real, accesibilidad.

Después invocamos a otra skill que tengo con el rol de Software Engineer. Ahí vino algo que no esperaba: detectó que el 80% de la infraestructura ya existía.

El email template para reset de password estaba creado. La ruta de confirmación ya manejaba tokens de recovery. El servidor de correo estaba configurado. La función resetPasswordForEmail() estaba disponible. Simplemente nunca la había invocado.

Esto fue un hallazgo, pero también una señal de alarma. Significaba que cuando definí las features del MVP al principio, ésta se me había colado parcialmente.

Claude la había considerado en su plan de desarrollo inicial, pero la implementó a medias — montó la infraestructura de soporte sin completar el flujo de usuario. Sin un PRD explícito que la definiera, la IA hizo lo que pudo con lo que entendió. Y yo no detecté en ningún momento que eso se nos estaba quedando fuera.Disclaimer: eso fue porque la primera iteración de Savia la hice pasando de propuesta > código. Y ahora he mejorado el flujo pasando de propuesta > PRD > código.

El PRD y la corrección que solo un humano puede hacer

Con todas las consideraciones sobre la mesa, tocaba estructurar. Tengo un template de PRD que fui construyendo y refinando dentro del skill de PM — no es un template genérico, es uno adaptado a cómo trabajo en Savia: incluye Jobs to Be Done, criterios de aceptación con Given/When/Then, edge cases, y un apartado que para mí era clave en este caso: el “why not” — qué pasa si no hacemos esta feature.

En este caso la respuesta era clara: cada usuario que olvide su contraseña se pierde para siempre. Con 10 usuarios activos que tengo ahora mismo, perder 1 es perder el 10% de la base.

Le pedí a Claude que generara el PRD completo usando ese template y los datos del análisis. 4 minutos después tenía un documento con 14 requisitos, 6 escenarios de aceptación y los edge cases cubiertos.

Y entonces pasó algo que para mí resume cómo funciona esta colaboración entre la propuesta que te hace una IA con el contexto que le has dado y el criterio del humano que la IA no puede reemplazar.

Claude propuso un rate limit de 10 peticiones cada 15 minutos para la recuperación de contraseña — el mismo que tenía en login. Yo lo bajé a 3. Nadie legítimo necesita solicitar más de 3 resets en 15 minutos. La IA propone valores razonables; el humano aplica el contexto que la IA no tiene.

Ajustamos el PRD. Definimos el scope, lo que entraba y lo que se quedaba fuera. Quedó así. Si quieres ver el PRD completo, déjame un comentario y te lo comparto en markdown.

Con el PRD aprobado, la implementación fue directa. 4 archivos nuevos, 7 modificados, 11 en total. Build verde, 435 tests passing. Mensaje genérico siempre, tanto si el email existe como si no — para que nadie pueda usar el formulario de reset para averiguar si un email está registrado. Es seguridad básica que muchas apps se saltan.

Y entonces lo desplegué y las rutas no funcionaban

Me llevó un rato depurar el error y detectar qué estaba pasando (Disclaimer: en otro post te contaré cómo estoy aprendiendo a sacar a Claude del bucle cuando se equivoca más de 2 veces con una cosa y se vuelve incapaz de solucionarla sin buenas instrucciones).

Al final dimos con ello: había puesto ñ en la URL — /recuperar-contraseña. El build compiló perfecto. Los tests pasaban. Pero en producción, el servidor no decodifica bien los caracteres especiales en las rutas. Mi ñ se convertía en %C3%B1 y las comparaciones internas fallaban silenciosamente.

Cuando Claude identificó el problema, propuso un fix técnico: interceptar todas las URLs en el middleware y decodificar los caracteres especiales antes de compararlos. Funcionaría, pero era un parche — añadía complejidad a un sitio crítico del sistema para resolver algo que no tenía por qué existir.

Como no se desarrollar, de manera muy inocente le dije: “¿Y si simplemente quitamos la ñ?” /recuperar-contrasena en vez de /recuperar-contraseña. Nueve archivos renombrados, problema eliminado de raíz.

Es el mismo patrón que con el rate limit. La IA tiende a resolver problemas con más código. A veces la mejor solución es cambiar el planteamiento. No necesitas un parche sofisticado si puedes eliminar la causa. Pero eso requiere dar un paso atrás y preguntar “¿por qué estoy resolviendo esto así?” — algo que, al menos hoy, sigue siendo más fácil para un humano que para una IA.

El patrón que se repite

Feedback ? análisis con roles especializados ? PRD ? implementación ? producción. No es un flujo de IA. Es un flujo de producto. Lo que la IA cambia es la velocidad: lo que habrían sido días de trabajo con un equipo distribuido se comprimió en 1 hora con una sola persona activando roles en secuencia.

Pero la velocidad no es lo importante. Lo importante es que en ningún momento delegué una decisión de producto. Corregí el rate limit. Aprobé el PRD. Decidí quitar la ñ en vez de parchear el servidor. La IA amplificó mi capacidad de ejecutar, pero el criterio siguió siendo mío.

Y esa es la parte del vibe coding de la que menos se habla. No es escribir código con prompts. Es tener un equipo que ejecuta a la velocidad que tú piensas — siempre que sepas qué pensar.

Si te apetece probarlo, Savia está en savia.company. Y sí, ahora puedes recuperar tu contraseña.


Artículos anteriores de la serie: