Cómo cierra un sprint cuando los agentes hacen el código y tú firmas al final
El día empezó con un bug que reportó la primera usuaria de NIDO: “los horarios fijos no se guardaron”. Una clase clásica de bug que no descubres por ti mismo — descubres cuando alguien intenta usar el producto de verdad. Resultó ser un cambio breaking de Zod 4 que rompía silenciosamente los schemas que esperaban estructuras parciales. Una línea para arreglarlo. Un commit a producción.
Hasta ahí, una sesión normal.
Lo que pasó después es lo interesante.
La decisión que estructuró el día
Wags propuso una regla nueva, después del fix: “los agentes hacen TODO el código posible sin esperarte. Tú consolidas las acciones humanas al final, en un único bloque.” Lo escribió como “Release Day” en el plan.
La regla parece obvia escrita así, pero cambia cómo se ordenan las cosas. En lugar de tener N sprints donde cada uno termina con un “OK Javier, ahora vas a la UI de Vercel a configurar X”, todos los sprints se concentran en código. Las UIs externas (Vercel, Sentry, Google Cloud, Clerk, GitHub Settings) se acumulan en una lista única que ejecutas cuando ya está todo listo. Costo de coordinación: cero.
Lo importante es que la regla no es “agentes hacen el 90% y tú llenas los gaps”. Es “agentes hacen el 100% del código, y tu único bloque es configuración externa”. Un agente no puede entrar a sentry.io con tu cuenta personal. Pero sí puede dejar el SDK instalado, el filtro PII escrito, el beforeSend configurado, y el astro.config.mjs apuntando a una variable SENTRY_DSN que está vacía en local. Cuando tú pegas el DSN real en Vercel, todo se enciende solo.
Lo que cerró hoy
Cuatro PRs. Sprint 1 ya estaba mergeado (Playwright como gate humano automatizado + harness vitest para RLS cross-user). Hoy se sumaron:
-
Sprint 2 — Vercel Analytics con filtro PII estricto y tests de integración in-process. El detalle interesante del filtro: usa allowlist por evento (qué keys SÍ pueden salir), no blocklist (qué keys NO pueden salir). Si en el futuro alguien intenta enviar
contentoemaildesde el caller, el sanitizador los descarta silenciosamente. El test del “peor caso” envenena el evento con PII en cada canal posible y verifica que NINGUNA cadena prohibida sobrevive en el JSON final. -
Sprint 3 Track C — Workflow CI con 5 jobs. Dos nuevos:
security(corre los tests svix HMAC anti-replay, rate limit fail-CLOSED, sanitizadores) ysql-rls-lint— un script Node que lee las migraciones y falla con exit 1 si una tablanido_*se crea sinenable row level securityo sin policy declarada. El día que alguien se olvide del RLS, el CI lo para antes de mergear. -
Sprint 3 Track A — Sentry con filtro PII estricto. El mismo principio del sanitizador de Vercel Analytics aplicado a Sentry:
beforeSendrecursivo que strippeamessages.content,bitacora.content,routine.data,facts.content,email,prompt,response. El user del evento se reduce a suidopaco. El request body se descarta entero. -
Sprint 3 Track B — Calendar OAuth completo. Cifrado AES-256-GCM de tokens en reposo (
NIDO_TOKEN_ENC_KEY), sync idempotente al Calendar (eliddel evento se deriva determinísticamente del plan + día + bloque, así re-ejecutar el sync no duplica), revoke integrado al kill switch (borra eventos NIDO del Calendar + revoca el token en Google + borra la fila local). Sin credenciales reales de Google todavía — los tests usan tokens fake.
Todo eso cerrado con 273 tests verdes (unit + integration + security + e2e). Cuatro PRs separados, no un PR gigante: porque los PRs gigantes son inrevisables. Linus armó esa estrategia.
El artefacto del día
Más importante que el código fue lo que se entregó como cierre: un runbook paso a paso. docs/projects/nido/RELEASE_DAY.md. Doce pasos ordenados por dependencia, con:
- Qué hacer exactamente en cada UI (Sentry, Vercel, Google Cloud, Clerk, GitHub).
- Cómo verificar que cada paso quedó bien (curl, MCP del agente, screenshots).
- Qué hacer si falla.
- Estimación de tiempo por paso.
- Plan B si algún servicio externo se complica.
El runbook es lo que separa “código completo” de “producto operable”. Sin el runbook, mañana yo tendría que recordar qué env vars iban en qué scope de Vercel, dónde se configuran los scopes OAuth de Google, qué endpoint de Clerk uso para Third-Party Auth. Con el runbook, sigo la lista.
Lo que no se hizo
No publiqué nada en producción todavía. NIDO sigue corriendo el commit del fix de Zod (en prod desde temprano) pero todo lo demás vive en 4 PRs que esperan ser mergeados. Mañana es Release Day: mergear los PRs, ejecutar los 12 pasos del runbook, y dejar el producto operable.
Tampoco arrancamos la observabilidad en producción. Sentry tiene el filtro funcionando con DSN vacío — no envía nada hasta mañana cuando ponga el DSN real.
Lo que aprendí
El modelo “agentes hacen todo el código, humano consolida al final” funciona, pero exige una disciplina específica: dejar los gaps explícitos. Cada vez que el agente no podía hacer algo (Sentry account, OAuth de Google, GitHub Secrets), tenía que registrarlo en el runbook con instrucción exacta. Si el runbook tuviera huecos, mañana me encontraría con sorpresas. Por eso el runbook se escribió antes de que la sesión cerrara, no después.
El otro aprendizaje es técnico: cuando una librería pasa a una versión major, mira los schemas que dependen de “parcialidad” (Partial<Record>, validaciones que aceptan campos faltantes). Son los más frágiles. Un test de regresión con una sola key parcial atrapa el bug antes de que llegue a producción.