Pixieby Sociofabric

A Relay That Holds Nothing: Ephemeral Delivery

The most valuable thing a message relay (the server that carries sealed messages between phones) can own is a database of undelivered messages. It is also the most dangerous thing it can own. So we decided the relay would not own one.

We have hidden the content, the sender, the linkage, and the type. This article takes away the last thing you would assume any relay must have: a mailbox.


1. The honeypot you get for free

Every straightforward messenger has a store-and-forward queue: when Bob is offline, his incoming messages pile up in a server-side inbox until his phone collects them. It is the natural design, and it quietly builds the single most sensitive object in the system.

A durable inbox is a standing record of who is about to hear from whom. It sits at rest, indexed and backed up, for as long as delivery is pending, and often (through logs and replicas) long after. That makes it:

Note that content encryption does not help here at all. The inbox rows can have perfectly encrypted bodies and still be a catastrophe. The damage is in the existence and shape of the rows: recipient, size, arrival time, rate. The chapters before this one worked to remove metadata (facts about a message, rather than its content) from the envelope. Keeping a durable inbox would hand almost all of it back, at rest, in a queryable table.

The cleanest way to not leak a database is to not have a database.


2. Publish, subscribe, and drop

The relay is built as pure publish/subscribe with no persistence. Publish/subscribe is a simple pattern: a sender publishes bytes to a named channel, anyone currently listening on that channel receives them, and that is the whole transaction.

Concretely, it runs on NATS (an open-source message bus, infrastructure built for exactly this publish-and-forward job) in its plain core mode, not the durable "JetStream" mode that would persist anything.

When a message arrives, the relay publishes it to the pair's current rotating subject: the channel name for one specific recipient device, which changes over time. That address is derived from a secret only the two ends hold, not from anything the relay knows.

Any device subscribed to that subject at that instant receives the bytes. Any device that is not receives nothing, and nothing is written down.

ALICE RELAY NO COPY · NO ROW A DEVICE IS SUBSCRIBED BOB · LIVE DELIVERED = 1 NOBODY SUBSCRIBED DELIVERED = 0 · NOTHING KEPT CONNECT AND IT STREAMS — MISS AND NOTHING IS LEFT BEHIND

The mental model is a live phone call versus voicemail. Voicemail records; a live call that no one picks up leaves no recording anywhere. The relay is the live call: connect at the same time and you talk; miss each other and there is simply nothing left behind to seize.

The only thing the relay reports back to the sender is a count: delivered = how many of the recipient's devices were live and got it, right now. Zero means "nobody was home." It is a delivery signal, not a stored state: the instant the publish returns, the relay's involvement is over.


3. If the relay forgets, who remembers?

Someone has to hold the message until Bob actually gets it, and we just said it isn't the relay. The answer: the sender does. Durability lives entirely in Alice's outbox, a local queue on her own device.

And here is the rule that makes it correct: an outbox entry is cleared only when Bob's device sends back an acknowledgement, not when the relay says delivered, and certainly not when Alice merely hit send. delivered > 0 means "a device was live and the bytes reached it." That is almost delivery, but it is not proof that the app processed and stored the message. Only Bob's explicit ack means "it is safely his now." Until that ack comes back, Alice's phone keeps the message and keeps trying.

ALICE RELAY BOB LOCAL OUTBOX MESSAGE M HELD UNTIL ACK COPY STREAMS · ORIGINAL STAYS NO STORAGE DELIVERED > 0 DOES NOT CLEAR BOB'S STORE M STORED ✓ ACK · SAFELY STORED CLEAR HERE ONLY DURABILITY LIVES WITH THE SENDER · ACKNOWLEDGEMENT RELEASES IT

This flips the trust model in the user's favor. The pending message lives on the device of the person who wrote it, protected by that device's own encryption, under that person's control, not in a server the person has to trust to hold their unsent thoughts.


4. The zombie-socket problem

Pure publish/subscribe has a nasty failure mode that is worth telling, because the fix is the kind of detail that usually gets glossed over.

On iOS, a backgrounded app's network connection does not cleanly close. It freezes. The socket (the open network connection) looks alive to the server for a while, so the relay counts Bob as "subscribed" and happily publishes to a connection that will never deliver. delivered reads 1, Alice's outbox relaxes, and the message quietly evaporates: the worst outcome, a silent loss.

The fix is a liveness ping: the relay pings each connection on a short interval (every few seconds) and reaps (drops) any connection that fails to answer within a tight timeout. A frozen, suspended app fails the ping and gets pruned. The live-subscriber count then deflates to its truth, zero, which correctly reports "nobody home" and triggers the fallback that actually reaches Bob: waking his phone. The whole no-mailbox design depends on delivered being honest, and the liveness ping is what keeps it honest.

RELAY BOB · FROZEN SOCKET LOOKS OPEN PING NO PONG TIMEOUT · REAP SOCKET DELIVERED = 1? LIVE = 0 PUSH WAKE ENABLED WAKE BOB NO PONG → NO SUBSCRIBER → AN HONEST ZERO → WAKE

5. Not losing messages without a mailbox

"No server storage" must not mean "lossy." The sender's outbox is engineered to survive the gap between Bob is offline and Bob is back:

The result behaves like a reliable queue from the users' point of view, while the server remains a stateless pipe. The cost is real and we accept it: the sender's device does more work and spends a little more battery retrying, and a message to a long-offline recipient waits on the outbox rather than a server. We considered that a fair price for deleting the single most dangerous object in the system.


6. The one deliberate exception

There is exactly one place the relay holds message bytes, and it is bounded and purposeful. To make the pull side private (so that Bob catching up on missed messages doesn't tell the relay which conversation he's reading), the relay keeps recent sealed envelopes in a short (about a minute) windowed pool. It serves them through Private Information Retrieval (PIR), a scheme that lets Bob pull one item out of the pool without the relay learning which one he took.

It is not a mailbox. It is a rolling one-minute window of sealed envelopes, filed under the routing subject of the conversation they belong to. Periodically the window is frozen into a snapshot, named by a hash (a short fingerprint) of the whole window, so client and server can agree on which version a query refers to. Nothing is ever looked up by its own content, which is exactly what lets the read be oblivious, meaning the relay answers the query without learning what was fetched. That mechanism is its own chapter: Reading Without Being Watched.


7. The honest residual

With no durable store, the relay's footprint shrinks to the transient (things it sees only in the moment of delivery) and to three bounded pieces of state, none of which is a mailbox:

None of that records who was about to hear from whom. The relay still cannot answer "who was Bob about to hear from last Tuesday?" Not because it declines to, but because it never wrote down anything that could be joined into an answer. That is the point: the strongest guarantee about a database is the one you get by not keeping it, and the second strongest is keeping only things that name nobody.


References & further reading

← The Envelope: Minimizing What the Relay Must SeeReading Without Being Watched: Oblivious Pull →