step domain
this domain owns the smallest durable retryable unit of work: where a step's boundary sits, its exact execution name, its retry and idempotency contract, and how work fans out under capacity limits. ordering, waits, and final outcome belong to the workflow domain; business rules belong to the domain service a step calls.
why
retries only work when the retried thing has a stable identity. boundaries, exact names, idempotency keys, and bounded fan-out group because each one is half of a retry contract: the name says what to rerun, the key says what effects count as done, and the claim says who is allowed to run it. without the whole contract, a retry either duplicates effects or skips them.
when to use
this domain owns a decision when the question is the smallest retryable unit — step boundaries and names, idempotency keys, retries, and bounded fan-out. ordering and final outcome belong to the workflow domain.
good and bad
bad
step: one anonymous callback inside a workflow
the unit of work has no durable name, boundary, or retry identity. when a callback times out or fails, logs show only "step 2 failed" with no way to identify which callback or what it was doing. retrying the workflow restarts all previous steps, causing duplicate work. observability is lost and diagnosis is impossible.
good
step: validate_workflow_inputinput: canonical requestoutput: typed validation result
the named step has one observable responsibility and an exact contract. logs show "validate_workflow_input failed on input X", and retrying touches only that step. each step is independently verifiable and resumable. the workflow is observable end-to-end.