Al terminar esta lección
- Construir un modelo conceptual de un slice (entidades, valores, derivados y multiplicidades) sin elegir tablas ni clases de framework.
- Redactar un contrato de entrada y salida que declare qué campos tienen autoridad del actor y cuáles se derivan en el servidor.
- Formular invariantes que un test o una restricción de base de datos pueda refutar.
- Derivar escenarios de aceptación con oráculo (efectos y no-efectos) a partir de reglas y casos de uso, y ubicarlos en el catálogo AC-01 a AC-12 de Nexo.
- Armar un Specification Bundle compacto y auditar su consistencia con IDs concretos.
6. Una especificación que sirva a humanos y agentes
Una especificación profesional no se escribe para archivar. Se escribe para reducir grados de libertad: cada decisión que queda sin escribir la va a tomar alguien más tarde, sin la evidencia que vos tenés hoy. El cliente tiene que poder validar comportamiento, el desarrollador construir, el tester derivar pruebas y un agente de IA recibir contexto suficiente sin inventar lo que falta.
Hasta el módulo 5 acumulaste piezas sueltas: evidencia (EV), reglas (RN), requerimientos, casos de uso (CU-01 a CU-04). El módulo 6 las convierte en una cadena verificable: cada artefacto referencia al anterior por ID y ninguno copia su contenido.
Recorremos esa cadena de izquierda a derecha, con el mismo método en cada pieza: problema que resuelve, definición operativa, ejemplo en Nexo, antipatrón y cómo se verifica.
Estas son las definiciones únicas que el resto del módulo cita por ID. No las reescribas en los artefactos: citá el ID.
- RN-01 (crédito estándar): un cliente ESTÁNDAR no puede confirmar si saldoDeudor + totalPedido supera limiteCredito. Igual al límite: permitido. Un centavo más: bloquea.
- RN-02 (tolerancia Platino, BLOCKED): el cliente PLATINO puede exceder el límite solo dentro de una tolerancia definida o con autorización. La tolerancia todavía no está validada.
- RN-03 (precio en servidor): el precio de una línea se calcula en servidor desde lista vigente y acuerdos autorizados.
- RN-05 (disponibilidad): una reserva nunca puede hacer disponible < 0 por depósito y SKU.
- RN-06 (idempotencia): una misma intención de pedido, identificada por su requestId, no puede generar más de un pedido: con el mismo requestId y el mismo contenido el resultado es el mismo pedido; con el mismo requestId y contenido distinto se informa un conflicto y no se produce ningún efecto nuevo.
- RN-07 (reserva blanda, BLOCKED): una reserva blanda de un pedido pendiente de autorización expira y libera la disponibilidad pasado un tiempo todavía no definido.
- RN-08 (unidad de venta): la cantidad de una línea respeta el múltiplo de venta del SKU (unidad o caja cerrada). Un acuerdo comercial puede cambiar ese múltiplo.
- RN-09 (cliente de contado): el cliente de contado no pasa por evaluación de crédito; se evalúa la condición de pago.
6.1 Modelo conceptual: vocabulario antes que tablas SQL
El problema. Cuando un equipo salta del discovery directo a CREATE TABLE, la estructura de la base de datos termina decidiendo preguntas de negocio sin que nadie las haya hecho: si un pedido puede existir sin líneas, si una reserva pertenece a un depósito o a un pedido, si el precio de una línea es un dato propio o se lee de la lista.
Definición operativa. El modelo conceptual describe los conceptos que el negocio reconoce y las relaciones entre ellos, con sus multiplicidades. En esta etapa evitamos IDs técnicos, timestamps de auditoría, tablas puente y nombres de clases de framework. Una entidad conceptual existe porque el negocio la nombra: Pedido, Producto, CuentaCorriente, ReservaStock. Las multiplicidades son el verdadero producto, porque obligan a preguntar lo que el lenguaje natural deja vago.
En Nexo. El modelo focal de CU-01 involucra Cliente, CuentaCorriente, Pedido, LíneaPedido, Producto, ListaPrecio, Depósito y ReservaStock. Cada línea del diagrama de abajo cierra una conversación que ya tuviste con el cliente.
Leé las multiplicidades como preguntas respondidas:
Pedido 1 *-- 1..* LineaPedido: un pedido confirmado no puede estar vacío, y las líneas no sobreviven sin su pedido (composición). Un borrador sí puede estar vacío: es una regla de ciclo de vida, no de estructura.LineaPedido 1 --> 0..* ReservaStock: una línea puede tener cero reservas (pedido pendiente sin reserva firme) o más de una. El "más de una" aparece porque menos del 5% de los pedidos se dividen entre CBA y CEN; cómo se elige el depósito sigue BLOCKED, así que el modelo deja la puerta abierta sin inventar la política.ReservaStock * --> 1 Deposito: toda reserva pertenece a exactamente un depósito. Esta es la base de RN-05 (disponible por depósito y SKU).Cliente 1 --> 1 CuentaCorriente: el límite y el saldo no viven en Cliente. Lo vas a ver corregirse en el caso (6.2).

