This is a better and more general fix for T92511 and T92508 than the ones that I committed before.
Previously, we tagged caches dirty when first accessing attributes. This led to incorrect caches when under some circumstances. Now cache invalidation is part of OutputAttribute.save().
A nice side benefit of this change is that it may make things more efficient in some cases, because we don't invalidate caches when they don't have to be invalidated.