Regenerate the spec page for §6.11 #91

Merged
paulhitt merged 1 commits from docs/regenerate-spec-6-11 into main 2026-09-02 18:54:36 +00:00
+48 -1
View File
@@ -3,7 +3,7 @@
<!-- GENERATED by Scripts/build-doc-pages.sh from flamenet-e2e/docs/SPEC.md.
Edits made HERE are deleted the next time that script runs.
Change the markdown source and re-run it.
source-sha256: e44d6dd348139078 -->
source-sha256: ba0062ff88813c30 -->
<article class="band doc doc-generated">
<div class="wrap wrap-narrow">
<h1 id="flamenet-messenger--end-to-end-encryption-spec">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.</p>
<h3 id="611-disappearing-messages">6.11 Disappearing messages</h3>
<p>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:</p>
<pre class="json"><code>{&quot;fnc&quot;:1,&quot;kind&quot;:&quot;ttl&quot;,&quot;ctl&quot;:1,&quot;secs&quot;:86400}</code></pre>
<p><code>secs</code> is the lifetime in seconds; <strong><code>0</code>
turns the timer off</strong>. The envelope sets <code>ctl</code>
(§6.10), so a build that does not recognise <code>ttl</code> stays quiet
instead of rendering it, and receivers MUST NOT show a <code>ttl</code>
envelope in the conversation.</p>
<p><strong>The timer belongs to the conversation, not to a message, and
it is symmetric.</strong> 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.</p>
<p>The relay is not told. <code>ttl</code> 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.</p>
<p>⚠️ <strong>Ages MUST be measured from the time the receiving device
recorded the message, never from a timestamp the sender
supplied.</strong> 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.</p>
<p>⚠️ <strong>A message carrying no usable date MUST be kept.</strong>
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.</p>
<p>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.</p>
<p>⚠️ <strong>Expiry runs when the conversation is read, not on a
schedule.</strong> 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.</p>
<p>🔴 <strong>The timer is not enforcement against the
recipient.</strong> They hold the plaintext — they can screenshot it,
photograph the screen, or run a build that ignores <code>secs</code>
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.</p>
<h3 id="612-link-previews">6.12 Link previews</h3>
<p>A message containing a URL MAY carry a preview of it:</p>
<pre class="json"><code>{&quot;fnc&quot;:1,&quot;kind&quot;:&quot;text&quot;,&quot;caption&quot;:&quot;look at this https://example.com/x&quot;,