This is an attempt at a “standard model” for how bidirectional backwards compatibility works.
The new system should be able to read the old version and the new version, and should always write the old version and the new version. When the new system recieves info in the old version, it needs to translate it to the new version and then use that internally so most of the system can be migrated to the new version. The old version is handled three ways:
When you receive information that includes the new version and the old version, which is included to maintain compatibility with the old system, you ignore the old version and just use the new version.
This gives us reads and writes between old and new systems:
This does mean, however, that you need to build the old system to gracefully ignore new versions that it does not recognize, but that can be as simple as a version flag where everything under a new version is ignored. If you don’t already have this, you can give the new system a handshake process whereby it checks if it’s talking to the new system and switches to the new communication model if it is. This would mean that the new system would only write the old information when talking to an old system, and only write the new information when talking to a new system. This only works when the new system can actively probe is counterpart for its version, though, so it doesn’t work for something like a save file.