fix(contacts): keep distinct custom dates instead of collapsing them

The mirror keyed each event on (contact, type) only, and the read deduped on
that same pair from an unordered query. So a contact with two custom dates
('Wedding', 'Graduation') mirrored just one — and, the winner being
order-dependent, the single event could ping-pong between the two dates across
syncs. A Custom date's UID now carries a discriminator (its label, else its
month-day), the read dedups on the full UID, and the query is ordered by
Data._ID so a genuine duplicate resolves the same way every time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 23:04:06 +02:00
parent 8881559e67
commit 7fe59b36c3
3 changed files with 74 additions and 11 deletions

View File

@@ -23,6 +23,37 @@ class SpecialDateFormattingTest {
.isEqualTo("contact-anniversary:abc@calendula")
}
private fun custom(label: String?, month: Int, day: Int) = ContactSpecialDate(
lookupKey = "k",
displayName = "Jane",
type = SpecialDateType.Custom,
month = month,
day = day,
year = null,
label = label,
)
@Test
fun `birthday and anniversary uids ignore the discriminator`() {
assertThat(birthday(5, 14, 1990).managedUid()).isEqualTo("contact-birthday:k@calendula")
}
@Test
fun `two custom dates on one contact get distinct uids by label`() {
assertThat(custom("Wedding", 6, 10).managedUid())
.isEqualTo("contact-custom:k:wedding@calendula")
assertThat(custom("Graduation", 9, 1).managedUid())
.isNotEqualTo(custom("Wedding", 6, 10).managedUid())
}
@Test
fun `label-less custom dates fall back to month-day so distinct dates survive`() {
assertThat(custom(null, 6, 10).managedUid())
.isEqualTo("contact-custom:k:06-10@calendula")
assertThat(custom(null, 9, 1).managedUid())
.isNotEqualTo(custom(null, 6, 10).managedUid())
}
@Test
fun `anchor date uses the known year`() {
assertThat(birthday(5, 14, 1990).anchorDate()).isEqualTo(LocalDate(1990, 5, 14))