Part 30 — Presence, Availability, Typing, Read Receipts & Ephemeral Realtime State Architecture

Reusable P2P Communication Platform

Status: Architecture specification
Part: 30
Primary language: Rust
Primary purpose: define the ephemeral realtime state plane for presence, availability, typing, recording, delivery/read receipts, device activity, and short-lived conversation state without polluting durable messaging/event-log semantics
Primary goals: low-latency UX, privacy-preserving presence, multi-device aggregation, bounded fan-out, battery-aware updates, graceful offline behavior, deterministic expiry, group scalability, abuse resistance, transport independence, and clean integration with messaging, calls, DTN, E2EE, and diagnostics


1. Purpose

A polished messenger needs more than durable messages.

Users expect:

online
offline
away
last seen
typing…
recording voice…
delivered
read
active on another device

These states are useful, but most of them are:

temporary
best-effort
time-sensitive
not worth durable replication

If they are implemented like normal durable messages, the system creates:

unnecessary database writes
large event logs
battery/network overhead
stale states
privacy problems
group fan-out explosions

The governing principle is:

Durable facts belong in the event/message system; transient hints belong in a separate bounded ephemeral-state plane.


2. Architectural Position

                   Dioxus UI
                      │
                      ▼
              Ephemeral State View
                      │
             ┌────────┼────────┐
             │        │        │
         Presence   Typing   Receipts
             │        │        │
             └────────┼────────┘
                      │
              Ephemeral Runtime
                      │
         Capability / Privacy Policy
                      │
                 Peer Transport
          Direct / Relay / Local Path

Durable state remains separate:

Message DB
Event Log
Call History

3. Ephemeral vs Durable Matrix

StateEphemeral?Durable?
Online nowyesno
Typingyesno
Recording voiceyesno
Speaking in callyesno
Delivery acknowledgementpartlyyes when it affects message state
Read receipttransient transport + durable message stateyes
Last seenderived/optionalmaybe bounded metadata
User blocknoyes
Message sentnoyes
Device revokednoyes

4. Major State Families

#![allow(unused)]
fn main() {
pub enum EphemeralStateKind {
    Presence,
    Availability,
    Typing,
    VoiceRecording,
    Uploading,
    DeliveryReceipt,
    ReadReceipt,
    ActiveDeviceHint,
    CallAvailability,
}
}

5. Presence

Presence answers:

is the peer currently reachable/active?

It must not imply:

guaranteed delivery
physical location
human attention

6. Presence State

#![allow(unused)]
fn main() {
pub enum PresenceState {
    Offline,
    Connecting,
    Online,
    Idle,
    Away,
    DoNotDisturb,
    Invisible,
    Unknown,
}
}

7. Unknown vs Offline

Important distinction:

Offline

means the system has strong reason to believe peer is not presently reachable.

Unknown

means:

no fresh presence data

Do not render unknown as confidently offline.


8. Presence Is Advisory

Message sending should not depend on presence.

Correct:

presence says offline
→ message still goes to outbox/mailbox/DTN according to policy

Incorrect:

presence says offline
→ refuse message

9. Availability

Presence and availability are related but different.

Example:

online
but
Do Not Disturb

or:

online
but
not accepting calls

10. Availability State

#![allow(unused)]
fn main() {
pub struct AvailabilityState {
    pub presence: PresenceState,
    pub messaging: MessagingAvailability,
    pub calling: CallingAvailability,
}
}

11. Messaging Availability

#![allow(unused)]
fn main() {
pub enum MessagingAvailability {
    Available,
    Delayed,
    DoNotDisturb,
    Unknown,
}
}

12. Calling Availability

#![allow(unused)]
fn main() {
pub enum CallingAvailability {
    Available,
    Busy,
    DoNotDisturb,
    CallsDisabled,
    Unknown,
}
}

13. Presence Scope

Presence can be:

device-scoped
account-aggregated
conversation-scoped
organization-scoped

14. Device Presence

#![allow(unused)]
fn main() {
pub struct DevicePresence {
    pub device: DeviceId,
    pub state: PresenceState,
    pub last_update: MonotonicInstant,
}
}

15. Account Presence Aggregation

An account may have several devices.

Example:

phone offline
desktop online
tablet idle

UI should usually show:

Online

because at least one trusted device is reachable.


16. Aggregation Rule

Example:

if any device Online → Online
else if any Idle → Idle
else if any Away → Away
else if all known Offline → Offline
else → Unknown

17. Invisible Mode

If user selects invisible:

local app may still communicate

but peers receive:

no online presence
or deliberately hidden state

according to privacy policy.


18. DND

DND is not offline.

Peer may still receive messages.

It mostly affects:

notifications
calls
typing/read visibility if configured

19. Presence Privacy

User options:

Everyone
Contacts
Verified contacts
Nobody

