Non-goals¶
Deliberately absent, each with the tipping point that would justify adding it. A missing feature here is a decision, not a gap — and every line names what would change the decision.
| Absent | Tipping point |
|---|---|
| DAG, automatic scheduling | Workflow is an ordered list. Add this when manual ordering becomes wrong, not when it becomes long. |
| Parallelism | When two independent steps dominate measured runtime. |
| Snapshot format, diff between runs | deepcopy and pickle cover the cases — see Recipes. Rollback was on this list; run(atomic=True) now covers it, because the tipping point turned out not to be memory but a silent default: only the caller who already knew to copy the store was safe. |
| Loading / writing to disk, formats | Out of scope: morphly orchestrates, the caller loads and writes. |
Declarative scope filters (get_filters) |
Filtering belongs to loading (build a reduced Store) or to the module. Annotated[list[X], Where(...)] is the extension point if it's ever worth it. |
YAML/TOML loading of Config |
PayrollPolicy.model_validate(tomllib.loads(path.read_text())) fits on one line, no dependency needed in the core. |
| Declarative workflow definitions (from a file) | The caller maps its step names to its functions; that's 5 lines on their side, and only they know their names. |
| Plugin registry / entry points | When modules live in third-party packages. |
| Branching, loops | A plain Python function calling two Workflows does the job — see Recipes. |
| Reading one entity by name in a signature | Two injectable shapes keep the contract readable. A module that needs one object reads the list and indexes it. |