I managed to do some constructive thinking last time, but messed up the implementation of KickoffCoordinator:
KickoffCoordinatoras an initialization parameter, because (I guess) I didn't know how else to actually enact what the coordinator needs to be doing: creating and adding tasks as appropriate.
So, we need to decouple what the coordinator is doing from what is processing the results of what the coordinator is doing. In other words, the coordinator's determining that a certain task needs to be added needs to be separate from the actual addition of the task (in some repository somewhere).
This is a complicated and controversial subject. Happily, first steps are somewhat less controversial and complicated. We'll turn the coordinator's output into a
Command object and change
KickoffCoordinator.proc_event() to emit those objects instead of directly modifying a repository. (My approach here is indebted to Architecture Patterns with Python, at least insofar as what I do is sensible.)
Soon: a proper message-processing system! So much writing about software either (i) does not involve a properly separated message-passing system or (ii) is concerned with operating such a system at large scale. It will be pleasant to construct a well-functioning system without worrying about Big Tech-level scale.