Product may support a smaller set initially.


20. Per-Peer Presence Privacy

Future advanced setting:

allow presence for selected peers

but avoid complex ACL UI in v1 unless needed.


21. Last Seen

last_seen is privacy-sensitive.

Do not derive it simply from every network packet.


22. Last Seen Policy

Possible:

#![allow(unused)]
fn main() {
pub enum LastSeenVisibility {
    Everyone,
    Contacts,
    Nobody,
}
}

23. Last Seen Granularity

To reduce tracking precision:

exact minute
coarse time
today
recently

Product choice.


24. Coarse Last Seen

Privacy-friendly examples:

recently
today
this week

instead of exact timestamp.


25. Last Seen Is Optional

The system remains fully functional without storing/displaying it.


26. Presence Transport

Prefer:

existing secure peer channel

or lightweight gossip/presence protocol where appropriate.

Do not create heavyweight connection churn just for presence.


27. Presence Protocol

Example ALPN/logical protocol:

presence/1

28. Presence Advertisement

#![allow(unused)]
fn main() {
pub struct PresenceAdvertisement {
    pub device: ScopedDeviceId,
    pub state: PresenceState,
    pub revision: u64,
    pub expires_after_ms: u32,
}
}

29. TTL

Presence must expire automatically.

Example:

online TTL: 30–90 s

if no refresh.

Exact values tune by platform/power mode.


30. No Permanent Online State

If a device crashes:

presence automatically expires

without requiring explicit offline packet.


31. Graceful Offline

On clean shutdown, may send:

Offline

but correctness never depends on it.


32. Presence Heartbeat

Refresh interval should be less than TTL.

Example:

refresh every 20–30 s
TTL 60–90 s

Desktop can be more frequent than battery-constrained mobile.


33. Battery-Aware Presence

Part 13 can reduce frequency.

Example:

foreground: 20 s
background: 60 s
battery saver: 120 s

with corresponding TTL adjustment.


34. Mobile Background

Do not rely on continuous background presence heartbeats.

Android/iOS may suspend the app.

Presence becomes:

Unknown/Offline

until push/wake/reconnect.


35. Push Is Not Presence

Push token availability does not mean:

user online

36. Direct Connection Hint

An active authenticated Iroh connection is useful evidence of reachability.

But still separate:

transport reachable

from:

human active

37. Activity State

#![allow(unused)]
fn main() {
pub enum UserActivity {
    Active,
    Idle,
    Background,
    Unknown,
}
}

38. UI Activity Detection

Use local platform/UI events.

Do not transmit every input event.


39. Idle Threshold

Example:

5–15 minutes

product-configurable.


40. Typing Indicator

Typing is:

conversation-scoped
short-lived
best-effort

41. Typing State

#![allow(unused)]
fn main() {
pub enum TypingState {
    Started,
    Stopped,
}
}

42. Typing Event

#![allow(unused)]
fn main() {
pub struct TypingEvent {
    pub conversation: ConversationId,
    pub sender: DeviceId,
    pub revision: u64,
    pub expires_after_ms: u32,
}
}

43. Never Persist Typing

Do not write typing events into:

SQLite history
offline event log
DTN
backup

44. Typing TTL

Example:

3–8 seconds

without refresh.


45. Typing Start

Send when:

composer transitions empty/not-typing
→ actively typing

46. Typing Refresh

Refresh periodically while typing.

Do not send on every keystroke.


47. Typing Stop

Send when:

message sent
composer cleared
input loses focus
typing idle timeout reached

But TTL remains fallback.


48. Typing Throttle

Example:

at most 1 update per 2–3 s

per conversation/device.


49. Group Typing

For groups, show:

Alice is typing…
Alice and Bob are typing…
Several people are typing…

Do not render huge participant list.


50. Group Typing Fan-Out

Avoid O(N²) chatter in large groups.

Potential strategies:

gossip topic
group relay
coalesced presence channel

depending group architecture.


51. Typing Privacy

User may disable:

Send typing indicators

Receiving typing can remain enabled.


52. Voice Recording Indicator

When composing a voice message:

Recording audio…

can be ephemeral.


53. Voice Recording State

#![allow(unused)]
fn main() {
pub enum RecordingState {
    Started,
    Stopped,
}
}

54. Recording Privacy

Optional user setting.

Do not transmit microphone audio until actual voice message/call pipeline does so.


55. Uploading Indicator

Potential:

Sending a file…

but usually local transfer progress is enough.

Remote "uploading" hints should be used sparingly.


56. Delivery Receipt

Delivery means:

recipient device/application has durably accepted the message.

Not merely:

transport packet arrived

57. Receipt Stages

#![allow(unused)]
fn main() {
pub enum MessageReceiptState {
    Sent,
    Delivered,
    Read,
}
}

58. Sent

Sent means:

