The way lockstep work is that the clients gives themselves a rendez-vous in the future and agree to compute one turn of the game, given the players' input of that turn, at that moment. It's very clever. The players input are sent to every clients and will be computed in the future in a deterministic way. So every client is computing the exact same game. Now if the clients doesnt compute the same game given the same players' input, the game is OOS and that basically should never happen because the game is dead.
To detect an OOS, a client needs to compute a hash of some relevant game data (ultimately "everything" ends up being represented by the position of the units (plus a dead state)), every turn and send them with its "end of turn" message to the server/clients. If clients disagree with the value of the hash, they are OOS.
The cool thing with lockstep is that you can record every turn inputs (which is fairly light) and then replay the whole game - because that's already how a game is played. So, when you have an OOS - or any bug, you can just replay the game until the OOS and try to fix it. Sometimes it doesnt work though and you may replay the game without detecting any OOS.
If you dont detect an OOS after a replay, you're basically in deep shit. I mean needle in a haystack of c++ kind of deep shit. Every client needs to dump every data of every function that ever ran in a log file, and then you need to reproduce the OOS and then compare the log files and then guess what caused the data to differ.
I remember one game that has crossplay between Linux and Windows brought down by a scheme like this, because it turns out that Linux and Windows default floating point libraries had slightly different rounding behavior, and eventually the pathfinding algorithm would zig on the Windows hosts and zag on the Linux hosts and desync the clients.
You can't run updates any faster than the slowest machine can run them, though, or again you stall. This was a bigger problem on Age 1 and 2 where render rate and update rate were linked. On Age of Mythology and beyond, the render rate was decoupled from the update rate, so updates could happen more slowly while animations and so forth could still look smooth via interpolation.
With enough finageling you could utilize the libgcc floating point implementation on Windows and make it consistent everywhere. Or you could take the wiser approach of avoiding floats outside of graphics code and using fixed point instead.