You seem to have a handle on this already.
My current 2D platformer has objects that implement different
concerns, including the following:
Notifiable - can be event-driven and scripted Collidable - can
interact with solid tiles (eg NPCs) Intersectable - exists in 2D space
and can intersect with the player (eg doors)
Intersectable - exists in 2D space and can intersect with the player (eg doors)
Separating entities by concern this way will go a long way to figuring out step #2.
The simplest answer to what goes into step #2 is it depends. You may have other steps in there that deal with networking, or streaming data, auto-saving, et cetera. But that kind of an answer doesn't help, either.
I've concluded moving things like moving platforms that the player can
stand on first is a good idea, but I don't know when to consider
scripting. The scripting in my game can give NPCs behaviours (walk
between here and there), suspend player input for 'cutscenes', show
dialog screens, and move the player to a new level.
You already have an answer to this question. Your separation-by-concern method can be used to separate individual script actions into their own queues, and be processed at appropriate times.
NPC scripts like walking can be processed at the start of the frame to give their usual "update" cycle something to do. Any entity-changing script can be integrated into the overall cycle in this manner. Where you do it (start of frame, end of frame) is up to you and what works best for your cases.
For the script actions that stop the game, like playing cutscenes or moving the player to a new level, the sensible thing to do is let the frame play out, and process them at the end of the frame. Do any resource clean up/loading and carry on from there.
The end effect is that you construct an API that the script consumes, and the surface of that API is a scheduling mechanism for the the actions that your loop will execute at appropriate times. This allows you to easily decouple script execution and game execution.
Keep it simple and integrated into how your loop is structured. Make the fact that it's coming from a script be an irrelevant part of the process. Don't let it dominate your game cycle.