I did mine pretty similarly. At the moment my keyframes and normal frames are kept completely separately (keyframe is a save file and a normal frame is a series of events and transactions).
Transaction is a reciept of an action, actions can take transactions and apply them forwards or backwards.
Actions are triggered by events, events can trigger an arbitrary number of actions (though it is usually one) and if they trigger at least one they're stored with the transaction in the timeline.
This means that you can go back in time and make changes, and any future actions that are still valid will still execute directly, but now you can detect and cancel individual invalid actions while keeping the rest of the timeline intact.
If an event triggers a number of actions that need to be executed in order they're bundled into a process (e.g. spawn item > place item).
Pretty fun stuff, it's taken me about 3 years to get it all working as it works with my modding API which allows users to design new actions and entities, so it was very complicated!