Date: 2026-03-06 Status: Accepted
Domain command types (InitCommand, RunCommand) used a Validate() []error method called in the usecase layer. This pattern had several issues:
- Validation was optional and could be forgotten
- Invalid command objects could exist in memory
- Error aggregation boilerplate duplicated across usecase functions
- Domain types did not enforce their own invariants
Adopt the Parse-Don't-Validate pattern for all domain command types:
- Domain primitives (RepoPath, Days) validate in their
New*()constructors - Command types use unexported fields with
New*Command()constructors - Constructors accept only pre-validated domain primitives
Validate() []errormethods are removed entirely- Usecase layer receives always-valid commands — no validation needed
A semgrep rule domain-no-validate-method prevents reintroduction of Validate() []error in the domain layer.
- Invalid commands cannot exist — correctness by construction
- Usecase functions are simpler (no validation boilerplate)
- Domain primitives are reusable across command types
- Parsing errors surface at cmd layer (further from domain logic)
- More types to maintain (one per validated concept)
- Error messages move from domain validation to primitive constructors