When calculating the stable timestamp, the replication coordinator does not allow it to advance beyond the oplog entry timestamp of the oldest uncommitted/aborted prepared transaction. This timestamp is maintained in the ServerTransactionMetrics service context decoration which is updated through the TransactionParticipant's TransactionMetricsObserver object when a transaction prepares, commits, or aborts a transaction.
It looks like the metrics are updated after the commit oplog entry is written in a side transaction, so if the commit point advances to include the commit's opTime before the transaction metrics are updated, a recalculation of the stable timestamp will be triggered, but the replication coordinator will not know it can advance the stable timestamp to include the commit oplog entry. The next operation to trigger a calculation of the stable timestamp will be able to advance to include the commit, but if nothing triggers a new calculation, anything waiting for a new committed snapshot will hang. This seems possible when aborting a prepared transaction as well.
A similar problem exists with prepare, because we also commit the prepare oplog entry before updating the oldest prepared timestamp in the transaction metrics, although this should lead to incorrectly advancing the stable timestamp instead of incorrectly holding it back.