I will have all the data that goes over the radio link in one big block. Some of the data is setpoints, other is just information going from point A to B.
The part of that block of data that is setpoints has an incoming and outgoing copy. The remote stations always work with (and write to) the outgoing data.
The incoming data is scanned for changes, and if an element of the incoming data is changed, I make a copy of it in a "handshake" file, and also copy it to the outgoing (working) data. I do this in a subroutine with a loop with indirect addressing so that it reduces the chance of a typo and I only call this subroutine when I know I have received data from the master PLC.
To know when I have received data from the master, I typically use the first setpoint as a "heartbeat" register and have logic that runs every scan comparing it to its handshake register. If it changes, I latch a bit, and reset the comms timeout alarm delay timer.
The bit that I latch will call the subroutine where the rest of the setpoints are checked for changes, the outgoing file gets updated and after the loop completes its cycle through the range I need covered, I unlatch that bit so I don't keep calling this routine unnecessarily.
In the master PLC, the same principle is applied. The outgoing data is considered to be the "live", active data used on its HMI and for control purposes, and changes are made to that outgoing data. The incoming data is checked against handshake registers (one for each setpoint) and if differences occur, the new value is written to both the handshake element and the outgoing register. Like in the remotes, I only run these checks when I know that the message has completed successfully, except here, I will ensure that both write and read messages are completed by looking at the MSG DN bits (not just the heartbeat transition).
The reason for this (as I am sure you are aware) is that radio telemetry is never 100%, so if for example, the master changes setpoint A from 0 to 1, and then the data gets sent. The remote receives it, updates its outgoing data, but the master fails trying to read it. Nothing is wrong yet, until it is changed again and the message succeeds, or if the write message fails on the next cycle after a subsequent change. Like you, I have shot holes in a handful of schemes and evolved my method to this point.
It is still not perfect. It is possible to get into a race situation when operators change the same setpoint at both master and remote and the polling happens to be in between the reading and writing, and the right combination of messages don't succeed. But this method has resolved the race condition more than 98% of the time for me. The big drawback is having to have basically three copies of each setpoint. I recently did a system with 15 remote sites, 9 of which needed remote setpoint controls, with about 20 setpoints at each of those sites. That ended up using a large percentage of the available space in a Micrologix 1400 acting as the master.
Having written all this out, I am not sure if I conveyed it well enough...