Laboratorio

Un registro de lo que ha salido mal cuando trabajo con agentes de IA: qué pasó, cómo se detectó y qué cambió después. Solo entran incidentes reales, con su fecha y en genérico, sin detalles de ningún empleador.

  1. Un agente de investigación que implementó en vez de investigar

    Qué pasó
    Le pedí a un agente que solo investigara. No se limitó a leer: implementó un arreglo y lo dejó en una rama del checkout principal, el que debe quedarse en main y limpio.
    Cómo se detectó
    Lo vi al revisar el resultado de la tanda: el checkout principal ya no estaba en main, sino en una rama con el arreglo hecho.
    Qué cambió
    En la segunda pasada de esa tanda, el prompt de investigación decía de forma explícita que era de solo lectura, y cada agente que construía creó su propio worktree a mano, fuera del checkout principal. Revisé el arreglo de esa rama y lo fusioné.
  2. Tests que daban la razón al error

    Qué pasó
    En una tanda de cinco tareas, cuatro builds salieron con errores. En dos, los tests cubrían justo la zona del error y pasaban: el agente escribió código y tests desde la misma suposición equivocada. Un tipo de interés, por ejemplo, aparecía a una centésima de su valor.
    Cómo se detectó
    Un segundo agente, en contexto limpio y con un modelo más fuerte, rastreó cada afirmación hasta el código o la fuente y suspendió esos cuatro builds antes de que llegaran a la rama principal.
    Qué cambió
    Publiqué el verificador como skill (skeptic-agents, licencia MIT). Desde entonces cada tarea lleva un encargo con criterios de aceptación y una lista de lo que queda fuera, y la corrección y los estándares escritos del repositorio se revisan por separado.
  3. Una charla fechada por la foto

    Qué pasó
    Un agente escribió en la página Ahora que había dado mi primera charla en octubre. Había sacado el mes de cuándo se subió la foto al repositorio, no de cuándo ocurrió la charla, que fue meses antes.
    Cómo se detectó
    Se corrigió el mismo día en que se publicó la página Ahora.
    Qué cambió
    Quité esa línea de Ahora. Regla desde entonces: un hecho no se fecha con la fecha de un archivo ni de un commit; la fecha la da quien lo vivió o una fuente que la cite.
    En el repositorio
    src/data/now.ts
  4. Un middleware de redirección por idioma que nunca se ejecutó

    Qué pasó
    La web tenía una redirección por idioma del navegador en el middleware de Astro. Estaba en el código y parecía publicada, pero en producción nunca se ejecutó: Vercel sirve las páginas prerrenderizadas antes de que pase por ninguna función. La cabecera Link y la reescritura a markdown del mismo middleware tampoco funcionaban.
    Cómo se detectó
    El 6 de octubre lo comprobé pidiendo /blog/ con un Accept-Language en inglés: devolvió un 200 de la caché, sin redirección y sin cookie de idioma.
    Qué cambió
    Quité el middleware en vez de moverlo. La cabecera Link pasó a vercel.json. Cualquier comportamiento futuro en el momento de la petición sobre una página estática tiene que traer una comprobación con `pnpm smoke` que demuestre que se ejecuta en producción.
    En el repositorio
    docs/adr/0003-no-request-time-code-on-static-pages.md
  5. Una regla de cortafuegos tumbó otra web mía

    Qué pasó
    Una regla exigía una cabecera que solo añade Cloudflare. Cuando quité Cloudflare y el DNS apuntó directo a Vercel, la regla empezó a bloquear a todos los visitantes de otra de mis webs.
    Cómo se detectó
    El mismo día del cambio de DNS, el 6 de octubre: la web dejó de responder a sus visitantes.
    Qué cambió
    Ninguna web mía tiene ya Cloudflare delante. Las reglas se publican con un script que va proyecto a proyecto (revisar, preparar, comparar, publicar o descartar, comprobar en vivo) y las reglas se identifican por nombre.
    En el repositorio
    docs/SECURITY.md, scripts/firewall-rollout.sh
  6. El formulario de contacto devolvía 500 con todo en verde en local

    Desde el hasta el

    Qué pasó
    Desde el 28 de junio hasta el 6 de octubre el formulario de contacto respondió 500 en producción. En local pasaba todo: tests, tipado y build. El desarrollo local no reproduce el enrutado de Vercel, que es por donde pasa esa ruta.
    Cómo se detectó
    A mano. Ninguna comprobación automática lo vio en más de tres meses.
    Qué cambió
    Existe `pnpm smoke`, una comprobación contra producción que lanzo a mano tras los despliegues que tocan las rutas de la API, astro.config.mjs o vercel.json: la home, el blog, el endpoint de geolocalización, el formulario de contacto (sin enviar correo) y el cortafuegos.
    En el repositorio
    scripts/smoke-prod.ts
  7. La protección anti-bots rompía el formulario de contacto

    Qué pasó
    Se probó Vercel BotID en el formulario de contacto dos veces, y las dos lo rompió: la primera bloqueó a visitantes reales; la segunda, el 6 de octubre, me bloqueó a mí.
    Cómo se detectó
    La primera vez, porque había gente que no podía enviarlo; la segunda, al probar yo el formulario.
    Qué cambió
    BotID está retirado y se queda así. El formulario se defiende con una trampa de tiempo y validación en el servidor. Antes de volver a probar algo parecido, se prueba desde un navegador normal.
    En el repositorio
    docs/setup/RESEND_SETUP.md
  8. Redirects sin barra final que no casaban con nada

    Qué pasó
    Le pasé a un agente el trabajo mecánico de renombrar un artículo de este blog y dejar redirects para que las URLs viejas no murieran. El sitio va con la barra final siempre activa y los redirects estaban escritos sin ella, así que ninguno casaba. Todas las peticiones caían en el 404 y el build seguía en verde.
    Cómo se detectó
    Semanas después, por la caída de tráfico: el artículo que más visitas traía había desaparecido del índice de Google.
    Qué cambió
    Los redirects de renombrado ahora casan con la barra final, y los enlaces dentro del contenido se canonizaron con ella. La conclusión del artículo: un build en verde no dice nada sobre lo que piensa Google, hace falta una comprobación que lo mire.

Los cambios de la web, mes a mes