Business Rule Guards
Syntax
decide(<Command>, <State>) { require <expression> else reject "<error message>" -> [<Event> { ... }]}Behavior
require guards are state-dependent preconditions evaluated inside decide at runtime. The guard expression has access to the current state’s fields.
decide(AddItem, Active) { require items.length < 50 else reject "Cart is full" require productId not in items.map(.productId) else reject "Product already in cart" -> [ItemAdded { cartId, productId, quantity }]}Guards short-circuit on the first failure. When a guard fails, decide returns Err(RejectionError) and no events are produced. The event stream remains untouched.
Guard conjunction and consistency
Multiple require guards in a single clause form a conjunction: all must hold for events to be produced. The compiler checks that the conjunction is satisfiable — guards that contradict each other make the clause permanently unreachable and are reported as an error.
Contrast with rejection clauses
require guards express conditions that may or may not hold depending on the runtime state. Rejection clauses (already, forbidden, impossible) express pairs where the transition is structurally impossible regardless of runtime values — no condition is checked.
Use require when the condition depends on state values. Use a rejection clause when the (Command, State) combination can never produce events.