Update: more testing since posting (iPhone 15 Pro, iOS 27.0.1, FB24933340).
1. The production configuration behaves the same. The repro above lists all three kinds in supportedHandleTypes. With [.generic] only (what we ship), value is still shown on the ring, the banner and in Recents.
2. Donation is ruled out for later calls too. After a successful donation (id in personHandle and customIdentifier, name in displayName), ringing the same handle again still shows the id. Putting the name in value and donating the id doesn't help either: the UI reads correctly, but a Recents redial returns the name and ignores the donated person and its customIdentifier.
3. A redial carries nothing else to map back from. In scene(_:continue:), both when the app is running and from a cold launch, the INStartCallIntent has only the contact's personHandle.value (type unknown) and display name. callRecordToCallBack, callRecordFilter, customIdentifier and contactIdentifier are all nil, and the intent and interaction identifiers are new on every tap. There's no conversation UUID, so whatever is in value is the only way back to the person.
4. callservicesd's name lookup never checks displayName. While reporting the call it logs:
Finding the appropriate localized name to use for handles
- handle can't/shouldn't be formatted as a phone number, so using the unmodified destination ID
Received result from SGSuggestionsService: result (null)
Suggestions: No suggested name found for '<private>'
SNAP Suggestions: Hiding suggested nickname to prevent phishing. (isDomestic = 0, handleType = 1)
That looks like Contacts, then Suggestions, then the raw value, with suggested names deliberately hidden for generic handles. That would explain both the ignored displayName and why donation doesn't help.
Revised questions:
Is displayName meant to be shown for .generic handles, or only as a fallback for .phoneNumber and .emailAddress handles that don't match a contact?
If LiveCommunicationKit can't show a name while keeping a stable identifier, is CallKit (with localizedCallerName) the recommended path outside mainland China, keeping LiveCommunicationKit only where CallKit isn't available?