sender successfully committed/transmitted according to sender-side semantics

Exact product semantics should align with Part 04/outbox.


59. Delivered

A robust definition:

recipient persisted message durably

Then it can send delivery receipt.


60. Transport ACK Is Not Delivery Receipt

Do not confuse:

QUIC stream write ACK

with:

recipient application stored message

61. Delivery Receipt Event

#![allow(unused)]
fn main() {
pub struct DeliveryReceipt {
    pub conversation: ConversationId,
    pub through_seq: MessageSequence,
    pub receiver_device: DeviceId,
}
}

62. Cumulative Receipts

Instead of:

one receipt per message

prefer:

delivered through sequence N

where sequence model permits.


63. Sparse Receipt

If ordering/gaps exist, use:

through N
+
exceptions

or explicit message IDs for unusual cases.


64. Read Receipt

Read means:

message crossed product-defined read threshold

not simply:

app received it

65. Read Threshold

Possible definition:

conversation visible
message rendered/within viewport
app foreground

Use a clear rule.


66. Read-Through Sequence

Prefer:

#![allow(unused)]
fn main() {
pub struct ReadReceipt {
    pub conversation: ConversationId,
    pub through_seq: MessageSequence,
}
}

67. Read Receipt Privacy

User setting:

Send read receipts

If disabled:

do not transmit read status

except possibly organization-managed policy if explicitly configured.


68. Group Read Receipts

Scaling challenge.

For small groups:

per-member read state

For large groups:

read count
or
limited visible participants

depending product.


69. Group Receipt Storage

Do not create one DB row per member/message unnecessarily.

Use cumulative state:

member X read through sequence N

70. Receipt Durability

Unlike typing, delivery/read status modifies durable message state.

Therefore:

receipt transport event

may be ephemeral in transit, but its resulting state should persist.


71. Receipt Retry

If receipt packet lost:

next cumulative receipt supersedes it

This reduces retry complexity.


72. Idempotency

Applying same receipt repeatedly must be safe.


73. Monotonicity

Read state must only move forward.

ReadThrough 105

followed by stale:

ReadThrough 99

must not regress.


74. Device-Level Receipts

Multi-device recipient may read on phone but desktop has not.

Logical account read semantics:

if any authorized device reads
→ account considered read

is common.


75. Multi-Device Receipt Aggregation

Maintain device state internally if useful.

Expose account-level result to sender.


76. Self-Sync

Recipient's other devices should learn:

read through N

so unread badges remain consistent.


77. Own-Device Read Sync

This is durable account/device sync, not peer-facing typing.


78. Delivery Across Devices

If message delivered to one recipient device:

Delivered

may be shown.

If product wants stronger semantics:

delivered to all devices

can be advanced detail.


79. Receipt Privacy Boundary

Sender should not learn:

which exact device read

unless product intentionally exposes it.

Prefer account-level receipt.


80. Active Device Hint

Optional local-account feature:

Active on Desktop

for user's own devices.

Do not expose device-level activity to arbitrary contacts by default.


81. Call Availability

Part 29 can consume:

CallingAvailability

to influence UI.

Presence does not guarantee call acceptance.


82. Busy State

If user is already in a call:

Busy

may be advertised according to privacy.


83. Presence During Calls

Could show:

Online

rather than:

In a call

unless user explicitly allows call-state visibility.


84. Sensitive Presence Metadata

Avoid exposing:

screen on
app foreground
device model
network type
exact battery

to peers.


85. Scoped Presence

Remote peers need only semantic state.


86. Presence E2EE

Presence for trusted peers should travel over authenticated encrypted channels.

Public presence, if ever added, needs a separate privacy/security model.


87. Presence Authentication

Reject spoofed:

Alice is online

unless signed/session-authenticated by Alice's authorized device.


88. Presence Revision

Each device maintains monotonic:

revision

during an incarnation.

Higher revision supersedes lower.


89. Restart Handling

After process restart, revision can reset only if paired with:

DeviceInstanceId/session incarnation

or a fresh presence epoch.


90. Presence Epoch

#![allow(unused)]
fn main() {
pub struct PresenceEpoch(pub u64);
}

or random session instance ID.


91. Stale Presence

If old presence arrives after a new epoch:

ignore

92. Ephemeral Envelope

#![allow(unused)]
fn main() {
pub struct EphemeralEnvelope {
    pub kind: EphemeralStateKind,
    pub source: ScopedDeviceId,
    pub revision: u64,
    pub expires_after_ms: u32,
    pub payload: Bytes,
}
}

93. TTL Validation

Remote cannot set:

24-hour typing TTL

Host clamps per event kind.


94. Max TTL Policy

Example:

typing ≤ 10 s
recording ≤ 15 s
presence ≤ 180 s

Exact values product-configured.


95. Ephemeral State Table

In memory:

