Ejemplo end-to-end — El "golden path"
Para qué sirve. Es la pieza que la gente copia. Una User Story real viajando de idea vaga a desplegada, mostrando el artefacto concreto que produce cada uno de los 10 pasos de
SCRUM-CON-IA.md. Si tienes que mostrar la metodología en una sola lectura, es esta.Dominio del ejemplo: un carrito de compras (checkout). Los nombres (
ABC-482,frontend) son ilustrativos.
El mapa: qué artefacto sale de cada paso
| Paso | Skill / evento | Artefacto que produce |
|---|---|---|
| 1 Refinamiento | grill-user-story → grill-intent (Gate 0) | la US (ABC-482) + intent.md |
| 2 Planning | opsx:propose | proposal.md + design.md + tasks.md + specs/ |
| 3 Rama | link-us | branch + implements.yaml |
| 4 Implementación | opsx:apply (con TDD) | test (RED) → código (GREEN), por el agente |
| 5 Smoke | skill de smoke | escenario end-to-end verde |
| 6 Code review | review propio del dev → dai pr → partner (con /dai-review) | PR (código + spec) + aprobación |
| 7 Merge | dai stamp | cobertura estampada en el tracker |
| 8 Daily | — (humano) | sincronización verbal |
| 9 Review/Demo | criterios Gherkin | US aceptada por el PO |
| 10 Retro | — (humano) | 1–2 mejoras |
Paso 1 — Refinamiento: de la idea vaga a la US testeable
1a · Cómo empieza (el ticket vago)
El PO crea un ticket en el gestor. Nace con identidad (ABC-482) y poco más:
ABC-482 · "Arreglar lo del carrito que a veces deja comprar de más"Impresentable para implementar. Acá entra la IA.
1b · grill-user-story produce la US
Acá entra la IA: grill-user-story interroga al PO hasta que la US es testeable por construcción (formato-us.md) y la publica en el gestor:
# 🔗 Metadata de trazabilidad
| Campo | Valor |
|--------------|------------------------------|
| ID | ABC-482 |
| spec_version | v1 |
| Autor | J. Pérez (PO) |
| Estado | pulida |
| Repos esperados | frontend |
# Finalizar la compra del carrito
## Historia
Como **comprador**
quiero **finalizar la compra de mi carrito**
para **recibir los productos que elijo sin sorpresas**.
## Casos de uso
- **Happy path** — el comprador finaliza un carrito con productos con stock → se crea la orden.
- **Alternativo** — intenta finalizar con el carrito vacío → el sistema lo frena.
- **Excepción** — un producto del carrito no tiene stock → se rechaza indicando cuál.
## 🔗 Criterios de aceptación
- [ ] **AC-1** —
- **Dado** un carrito con productos que tienen stock
- **Cuando** el comprador finaliza la compra
- **Entonces** se crea la orden y el carrito queda vacío
- [ ] **AC-2** —
- **Dado** un carrito vacío
- **Cuando** se intenta finalizar la compra
- **Entonces** el sistema lo rechaza y NO crea ninguna orden
- [ ] **AC-3** —
- **Dado** un carrito con un producto sin stock
- **Cuando** se intenta finalizar la compra
- **Entonces** se rechaza indicando qué producto no tiene stock
## Fuera de scope
- El pago (pasarela, tarjetas) es otra US.
## Reglas de negocio
- Una orden creada descuenta el stock de cada producto.Nota que la US no dice tablas, endpoints ni framework — solo el QUÉ. Y cada AC es un test en potencia (Art. 3 del manifiesto).
1c · Gate 0 — grill-intent desafía el problema
Con la US ya formada, antes de invertir en el spec, el Gate 0 cuestiona el problema detrás (contra el MANIFIESTO.md):
IA: ¿Qué duele HOY, concretamente? "Comprar de más" es un síntoma.
PO: Un cliente finalizó la compra de un producto que ya no tenía stock, y quedó
una orden que no podemos cumplir. También pasa que finalizan con el carrito
vacío y se genera una orden fantasma.
IA: ¿Quién siente el dolor? "El sistema" no es un usuario.
PO: El comprador (recibe un error después de comprar) y depósito, que recibe
órdenes que no puede despachar.
IA: ¿Y si no lo hacemos? (costo de no actuar)
PO: Órdenes que se cancelan a mano, clientes enojados. Pasó bastante el último mes.
IA: La solución implícita es "validar el carrito al finalizar". ¿Es el salto correcto,
o el problema real es que el stock que muestra el carrito no es confiable?
PO: No, validar al finalizar es lo correcto: el stock ya existe, falta chequearlo
en el momento de la compra.
Veredicto: a-spec ✅ (problema real, usuario concreto, costo claro, sin solution-lock)→ produce openspec/intents/20260703-checkout-invalido/intent.md con ese veredicto. Si hubiera dado reframe o don't build, la US volvería al PO antes de gastar un solo artefacto de spec — ese es el punto del Gate 0.
Paso 2 — Planning: opsx:propose deriva el CÓMO
El dev corre opsx:explore → opsx:propose sobre la US. OpenSpec genera el design y las tareas. El dev valida y ajusta:
# design.md (extracto)
## Enfoque
Guard de validación en el caso de uso `FinalizarCompra`. El carrito se valida ANTES
de crear la orden: no vacío, y todos sus productos con stock.
## Reglas de la transición
carrito con stock ──finalizar──► orden creada, carrito vacío (permitido)
carrito vacío ──finalizar──► ✗ CarritoVacioError
producto sin stock ──finalizar──► ✗ SinStockError(producto)# tasks.md (extracto)
- [ ] T1. Test: finalizar carrito con stock → orden creada, carrito vacío (AC-1)
- [ ] T2. Test: finalizar carrito vacío → CarritoVacioError, sin orden (AC-2)
- [ ] T3. Test: producto sin stock → SinStockError con el producto (AC-3)
- [ ] T4. Guard de validación en FinalizarCompra
- [ ] T5. Smoke end-to-end del flujoLas tareas nacen del cómo, definidas por quien va a implementar — no bajadas desde arriba (Art. 1).
Paso 3 — Rama: link-us ata el código al QUÉ
$ dai link-us ABC-482 --us us.md --change finalizar-compra
✓ branch: feature/ABC-482-finalizar-la-compra-del-carrito
✓ archivo: openspec/changes/finalizar-compra/implements.yaml (ac_hash 7f3a9c2e)# implements.yaml — el ÚNICO link AUTORADO: se escribe, no se deriva (schema ADR-0004)
change: finalizar-compra
repo: frontend
implements:
- id: ABC-482
version: v1
ac_hash: 7f3a9c2e # lo calculó `dai ac-hash` sobre los criterios de la US v1
introduces:
- guard-carrito-vacio
autor: D. Force (dev)El key
ABC-482no se tipeó: salió del argumento. La rama y el link son correctos por construcción (Art. 8, Art. 9).
Paso 4 — Implementación: el agente construye con TDD (/opsx:apply)
/opsx:apply implementa las tareas del change, un test a la vez. Vertical slice del AC-2 (el guard del carrito vacío). Primero el test (RED):
test("un carrito vacío no se puede finalizar", async () => {
const carrito = await nuevoCarrito({ items: [] });
const accion = finalizarCompra(carrito.id);
await expect(accion).rejects.toThrow(CarritoVacioError);
expect(await ordenesDe(carrito.id)).toHaveLength(0); // NO se creó ninguna orden
});
// ▶ FALLA: finalizarCompra todavía no valida el carrito.Después el código mínimo (GREEN):
export async function finalizarCompra(id: CarritoId) {
const carrito = await repo.obtener(id);
if (carrito.items.length === 0) throw new CarritoVacioError(id);
const sinStock = carrito.items.filter((i) => !hayStock(i));
if (sinStock.length > 0) throw new SinStockError(sinStock);
const orden = await crearOrden(carrito);
return repo.vaciar(carrito, orden);
}
// ▶ VERDE. Repetir el ciclo para AC-1 y AC-3.El test (que escribió el agente) verifica por la interfaz pública (
finalizarCompra,ordenesDe), no espía lo interno. Sobrevive a un refactor (Art. 7 + skilltdd). El dev revisa cada slice: es responsable del código.
Paso 5 — Smoke: el flujo entero, verde
$ smoke checkout
✓ carrito con stock → orden creada, carrito vacío
✓ carrito vacío → rechazado, sin orden
✓ producto sin stock → rechazado indicando el producto
SMOKE OK (3/3)Paso 6 — Code review: el dev primero, después un partner
Primero el dev revisa la implementación de la IA — minucioso y con criterio (correctitud, casos borde, seguridad, calidad). El dev es responsable del código, no la IA (anti vibe-coding). Ajusta y commitea lo que haga falta.
Con el smoke verde y todo commiteado (lo que quede suelto no entra en la PR), crea la PR con dai pr — precargada con la US, el estado del check y los links (los dos activos: código + spec trazable) — y la asigna a un partner:
$ dai check
✅ ABC-482 al día (v1)
$ dai pr --assignee mgomez \
--description "Permite comprar sin crear cuenta: el checkout acepta un email de
contacto y genera la orden como invitado. Baja el abandono del paso 2."
✓ PR #123 creada → …/pull/123 (base: main · US: ABC-482 @ v1 · dai check ✅)El partner revisa la PR. Se apoya en la skill /dai-review para un primer pase: deja un review inline (resumen + un comentario anclado por línea, low/medium/high). La skill le muestra el preview y espera su OK antes de postear; después el partner firma aprobación o rechazo:
🤖 /dai-review — resumen
US: ABC-482 @ v1 · dai check: ✅ al día · DoD: 5/5
1 comentario en línea: 1 🔵 Low.
🔵 Low — src/checkout/errors.ts:12
CarritoVacioError y SinStockError podrían extender un DomainError común,
como el resto del módulo.
👤 M. Gómez (partner): reviso el preview, lo posteo, y apruebo tras el ajuste.El dev revisa su propio código; un partner distinto revisa la PR y firma (Art. 5). El review sale con el nombre y el token del partner (nunca
APPROVEautomático): la skill asiste, la persona firma.
Paso 7 — Merge: la trazabilidad se estampa sola
Al mergear, se corre dai stamp (el dev, o el CI si está automatizado — ADR-0003). Deduce que la US de esta rama es ABC-482, lee el implements.yaml y estampa la cobertura inversa en el ticket, con links a la implementación:
ABC-482 · implementado por (lo estampó dai stamp)
┌──────────┬───────────────────┬─────────┬──────────┬───────────┐
│ repo │ change │ versión │ ac_hash │ estado │
├──────────┼───────────────────┼─────────┼──────────┼───────────┤
│ frontend │ finalizar-compra │ v1 │ 7f3a9c2e │ ✅ al día │
└──────────┴───────────────────┴─────────┴──────────┴───────────┘
branch → …/tree/feature/ABC-482-finalizar-la-compra-del-carrito
commit → …/commit/abc123 (ancla durable)El estado se deriva, no se reporta (Art. 10). El link (branch + commit) hace que el ticket sea un router hacia la implementación real (§2.5).
Paso 8 — Daily (humano, a propósito)
"Ayer cerré ABC-482, la validación del checkout con el guard de carrito. Hoy tomo ABC-490. Sin trabas." — La IA no genera esto; el equipo se sincroniza (Art. 6).
Paso 9 — Review / Demo
El PO valida contra los mismos criterios que ya eran tests. Finaliza un carrito, prueba con uno vacío, prueba con un producto sin stock, ve los rechazos. AC-1, AC-2, AC-3 verdes → US aceptada. Cero sorpresas: si el QUÉ hubiera cambiado, el @version lo habría gritado antes.
Paso 10 — Retro (humano)
"El Gate 0 nos ahorró rediseñar el stock, que no hacía falta. Mejora para el próximo sprint: sumar el smoke al pipeline y no correrlo a mano." La matriz de trazabilidad aportó el dato; la decisión la tomó el equipo (Art. 6).
Epílogo — Y cuando el QUÉ cambia (el @version gritando solo)
Dos sprints después, el PO agrega un criterio a ABC-482 (ahora exige avisar al comprador qué productos quedaron sin stock, sin cancelar el resto del carrito).
Lo hace con dai edit-us ABC-482: la baja del tracker, la abre en su editor, valida el formato cuando guarda, y le pregunta si el cambio es material o editorial.
── formato de la US (.dai/us/ABC-482.md) ────────────
✓ formato válido — 4 criterio(s), 4 en Gherkin completo
Cambiaron los criterios (ac_hash 7f3a9c2e → b81d40f5).
s = cambio material: subo spec_version a v2 y los repos con v1 se marcan ATRASADOS
n = cambio editorial (typo, redacción): se queda en v1
¿Subo spec_version a v2? (S/n) s
── ABC-482 · qué cambia en jira ────────────
título: Finalizar la compra del carrito (sin cambios)
criterios: 4
version: v1 → v2
ac_hash: 7f3a9c2e → b81d40f5
──────────────────────────────────────
Esto PISA la US ABC-482 en jira. ¿Guardo? (s/N) s
✓ ABC-482 actualizada en jira → https://acme.atlassian.net/browse/ABC-482La US sube a v2 → cambia el ac_hash.
ABC-482 · implementado por
┌──────────┬───────────────────┬─────────┬──────────┬────────────────────────────┐
│ repo │ change │ versión │ ac_hash │ estado │
├──────────┼───────────────────┼─────────┼──────────┼────────────────────────────┤
│ frontend │ finalizar-compra │ v1 │ 7f3a9c2e │ ⚠️ ATRASADO (la US es v2) │
└──────────┴───────────────────┴─────────┴──────────┴────────────────────────────┘Nadie le avisó al dev: dai check lo marcó solo al re-derivar el hash de la US viva y compararlo con el estampado (Art. 11). El dev abre una nueva iteración —mismo ABC-482, ahora contra v2— y el ciclo vuelve a empezar desde el paso 3.
Qué demuestra este recorrido
- Los 10 pasos son tu Scrum de siempre — solo que en cada uno hay una skill.
- El link nunca se escribió dos veces:
implements.yamluna vez, la cobertura se derivó. - Nada llegó a producción sin ser testeable y trazable (Arts. 3, 9, 10).
- Los rituales humanos siguieron siendo humanos (Art. 6).
- Y cuando el negocio cambió, el desajuste se hizo visible solo (Art. 11).