A signed claim

Last updated

Presence is a signed claim a device makes about itself, carried by a frame the relay never stores. The relay computes no presence and keeps no server-side last seen. A relay able to synthesise presence could show a person at their keyboard when they were away.

The LIVE frame

Protocol version 2 adds frame tag 21, the same shape in both directions: a group, an epoch and a sealed body. The body is a LiveBody, signed by the device it describes with the same Ed25519 key that signs envelopes, and the relay cannot read it. The relay sees a group id, a size and a time.

Nothing about a beat is durable, and a beat never gets a sequence number and is never written to Postgres or returned by a reconciliation round. No head attestation, checkpoint or compaction manifest names one. A beat published into a group nobody is watching is discarded, and that raises no error.

The retired ephemeral kind

The kind space reserved 0x00F0 ephemeral for presence, but it could never be implemented. Under enc: 1 an envelope's kind lives inside the ciphertext, so a relay told to drop one kind and keep the rest cannot tell them apart. The WRAP and HANDSHAKE frames left the envelope to close the same hole, and presence gets a frame for the same reason.

0x00F0 stays allocated forever, unused.

What a beat claims

The LiveBody fields
FieldMeaning
kind1 presence, 2 typing. 3 and 4 are reserved and never sent
memberthe author's device key, the same 32 bytes an envelope carries
state1 active, 2 idle, 3 away. Presence only
channelthe channel slug. Typing only
atthe author's clock, in milliseconds
ttlhow long the claim is good for, in seconds
certthe delegation certificate, when the author speaks under a delegated key
sigEd25519 over the canonical body

at is compared and never rendered. A receiver uses it to discard a beat older than one already held from the same device, so a replayed beat cannot mark somebody away. A member list's last seen is computed on the reader's own machine from the newest envelope it observed.

ttl is clamped by the receiver at 120 seconds. Without the clamp, one beat claiming a year would leave a dot on a laptop shut since then. The receiver applies the clamp because the sender is the party with the motive.

Limits

What bounds the ephemeral path
LimitValueWhy
ct size4 KiBA beat is a signed struct with no payload
frames per connection per minute60Budgeted separately from the envelope allowance, so presence can never starve a durable write
client beacon interval20 secondsAlso why a shed frame needs no error
receiver ttl clamp120 secondsA sender cannot claim to be present indefinitely

A refused beat is refused on the frame. The connection stays up and durable traffic is unaffected.

Shedding

A subscriber whose send queue is full is normally downgraded to reconciliation and told so. A dropped envelope is a hole in an author chain, which raises a security alarm on somebody else's screen.

A beat is not durable, so a full queue sheds it. The relay drops it silently, counts it for the operator and never reports a hole in the client's log. The next beat arrives twenty seconds later.

Operator settings

WEALD_RELAY_LIVE is on or off, and off refuses every beat as a deliberate posture. A self-hoster who does not want to carry a beat every twenty seconds per connected device turns it off. Clients then render presence as unavailable.

WEALD_RELAY_LIVE_FANOUT defaults to process, which is correct in a single-process deployment and in no other. A relay told it runs more than one instance refuses to start, since each member would otherwise see half the room. A relay that will not start gets a human's attention.

Presence unavailable

A version 1 relay, a relay with the ephemeral path off, and a workspace synced through git all produce the same client state: presence unavailable. That state differs from everybody being offline. A client that rendered it as offline would tell every member that the whole team had gone home.