Collaborator presence is ephemeral and non-authoritative, expires without heartbeat, and reconnects with versioned session tokens so editing authority never derives from stale presence alone.
Package status: AI-assisted reference package. Static package validation has passed; implementation scenarios remain not run and human domain review is required before stable adoption.
Decision
Presence indicates who appears to be viewing or editing a surface; it is not proof of permission and not durable document state. Each presence session heartbeats on a short interval; missing heartbeats expire the entry automatically. Reconnect obtains a new session token with incremented generation so late packets from old connections cannot resurrect stale avatars. Editing locks or operational transforms remain authoritative for write access; presence only informs UI affordances.
Scope
- Presence join, heartbeat, leave, expiry, and reconnect handshake.
- Bounded audit events for join and leave only; heartbeats are not audit-logged.
- Session token generation and stale packet discard rules.
- Fan-out of presence updates to subscribers on a document or room channel.
- Limits on concurrent presence entries per user and per document.
- Metrics on reconnect rate, ghost sessions prevented, and heartbeat lag.
Outside this block
- Authorization for document edits.
- Full CRDT or OT merge algorithms.
- Persistent user profile status across products.
Contract
- Presence entries expire when heartbeats cease for longer than the profile TTL; no manual janitor is required for correctness.
- Reconnect must bump session generation; messages with older generation are dropped for display state.
- Presence loss does not revoke write tokens or imply save completion.
- Join includes explicit document or room id; global presence streams cannot leak unrelated resources.
- Maximum concurrent sessions per user per document enforced; excess joins evict oldest ephemeral session.
- Server time drives expiry; clients may skew but cannot extend TTL beyond server acknowledgment.
- Disconnect without leave still expires entry within TTL.
- Join and leave emit bounded audit events with document_id, session_id, generation, and hashed actor id; audit excludes heartbeat noise and direct PII fields such as email or IP.
Implementation guidance
- Store presence in memory or short-TTL store, not primary document tables.
- Debounce fan-out updates to reduce chatter on large rooms while staying under UX latency budget.
- Include generation in websocket frames to simplify client discard logic.
Failure handling and safeguards
- If presence service partitions, prefer showing fewer avatars over showing ghosts.
- Do not expose precise geolocation in presence payloads unless explicitly scoped and consented in product policy.
- Rate-limit join storms after reconnect mass events.
Verification and operations
- Monitor expired-session count, stale packet drops, reconnect success, and heartbeat p99 lag.
- Chaos-test broker restarts to verify ghosts disappear within TTL.
- Execute acceptance scenarios in the target repository; packaged scenarios are not executed evidence.
Adoption assumptions
- TTL and generation rules in fixtures are profile choices.
- Teams map transport (WebSocket/SSE) to the same semantic contract.