What we learned building a permission system for phone numbers
If your contact details are going to come from you rather than from a copy someone made, you need to be able to decide who gets what. That sounds like a settings screen. It is not. It turned out to be the hardest part of the product, and three decisions in particular ended up holding everything else up.
1. Circles grant. They never deny.
The obvious model is folders: put people in groups, then hide things from some groups. We tried thinking about it that way and it produces a question nobody can answer reliably — what happens to someone who is in two groups with different rules?
Every answer to that is bad. Take the most restrictive and people are confused when adding someone to a group removes something. Take the most permissive and “hidden” does not mean hidden.
So circles only ever grant. A person sees the union of what their circles give them. Adding a circle can reveal more; it can never reveal less. That makes the rule statable in one sentence, which means people can actually predict it, which is the entire point of a permission system.
The cost is that “stop showing this to Sam” is sometimes two steps rather than one. We took that trade deliberately. A model you can hold in your head beats a model with fewer taps.
2. There is a floor, and it is not zero.
Everyone you connect with gets your name, photo, handle, mobile, and nickname — always, without configuring anything.
We went back and forth on this. The privacy-maximal position is that every field starts off and you opt in to each one. It sounds right, and it is wrong, because a contact app where a new connection shows a blank card is not a contact app. It is a settings chore with a person attached.
A floor that low is not much to give away — it is roughly what you would tell someone who asked in person. And having it means connecting produces something immediately, instead of producing homework.
Health details sit outside all of this, behind their own consent step. Allergies are not a contact field and should not be governed like one.
3. Revoking has to actually revoke.
This is the one that shaped the architecture, and it is the most technically inconvenient thing in the product.
If your phone kept a local copy of the fields other people share with you, then revocation would be a polite request. They stop sharing, and a copy of what they shared is still sitting on your device, silently, indefinitely. Everyone would technically be told the truth and nobody would actually have control.
So it does not keep a copy. Fields shared with you are read live, every time. Stop sharing and it is gone — not gone from the interface while lingering in storage, gone.
That decision costs us real things. It constrains what works offline. It means more requests. It rules out designs that would have been simpler. We keep it because it is the difference between a promise and a feature, and this whole product is a bet that people will only hand over the authoritative version of their details to something that keeps the promise.
What generalises
None of this is really about contacts. It is about what happens when you ask people to stop keeping their own copy of something and trust a shared source instead. They will do it — but only if the rules are simple enough to predict, the default is generous enough to be worth turning on, and the undo genuinely undoes.
Get one of those three wrong and the other two do not matter.