Cool post but I’m more in favor of persisting in an event store the resulting change of a command on an aggregate state.
Indeed, the business logic on how to apply a command may change over time. It means rehydrating an aggregate using our event store may result in something different over time.
Instead of persisting the so-called command event, I generally prefer having a service upfront that is in charge of validating the command and computing the delta on the aggregate (and maybe also applying a concurrency control as well as event sourcing as such does not prevent concurrent accesses isn’t it?). This delta is an immutable event that is persisted in the event store. Then, computing a state is idempotent by design. The same set of events will always produce the very same resulting state over time, regardless of the current application version or whatever.
Also for me, business events in the way you represent them is a DDD anti-pattern. DDD was invented to tackle this very problem of managing shared models within an enterprise. If we need to share data across bounded contexts, I would prefer doing it using Anti-Corruption Layers in between to make sure we do not have dependencies across our bounded contexts.
Last but not least, I feel like it is not a great approach to mix command and events. I mean one of the benefits of an event storming workshop is to get a clear view of what are the commands and the events produced by a system (that’s why we have two different post-it colors :). BookingAccepted, for example, is nothing but an event. This concept of command event might be somewhat confusing.
But again, that’s my opinion ;)