It's possible for the ShardingDDLCoordinator to receive a PrimarySteppedDown error and retry before its stepdown token is cancelled to prevent the retry. If this happens while the MovePrimaryCoordinator is in the kCatchup phase, it is possible that it calls MovePrimaryDonor::onBeganBlockingWrites() multiple times, triggering an invariant by setting the promise twice.
Similarly to MovePrimaryDonor::onReadyToForget(), MovePrimaryDonor::onBeganBlockingWrites() should do nothing if the promise was already set.
Despite the fact that the critical section is taken by the coordinator with local write concern, the donor does not transition to blocking writes until it persists the blocking timestamp with majority write concern. In other words, there is no risk that acquiring the critical section is rolled back while the donor believes that it is still held because both the coordinator and donor are running on the same node.