Identidad, valor y derivado
No todo sustantivo merece una entidad. Una pregunta rápida ordena el modelo: ¿el negocio distingue dos instancias aunque tengan los mismos atributos? Si sí, tiene identidad (entidad): dos pedidos iguales en contenido siguen siendo dos pedidos. Si dos instancias con los mismos atributos son intercambiables, es un valor: Money de 12.450,00 ARS es el mismo en cualquier lugar. Si se puede recalcular a partir de otros datos, es un derivado y guardarlo como dato primario invita a que diverja.
¿Entidad, valor o derivado?
Clasificá cada concepto del modelo de Nexo según cómo lo distingue el negocio.
Pedido 48172
Money (monto en centavos más moneda)
Total del pedido
ReservaStock de 3 unidades de AX-442 en CBA
Disponible = onHand - reserved
Precio aplicado a una línea (con la regla que lo justificó)
El modelo no obliga a implementar DDD formal. Obliga a que, antes de escribir código, hayas preguntado qué cosas el negocio distingue.
Modelo conceptual vs. modelo de tablas
pedido(id, cliente_id, total, estado, created_at, updated_at, deleted_at), pedido_linea(id, pedido_id, sku, qty, unit_price).
- No dice si un pedido confirmado puede estar vacío.
totalyunit_priceaparecen como datos primarios sin autoridad.- No hay concepto de reserva ni de depósito: la pregunta de la última unidad todavía no se hizo.
- Los timestamps de auditoría tapan lo que importa.
Pedido compone 1..* LíneaPedido; cada línea conserva el precio aplicado y la regla que lo justificó; una línea se respalda con 0..* ReservaStock y cada reserva pertenece a un único Depósito.
- Cada multiplicidad es una pregunta que el cliente respondió.
- Los datos de auditoría se agregan después, en el diseño.
- Se puede validar con el dueño sin saber SQL.
Cómo se verifica. Tomá tres episodios reales (48172, el cliente de contado, un reintento) y recorrelos sobre el diagrama. Si un episodio necesita un concepto que no está o contradice una multiplicidad, el modelo está mal. Es el mismo método de revisión contra episodios que usaste con los casos de uso.
6.2 Contratos: qué entra, qué sale y quién tiene autoridad
El problema. Un contrato mal pensado convierte al cliente en autoridad de cosas que no controla. Si el body del request trae unitPrice, alguien va a querer persistirlo "para respetar lo que vio el cliente"; si trae creditApproved, un script puede saltear RN-01.
Definición operativa. Un contrato de entrada no transporta decisiones que el servidor puede calcular de forma autoritativa. Para cada campo, la especificación dice quién tiene autoridad: el actor (declara intención), la identidad autenticada, o una fuente del sistema (precio, crédito, estado). El contrato de salida enumera los resultados de negocio posibles, no solo "ok" y "error".
export type CreateOrderCommand = {
requestId: string; // identifica la intención (RN-06)
sellerId: string; // lo fija el servidor desde la sesión, nunca el body
clientId: string; // identidad autenticada o selección autorizada
items: Array<{ sku: string; quantity: number }>; // sin unitPrice: RN-03
deliveryMethod: "pickup" | "delivery";
preferredDepositId?: string; // "CBA" | "CEN": preferencia, no orden
};
export type CreateOrderResult =
| { kind: "confirmed"; orderId: string; totalCents: number }
| { kind: "pending_authorization"; orderId: string }
| { kind: "rejected"; reason: "credit" | "stock" | "invalid_sku" }
| { kind: "conflict"; reason: "request_id_reused" }
| { kind: "temporarily_unavailable"; dependency: "master_data" };
Este contrato no define la arquitectura. Sí fija una frontera de autoridad: precio, crédito, estado, reserva y permisos no llegan como verdad desde afuera. Fijate también que cada alternativo de CU-01 (A1 a A5) tiene un resultado con nombre: invalid_sku, stock, pending_authorization, conflict, temporarily_unavailable. Un alternativo que no se puede mapear a un resultado es un alternativo mal especificado.
Matriz de autoridad
Esta tabla es un artefacto en sí mismo y va dentro del bundle. Para cada campo responde tres cosas: quién manda, de dónde sale el valor y qué hace el servidor si el cliente lo manda igual.
| Campo | Autoridad | Si el cliente lo manda igual |
|---|---|---|
requestId | Cliente (genera la clave de la intención) | Es el único identificador que el cliente controla. Su reutilización con otro contenido es conflicto (RN-06). |
sellerId | Sesión autenticada | Se ignora; el servidor usa el de la sesión. |
clientId | Selección del vendedor, validada contra su cartera | Fuera de cartera: forbidden, sin filtrar datos (NFR-03). |
sku, quantity | Cliente (intención) | Se valida: entero positivo, SKU existente o equivalente vigente (RN-04), múltiplo de venta (RN-08). |
unitPrice, descuento | Servidor (lista y acuerdos vigentes) | No existe en el contrato. Si llega, se ignora y se registra el intento (RN-03). |
creditApproved, límite, saldo | Servidor (cuenta corriente y política) | No existe en el contrato (RN-01, RN-02). |
status, reserved | Servidor (máquina de estados) | El estado nunca es input libre. |
deliveryMethod | Cliente (dato requerido) | Se valida contra el conjunto cerrado; afecta pasos posteriores, no el precio. |
La pantalla de armado de pedido ya calcula y muestra el total. El equipo front propone enviar `unitPrice` por línea para que el backend lo guarde y el vendedor vea el mismo número que confirmó. ¿Cómo lo resolvés en el contrato?
Validación estructural, regla de negocio y concurrencia
Las comprobaciones sobre un request no son todas del mismo tipo, y mezclarlas produce pruebas confusas. Separalas por dónde se pueden decidir:
- Estructural (boundary):
quantityes un entero positivo,deliveryMethodpertenece al conjunto cerrado,requestIdtiene formato. Se rechaza sin tocar el dominio. - De dominio (reglas): la cantidad respeta el múltiplo de venta (RN-08), el SKU tiene equivalencia vigente (RN-04), saldo más pedido no supera el límite (RN-01). Necesita datos, no concurrencia.
- De persistencia y concurrencia: hay stock suficiente en este instante (RN-05), el
requestIdya existe (RN-06). Solo la base puede responder de forma consistente, dentro de la transacción.
Un error de modelado frecuente es poner todo en el schema de validación (parece prolijo, pero la regla de crédito termina duplicada en el DTO) o todo en la entidad (la validación de formato exige instanciar el dominio). La separación vuelve las pruebas más expresivas: una prueba estructural no necesita base de datos y una de concurrencia no necesita un navegador.
Los errores también son comportamiento
"Validation failed" no le sirve a nadie: el consumidor necesita distinguir SKU inexistente, cantidad inválida, conflicto de idempotencia, falta de permiso, falta de stock y dependencia caída. No todos necesitan un código HTTP distinto, pero sí una semántica estable: qué puede reintentar el cliente, qué debe mostrar, qué quedó registrado y qué efectos se revirtieron. El contrato decide esto una vez, para que ningún agente (ni ningún desarrollador apurado) lo resuelva por preferencia.
| Resultado | HTTP | ¿Reintentable? | Efectos que deben existir |
|---|---|---|---|
confirmed | 201 | Sí, devuelve el mismo pedido (RN-06) | Pedido, líneas con precio aplicado, reservas, registro de idempotencia |
pending_authorization | 202 | Sí, mismo pedido | Pedido en PENDIENTE_AUTORIZACION con causa y reserva blanda (RN-07) |
rejected (credit, stock, invalid_sku) | 422 | Con otro contenido, sí | Ninguno: ni pedido, ni reserva |
conflict (request_id_reused) | 409 | No: hay que generar otro requestId | Ninguno nuevo |
temporarily_unavailable | 503 | Sí, con el mismo requestId | Ninguno: sin precios ni límites inventados |
La elección 409 para conflicto y 422 para rechazo de negocio es una decisión de este contrato, no una verdad universal. Lo importante es que está escrita y que un test la verifica.
POST /api/orders HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
{
"requestId": "0f0b1c52-5f0a-4a0e-9a4e-2f9a0c3a77b1",
"clientId": "CLI-0412",
"items": [{ "sku": "AX-442", "quantity": 3 }],
"deliveryMethod": "pickup",
"preferredDepositId": "CBA"
}
{
"kind": "rejected",
"reason": "stock",
"issues": [
{ "sku": "AX-442", "requested": 3, "available": 2, "depositId": "CBA" }
]
}
El detalle por línea (issues) pertenece al contrato HTTP; el tipo de aplicación CreateOrderResult conserva su forma canónica. Es el caso del pedido 48172: AX-442 tiene 8 unidades en CBA, 6 están reservadas a mano en la pizarra del depósito (el ERP no registra reservas), el pedido pide 3 y falta 1 unidad (quedan 2 disponibles).
Un contrato que le da autoridad al cliente
Hacé clic en las líneas del contrato que ceden autoridad que debería tener el servidor o que dejan un resultado sin semántica.
6.3 Invariantes: frases que deben sobrevivir a cualquier implementación
El problema. Las reglas de negocio se escriben para humanos y suelen tener excepciones. Hay propiedades que el sistema no puede romper aunque cambie el framework, el motor o el equipo: son las que se ponen en riesgo cuando alguien "optimiza".
Definición operativa. Una invariante es una propiedad que se cumple antes y después de cada operación, escrita de forma que un test o una restricción pueda refutarla. "El stock tiene que ser consistente" no es una invariante; "la disponibilidad por depósito y SKU nunca es negativa" sí.
- INV-01: la disponibilidad por depósito y SKU nunca queda negativa (deriva de RN-05).
- INV-02: una misma intención (mismo
requestId) no produce dos pedidos (deriva de RN-06). - INV-03: una línea confirmada conserva el precio aplicado y la fuente o regla que lo justificó (RN-03).
- INV-04: una autorización solo modifica un pedido en estado compatible y queda auditada (NFR-02).
- INV-05: un fallo antes del commit no deja efectos parciales; un fallo externo después del commit no duplica efectos al reintentar (NFR-04).
Una RN dice "qué quiere el negocio"; una invariante dice "qué no se puede romper nunca". RN-05 y RN-06 son las dos reglas de Nexo que ya son invariantes técnicas; RN-01 no lo es, porque tiene excepciones legítimas (la autorización).
Cómo se verifica: en el lugar más bajo posible. Una invariante que depende de que cada desarrollador "se acuerde" se rompe. La mejor defensa es que la base de datos la rechace:
-- INV-01: la disponibilidad nunca es negativa (RN-05)
ALTER TABLE stock_level
ADD CONSTRAINT stock_level_reserved_bounds
CHECK (reserved >= 0 AND reserved <= on_hand);
-- INV-02: una intención, un registro (RN-06)
ALTER TABLE idempotency_keys
ADD CONSTRAINT idempotency_keys_request_id_key UNIQUE (request_id);
-- La reserva atómica que respeta INV-01 sin depender del orden de los requests
UPDATE stock_level
SET reserved = reserved + $3
WHERE product_id = $1
AND warehouse_id = $2
AND on_hand - reserved >= $3;
-- 0 filas afectadas = InsufficientStock
Fijate la diferencia con la versión ingenua que lee available y después escribe: entre la lectura y la escritura hay una ventana por donde entran dos requests. La especificación no impone UPDATE ... WHERE (podría ser SELECT FOR UPDATE u otra técnica; eso lo decide un ADR en el módulo 7), pero sí impone que el resultado no viole INV-01 bajo concurrencia.
Ordená el viaje de una invariante
Ordená de lo que se escribe primero a lo que se ejecuta como defensa final.
- Posición 1 de 5: Se deriva un criterio de aceptación con dos reservas concurrentes (AC-06)
- Posición 2 de 5: Una restricción CHECK y una prueba de integración concurrente la defienden en ejecución
- Posición 3 de 5: Se reescribe como invariante refutable (INV-01) sin atarse a una técnica
- Posición 4 de 5: Un ADR elige el mecanismo (actualización condicional en PostgreSQL)
- Posición 5 de 5: Una regla de negocio confirmada por el cliente (RN-05: una reserva nunca hace disponible < 0)
6.4 Escenarios de aceptación: convertir la promesa en ejemplos ejecutables
El problema. "El sistema valida el crédito" no se puede probar. Dos personas lo leen y entienden cosas distintas. Un ejemplo con datos concretos sí.
Definición operativa. Un criterio de aceptación (AC) es un ejemplo ejecutable de una regla o de un flujo: datos concretos, una acción, un oráculo que dice qué efectos deben existir y cuáles no. BDD no reemplaza al caso de uso: el CU conserva el objetivo completo y el AC demuestra una propiedad. La traducción empieza por las decisiones con particiones relevantes: el límite exacto, un centavo por encima, la categoría con excepción, el fallo de stock.
Característica: Registrar pedido mayorista (CU-01)
Escenario: AC-06 dos pedidos compiten por la última unidad
Dado que el depósito CBA tiene 1 unidad disponible de SKU X
Y dos vendedores construyen pedidos distintos
Cuando ambos intentan confirmar al mismo tiempo
Entonces exactamente uno obtiene la reserva
Y el otro recibe un rechazo por stock
Y la disponibilidad final es 0 y nunca negativa
El escenario no impone si la implementación usa SELECT FOR UPDATE, UPDATE ... WHERE available >= quantity, concurrencia optimista o serialización. Impone el comportamiento. Esa separación te permite elegir arquitectura después sin reescribir la intención.
Para los bordes de una regla, un esquema de escenario compacta las particiones. RN-01 con límite 500.000,00 y saldo 480.000,00:
Esquema del escenario: AC-02 y AC-03 borde del límite de crédito (RN-01)
Dado un cliente ESTÁNDAR con límite 500.000,00 y saldo deudor 480.000,00
Cuando el vendedor registra un pedido con total <total>
Entonces el resultado es <resultado>
Y <efecto_reserva>
Ejemplos:
| total | resultado | efecto_reserva |
| 20.000,00 | un pedido CONFIRMADO | existe una reserva firme |
| 20.000,01 | un rechazo por crédito | no hay stock reservado |
Dos escenarios con el mismo título, uno verificable
Escenario de aceptación: UI y adjetivos vs. oráculo observable
Escenario: crédito
Dado un cliente con poco crédito
Cuando hace clic en Confirmar pedido
Entonces ve un mensaje de error
Y el pedido no se guarda
- "Poco crédito" no se puede preparar en un test.
- "Hacer clic" y "mensaje" atan el criterio a una pantalla.
- "No se guarda" no dice qué efectos no deben existir (¿y la reserva?).
Escenario: AC-03 un centavo sobre el límite
Dado un cliente ESTÁNDAR con límite 500.000,00 y saldo 480.000,00
Cuando el vendedor registra un pedido de 20.000,01
Entonces el resultado es un rechazo por crédito
Y no existe pedido confirmado
Y no hay stock reservado
- Datos concretos y partición clara.
- Acción de negocio, no gesto de interfaz.
- Oráculo con efectos y no-efectos.
El catálogo AC-01 a AC-12 de Nexo
Este es el catálogo que usa el resto del curso. Cada AC tiene un ID estable y referencia la regla o el alternativo del que sale; el texto completo de la regla no se copia: se cita por ID. Los módulos 7 a 12 solo lo citan.
| AC | Qué demuestra | Sale de | Oráculo (resumen) |
|---|---|---|---|
| AC-01 | Happy path | CU-01 curso principal | Pedido CONFIRMADO, precio por línea trazable, reserva firme creada |
| AC-02 | Borde exacto de crédito | RN-01 | saldo + pedido == límite: confirmado |
| AC-03 | Un centavo sobre el límite | RN-01 | Rechazo por crédito, sin pedido ni reserva |
| AC-04 | Precio calculado en servidor | RN-03 | Un precio manipulado en el request se ignora; la línea conserva el aplicado |
| AC-05 | SKU inválido | CU-01 A1, RN-04 | Rechazo invalid_sku, sin pedido parcial ni reservas |
| AC-06 | Última unidad concurrente | RN-05 | Con una unidad y dos reservas concurrentes, exactamente una confirma |
| AC-07 | Retry idempotente | RN-06, CU-01 A4 | Mismo requestId y mismo contenido: un pedido, mismo resultado. Con contenido distinto: conflicto sin segundo efecto |
| AC-08 | Autorización de crédito | RN-01, RN-02 (BLOCKED), RN-07 (BLOCKED), CU-01 A3, CU-02 | PENDIENTE_AUTORIZACION con causa, solicitud creada, reserva blanda, sin reserva firme; al autorizar, confirma con motivo y auditoría |
| AC-09 | Cantidad inválida o fuera de múltiplo | RN-08 | Rechazo con detalle de la línea, sin efectos |
| AC-10 | Falla de persistencia | Garantía mínima, INV-05 | Error inyectado antes del commit: rollback completo |
| AC-11 | Handoff a preparación (outbox) | CU-01 paso final, CU-03 | Al confirmar queda un mensaje en la outbox en la misma transacción; el worker lo entrega una sola vez y el pedido queda marcado pendiente de facturación |
| AC-12 | Proveedor externo caído | NFR-04, INV-05 | Con el pedido ya confirmado y el proveedor externo caído, el pedido sigue válido y la entrega queda reintentable sin duplicar efectos |
Tres cosas para notar del catálogo. Primero, AC-08 depende de dos reglas BLOCKED (RN-02 y RN-07): el AC se escribe sobre lo que sí se sabe (el pedido queda pendiente, hay una solicitud, no hay reserva firme) y marca los valores como parámetros pendientes, sin inventar una tolerancia ni un plazo. Segundo, AC-12 usa un proveedor externo contra un doble de prueba: la emisión fiscal real queda fuera del primer release y solo se especifica el contrato de fallo. Tercero, los AC son promesas de negocio; las pruebas del módulo 10 se derivan de ellos y un AC puede requerir más de una prueba. El módulo 10 no es una copia uno a uno de esta lista.
¿A qué AC corresponde cada situación?
Elegí el criterio de aceptación que debería fallar si esa situación se rompe.
El vendedor presiona dos veces Confirmar y se crean dos pedidos con las mismas líneas.
Un script envía unitPrice: 1 y el pedido queda con ese precio.
Una caja cerrada se vende de a 12 y el pedido llega con 13 unidades.
Se corta la conexión a la base después de insertar el pedido y antes de reservar; queda un pedido sin reservas.
Con 1 unidad en CBA, dos vendedores confirman y ambos reciben un pedido CONFIRMADO.
6.5 Specification Bundle: contexto pequeño, explícito y trazable
El bundle de un slice no es el manual ni el repositorio entero: es el paquete mínimo de artefactos que restringen el cambio. Para CU-01 incluye objetivo, actores, precondiciones, las RN focales (RN-01 a RN-09 según corresponda), NFR relevantes, contrato, modelo conceptual focal, ADR que afecten persistencia y concurrencia, criterios de aceptación y los archivos o módulos autorizados. Todo lo demás se referencia o se deja fuera.
- Objetivo observable del slice. 2. IDs de RN/NFR con definición completa. 3. Caso de uso y alternativos. 4. Invariantes. 5. Contratos de entrada, salida y errores. 6. Decisiones arquitectónicas que restringen el cambio. 7. Tests esperados y gates. 8. Fuera de alcance. 9. Unknowns que deben bloquear la implementación si aparecen.
Una definición, muchas referencias
La trazabilidad no necesita una herramienta pesada: alcanzan IDs estables y enlaces explícitos. El peligro real es la duplicación textual. Si la regla de crédito está escrita de tres maneras (en el CU, en un prompt y en un test), tarde o temprano divergen. La regla se define una vez, en su archivo; los demás artefactos la citan.
id: RN-03
enunciado: "El precio de una línea se calcula en servidor desde lista vigente y acuerdos autorizados."
frontera: "El cliente no envía un unitPrice autoritativo."
estado: confirmada en principio
# file: docs/cu/trazabilidad.yaml (referencia, no copia)
- ac: AC-04
regla: RN-03 # solo el ID; la definición vive en RN-03.yaml
caso_de_uso: CU-01 # paso 3
contrato: CreateOrderCommand.items # sin unitPrice
prueba: tests/integration/create-order-price.test.ts
Cuando la regla cambia, se edita un archivo y se revisa la lista de referencias. Con copias, hay que acordarse de dónde estaban.
Qué se verifica en el bundle
Un bundle se revisa con IDs, no con impresiones. Algunas auditorías concretas y verificables:
- "Todo ID referido está definido": buscá cada
RN-,AC-,CU-yADR-y confirmá que existe su definición. - "Ninguna regla aparece con dos redacciones": buscá frases clave (por ejemplo "supera el límite") y comprobá que solo hay una definición.
- "Todo AC referencia una RN, un CU o una invariante": un AC huérfano no se sabe por qué existe.
- "Todo BLOCKED está en la sección de bloqueados": TTL de reserva (RN-07) y tolerancia Platino (RN-02) no pueden aparecer como constantes en ningún otro lado.
Auditá este fragmento de bundle
Hacé clic en las líneas que rompen la regla de una sola definición, referencian algo no definido o convierten un BLOCKED en constante.
Qué puede hacer el agente: detectar inconsistencias entre RN, CU, contratos y escenarios; resumir módulos existentes; proponer escenarios candidatos para particiones que no listaste (cantidad cero, SKU discontinuado); señalar duplicación textual.
Qué no debe decidir: resolver una contradicción entre dos fuentes, completar un campo cuya autoridad no está definida, transformar un prototipo de UI en regla o rellenar un valor BLOCKED con algo plausible.
Contexto mínimo útil: el bundle focal del slice (no el manual) y, si trabaja con código, solo los módulos necesarios más la estructura del repositorio.
Cómo verificar: exigí una auditoría con IDs concretos. "RN-03 no aparece en AC-04" es verificable; "la spec parece bien" no sirve.
Un prompt de ejemplo:
Rol: auditor de especificaciones. No escribas código ni propongas reglas nuevas.
Entrada: el bundle adjunto (CU-01, RN-01..RN-09, contrato CreateOrder, AC-01..AC-12).
Tarea: devolvé una tabla con tres columnas.
1. IDs referenciados pero no definidos.
2. Reglas definidas con más de una redacción (citá las dos frases).
3. Valores concretos que correspondan a una regla BLOCKED.
Si no encontrás nada en una columna, escribí "ninguno" y no inventes hallazgos.
Revisá la salida contra el bundle: abrí cada ID que el agente declara "no definido" y confirmá que realmente falta. Un auditor que reporta hallazgos inexistentes es un auditor que está rellenando.
Vocabulario del módulo 6
Frente
Modelo conceptual
Errores frecuentes
- Síntoma: el agente propone persistir
unitPriceocreditApproved. Causa: el DTO se copió de un prototipo y nadie definió la autoridad de cada campo. Corrección: matriz de autoridad dentro del bundle y un AC (AC-04) que pruebe que el valor se ignora. - Síntoma: el modelo conceptual tiene
created_at,deleted_aty tablas puente. Causa: se diseñó la base antes de preguntar. Corrección: quitá todo lo que el negocio no nombra y agregá las multiplicidades que respondan preguntas. - Síntoma: una invariante dice "el stock tiene que ser coherente". Causa: es un deseo, no una propiedad refutable. Corrección: reescribila con un valor medible ("
on_hand - reserved >= 0por depósito y SKU") y asigná quién la defiende (CHECK, prueba concurrente). - Síntoma: un escenario dice "hace clic" y "se ve un error rojo". Causa: se redactó sobre la pantalla. Corrección: acción de negocio y oráculo de efectos y no-efectos; la UI tiene sus propias pruebas.
- Síntoma: el bundle crece a veinte páginas y el agente igual pregunta lo esencial. Causa: se pegó todo en lugar de seleccionar. Corrección: aplicá la plantilla de 9 puntos y probá el bundle con una persona que no participó del discovery.
- Síntoma: un BLOCKED aparece como constante en un test o en un prompt. Causa: alguien llenó el vacío para avanzar. Corrección: el valor vive solo en la sección BLOCKED y se implementa como parámetro, nunca como literal.
Para llevarte
- Un modelo conceptual se valida con multiplicidades y episodios reales, no con tablas.
- Cada campo de un contrato tiene una autoridad declarada; precio, crédito, estado y reserva nunca vienen del cliente.
- Los alternativos del CU se convierten en resultados con nombre y semántica estable (qué se reintenta, qué efectos existen).
- Una invariante es refutable y se defiende lo más abajo posible (CHECK, UNIQUE, actualización condicional) además de en tests.
- Los AC llevan ID, datos concretos y oráculo con no-efectos; el catálogo AC-01 a AC-12 es la referencia del resto del curso.
- El bundle define cada regla una vez, cita por ID y declara lo que el agente no puede decidir.
¿Cómo valoras el contenido técnico de esta lección?
Tu feedback nos ayuda a mejorar los laboratorios prácticos de Eje Z.