diff --git a/Resources/Views/spec.leaf b/Resources/Views/spec.leaf index d98786f..14869fa 100644 --- a/Resources/Views/spec.leaf +++ b/Resources/Views/spec.leaf @@ -3,7 +3,7 @@ + source-sha256: ba0062ff88813c30 -->

Flamenet @@ -608,6 +608,53 @@ itself, the piece-level tests passed on both sides, and no vector covers this envelope. It is the standing argument for the interop harness: agreement between two implementations that share an author is not agreement.

+

6.11 Disappearing messages

+

A conversation MAY carry a timer. Both sides then delete each message +once it has been on the device that long, and the announcement rides the +ratchet like any other content:

+
{"fnc":1,"kind":"ttl","ctl":1,"secs":86400}
+

secs is the lifetime in seconds; 0 +turns the timer off. The envelope sets ctl +(§6.10), so a build that does not recognise ttl stays quiet +instead of rendering it, and receivers MUST NOT show a ttl +envelope in the conversation.

+

The timer belongs to the conversation, not to a message, and +it is symmetric. Either side may change it; the change applies +on both devices, to messages already delivered as well as to new ones. A +one-sided timer would be a worse promise than no promise at all — the +interface would say a message had disappeared while a copy stayed on the +other phone.

+

The relay is not told. ttl is a content envelope inside +the ciphertext (§6.6), so a timed conversation is indistinguishable at +the server from any other; the server's own retention (§9) is a separate +mechanism and is unchanged by it.

+

⚠️ Ages MUST be measured from the time the receiving device +recorded the message, never from a timestamp the sender +supplied. A sender who chose the age could backdate a message +so it vanished from the recipient's phone before it was read, or +forward-date one so it never expired at all. The device's own record +time is the only clock in the exchange that the other party cannot +set.

+

⚠️ A message carrying no usable date MUST be kept. +Those predate the field, and an unknown age is not evidence of an old +one. Deleting somebody's history on a guess cannot be undone.

+

Attachments MUST be purged with the message that referenced them. A +bubble that vanished while its blob stayed in the cache is precisely the +failure the feature exists to prevent.

+

⚠️ Expiry runs when the conversation is read, not on a +schedule. Nothing wakes the device to delete a message, so one +past its lifetime can remain on disk until something next opens that +thread. A periodic sweep would narrow that window without closing it, +since it too leaves data between runs. What is guaranteed is narrower +and worth stating exactly: an expired message is never rendered, and is +removed the moment the thread is touched.

+

🔴 The timer is not enforcement against the +recipient. They hold the plaintext — they can screenshot it, +photograph the screen, or run a build that ignores secs +entirely. Disappearing messages limit what accumulates on a device that +is later lost, seized, or handed to somebody else. They do not make a +message unrecoverable by the person it was sent to, and the interface +MUST NOT imply that they do.

A message containing a URL MAY carry a preview of it:

{"fnc":1,"kind":"text","caption":"look at this https://example.com/x",