Yep, looks like an internal change last week broke it in a rather stupid way.
Just in case people care about technicalities: using compareexchange for thread safety and replacing the stored xp value with zero after a read is smart, reading the stored value afterwards again (aka the zero) instead of reusing the previously read value to grant the xp is not.