Skip to content

Commit f1fa410

Browse files
reid-spencerclaude
andcommitted
Upgrade RIDDL to 1.20.0 and document all language changes since 1.15.0
New statements: reply, require (with invariant refs), do (prompt alias). Extended set (state refs) and let (type annotations). New options: auto-id (entity), external (context). New aggregate use cases: graph, table. Added validation notes throughout language reference and cheat sheet covering the new CompletenessWarning system (1.19.0) and all 1.20.0 validation checks. Re-extracted EBNF grammar. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3633487 commit f1fa410

4 files changed

Lines changed: 201 additions & 24 deletions

File tree

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ lazy val root = Root(
1818
devs = developers
1919
).configure(
2020
With.Scala3.configure(version = Some("3.7.4")),
21-
With.Riddl.library(version = "1.15.0", nonJVMDependency = false)
21+
With.Riddl.library(version = "1.20.0", nonJVMDependency = false)
2222
).settings(
2323
resolvers += "GitHub Package Registry" at "https://maven.pkg.github.com/ossuminc/riddl",
2424

docs/riddl/references/cheat-sheet.md

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ the [Language Reference](language-reference.md).
3434
| Define a request, response, or notification | [Message](#message) |
3535
| React to incoming messages | [Handler](#handler) / [On Clause](#on-clause) |
3636
| Create a reusable computation | [Function](#function) |
37+
| Assert a precondition in a handler | [`require` statement](#concrete-statements) |
38+
| Reply to a query | [`reply` statement](#concrete-statements) |
3739
| Split a model across files | [Include](#include) |
3840

3941
---
@@ -148,7 +150,7 @@ Include.
148150
- Maps to a DDD Bounded Context
149151
- Context-level handlers act as the context's external API
150152
- Adding Groups makes the context an Application (UI model)
151-
- Options: `service`, `gateway`, `package`
153+
- Options: `service`, `gateway`, `package`, `external`
152154

153155
> *[For more details →](../concepts/context.md)*
154156
@@ -169,7 +171,8 @@ in the `with { }` metadata block, not in the body.)*
169171

170172
- Entities have one or more named States, each backed by a record type
171173
- Supports `morph` (change state) and `become` (change handler)
172-
- Options: `event-sourced`, `aggregate`, `transient`, `available`
174+
- Options: `event-sourced`, `aggregate`, `transient`, `available`,
175+
`auto-id` (auto-assign ULID at instantiation)
173176
- The primary unit of consistency in a reactive system
174177

175178
> *[For more details →](../concepts/entity.md)*
@@ -309,6 +312,7 @@ messages, states, and parameters in RIDDL.
309312
- **Aggregation** (record): `type X is { field1: T1, field2: T2 }`
310313
- **Alternation** (union): `type X is one of { T1, T2, T3 }`
311314
- **Enumeration**: `type X is any of { A, B, C }`
315+
- **Aggregate use cases**: `graph`, `table`
312316
- **Collection**: `many T`, `set of T`, `mapping from K to V`, `T?`
313317
- **Simple predefined types** — use the name alone, no parameters:
314318
`Abstract`, `Nothing`, `Boolean`, `Current`, `Date`, `DateTime`,
@@ -448,7 +452,7 @@ type.
448452
|---|---|
449453
| `on command X` | A specific command message |
450454
| `on event X` | A specific event message |
451-
| `on query X` | A specific query message |
455+
| `on query X` | A specific query message (use `reply` to send result) |
452456
| `on init` | Processor initialization |
453457
| `on term` | Processor termination |
454458
| `on other` | Any unmatched message (catch-all) |
@@ -495,19 +499,27 @@ interactions between definitions, not full implementations.
495499
|---|---|---|
496500
| `send` | `send event X to outlet Y` | Route a message through an outlet or inlet (pub/sub, streaming). |
497501
| `tell` | `tell command X to entity Y` | Send a message directly to a specific processor (point-to-point). |
502+
| `reply` | `reply result ProductInfo` | Send a result back to a query sender without knowing their identity. Use in query handlers. |
498503

499504
#### Data
500505

501506
| Statement | Syntax | Description |
502507
|---|---|---|
503-
| `set` | `set field status to "Active"` | Assign a value to a state field. |
504-
| `let` | `let total = "price * qty"` | Create a local variable binding. |
508+
| `set` | `set field status to "Active"` | Assign a value to a state field. Also accepts a state ref: `set state X to "value"`. |
509+
| `let` | `let total = "price * qty"` | Create a local variable binding. Optional type annotation: `let total: Decimal = "price * qty"`. |
510+
511+
#### Preconditions
512+
513+
| Statement | Syntax | Description |
514+
|---|---|---|
515+
| `require` | `require "amount > 0"` | Assert a precondition as a literal string. |
516+
| `require` | `require invariant BalanceNonNegative` | Assert a precondition by referencing a named invariant. |
505517

506518
#### Description / Implementation
507519

508520
| Statement | Syntax | Description |
509521
|---|---|---|
510-
| `prompt` | `prompt "Calculate the total"` | Natural-language action description for implementation. |
522+
| `prompt` / `do` | `prompt "Calculate the total"` | Natural-language action description for implementation. `do` is an alias: `do "Calculate the total"`. |
511523
| `error` | `error "Invalid state"` | Produce a named error. |
512524
| `code` | `` ```scala ... ``` `` | Embed implementation code (scala, java, python, mojo). |
513525

@@ -522,10 +534,10 @@ interactions between definitions, not full implementations.
522534

523535
| Context | Available Statements |
524536
|---|---|
525-
| All handlers | when, match, send, tell, set, let, prompt, error, code |
537+
| All handlers | when, match, send, tell, reply, require, set, let, prompt/do, error, code |
526538
| Entity handlers | All above + morph, become |
527-
| Functions | when, match, set, let, prompt, error, code |
528-
| Saga steps | send, tell, prompt, error |
539+
| Functions | when, match, require, set, let, prompt/do, error, code |
540+
| Saga steps | send, tell, prompt/do, error |
529541

530542
> *[For more details →](../concepts/statement.md)*
531543
@@ -747,8 +759,8 @@ behavioral flags, or classification metadata.
747759
- `option is kind("core")` — classification
748760
- Boolean if no arguments: `option is event-sourced`
749761
- Entity options: `event-sourced`, `aggregate`, `transient`,
750-
`available`
751-
- Context options: `service`, `gateway`, `package`
762+
`available`, `auto-id`
763+
- Context options: `service`, `gateway`, `package`, `external`
752764

753765
> *[For more details →](../concepts/option.md)*
754766
@@ -823,6 +835,25 @@ cannot be expressed in Markdown descriptions.
823835

824836
---
825837

838+
## Validation Severity Levels
839+
840+
| Severity | Kind | Meaning |
841+
|:---:|---|---|
842+
| 0 | Info | Informational note |
843+
| 1 | StyleWarning | Naming/style convention issue |
844+
| 2 | MissingWarning | Missing optional content |
845+
| 3 | UsageWarning | Unused or unreferenced definition |
846+
| 4 | **CompletenessWarning** | Valid but incomplete for implementation |
847+
| 5 | Warning | Likely mistake or problematic pattern |
848+
| 6 | Error | Invalid — prevents compilation |
849+
| 7 | SevereError | Fatal — halts processing |
850+
851+
Severity ≥ 4 is **actionable**. CompletenessWarnings (new in 1.19.0)
852+
flag models that validate but lack detail for code generation.
853+
Toggle with `-c` / `--show-completeness-warnings`.
854+
855+
---
856+
826857
## Abstract / Meta Concepts
827858

828859
These concepts appear in the documentation hierarchy but are not

docs/riddl/references/language-reference.md

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ RIDDL has a rich type system supporting both simple and complex data structures:
114114
- **Alternation**: `one of { TypeA, TypeB, TypeC }` - Union/sum types
115115
- **Enumeration**: `any of { Value1, Value2, Value3 }` - Enumerated values
116116

117+
**Aggregate Use Cases:**
118+
- **Graph**: `graph` — models graph-structured data
119+
- **Table**: `table` — models tabular data
120+
117121
**Collection Types:**
118122
- **Sequence**: `sequence of Type` or `many Type`
119123
- **Set**: `set of Type`
@@ -261,6 +265,24 @@ metadata and cannot contain other RIDDL definitions.
261265
items is many Item
262266
```
263267

268+
!!! warning "Type Validation"
269+
**Errors:**
270+
271+
- Defining a type whose name exactly matches a predefined type name
272+
(e.g., `type Currency is Decimal(10,2)`) — this shadows the built-in
273+
type and is not allowed
274+
275+
**Style Warnings:**
276+
277+
- Defining a type whose name is a case-variant of a predefined type
278+
(e.g., `type timestamp is TimeStamp`)
279+
280+
**Completeness Warnings:**
281+
282+
- Command types with no fields (excluding `???` placeholders)
283+
- Event types not produced by any handler
284+
- Query types without corresponding result types (and vice versa)
285+
264286
## Entities and States
265287

266288
Entities are stateful objects with explicit states. Each state
@@ -320,6 +342,36 @@ type ProductRecord is {
320342
}
321343
```
322344

345+
!!! warning "Entity Validation"
346+
The following conditions produce validation messages:
347+
348+
**Errors:**
349+
350+
- Defining a type whose name exactly matches a predefined type
351+
(e.g., `type Currency is Decimal(10,2)`) — shadows the built-in
352+
353+
**Warnings:**
354+
355+
- Entity Id type defined inside entity body instead of containing
356+
context (move it to the context level)
357+
- Entity Id type defined at domain level or beyond (scope too broad)
358+
- Entity Id type not defined at all
359+
360+
**Completeness Warnings:**
361+
362+
- States without an `on init` clause
363+
- `on init` without a `set` statement
364+
- Command handlers that don't `send` an event
365+
- Query handlers that don't `reply` or `send` a result
366+
- Entities without any `on query` clause
367+
- Entities without an outlet streamlet for publishing events
368+
- Entities with no handlers at all
369+
- FSM entities (2+ states) without `morph` or `become` statements
370+
- Empty handlers (no statements or only `???`)
371+
- Handlers with only `prompt` statements (no `tell`, `send`,
372+
`morph`, `set`, etc.)
373+
- Empty `on other` clauses (silently discards messages)
374+
323375
When an entity has multiple states with their own handlers,
324376
it models a finite state machine—each state responds to
325377
messages differently, and the `morph` statement transitions
@@ -442,7 +494,7 @@ handler ProductCommandHandler is {
442494
}
443495
444496
on query GetProduct {
445-
reply result ProductInfo with { product: @fields.data }
497+
reply result ProductInfo
446498
}
447499
} with {
448500
briefly as "Processes commands for product management"
@@ -495,15 +547,17 @@ tell command ProcessPayment to entity PaymentService
495547
```
496548

497549
### Set Statement
498-
Assigns values to fields:
550+
Assigns values to fields or transitions to a named state:
499551
```
500552
set field status to "Active"
553+
set state ActiveOrder to "initial values"
501554
```
502555

503556
### Let Statement
504-
Creates a local variable binding:
557+
Creates a local variable binding, with an optional type annotation:
505558
```
506559
let totalPrice = "subtotal + tax + shipping"
560+
let discount: Decimal = "totalPrice * 0.1"
507561
```
508562

509563
### When Statement
@@ -558,12 +612,46 @@ match "orderStatus" {
558612
}
559613
```
560614

561-
### Prompt Statement
615+
### Reply Statement
616+
Sends a result back in response to a query, without the handler
617+
needing to know the sender's identity:
618+
```
619+
reply result ProductInfo
620+
```
621+
622+
Use `reply` in query handlers. It satisfies the completeness check
623+
that query handlers must send a result.
624+
625+
!!! warning "Validation"
626+
Query handlers that do not contain a `reply` or `send` of a result
627+
will produce a **CompletenessWarning**.
628+
629+
### Require Statement
630+
Asserts a precondition that must hold before proceeding:
631+
```
632+
require "amount > 0"
633+
```
634+
635+
You can also reference a named invariant:
636+
```
637+
require invariant BalanceNonNegative
638+
```
639+
640+
!!! warning "Validation"
641+
Invariants defined in an entity but never referenced by any
642+
`require invariant` statement produce a **UsageWarning**.
643+
644+
### Prompt Statement (alias: `do`)
562645
Describes an action in natural language for implementation:
563646
```
564647
prompt "Calculate the total price including all applicable taxes and discounts"
565648
```
566649

650+
The `do` keyword is an alias for `prompt`:
651+
```
652+
do "Calculate the total price including all applicable taxes and discounts"
653+
```
654+
567655
This is useful for describing complex business logic that will be implemented
568656
in target code.
569657

@@ -636,6 +724,11 @@ saga CheckoutProcess is {
636724
}
637725
```
638726

727+
!!! warning "Saga Validation"
728+
**Completeness Warnings:**
729+
730+
- Saga step do-statements must contain `tell command`
731+
639732
## Repositories
640733

641734
Repositories define persistence:
@@ -763,6 +856,13 @@ context ReportingContext is {
763856
}
764857
```
765858

859+
!!! warning "Projector Validation"
860+
**Completeness Warnings:**
861+
862+
- Projectors not referencing any repository
863+
- Projector handlers not `tell`ing to a repository
864+
- Declared repository references never used in `tell`
865+
766866
## Streamlets
767867

768868
Streamlets process streaming data. They define components for building
@@ -822,6 +922,22 @@ context DataPipeline is {
822922
}
823923
```
824924

925+
!!! warning "Streamlet Validation"
926+
**Completeness Warnings:**
927+
928+
- Isolated streamlets not connected to any connector
929+
- Sources without a downstream path to a sink
930+
- Sinks without an upstream path from a source
931+
- Unattached inlets and outlets
932+
- Flow/Split/Router handlers that don't send to outlets
933+
- Source streamlets without `on init` or `on other`
934+
- Streamlet handlers that receive but don't `tell` to entities
935+
936+
!!! warning "Context Validation"
937+
**Completeness Warnings:**
938+
939+
- Contexts with entities but no Sink streamlet for incoming messages
940+
825941
## Connectors
826942

827943
Connectors link outlets to inlets, defining how data flows between streamlets
@@ -999,6 +1115,32 @@ entity Product is {
9991115
}
10001116
```
10011117

1118+
## Validation Message Severity
1119+
1120+
RIDDL's validator produces messages at the following severity levels
1121+
(from lowest to highest):
1122+
1123+
| Severity | Kind | Description |
1124+
|:---:|---|---|
1125+
| 0 | Info | Informational notes |
1126+
| 1 | StyleWarning | Naming and style conventions |
1127+
| 2 | MissingWarning | Missing optional content |
1128+
| 3 | UsageWarning | Unused definitions or unreferenced declarations |
1129+
| 4 | **CompletenessWarning** | Model is valid but incomplete for implementation |
1130+
| 5 | Warning | Likely mistakes or problematic patterns |
1131+
| 6 | Error | Invalid constructs that prevent compilation |
1132+
| 7 | SevereError | Fatal errors that halt processing |
1133+
1134+
**CompletenessWarning** (severity 4) was introduced in RIDDL 1.19.0. These
1135+
warnings identify models that parse and validate correctly but are missing
1136+
details needed for a complete, implementable specification. They can be
1137+
toggled with the `-c` / `--show-completeness-warnings` CLI flag (default:
1138+
`true`).
1139+
1140+
Messages at severity 4 (CompletenessWarning) and above are considered
1141+
**actionable** — they should be addressed before considering a model ready
1142+
for translation or code generation.
1143+
10021144
## Best Practices
10031145

10041146
1. **Include Metadata**: Add descriptions to all definitions with `with` clauses after their closing braces
@@ -1114,6 +1256,7 @@ From the formal grammar analysis, several important syntax points deserve specia
11141256
- `prompt` replaces bare quoted strings for describing implementation logic
11151257

11161258
8. **Removed Statements**: The following statements have been removed from the language:
1117-
- `if`, `foreach`, `call`, `stop`, `focus`, `reply`, `return`, `read`, `write`
1259+
- `if`, `foreach`, `call`, `stop`, `focus`, `return`, `read`, `write`
11181260
- Use `when` for conditionals, `match` for pattern matching, and `prompt` for implementation descriptions
1261+
- Note: `reply` was restored in 1.20.0 with new semantics (see Statement Syntax)
11191262

0 commit comments

Comments
 (0)