Pilar 6: El volante de aprendizaje de IA — cómo hacer que tu agente sea permanentemente más inteligente

Search for a command to run...

No comments yet. Be the first to comment.
Línea de apertura (opcional, para el feed): En cada sesión nueva, Claude abre el README, escanea el árbol de directorios, busca el pom.xml, encuentra src/main/java... 33 tool calls para orientarse. Co

Línea de apertura (opcional, para el feed): Tu equipo hizo commit directo a main porque "era un cambio pequeño". Dos horas después, toda la rama de producción estaba rota, tres desarrolladores bloquea

Línea de apertura (opcional, para el feed): Llevas seis meses usando Claude para tus decisiones de arquitectura Java. Eres más rápido. Pero ya no sabes si elegirías Spring Security + JWT o Keycloak si

Línea de apertura (opcional, para el feed): Claude generó el controlador REST en 20 segundos. Pasó code review. Llegó a producción. Dos días después, el campo monto devolvía la ciudad del cliente. Aqu

Línea de apertura (opcional, para el feed): Llevas tres meses usando Claude en tu proyecto Java. Los mismos errores de hace tres meses siguen apareciendo. == para comparar BigDecimal. LocalDate.now() directo en el dominio. javax.* en lugar de jakarta.*. El modelo no aprendió porque tú no le enseñaste. Este es el último pilar: convertir cada bug en inteligencia permanente.
Parte de la serie "Los 6 pilares del desarrollo asistido por IA" — basado en el material de Thor Henning Hetland (Totto) / Ægis. Adaptado a proyectos Java.
Los cinco pilares anteriores construyen la base: contexto inteligente (Pilar 1), delegación estratégica (Pilar 2), verificación sistemática (Pilar 3), agencia técnica (Pilar 4) y guardrails de proceso (Pilar 5). El Pilar 6 responde la pregunta que todos estos dejan abierta:
¿Cómo hace el sistema para volverse más inteligente con el tiempo, no solo más rápido?
La respuesta no es confiar en que el modelo aprenda solo. Los modelos no aprenden de tus sesiones. Lo que aprendiste tú al arreglar ese bug el martes desaparece en el siguiente chat si no lo documentas. El Pilar 6 es el mecanismo para convertir cada bug resuelto, cada patrón descubierto y cada edge case encontrado en inteligencia permanente del sistema.
Hay dos tipos de equipos que usan IA:
La diferencia no está en el modelo. Está en si el equipo actualiza el contexto o no.
Con el enfoque estático, el CLAUDE.md del Pilar 1 se queda exactamente igual que el día que se escribió. La IA no aprende que BigDecimal se compara con .compareTo(), no aprende que el endpoint /pagos tiene validaciones especiales antes del publish a Kafka, no aprende que Optional.empty() en PedidoService.findById() puede significar "cancelado" además de "no existe".
Con el enfoque continuo, cada bug que se arregla se convierte en un anti-patrón documentado. Cada patrón que funciona bien se convierte en una skill. Cada edge case descubierto se convierte en un requisito de test. La IA del mes 3 es cualitativamente diferente a la del día 1.
El volante gira con tres artefactos:
LEARNINGS.md — captura diaria de bajo rozamiento (5 min)
IMPLEMENTATION-HISTORY.md — registro de features implementadas
Skills como módulos vivos — no documentos estáticos, sino módulos con ciclo de vida
Una entrada de LEARNINGS.md en un proyecto Java real tarda 5 minutos en escribir. Esos 5 minutos previenen que el mismo bug ocurra en los próximos 8 endpoints.
Formato estándar (bajo rozamiento):
## LEARNINGS.md
### 2026-07-29 — BigDecimal comparación incorrecta
**Contexto:** Revisión del PR de PedidoService.calcularTotal()
**Bug:** La IA generó `if (monto == BigDecimal.ZERO)` para validar monto vacío.
Pasó todos los unit tests porque los tests usaban el mismo literal.
Falló en producción con valores calculados (0.00 != 0 por referencia).
**Insight capturado:**
- Comparar BigDecimal con `==` es siempre incorrecto.
- Usar siempre `monto.compareTo(BigDecimal.ZERO) == 0` o `BigDecimal.ZERO.equals(monto)`.
**Acciones:**
- [x] Añadido a CLAUDE.md sección Anti-patrones (#8)
- [x] Actualizado skill domain-model.md con sección "Comparaciones monetarias"
- [x] Añadido test de propiedad con jqwik: comparación con valores calculados
**Resultado:** Cero bugs de comparación BigDecimal en los siguientes 6 servicios.
### 2026-07-31 — LocalDate.now() en dominio no es testeable
**Contexto:** Debugging de PedidoService.estaVencido() — tests no deterministas
**Bug:** La IA usó `LocalDate.now()` directamente en el método de dominio.
Los tests fallaban aleatoriamente dependiendo de la fecha de ejecución.
**Insight:**
- Nunca usar `LocalDate.now()` o `Instant.now()` directamente en clases de dominio.
- Inyectar `Clock` como dependencia y usar `LocalDate.now(clock)`.
- Permite fijar el tiempo en tests: `Clock.fixed(Instant.parse("2026-01-15T00:00:00Z"), ZoneOffset.UTC)`
**Acciones:**
- [x] Añadido a CLAUDE.md Anti-patrones (#9)
- [x] Creado skill testing.md — sección "Time-dependent testing con Clock"
- [ ] Refactorizar PedidoService para inyectar Clock (backlog JIRA-789)
Un bug en un parser de Spring Boot que asumió que un campo de versión era de longitud fija. La IA generó código basado en la especificación v6 sin saber que v7+ cambió el tamaño del campo.
El problema (5 minutos de análisis):
// Lo que generó Claude — asumió versión fija
int version = buffer.readByte(); // correcto hasta v6
// v7+ usa 2 bytes — parseó el byte de datos como parte de la versión
La solución permanente (10 minutos de documentación):
### 2026-07-15 — Campos de versión de longitud variable
**Anti-patrón:** Nunca asumir tamaño fijo de campos sin verificar la versión del protocolo.
**Regla:** Leer siempre la versión primero. Campos de longitud variable según versión
requieren dispatch explícito: v1-6 = 1 byte, v7+ = 2 bytes (little-endian).
**Acciones:**
- [x] CLAUDE.md Anti-patrones: "Verificar versión de protocolo antes de parsear campos"
- [x] Skill creada: .claude/skills/parsing-versioning.md
Resultado: Cero bugs de parsing de versión en los siguientes 5 parsers generados.
El error más común es decir "lo documento después". Después nunca llega. La solución es reemplazar la intención por disparadores situacionales inmediatos:
El mecanismo más efectivo es integrar los disparadores directamente en el PR template. El volante gira automáticamente con cada merge:
<!-- .github/pull_request_template.md — sección de aprendizaje -->
## Documentación del aprendizaje
- [ ] `IMPLEMENTATION-HISTORY.md` actualizado (si fue una feature significativa)
- [ ] `LEARNINGS.md` tiene una entrada (si hubo nuevos insights o bugs encontrados)
- [ ] Skills relevantes actualizados en `.claude/skills/`
- [ ] `CLAUDE.md` actualizado si hay nuevos patrones o anti-patrones
Cuando esta sección está en el template, el equipo la ve en cada PR. No hace falta recordar. El proceso captura el aprendizaje automáticamente.
Los skills del Pilar 1 no son documentos que se escriben una vez. Tienen un ciclo de vida:
Ejemplos de evolución en un proyecto Java:
spring-boot.md se divide en spring-boot-controllers.md y spring-boot-config.md cuando supera las 400 líneas
javax-patterns.md se archiva después de completar la migración a Jakarta EE
jpa-patterns.md y hibernate-config.md se fusionan en persistence.md cuando el equipo unifica criterios
El volante produce retorno compuesto, no lineal:
| Momento | Contexto | Automatización | Tiempo por feature |
|---|---|---|---|
| Día 1 | 200 líneas / 5 skills | 10% | 4 horas |
| Mes 1 | 767 líneas / 20 skills | 40% | 1.5 horas |
| Mes 3 | 1.200+ líneas / 51 skills | 75% | 30 minutos |
El multiplicador de 8× no viene de un modelo más caro. Viene de un contexto más rico que permite a Haiku 4.5 hacer lo que antes requería Sonnet 5, y a Sonnet 5 hacer lo que antes requería intervención humana.
Cuatro KPIs que miden si el sistema está aprendiendo o estancado:
| Métrica | Target | Cómo medirla en Java |
|---|---|---|
| Tasa de captura | >80% de sesiones documentadas | Entradas en LEARNINGS.md / días de desarrollo activo |
| Reducción de errores repetidos | 90% de caída en 3 meses | Bugs del mismo tipo en JIRA: mes 1 vs. mes 3 |
| Crecimiento del contexto | +50 líneas/semana en los primeros 3 meses | wc -l CLAUDE.md + total líneas en .claude/skills/ |
| Precisión al primer intento | De 3-4 iteraciones a 1 | Rondas de revisión promedio antes del merge |
El volante no requiere grandes inversiones de tiempo. Requiere consistencia:
1. Crea LEARNINGS.md en la raíz del proyecto (5 min):
# LEARNINGS.md — Registro de aprendizaje del equipo
## Formato de entrada
- **Fecha:** YYYY-MM-DD
- **Contexto:** ¿En qué estabas trabajando?
- **Insight:** ¿Qué aprendiste?
- **Acciones:** ¿Qué actualizaste? (CLAUDE.md / skill / test)
- **Resultado:** ¿Qué evitó este aprendizaje?
---
<!-- Primera entrada: usa el bug más reciente que arreglaste -->
2. Añade la sección de aprendizaje al PR template (10 min): Copia el bloque de la sección anterior a .github/pull_request_template.md. A partir de ese momento, cada PR activa el ciclo.
3.Añade la primera entrada basada en el último bug de Java (15 min): No esperes al próximo bug. El último que arreglaste esta semana — el NullPointerException en el servicio de pagos, la excepción de Hibernate inesperada, el test que fallaba aleatoriamente — ya tiene un insight que vale la pena capturar.
Seis pilares. Una arquitectura de trabajo que se autorefuerza:
El Pilar 6 cierra el ciclo: los aprendizajes capturados enriquecen el CLAUDE.md y los skills del Pilar 1, que mejoran la delegación del Pilar 2, que hacen más efectiva la verificación del Pilar 3, que fortalecen la agencia del Pilar 4, que se integran en los guardrails del Pilar 5, que generan más aprendizajes para capturar.
Cada bug resuelto hace al sistema más inteligente. Cada patrón documentado hace al equipo más rápido. Cada insight capturado compone.
Haz que tu IA sea permanentemente más inteligente con cada bug resuelto y patrón descubierto. Tus prompts de sistema son un motor de aprendizaje activo, no archivos estáticos.
¿Tienes algún LEARNINGS.md en tu proyecto Java? ¿O esos insights viven solo en tu memoria hasta que se olvidan? El próximo bug que arregles es el mejor momento para empezar.
Enjoy!
Joe