#![allow(unused)]
fn main() {
pub struct EphemeralStateStore {
    // key → value + expiry
}
}

96. No Primary DB Requirement

Most ephemeral state lives:

memory only

97. Optional Bounded Presence Cache

Could persist:

last seen coarse timestamp

if feature enabled.

Typing/recording never persisted.


98. Expiry Scheduler

Use efficient timer wheel/min-heap instead of one Tokio task per ephemeral item.


99. Timer Wheel

Useful at scale:

presence
typing
group indicators

100. Expiry Event

When TTL ends:

state removed
UI notified

No network packet required.


101. Coalescing

If presence updates:

Online rev 10
Online rev 11
Online rev 12

only latest matters.


102. Bounded Channel

Use bounded async channel for ephemeral updates.


103. Backpressure Policy

If overloaded:

drop stale typing
coalesce presence
preserve durable receipts

104. Priority

Recommended:

delivery/read receipts
presence
typing
recording
low-value UI hints

But durable message/control/call traffic still outranks most ephemeral state.


105. Traffic Priority Relative to Core

Example:

Call control
Audio
Security
Message delivery
Receipts
Presence
Typing
Bulk files
Background sync

Exact ordering depends product, but typing should never delay a message.


106. Battery Policy

Typing indicator can be suppressed under extreme battery/network constraints.

Read receipts can batch.

Presence heartbeat frequency can reduce.


107. Metered Networks

Presence overhead is small, but avoid pointless chatter.

Use connection/session reuse.


108. Offline Behavior

If no live path:

do not queue typing
do not queue old presence
do not queue recording indicator

They are stale by the time network returns.


109. Receipts Offline

Delivery/read receipts are different.

They should be represented durably enough to synchronize later.


110. Receipt Coalescing Offline

Instead of queueing every read:

store latest read-through sequence

Then send one update when connected.


111. DTN

Do not send:

typing
presence
recording

through DTN.

They lose meaning by delayed delivery.


112. DTN Receipts

Delivery/read receipts can traverse delayed channels if useful, because they represent durable message state.


113. Relay

Presence can use relay if there is an active lightweight channel.

Do not force relay connection solely for high-frequency typing unless product policy justifies it.


114. LAN / Local Mesh

Presence/typing work normally over local peer paths without Internet.


115. Internetless Operation

Two devices on same router can still exchange:

presence
typing
receipts

over local transport.


116. Multi-Path Duplication

Do not blindly send ephemeral state over every path.

Select one control path.

Receipts can be retried/cumulative.


117. Path Handoff

Presence state survives path changes logically.

Transport path is replaceable.


118. Group Presence

Large group presence is expensive.

Do not show:

online status for 10,000 members

via full mesh fan-out.


119. Group Presence Policy

Options:

only active conversation participants
recently active subset
server/relay aggregate
none

120. Small Groups

Direct fan-out is acceptable.


121. Large Groups

Use:

gossip aggregation
group presence service
bounded active-member set

if feature is required.


122. Presence Subscriptions

Only subscribe to peers currently relevant.

Examples:

open conversation
visible contact list
active call setup

123. Do Not Track Every Contact Continuously

This improves:

battery
privacy
network load

124. Lazy Presence

When opening conversation:

subscribe/request fresh presence

125. Contact List Presence

May subscribe only to visible rows.


126. UI Virtualization Integration

Dioxus contact list:

visible contacts
→ presence subscriptions

offscreen contacts can use stale/unknown state.


127. Subscription Lease

Presence subscription itself can have TTL.


128. Presence Subscription API

#![allow(unused)]
fn main() {
pub trait PresenceService {
    async fn subscribe(
        &self,
        peer: AccountId,
    ) -> Result<PresenceSubscription, PresenceError>;
}
}

129. Typing API

#![allow(unused)]
fn main() {
pub trait TypingService {
    async fn set_typing(
        &self,
        conversation: ConversationId,
        active: bool,
    ) -> Result<(), TypingError>;
}
}

130. Receipt API

#![allow(unused)]
fn main() {
pub trait ReceiptService {
    async fn mark_read_through(
        &self,
        conversation: ConversationId,
        seq: MessageSequence,
    ) -> Result<(), ReceiptError>;
}
}

131. UI State Model

#![allow(unused)]
fn main() {
pub struct ConversationEphemeralState {
    pub peer_presence: PresenceSummary,
    pub typers: Vec<AccountId>,
    pub recorders: Vec<AccountId>,
    pub read_through: Option<MessageSequence>,
}
}

132. View Model

Dioxus consumes a read-only projection.

It does not manage TTL itself.


133. Typing UI

If one peer:

Typing…

If multiple:

Alice and Bob are typing…

If many:

Several people are typing…

134. Accessibility

Typing indicator should have:

screen-reader label
non-animation fallback

135. Motion

