SC.View#_touchBoundaryFrame (in core_foundation/views/view/touch.js and used by touchIsInBoundary, which is used by ButtonView's tap support among others) is a cacheable property of "frame" and "parentView". Unfortunately, these are not sufficient; the button's touch boundary changes whenever its location on the screen changes, not just its location relative to its parentView.
The solution appears to be to make it a property of "clippingFrame" instead, which is reliably invalidated all the way down the view tree (frame is not, if for example any ancestor's isFixedLayout = true)
It may also need "frame" and/oror "parentView"; further testing should validate this. Also of course it will need a unit test.
Fixed in master.