Quality: smells, errors, and warnings
The validator checks structure. Business clarity still requires judgment.
The four anti-patterns
These shapes are warnings worth investigating, not automatic rejections.
Left chair
1 Command → many Events. Check whether several business capabilities are mixed together.
Right chair
many Events → 1 Read Model. Check whether the Read Model answers more than one question.
Bed
1 Screen → many Commands. Check whether the Screen combines unrelated user intents.
Shelf
1 workflow → many scenarios, others → none. Check which workflows still rely on implicit rules.
What the validator rejects outright
The default profile rejects invalid HCL and unknown syntax, missing required semantic attributes, wrong literal types and invalid examples, duplicate identities, unresolved or wrong-kind references, non-canonical flow directions, invalid pattern-specific scenario structure, non-contiguous chapters, and incorrect Automation/Translation externality. Diagnostics use stable EMxxx codes — EM0xx structural, EM1xx references, EM2xx flow, EM3xx scenarios, EM4xx modeling judgment.
What it leaves to human judgment
Some checks need judgment rather than hard rejection: a Command with no incoming flow, API endpoint, or trigger (EM404); the four anti-patterns above; an open hotspot (EM406). Three profiles decide how strict that judgment is:
| Profile | Judgment diagnostics (EM404, EM406, the four smells) |
|---|---|
workshop | Informational — incomplete discovery stays easy to work with |
valid (default) | Warnings |
strict | EM404 and EM406 become errors; the four smells stay non-blocking judgment signals |
This Command has no incoming flow, API endpoint, or trigger:
Under the default valid profile, it's a warning and the file still validates:
Under --profile strict, the same diagnostic becomes a hard error and nothing is reported valid:
A shipped example also produces a right-chair warning:
Use strictness to make an agent-ready model more explicit; don't use permissiveness to hide uncertainty. Unknown business facts belong in hotspot blocks, not in silence.
Validity-spotting drill
For each item, decide: invalid (validator-level problem), valid but suspicious (a warning or smell), or valid.
Answer
Invalid Events are bounded-context-owned contracts and must be declared inside a bounded_context.
Answer
Invalid Relationships are typed, unquoted HCL traversals — this is a string.
Answer
Invalid A readmodel block only exists inside a state_view, automation, or translation workflow — and even declared correctly, it would still need a concrete question.
Answer
Valid but suspicious A left-chair smell — investigate whether several capabilities are hiding inside one Command.
Answer
Invalid A Translation must consume at least one Event from an external bounded context — the validator checks this externality rule directly.
Answer
Invalid State Change scenarios require one when, targeting a Command.
Keep going
The full guide includes more exercises, facilitation notes, and a capstone.