Avoid excessive animated dots if user prefers reduced motion.


136. Presence UI

Prefer simple:

Online
Away
Last seen recently

Avoid misleading precision.


137. Delivery/Read UI

Potential states:

clock → queued
single check → sent
double check → delivered
colored double check → read

Exact iconography is product/UI decision.

Architecture exposes semantics, not icon assumptions.


138. Group Receipt UI

For small groups:

Seen by Alice, Bob

For larger:

Seen by 23

139. Receipt Detail Screen

Optional:

Delivered to
Read by

for group messages.


140. Privacy Setting Changes

If user turns off read receipts:

future receipts stop

Do not attempt to retract already disclosed reads.


141. Typing Setting Changes

Apply immediately.


142. Presence Setting Changes

Send updated hidden/invisible state or simply stop publishing and let TTL expire.

Prefer explicit privacy-state update when useful.


143. Blocked Peer

Blocked peer should receive no new:

presence
typing
read receipts

unless protocol requires a neutral response.


144. Block Semantics

Do not reveal:

"You were blocked"

through presence behavior more than necessary.


145. Abuse Resistance

Attackers can abuse ephemeral channels to:

wake device
spam UI
consume CPU
create notification-like effects

Use quotas.


146. Per-Peer Limits

Examples:

typing events/sec
presence updates/min
receipt updates/sec

147. Invalid TTL

Clamp/reject.


148. Invalid Conversation

Typing for conversation peer is not a member of:

reject

149. Receipt Authorization

Only legitimate recipient/member can send receipt for message/conversation.


150. Forged Read Receipt

Authentication prevents arbitrary peer from claiming another user's read state.


151. Receipt Sequence Validation

Receipt cannot acknowledge:

message sequence that never existed

without being bounded/ignored.


152. Future Sequence

If receipt claims far-future sequence:

reject as protocol violation

153. Receipt Regression

Ignore lower sequence than current.


154. Presence Flood

Coalesce before reaching UI.


155. Typing Flood

Throttle and collapse to:

typing=true

until TTL.


156. Untrusted Peer Presence

Unknown peers do not get automatic presence subscription.


157. Presence Discovery vs Contact Discovery

Do not confuse:

discover nearby peer

with:

show them permanently online

158. Security

All peer-facing ephemeral state is authenticated.


159. E2EE

For trusted conversations, ephemeral payloads can use session encryption from Part 28.


160. Privacy of Read Receipts

Read receipts can reveal behavior/time patterns.

Default should be user-controllable.


161. Timing Privacy

Optional batching can reduce exact behavioral leakage.

Example:

send read receipt within 0–2 s randomized/coalesced window

if product wants.


162. Last Seen Leakage

Exact last-seen timestamps can enable surveillance.

Prefer coarse display.


163. Presence Leakage

Do not expose per-device:

phone online
desktop online

to contacts by default.

Account-level aggregate only.


164. Call Presence Leakage

Do not reveal:

currently in a call

unless explicit product feature.


165. Diagnostics

Part 18 adds:

presence subscriptions
presence RTT
typing sends
typing drops/coalesces
receipt queue depth
receipt latency

166. No User Behavioral Logs

Do not persist detailed history:

Alice was typing at 11:03:12

for diagnostics.


167. Developer Metrics

Aggregate:

ephemeral frames sent
coalesced
dropped
expired

168. Receipt Metrics

Can measure:

message delivery latency
read latency

locally, but avoid telemetry with identifiable peer unless explicit privacy policy.


169. Event Types

Internal:

#![allow(unused)]
fn main() {
pub enum EphemeralEvent {
    PresenceChanged,
    TypingChanged,
    RecordingChanged,
    DeliveryAdvanced,
    ReadAdvanced,
}
}

170. Actor Model

Suggested services:

PresenceActor
TypingActor
ReceiptActor
EphemeralExpiryActor

or one bounded EphemeralRuntime if simpler.


171. Avoid Actor Explosion

Do not create one actor per peer/conversation unless measured scale requires it.


172. Central Ephemeral Runtime

Recommended:

#![allow(unused)]
fn main() {
pub struct EphemeralRuntime {
    // bounded state maps
    // timer wheel
    // subscriptions
    // transport sender
}
}

173. State Key

#![allow(unused)]
fn main() {
pub enum EphemeralKey {
    Presence(AccountId),
    Typing(ConversationId, AccountId),
    Recording(ConversationId, AccountId),
}
}

174. Memory Bounds

Limit:

tracked peers
tracked conversations
group typers
presence subscriptions

175. LRU Eviction

If too many inactive presence entries:

evict oldest

after TTL/subscription expiry.


176. Active Conversation Priority

Keep ephemeral state for:

currently open conversation
active call
visible contacts

before background contacts.


177. Persistence Boundary

Only receipt-derived durable state crosses into message DB.


