Structural Checks
Dead Code Detection
Every command and event declared in a context must appear in at least one decider’s commands: or events: list within that same context. Declarations that are not referenced by any decider are dead code.
The scope is per-context, not per-decider. A command declared at the context level and listed in any one of that context’s deciders is live. Only declarations unreferenced by all deciders in the context are flagged.
What It Checks
- Every
commanddeclared in a context must appear in at least one decider’scommands:list in that context. - Every
eventdeclared in a context must appear in at least one decider’sevents:list in that context.
A command or event referenced by at least one decider passes the check regardless of how many other deciders omit it.
Error Format
Dead code: command 'CancelOrder' is declared but not referenced by any decider.Add 'CancelOrder' to a decider's commands list, or remove the declarationDead code: event 'OrderCancelled' is declared but not referenced by any decider.Add 'OrderCancelled' to a decider's events list, or remove the declarationWhy Dead Code Is an Error
Closed-world specification. A .ddd file is a complete description of its domain. Every declaration must participate in the system’s behaviour. An unreferenced command signals either a missing decider — meaning the specification is incomplete — or a leftover declaration that was never removed — meaning the specification is noisy. Both conditions undermine the compiler’s purpose: to accept only internally consistent domain descriptions.
Verification boundary. The compiler’s checks — exhaustiveness, evolve totality, guard consistency — operate on deciders. Commands and events outside any decider exist outside the verification boundary. They are claims about the domain that the compiler cannot reason about. An unverified declaration is not a hint about future intent; it is a gap in the specification.
“Unknown = error.” The compiler never silently succeeds when it cannot verify. A declaration it cannot place inside the verification boundary is not a suggestion to clean up later — it is an unresolvable gap. The compiler has no way to determine whether the declaration represents an incomplete design or a mistaken leftover, so it rejects the file.
Warnings are ignored. A warning communicates “this might be a problem.” Dead code in a domain specification is always a problem — either the specification is incomplete or it contains noise. Neither is acceptable when the compiler’s guarantee is that accepted files are internally consistent.
Formal Basis
The dead code check enforces that the union of all deciders’ command and event sets equals the context’s declaration sets:
⋃ decider.commands = context.commands⋃ decider.events = context.eventsAny element present in the context set but absent from the union is dead. Because both sides are finite sets with statically known members, the compiler can evaluate this condition without executing any code.
Future: TypeDecl Detection
Dead type declarations — types declared in a context but not referenced by any field — will extend this check in a future phase.