Our identity sync reads employees from the HR system every hour and creates, updates or disables accounts in our directory. On a Monday in April, twenty three people could not sign in to anything. Their accounts had been disabled overnight as leavers, and new accounts with the same names had been created for them as joiners an hour later, with no groups, no mailbox history and new usernames ending in a 2.
All twenty three had an accented letter somewhere in their name. José, Zoë, Müller, Gonçalves.
The HR vendor had moved its API to a new platform at the weekend. The data was the same, but the new platform returned text in decomposed Unicode form. In the old feed, é was one character. In the new one it was an e followed by a separate combining accent. They look identical on every screen and compare as different strings in every language we use.
Our sync matched HR records to directory accounts by a key built from first name, last name and date of birth. It was written that way in 2018, before the HR system exposed a stable employee id through its API. With the new feed, José's key no longer matched the José in the directory, so the sync concluded that the existing account belonged to someone who was no longer in HR, and disabled it. On the next run it found an employee in HR with no account, and created one.
We restored the accounts from the directory's recycle bin, merged the duplicates by hand and had everyone back by eleven. The sync now matches on the HR system's employee id, available for four years and never adopted because the old key worked. Every text field from an external system is normalised to the composed form at the point where it enters our code, before it is compared, stored or logged. Contract tests for each integration include names in both forms, names with apostrophes and names with characters outside the Latin alphabet. And disabling an account is now a two step action: the sync marks it, and it is only disabled if the next run agrees.
Two strings that look the same are not a promise that they are the same. A matching key built from names is a key built from whatever the other system decides a name is made of this week.
– Sergey Shinder
Top comments (0)