178. Transactional Receipt Apply

When a read receipt advances:

validate
update message/conversation read projection atomically
emit UI event

179. Receipt Compression

For account sync, store:

conversation_id
read_through

not one row for every message.


180. Device Receipt State

Optionally:

device_read_through

for own-device synchronization.


181. Conversation Sequence

Receipts depend on stable per-conversation message ordering/sequence architecture from messaging core.


182. If No Contiguous Sequence

Use monotonic logical index assigned by conversation layer.

Do not use wall-clock timestamp.


183. Edited Messages

Read status remains tied to logical message sequence.

Edit does not make message unread again by default.


184. Deleted Messages

Receipt progression remains monotonic even if old messages deleted.


185. Reactions

Do not alter read-through semantics.


186. Threads

If threaded conversations added:

conversation-level read
thread-level unread

may require separate cursors.


187. Read Cursor

#![allow(unused)]
fn main() {
pub struct ReadCursor {
    pub conversation: ConversationId,
    pub through: MessageSequence,
}
}

188. Unread Count

Derived:

latest visible sequence - read cursor

with deleted/system-message rules.


189. Mentions

Unread mentions are separate derived projection.


190. Device Sync

Read cursor sync should be:

max(current, incoming)

191. Conflict Resolution

Monotonic max makes read-state sync simple.


192. Delivery Cursor

Same concept:

#![allow(unused)]
fn main() {
pub struct DeliveryCursor {
    pub conversation: ConversationId,
    pub through: MessageSequence,
}
}

193. Partial Delivery

If gaps exist:

through N + gap set

temporarily.

Once gaps fill:

advance contiguous cursor

194. Receipt Batching

Batch multiple conversations into one control frame where appropriate.


195. Batch Limits

Bound:

receipt count
frame bytes

196. Typing Over Slow Link

Typing is first to drop.


197. Presence Over Slow Link

Reduce heartbeat.


198. Receipts Over Slow Link

Batch/coalesce but eventually deliver.


199. Emergency Mode

Part 17 may suppress:

typing
fine-grained presence

to conserve bandwidth.

Preserve:

critical delivery/read state only if useful

200. Disaster Mesh

In unstable mesh:

presence accuracy degrades naturally

Do not flood mesh trying to maintain perfect online lists.


201. Partition Semantics

During network partition:

peer state eventually expires

to Unknown/Offline.


202. Merge After Partition

Fresh revision/epoch supersedes stale presence.


203. Call Reconnect Integration

Part 29 can use presence as a hint, but transport/liveness determines actual reconnect.


204. Call Busy Integration

Active call controller can expose:

CallingAvailability::Busy

if privacy policy allows.


205. Message Composer Integration

Dioxus composer emits local activity events:

Typed
Cleared
Sent
LostFocus

Typing service converts to throttled protocol updates.


206. Debounce

Do not immediately send typing on every tiny focus event.

Use short debounce.


207. Recording Composer Integration

Voice recorder lifecycle:

record start
cancel
send

maps to recording hints.


208. Read Detection

UI reports:

highest message sequence truly read

to application layer.

Do not let storage layer guess visibility.


209. Read Detection Conditions

Recommended:

conversation foreground
window/app active
message row visible beyond threshold

210. Scroll Position

If user is reading old history:

do not mark newer offscreen messages read

211. Conversation Open

Opening conversation does not automatically mean all loaded messages read unless viewport rule says so.


212. Accessibility Cases

Screen-reader navigation should integrate with read semantics carefully.

Do not require visual pixels specifically.

Use:

semantic exposure/read intent

where platform can report it.


213. Desktop Multi-Window

If same conversation open in two windows:

max visible/read cursor

wins.


214. Own Multiple Devices

If phone reads message:

desktop unread badge clears

after secure sync.


215. Receipt Loop Prevention

Own-device sync receipt must not bounce forever.

Use:

origin device
revision
monotonic merge

216. Protocol Version

Dedicated logical protocol:

ephemeral/1

or combined control protocol with typed namespaces.


217. Protocol Separation

Recommended:

presence/1
receipts/1

or one:

state/1

depending implementation.

Do not mix into raw message payload schema if it creates coupling.


218. Wire DTOs

Dedicated versioned DTOs:

PresenceFrameV1
TypingFrameV1
ReceiptFrameV1

219. Postcard

Good fit for compact wire encoding.

Do not serialize arbitrary internal structs directly.


220. Canonical Limits

Define:

max group typers/frame
max receipt batch
max TTL
max peer subscriptions

221. Capability Negotiation

Part 07 advertises:

presence-v1
typing-v1
delivery-receipts-v1
read-receipts-v1

222. Optional Capabilities

If peer does not support typing:

messaging still works

223. Read Receipt Capability

If unsupported/disabled:

stop at Delivered

