Interesting problem and proposed solution...
My gut tells me however that you might be unnecessarily combining two things which could instead be handled independently, and therefore with lower complexity.
Let's assume software version 1.0 uses state machine X1, and X1 accepts transition events (i.e., log entries) from the set E1, and software version 2.0 uses state machine X2, and X2 accepts transition events (i.e., log entries) from the set E2.
While in practice it's likely the case that E2 is a superset of E1, and X2 is therefore "backward compatible" with X1, let's not assume any compatibility for the sake of argument.
From Raft's perspective, it doesn't need to know or care anything about X1 or X2, and the events in E1 and E2 are just opaque binary blobs that get appended to a consensus log. Similarly X1 and X2 are opaque binary blobs that Raft itself only encounters in passing, as the payloads of InstallSnapshot messages. So Raft itself is not affected by any of what follows.
So now you can transform this problem by first creating a new state machine X3 which contains X1 + X2 + Z, where Z is a boolean state variable that means "if false, use X1, otherwise use X2", and then upgrading each one node at a time from X1 -> X3, and then finally flipping Z from false to true with a special new log entry E3.. This final Z flip then becomes your atomic, point-in-time upgrade point.
Each node, immediately after restarting after the upgrade, would contain one-time upgrade logic that looks at its state machine, and if it is in the form X1, converts X1 into X3 (just like any automated "schema update" would do).
With this approach, you just iterate over the nodes, doing: remove from cluster, upgrade, add back to cluster.
While you are upgrading nodes, some will have state machine X3 while others will still have X1, but all nodes will continue to send only E1 messages, and their state machines will agree on the X1 part.
When you flip the Z bit, everybody starts sending E2 messages, all at the same time.
Finally, you can "garbage collect" X1 later at your convenience by doing a second upgrade, this time going from X3 -> X2 by discarding X1.
Not sure if this is simper overall, but at least it has the property that you don't have to muck with the mechanics of Raft itself to solve the problem.
-Archie