As for the "paid" and "delivered" _states_ in relation to paid_at and delivered_at timestamps. You can have your cake and eat it too.
Pretty sure that's not what vemv said. Trying to put words in their mouth is very much not cool.
This same colleague had implemented a similar FSM (flying spaghetti monster as known by the team) in an FX (foreign exchange) platform at a previous company. Which after a job change I got the pleasure of experiencing, nobody in the team knew how it worked and everyone was petrified of making changes
It’s like the difference between solving a maze, and solving a maze with constantly moving walls and traps in it.
In the end I don't pursue an absolute truth. Things are often gradients, one can pick whatever tone seems more reasonable.
But suddenly requirements change, and you have 4 or 5 new states that could go back and forth. The original approach ends up being way more complex than implementing a FSM in the first place; or even, than implementing the FSM when you add a third state.
Sure, you start with two explicit states. But then you add `deleted` and now you have four states, whether you know it or not. Then there's talk of adding a third boolean column, and folks are wondering what it _means_ to be "deleted" but not "completed" and whether that is a valid state, and pretty soon the team is reinventing the concept of a state machine without any of the vocabulary that makes it straightforward.
e.g. one can consider a re-purchased return simply a new purchase, instead of doing a purchased->returned->purchased transition.
Most systems I've worked on end up with one of the "original" states being a catchall or misc type entity that could carry any number of other meanings depending on timing and context. A lot of legacy code work in my experience is actually a game of "find and name the states" when they're spread out across multiple systems, written at different times and with different understandings of the broader system, and with different methods to track and modify them.
This used to be one of the states where dishonest people would "launder" salvage titles to remove the brand. If a vehicle is totaled (flood damage also counts), the title gets branded with the word SALVAGE. Every subsequent title for that vehicle should also have SALVAGE written on it. Before you can get a license plate for such a vehicle, it needs to be inspected for safety.
The human-readable diagram took up an 11"x17" piece of paper.
The first seems to imply that delivery cannot occur until the state 'paid' has been reached, while the second contains no such implication. Either might be correct, depending on how the business operates, and modeling the states and the allowable transitions between them is an excellent way to find out what questions need to be answered before you can produce a correct implementation - better in every way than implementing what seems right intuitively, and then seeing what happens.
My problems with them being that they cram together pieces of information that could be considered separatedly.
For instance you could write a FSM that transitions from "paid" to "delivered"... or you could have two columns, paid_at and delivered_at, and consider those two columns orthogonal.
As I see it, it scales better for humans - it's easier for us to consider 10 or 20 things separately than as part of an intrincate, bespoke rule system.
You can still have some simple validation rules e.g. "delivered_at can't be set if paid_at hasn't been set". Which probably, if you squint is like a FSM in some mathematical sense, but in practice much complexity is avoided.