224. Presence Capability

If unsupported:

Unknown

not error.


225. Interoperability

Part 23 should add test vectors for:

presence TTL
typing expiry
receipt monotonicity
duplicate updates
multi-device aggregation

226. Conformance Tests

Examples:

Typing Started
wait beyond TTL
→ not typing

ReadThrough 20
ReadThrough 17
→ remains 20

227. Fuzzing

Part 10 fuzz:

ephemeral frame parser
TTL values
receipt ranges
group typing sets
revision handling

228. Property Tests

Examples:

read cursor never decreases
delivery cursor never decreases
expired typing never survives
stale presence epoch cannot overwrite fresh
memory use remains bounded

229. Duplicate Test

Same typing/presence/receipt update multiple times.

No duplicate UI artifact.


230. Reordering Test

Receive:

rev 5
rev 3
rev 4

final state remains rev 5.


231. Presence Loss Test

Drop all heartbeat packets.

State expires.


232. Clean Shutdown Test

Explicit offline arrives.

UI updates quickly.


233. Crash Test

No explicit offline.

TTL still clears presence.


234. Battery Saver Test

Heartbeat interval grows without causing permanent false-online state.


235. Group Typing Stress

Hundreds of participants.

UI/state remains bounded.


236. Receipt Storm Test

Read 1,000 messages quickly.

Network should send:

one/few cumulative receipts

not 1,000 packets.


237. Multi-Device Receipt Test

Phone reads through 100.

Desktop reads through 80.

Account state remains:

100

238. Privacy Test

Read receipts disabled.

No read frames emitted.


239. Block Test

After blocking:

presence/typing/receipts

stop according to policy.


240. Unknown Peer Flood Test

Thousands of presence updates from unknown peer.

Expected:

drop/rate limit
bounded memory

241. Diagnostics Test

No ephemeral user history persists after expiry unless explicitly feature-derived.


242. Performance Goals

Presence/typing processing should be effectively negligible compared with:

media
file transfer
message encryption

243. Allocation Policy

Reuse small buffers where useful.

Do not overengineer zero-copy for 20-byte typing events.


244. Serialization Size

Keep typical typing/presence update compact.


245. Startup

Startup sequence:

load privacy/settings
start ephemeral runtime
connect transport
publish fresh presence when allowed
restore durable receipt cursors

Do not restore old typing state.


246. Shutdown

Optional:

send offline
flush latest durable receipts

but correctness relies on TTL and durable receipt state.


247. Headless Mode

Part 16 daemon can run presence/receipt services without UI.

Typing service may be unused.


248. Embedded Node

Part 20 node may expose:

Available
GatewayOnline

only if product needs peer presence.

Avoid treating infrastructure nodes as human presence.


249. FFI

Part 19 exposes:

subscribe_presence
set_typing
mark_read
subscribe_receipts

at semantic level.


250. WASM / Plugins

Plugins should not automatically observe:

presence graph
typing
read behavior

These are sensitive behavioral signals.

Require explicit permission if ever exposed.


251. Plugin Permission

Potential future:

ObserveConversationPresence

high privacy impact.

Not default.


252. Telemetry

Do not upload raw:

presence history
typing events
read timestamps

to analytics by default.


253. Suggested Workspace

crates/
├── comm-presence-core/
├── comm-presence-protocol/
├── comm-presence-runtime/
├── comm-typing/
├── comm-receipts/
├── comm-availability/
├── comm-ephemeral-store/
├── comm-ephemeral-diagnostics/
└── comm-ephemeral-testkit/

254. comm-presence-core

Owns:

presence types
availability
privacy policy
aggregation rules

255. comm-presence-protocol

Owns:

wire DTOs
versioning
TTL limits
revisions

256. comm-presence-runtime

Owns:

subscriptions
heartbeats
aggregation
expiry
transport

257. comm-typing

Owns:

composer activity
debounce
refresh
TTL
group aggregation

258. comm-receipts

Owns:

delivery cursor
read cursor
batch/coalesce
multi-device merge
durable projection updates

259. comm-availability

Combines:

presence
DND
call busy
messaging availability

260. comm-ephemeral-store

In-memory bounded state plus timer wheel.


261. comm-ephemeral-testkit

Provides:

fake clock
fake transport
multi-device peers
loss/reorder injection
privacy scenarios

262. Public Commands

#![allow(unused)]
fn main() {
pub enum EphemeralCommand {
    PublishPresence(PresenceState),
    SubscribePresence(AccountId),
    UnsubscribePresence(AccountId),
    SetTyping {
        conversation: ConversationId,
        active: bool,
    },
    SetRecording {
        conversation: ConversationId,
        active: bool,
    },
    MarkReadThrough {
        conversation: ConversationId,
        through: MessageSequence,
    },
}
}

263. Public Events

