In AActor::GatherCurrentMovement, bWasAttachmentModified will be set to true if the actor’s root component has an AttachParent, even if none of the values in the AttachmentReplication struct have changed.
Additionally, AActor::PreReplication will set the AttachmentReplication struct’s AttachParent and AttachComponent to null before calling GatherCurrentMovement, which will get the current values for these pointers. After GatherCurrentMovement, PreReplication then checks if the old AttachParent/AttachComponent differ from the current AttachParent/AttachComponent, marking the struct dirty if so.
However, AActor::GatherCurrentMovement also performs this handling of setting the AttachParent/AttachComponent to null before later checking if the old values differ from the current ones. Because these were already reset to null in PreReplication, the “old” values in GatherCurrentMovement will always be null. If the actor’s root component has a non-null AttachParent, this value will always differ from the OldAttachParent, causing AttachmentReplication to be marked as dirty.