Elections and Data Routing in Mali
When my colleague Jared and I landed in Bamako, I was expecting to head to our hotel, have an early dinner, and then grab the sleep we missed out on during our plane ride over, so that we would be prepared to get to work the next morning. Instead, plans were quickly set and we had an hour to settle in before a car arrived to whisk us away to the recently opened data center. With the first round of Mali’s presidential elections five days away, time was at a premium to make sure systems were up and running as soon as possible so that any issues could be taken care of. The elections have come during a challenging time for the country, and it was key for citizens to be able to exercise their voice in a free and fair manner. Ensuring that this occurred requires comprehensive election observation, and it was our job to provide technical assistance to this mission.
Our task was to provide support for the data center being run by our local partner, COCEM, so that they could receive text messages from 1000+ election observers who they had deployed at polling stations across the country. Their reports would be stored in an instance of the Apollo DemTool that COCEM was using, but we still needed a tool that could receive text messages and turn them into digital content to be passed onto the Apollo database. To do this, we relied on a software tool called Telerivet. Essentially, Telerivet allows a number of phones to be networked together and work in sync to send and receive SMS. Telerivet’s online dashboard lists all messages sent in to the phones running the software, and allows the user to broadcast text messages back to any set of phones. It’s an easy way to send out mass texts to large groups of people, as well as to collect and sort through high volumes of incoming texts.
This was perfect for our context of receiving a series of messages from a large number of observers, as well as needing to send out reminders and updates every day or two. Operating in Mali added an additional factor to consider: the two main telecom providers in Mali are Orange and Malitel, and each provides deals where one can send text messages for free to other phones that are in the same network (Orange to Orange, or Malitel to Malitel). Thus, we had a strong incentive to keep messaging within network. For incoming texts, this was easy - we simply assigned each observer a certain number to text in to, and ensured that that number was for a Telerivet phone on the right network. The challenge was to make sure that the message blasts we sent out to them also stayed within network. Since we assigned different Telerivet phones to observers in different parts of the country, we also wanted to make sure that messages were coming out from the phone assigned to an observer so that they would already recognize the number sending out a message to them, and confusion would hopefully be minimized.
Luckily, Telerivet has a custom routing feature that helps to solve just such a problem. The feature lets you use if/else logic to create logic trees. Send a list of phone numbers through a custom route, and each number will go to the correct branch of the logic tree and perform an action, which is usually to send out the message to the recipient phone from a specific telerivet phone. These trees can be fairly simple, but you can also nest if/else statements to create quite complex layers of logic. To satisfy our criteria, our logic tree would have to sort both by carrier and by region. We already had the observer phones grouped by region, and were able to upload this into Telerivet. To sort by carrier, we found out from our partners that a phone number’s carrier could be determined by looking at the first two digits of the phone number. Testing this out quickly led to a few stages of troubleshooting, where we would realize we used an ‘and’ where we should have used ‘or’, or that we needed to switch an ‘else’ to an ‘else if’. After making as many fixes as we could find, we ran into a problem. Despite our massive logic tree seeming correct as far as we could tell, it kept sending to all recipient numbers from a single Telerivet phone. One recipient phone would seemingly navigate the logic tree correctly and be sent to by the right Telerivet phone, but then all the other recipient phones would receive from that number whether they were Orange or Malitel, or grouped as Bamako or Timbuktu. We did test after test using the phones of our colleagues as recipients, who humored us by coming by our table every few minutes to report on the umpteenth test message they had received.
Over the course of the next few days, as we got time, we would try various alterations and simplifications to our attempt. Each change seemed to leave us no better off, and we were left second guessing every step we took. Was the problem that we didn’t have an ‘else’ at the end of our logic tree as a catch-all? Or was putting in the ‘else’ a problem that was somehow stopping the logic tree from resetting to the beginning for the subsequent numbers in the list? Finally, we came up with a partial solution that worked. We gave up on the regional sorting, figuring that observers could handle being sent to from numbers they didn’t recognize, and instead focused on simply sending from the right carrier so that we could at least keep costs down. Before uploading to Telerivet, we assigned phone numbers into groups based on their carrier, which upon upload were transferred into groups within Telerivet. We then created a custom route to send the ‘Orange’ group from the set of Orange Telerivet phones, and the ‘Malitel’ group from the set of Malitel phones. When we set this as the default route and sent in messages from Apollo, the messages were sent from the a phone of the correct carrier, with Telerivet even balancing the broadcast between the different Telerivet phones to help share the load and send out the messages more quickly.
We also decided to send out an email on Friday to check in with the developers of Telerivet and see if they could figure out what might be happening. On Monday we heard back from the developers and found out what was going on. It turned out we had actually stumbled upon a bug in the program, which as of that morning was now fixed, and they passed along a bug bounty as a reward to thank us for alerting them of the issue. We were relieved that the problem was not some absentmindedness on our part and glad that they were able to push out a bug fix so quickly. The ordeal showed us that as a user, you can never be sure whether problems are being caused more by the user or the software - in our case, some of both happened. These are some good lessons to keep in mind as we look to conduct some user testing of Apollo while here.
With Telerivet fixed and ready to go, COCEM was able to successfully communicate and receive messages from their observers. The result was a successful observation during the first round in which 99% of observer data was received. With lessons learned, we’re ready to help COCEM continue its mission as it gets ready for the second round of elections this Sunday!