#![allow(unused)]
fn main() {
pub enum EphemeralEvent {
    PresenceUpdated {
        account: AccountId,
        presence: PresenceSummary,
    },
    TypingUpdated {
        conversation: ConversationId,
        accounts: Vec<AccountId>,
    },
    RecordingUpdated {
        conversation: ConversationId,
        accounts: Vec<AccountId>,
    },
    DeliveryAdvanced {
        conversation: ConversationId,
        through: MessageSequence,
    },
    ReadAdvanced {
        conversation: ConversationId,
        through: MessageSequence,
    },
}
}

264. Implementation Phases

Phase 1 — Receipt Cursors

delivery
read
monotonic merge
durable projections

Phase 2 — Typing

debounce
TTL
privacy

Phase 3 — Presence

device state
account aggregation
subscriptions
TTL

Phase 4 — Availability

DND
busy
calling availability

Phase 5 — Multi-Device

read sync
presence aggregation
answered/busy integration

Phase 6 — Group Scaling

typing aggregation
receipt scaling
presence subscriptions

Phase 7 — Battery / Offline Hardening

background
low power
partitions
coalescing

Phase 8 — Privacy / Abuse Hardening

visibility controls
block behavior
rate limits
behavioral-data minimization

Phase 9 — Interoperability

ephemeral/1 vectors
receipt monotonicity
TTL tests

265. Initial Production Recommendation

For v1, ship:

account-level online/offline/unknown
typing indicator
delivery receipts
read receipts
multi-device read sync
privacy toggles
DND/busy availability

Defer initially:

precise last-seen timestamps
per-device public presence
large-group full presence lists
complex custom statuses
plugin access to behavioral state

266. Definition of Done

Part 30 is complete when:

  • presence is advisory and never blocks message delivery
  • unknown and offline are distinct states
  • multi-device presence aggregates correctly
  • presence expires automatically without graceful shutdown
  • mobile/background presence does not require continuous wakeups
  • typing/recording indicators are never persisted or sent through DTN
  • typing is throttled and TTL-driven
  • group typing remains bounded
  • delivery means durable recipient acceptance, not transport ACK
  • read receipts use monotonic read-through cursors
  • delivery/read receipts coalesce instead of generating one packet per message
  • receipt state survives reconnect/offline operation
  • read receipt privacy can be disabled
  • blocked peers stop receiving behavioral state according to policy
  • exact last-seen data is optional and privacy-controlled
  • ephemeral state cannot consume unbounded memory
  • stale revisions/epochs cannot overwrite fresh state
  • battery/network pressure can reduce/suppress low-value ephemeral traffic
  • call availability integrates with Part 29 without exposing unnecessary call details
  • Dioxus consumes semantic projections rather than managing TTL/state correctness
  • plugins/WASM do not receive behavioral signals by default
  • Part 23 conformance tests cover TTL, monotonic receipts, duplicate/reordered frames, privacy settings, and multi-device aggregation

267. Relationship to Earlier Parts

Part 30 integrates directly with:

02 — Multi-Device Identity
03 — Transport / Routing Policy
04 — Offline Event Log
07 — Capability Negotiation
08 — Resource Limits
09 — Crash Recovery
10 — Fuzzing / Protocol Tests
12 — Multipath
13 — Battery-Aware Scheduling
14 — Proximity
16 — Daemon / Headless
17 — Emergency Priority
18 — Diagnostics
19 — C ABI / FFI
21 — Third-Party Extensions
22 — WASM Components
23 — Interoperability
24 — Plugin Ecosystem
28 — E2EE / Privacy
29 — Realtime Calls

268. Final Architecture

                    DIOXUS / SDK
                        │
                        ▼
                Ephemeral Projection
             ┌──────────┼───────────┐
             │          │           │
         Presence     Typing     Receipts
             │          │           │
             └──────────┼───────────┘
                        │
                Ephemeral Runtime
            ┌───────────┼────────────┐
            │           │            │
         TTL/Expiry   Privacy      Coalescing
            │           │            │
            └───────────┼────────────┘
                        │
                 Secure Control Path
                        │
             Direct / Relay / LAN

Durable boundary:

Typing/Presence
    → memory only

Delivery/Read receipt
    → control message
    → monotonic durable cursor
    → message/conversation projection

269. Final Principle

Ephemeral state should make the application feel alive without turning every user action into durable distributed data.

The right distinction is:

"Typing…"
    → disposable hint

"Online"
    → expiring reachability hint

"Delivered"
    → durable message fact

"Read"
    → durable user-state fact with privacy controls

The architecture should therefore optimize for:

freshness
privacy
low overhead
bounded memory
automatic expiry
coalescing

rather than perfect historical consistency.

That is the role of Part 30: provide polished realtime UX while keeping the durable messaging, security, offline, and DTN architecture clean and efficient.