After more reading, I realized the following fact:
iOS has different version number strategy than macOS. Specifically, an iOS app's version number typically looks like major.minor.patch (build), whereas for macOS app it looks like major.minor.patch. No build number for macOS app due to historical reasons.
On iOS, major.minor.patch = CFBundleShortVersionString, and build = CFBundleVersion
on macOS, major.minor.patch = CFBundleVersion
Which causes problem for a cross platform app that used to be iOS only, but recently start to support macOS via Mac Catalyst (exactly our case. =_=!)
The app versioning used to work well with iOS versioning pattern major.minor.patch (build) where the "must contain a higher version" requirement only applies to the build part when the version number is the same. If the version is different, no need to compare build at all.
But on macOS, because there is no build number, it directly compares the major.minor.patch version number, which unfortunately uses the same dict key CFBundleVersion as on iOS. Thus, the single component build number on iOS, becomes the sole number for macOS version comparison.
That doesn't pose a problem if your app's build increases daily. But it causes huge problem if you assign the build manually when you do the App Store upload, like us.
How to solve it? Well, I hope App Store Connect can add some special handling for cross-platform app that originated from iOS, to first compare the version number via CFBundleShortVersionString, so that CFBundleVersion can be treated as a build number to be used for further comparison.
Otherwise, we have to discard the 20-million integers (20240801 to be exact) we've inadvertently wasted for the macOS version number. 😩