Spec 8.9c, the Android half, matching iOS. Each contact gets a random 32-byte
token, sent over the encrypted channel on the delivery-key envelope, which is
already the per-contact one. The relay is given only SHA-256 of it, and
presenting the token is what reads a presence.
Per pair rather than one shared secret, so taking one contact off the list
costs the others nothing. That is the difference from the sealed-sender
delivery key, where cutting somebody off replaces a key everybody holds.
Where a token is held its answer wins; a contact with no token yet keeps
whatever the roster said, so a half-migrated pair does not read as offline
while both ends catch up.
The HTTP stays out of the engine. Conversations has the vault and the e2e
surface but not the mobile one, so it mints the token and raises a flag, the
same arrangement avatarsUpdated already uses, and Session publishes.
A star inside a block comment opens a nested one in Kotlin, which is how a
doc comment naming a route path took out the whole file. The path is described
rather than written now.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>