Notification matrix
Applies to: SimpleTwo 0.9.x · Checked: 20.09.2026
Two questions, deliberately kept apart: does a notification arrive at all, and what does it say. Both are below, and the first is a table whose every row is asserted by a test: a row changed in the product and not here is a defect in whichever was not changed.
1. The order the rules are applied
Earlier rules win. This order is the policy.
- You wrote it → nothing.
- The conversation or the thread is muted → nothing. Mute beats every relationship, including your manager: a switch you can see must not do less than one you cannot.
- Your app is connected and awake → nothing: the socket already delivered it. Messages only — a call does not consult the socket at all. "Awake" is the client's own statement, not the existence of a connection: a suspended app holds a socket and reaches nobody.
- Your notification level says no → nothing.
- Do Not Disturb → only what is addressed to you, and only from somebody who passes the gate (§3).
- Otherwise it arrives.
2. The table
The recipient is available unless the row says otherwise.
| What happened | Sender | Recipient state | Arrives? | How |
|---|---|---|---|---|
| Direct message | anyone | available | yes | banner with sound |
| Direct message | anyone | DND, gate "favourites" (default) | no | held |
| Direct message | favourite | DND | yes | time-sensitive, subtitle "★ Favourite" |
| Direct message | manager | DND | yes | time-sensitive, subtitle "★ Your manager" |
| Direct message | manager | DND, gate "nobody" | no | held — an explicit "nobody" is honoured |
| Mentioned in a group | anyone | available | yes | time-sensitive, "↗︎ Mentioned you" |
| Mentioned in a group | manager / favourite | DND | yes | breakthrough |
| Mentioned in a group | anyone else | DND | no | held |
| Mentioned in a group | anyone | level "none" | no | "none" means none |
| Reply to your message | anyone | level "all" | yes | banner, "↩︎ Replied to you" |
| Message in a thread you follow | anyone | level "mentions" | yes | banner |
| Message in a thread you follow | manager | DND | no | following is not being addressed |
| Ordinary room message | anyone | level "all" | yes | banner |
| Ordinary room message | anyone | level "mentions" | no | held |
| Ordinary room message | manager | DND | no | a busy room is exactly what DND is for |
| Anything | anyone | conversation or thread muted | no | whoever sent it |
| Channel post | anyone | level "all" | yes | banner, lower relevance: a feed must not out-shout a colleague |
| Call | anyone | iPhone | rings | VoIP push → the system call screen |
| Call | anyone | Android | rings | high-priority push → full-screen call |
| Call | anyone | Mac | banner with sound | Answer / Decline; on macOS this is not a ring in the system sense |
| Call | favourite / manager | DND | rings | the same gate as messages |
| Call | anyone else | DND | no ring | a missed-call record remains |
| Call | anyone | a pass holder: in the call, not in the chat | rings | they are part of the signal's audience |
| Call cancelled | the caller | a device that rang | stops the ring | a second push on the same transport |
| Call cancelled | the caller | a device that did not ring | nothing | a withdrawal to an un-rung phone would itself be a ring |
| Call cancelled | the caller | Mac | nothing | the banner stays until dismissed |
| Other call steps | anyone | any | nothing | join, end, decline, hold — these are not notifications |
| Presence change | somebody you subscribe to | available | yes | silent, no sound, collapses per person |
| Presence change | somebody you subscribe to | DND | no | held |
3. The Do Not Disturb gate
Each recipient picks the widest circle they still accept in Do Not Disturb; every tier includes the ones below it:
| Gate | Who gets through |
|---|---|
org | anyone in the company |
favorites | favourites, priority contacts, your manager |
priority | priority contacts and your manager |
manager | your manager only |
none | nobody |
The default is favorites and today everybody is on it: the per-user setting does not exist
yet, and neither does the priority-contact list. Anybody expecting priority to mean something
would get "your manager and nobody else", which is why the default stays at favorites until the
list ships.
4. Where the manager comes from
From a directory attribute that arrives as a claim at sign-in. Matching is by DN: the manager's distinguished name in one account matches the employee's own DN in another.
A mail address in that field matches nobody and is written to the audit log
(directory.manager_unresolved). That matters here in particular: a misconfigured manager breaks no
sign-in and shows nothing red — it simply never breaks through Do Not Disturb, and that looks like
"breakthrough does not work". How to configure it: ADFS.
5. What a notification says
| Element | Rule |
|---|---|
| Title | the room's name; for a direct chat, the person |
| Subtitle | why you are being told, then who, then about what |
| Body | the message, cut at 240 characters |
| Structured messages | 📍 location · 👤 contact · 📎 attachment · 📌 pinned — never raw JSON |
| Secret chats | 🔒 an encrypted message: that something arrived and from whom, never what it says |
| Grouping | one stack per conversation, by topic within one |
| Breakthrough | always names the relationship that let it in: an unexplained banner in DND reads as a broken setting |
The text is composed by both sides: the server builds a complete notification and knows people by their logins, and the device rewrites it before display — substituting names from its own directory cache and the app's language. The server's version is not a fallback nobody sees: it is what appears whenever the device extension did not run. The rewriting rule is one — never make a notification worse: an unknown field, an empty cache or a payload from an older service all return the server's text untouched.
6. What does not exist yet
- the per-user gate setting and the priority-contact list (§3);
- actions inside the notification (reply, mark as read) — the payload is ready for them;
- the contents of secret chats on the lock screen: the extension cannot decrypt them either, because the key lives in the app's own keychain.