Caso guiado de principio a fin
Caso guiado de principio a fin
Objetivos
- Aplicar los siete pasos a pedidos reales.
- Ver cómo las mismas reglas producen recorridos distintos.
- Practicar la clasificación, el documento y el cierre.
Caso ficticio. El proyecto, los commits y las salidas de este capítulo son inventados con fines didácticos. Las reglas aplicadas son las del protocolo. El comportamiento real depende del modelo y del runtime.
El proyecto
Facturín es una aplicación de facturación en TypeScript con pruebas en Bun, y una CLI facturin que usan también algunos scripts de clientes. Usa Claude Code con Gentle AI, RDD activo y Engram.
Pedido 1: una pregunta
¿Por qué la factura 1042 sale con el IVA duplicado?
| Paso | Decisión |
|---|---|
| Authorize | Investigación: solo lectura |
| Explore | Lee src/billing/tax.ts y reproduce el cálculo |
| Uncertainty | No hay decisión de producto |
Respuesta del agente:
El IVA se aplica dos veces cuando la factura tiene un descuento: applyDiscount()
llama a computeTax() en src/billing/tax.ts:48 y total() vuelve a llamarla
en src/billing/total.ts:22. La factura 1042 tiene un descuento del 10%.
No cambié nada. Si quieres, lo corrijo.
No hubo documento, ni línea Risk ni escritura. Encontrar el error no autorizó corregirlo.
Pedido 2: un arreglo con riesgo nombrado
Corrígelo.
“Corrígelo”, contra la propuesta inmediatamente anterior, es una autorización clara.
Classify
| Criterio | Resultado |
|---|---|
| Comprendida | Sí: se sabe qué y dónde. Una tanda de lectura bastó |
| Riesgo contenido | Por comprobar: podría afectar a facturas emitidas y a scripts de clientes |
| Reanudable desde el diff | Sí |
Antes de decidir mira el código: total() solo calcula, no modifica facturas guardadas. Con esa mirada acotada revisa los puntos candidatos:
| Punto | ¿Aplica? |
|---|---|
| 1, datos | No: no altera lo persistido |
| 3, contrato | Sí: la salida de facturin total cambia para quien tenga descuentos, y la consumen scripts de clientes |
Sin embargo, es justamente el cambio pedido. La exclusión del punto 3 dice que los cambios solicitados no son de alto riesgo por sí mismos. Solo lo serían las roturas no pedidas en código compartido.
El parent comprueba eso con el helper compartido: computeTax() lo usa también facturin preview. Corre la comprobación diferencial sobre ese comando.
Implementar inline
# RED observado: una prueba por la regla
$ bun test src/billing/total.test.ts
✗ total no aplica el IVA dos veces con descuento # esperado 119, recibido 141.61
# GREEN tras el cambio de una línea
$ bun test src/billing/total.test.ts
✓ 12 pasan
# PRESERVE: una prueba para facturin preview, que comparte el helper
# Diferencial en una copia de la base dentro de mktemp -d
$ diff <(base/facturin preview 1041) <(facturin preview 1041)
# sin diferencias
# Suite completa, una vez
$ bun test
✓ 318 pasan
Cierre
Corregí el IVA duplicado con descuento: total() ya no recalcula el impuesto.
Comprobaciones:
- RED observado y luego GREEN en total.test.ts
- bun test: 318 pasan
- Diferencial de facturin preview contra la base: sin diferencias
Risk: none. La salida cambia solo para facturas con descuento, que es lo pedido,
y los otros comandos que comparten computeTax() no cambian.
No hice commit. Falta decidir si lo incluyes en la siguiente entrega.
flowchart LR
A["Corrígelo"] --> B["Comprendida y reanudable"]
B --> C["RED, GREEN y PRESERVE inline"]
C --> D["Diferencial"]
D --> E["Suite una vez"]
E --> F["Risk: none, sin commit"]
Una variante: si el diferencial hubiera mostrado un cambio en facturin preview, la línea sería Risk: item 3 y se activaría el verificador. Además habría que corregir la regresión y fijarla con una prueba.
Pedido 3: una feature grande
Agrega facturación recurrente mensual. Quiero que corra en varias etapas porque espero la confirmación del banco para el cobro automático. El mensaje de error debe ser exactamente “No se pudo programar el cobro”.
Authorize y Explore
Autorizado. El parent lee el módulo de facturas y lo que existe de programación. Los archivos que va a editar los lee inline. Solo pide un explorador si necesita un mapa que exceda la tanda de evidencia, y aquí necesita uno, porque no conoce el módulo de pagos.
Resolve uncertainty
Queda una decisión de producto: ¿qué pasa si el cobro falla tres veces? Hay una sola pregunta:
¿Qué hacemos cuando un cobro recurrente falla tres veces seguidas?
A. Suspender la suscripción y avisar
B. Seguir reintentando cada mes
El usuario responde “A”. El parent espera esa respuesta antes de seguir con lo que depende de ella.
Classify
La prueba de reanudación falla por dos motivos que el propio pedido menciona: varias etapas y una espera externa. Es grande. Eso activa el Tracking trigger, y no un writer.
Track before the first write
Mensaje al usuario, en una línea:
Creé odd/tasks/recurring-billing.md con 4 tareas.
# Facturación recurrente mensual
Branch: `feat/recurring-billing` · Delivery: ask-on-risk · Runner: `bun test`
Engram mirror: `odd/recurring-billing/tasks` · Route: inline salvo motivo
## Specs
S1. "Agrega facturación recurrente mensual." Aceptación: se genera una factura por mes por suscripción activa.
S2. Mensaje exacto: "No se pudo programar el cobro".
S3. Tres fallos seguidos, respuesta del usuario: "A" a "Suspender la suscripción y avisar".
S4. "espero la confirmación del banco para el cobro automático". Aceptación: el cobro automático no se activa antes de esa confirmación.
## Tasks
- [ ] T1 (S1) inline · modelo y generación mensual
- [ ] T2 (S2, S3) inline · programación de cobros y fallos
- [ ] T3 (S1) inline · Risk item 1, migración de la tabla de suscripciones
- [ ] T4 (S4) bloqueada · activar el cobro cuando el banco confirme
## Log
L1 2026-11-06 usuario (textual): > Agrega facturación recurrente mensual. Quiero que corra en varias etapas porque espero la confirmación del banco para el cobro automático. El mensaje de error debe ser exactamente "No se pudo programar el cobro".
L2 2026-11-06 pregunta: fallos seguidos. Usuario (textual): > A
Por el contrato de idioma, un agente generaría este documento en inglés y conservaría las citas en tu idioma. Aquí se muestra en español para facilitar la lectura.
Observa lo que no hay: el agente no agregó reintentos configurables, panel de administración ni notificaciones por correo, porque nadie los pidió.
Implementar
gitGraph
commit id: "main"
branch feat/recurring-billing
checkout feat/recurring-billing
commit id: "T1, generación mensual"
commit id: "T2, cobros y fallos"
commit id: "T3, migración, Risk item 1"
| Tarea | Ruta | Comprobaciones | Resultado |
|---|---|---|---|
| T1 | Inline, sin motivo de writer | RED y GREEN, 180 líneas | risk: medium, under_budget |
| T2 | Inline | RED y GREEN, 190 líneas | risk: medium, under_budget |
| T3 | Inline, commit propio | RED y GREEN, ensayo en base aislada | risk: high, review_due: true |
Al crear el documento, el pronóstico era de unas 350 líneas y no activó nada. Después de T2, el conteo acumulado son 370 líneas y, al sumar la migración que falta, el pronóstico actualizado supera 400. Antes del siguiente commit aplica ask-on-risk: el parent pregunta una vez por la estrategia de cadena. El usuario elige stacked-to-main. La elección queda en el documento.
T3: el punto de alto riesgo
La migración modifica datos que no se pueden reconstruir. El orden es:
- Cerrar antes la porción abierta. T1 y T2 están pendientes
under_budget, y se evalúan como porción antes de T3. - Commit propio para T3.
- Autoverificación de T3.
- Verificador independiente, con el documento completo, el commit base y las formas de las sondas. Corre las sondas en una copia con
mktemp -dy devuelve un veredicto porS#. review assessdevuelvehigh_risk. Con RDD activo, se ejecutanext_transition.commandcon lentes elegidas.
gentle-ai review assess --cwd . --agent claude-code \
--base-ref a1b2c3d --committed-only --json \
--escalate-item 1 --escalate-reason "migra la tabla de suscripciones"
El next_transition que devuelve este comando no lleva el escalamiento, así que el mismo par de flags se repite en START. Se piden las lentes risk,resilience, con este motivo: “migración de datos con posible fallo a mitad de camino”. El sobre de consentimiento llega al usuario sin resumirse. El usuario acepta.
Un hallazgo y su corrección
El verificador encuentra un bloqueo: si la migración falla a la mitad, queda en un estado no recuperable. El parent hace un lote de corrección y una recomprobación limitada a ese bloqueo. Pasa.
También encuentra un aviso: el formato de fecha de un reporte antiguo ya era inconsistente antes de esta rama. Lo reprodujo en la base, así que es un aviso, y no se corrige porque no está en el alcance.
Un cambio de requisito
Mejor que sean dos fallos seguidos, no tres.
S3. Dos fallos seguidos, corrección del usuario (L5): "Mejor que sean dos fallos seguidos, no tres". Respuesta anterior: "A".
- [ ] T2 (S2, S3) reabierta por L5 · ajustar el umbral
L5 2026-11-07 usuario (textual): > Mejor que sean dos fallos seguidos, no tres.
Solo cambian S3 y T2. T1 y T3 siguen hechas.
Interrupción y reanudación
Se acaba el día, y mientras T4 sigue bloqueada, el usuario dice “seguimos la próxima semana”. Una semana después, en una sesión nueva:
sequenceDiagram
participant P as Parent nuevo
participant E as Engram
participant D as Archivo local
P->>E: mem_context
P->>E: mem_search recurring-billing
P->>E: mem_get_observation
P->>D: Leer odd/tasks/recurring-billing.md
P->>P: Conciliar con git log y pruebas
P->>P: T4 sigue bloqueada, informar
Cierre
Terminé T1, T2 y T3. T4 sigue bloqueada porque espera la confirmación del banco.
Comprobaciones:
- bun test: 342 pasan
- Verificador independiente en T3: S1 a S3 cumplidas, S4 sin cumplir porque espera al banco
- Revisión RDD de T3: aprobada y reconocida
- Sin ejecutar: cobro real, requiere el banco
Risk: item 1 (migración de la tabla de suscripciones)
Necesito tu decisión: ¿hago push de feat/recurring-billing para el primer PR?
Comparación de los tres recorridos
flowchart TD
subgraph P1["Pedido 1: la pregunta"]
A1["Authorize"] --> A2["Explore"] --> A3["Respuesta"]
end
subgraph P2["Pedido 2: el arreglo"]
B1["Authorize"] --> B2["Explore"] --> B3["Classify"] --> B4["Inline con test-first"] --> B5["Close con Risk"]
end
subgraph P3["Pedido 3: la feature"]
C1["Authorize"] --> C2["Explore"] --> C3["Una pregunta"] --> C4["Classify"] --> C5["Documento"] --> C6["Commits, verificador y RDD"] --> C7["Close"]
end
| Aspecto | Pedido 1 | Pedido 2 | Pedido 3 |
|---|---|---|---|
| Escrituras | 0 | Inline | Inline |
| Subagentes | 0 | 0 | Explorador y verificador |
| Documento | No | No | Sí |
| Commits | No | No | Sí |
| Preguntas | 0 | 0 | 1 de producto, 1 de cadena |
| Revisión RDD | No | No | Solo T3 |
Toda la feature del pedido 3 corrió inline, sin writers, porque nada cumplía el motivo de paralelismo. Es lo que el curso ha repetido: grande no significa delegado.
Actividad
Repite este capítulo con tu proyecto y los tres pedidos del capítulo 1. Para cada uno, escribe la clasificación, la ruta, el artefacto y la línea Risk. Si puedes, pídeselos después a tu agente con Gentle AI instalado y compara los resultados.
Autoevaluación
-
En el pedido 3, ¿qué activó el documento de feature?
- A. La cantidad de tareas
- B. La palabra “recurrente”
- C. La migración
- D. Que falla la prueba de reanudación
-
¿Por qué no hubo writers en el pedido 3?
- A. Porque nada cumplía un motivo de writer
- B. Porque Claude Code no los admite
- C. Porque RDD estaba activo
- D. Porque el usuario los prohibió
-
El verificador detectó una inconsistencia que ya existía en la base. ¿Cómo se trató?
- A. Como un bloqueo
- B. Como un motivo para ampliar el alcance
- C. Como un aviso, sin corregirla
- D. Se reabrió T1
-
El usuario cambió el umbral de fallos. ¿Qué tareas se reabrieron?
- A. Todas
- B. Solo la vinculada a la especificación afectada
- C. Las posteriores a T2
- D. Ninguna: se creó una feature nueva
Respuestas
- D. Varias etapas y una espera externa hacen fallar esa prueba.
- A. Una tarea grande sin motivo se ejecuta inline.
- C. Un defecto preexistente es un aviso y un hallazgo no amplía el alcance.
- B. Se reescribe la
S#afectada y se reabre su tarea.
Lista de control
- Puedo trazar los tres recorridos sin ayuda.
- Hago la comprobación de código compartido antes de declarar
Risk: none. - Ubico la evaluación y el verificador en el orden correcto.
- Aplico un cambio de requisito sin rehacer lo demás.
Fuentes
Reglas de internal/components/agentguidance/routing.go, internal/assets/skills/_shared/odd-orchestrator-sections.md y docs/usage.md. Ejemplo elaborado para este curso a partir de la frase de muestra de docs/quickstart.md.