Now, bear in mind my direct experience is mainly with writing low-level flash code on microcontrollers with on-chip flash. But, I can't imagine it's terribly different than the much higher density mass storage flash.
I'll use "set" and "erase" to describe the operations on bits below. In typical flash, "erase" clears the bit to 1, and "set" deposits a charge and causes it to read as 0. Or, you can flip those around with "erase" leaving a 0 and "set" leaving a 1. Either way, the principle holds, and is the same principle you were highlighting.
The flash I've worked with puts an upper bound on the number of times you can set the same bit without an intervening erase cycle. This makes a certain amount of sense to me. The process of flipping a bit from erased to set deposits electrons onto an otherwise-floating transistor gate. Setting the same bit more than once could threaten to break down that gate prematurely by depositing too much charge. At least, I guess that's the reason behind the admonition to not re-program a given word more than once.
That said, write blocks tend to be much smaller than erase blocks, so that does give you some flexibility. So, while a given bit can only be "set" a certain number of times, the hardware generally gives you some granularity to avoid setting it too often.
Anyway, that constraint can limit the number of times you can "modify in place" a given block, and limit the ways in which that modification could be carried out. To me, the most interesting scenario is the "append to log" scenario. This one seems most compatible with the underlying physics. It does require the filesystem to pad sectors beyond EOF with an appropriate value for rewriting later. For example, if flash needs 1s, then the portion of a sector beyond EOF written by the filesystem needs to be 0xFF.
As far as checksums go, if you go with CRCs, they have a really nice property: They're fully linear codes. The CRC for a given block of data is equal to the XOR of the CRCs for each of the 1 bits in that block if you were to assume the other bits were zero. (Assuming no pre/post inversions.) That is, suppose you wanted to CRC this string: 10010001. Then: CRC(10010001) = CRC(10000000) ^ CRC(00010000) ^ CRC(00000001).
So, you could protect a block of data that's updated in this way by just appending the CRC of the delta to the "CRC list". The reader would then need to XOR all of the provided CRCs. Now, if your flash erases to 1 and sets to 0, then you could store CRCs inverted, with the unused CRCs reading as 0xFFFFFFFF. The reader wouldn't even have to know how many CRCs are valid at that point -- it could just read them all in and XOR them. If there's an even number of potential CRCs (as seems likely), the reader wouldn't even need to apply any inversions.