Reply to a story, as a sealed direct message
Android half of ios#30, spec §6.20. A reply is an ordinary direct message to the author carrying `sre.sid`, landing in the existing conversation. Stories gain no comment thread and no viewer list. The reference carries the id and nothing else. A story's author had the story by definition, so the only way they no longer hold it is that their own timer removed it — sending a copy back would resurrect exactly that, at a moment they did not choose. 🔴 `Content.text` returns the raw body when it has nothing to wrap, so `storyReplyId` had to join that condition. Left out, a reply with no message id and no quote would have gone out as plain text and arrived with the reference silently dropped — on exactly the path a story reply normally takes. There is a test for it. The disclosure is shown before the first reply this account sends, names what is revealed, and says where the reply goes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b25481c262
commit
52a793ce5c
@@ -429,6 +429,7 @@ data class Content(
|
||||
forwarded: Boolean = false,
|
||||
lifetimeSeconds: Int? = null,
|
||||
|
||||
|
||||
/** The story this answers (§6.20). */
|
||||
storyReplyId: String? = null,
|
||||
): String =
|
||||
@@ -585,11 +586,8 @@ data class Content(
|
||||
forwarded: Boolean = false,
|
||||
mentions: List<Long> = emptyList(),
|
||||
lifetimeSeconds: Int? = null,
|
||||
|
||||
background: Int? = null,
|
||||
|
||||
storyReplyId: String? = null,
|
||||
|
||||
storySet: StorySet? = null,
|
||||
): String {
|
||||
val parts = mutableListOf("\"fnc\":1", "\"kind\":${quote(kind)}")
|
||||
|
||||
@@ -188,7 +188,10 @@ class Vault(private val storage: Storage, private val key: SecretKey) {
|
||||
* as "expires at the epoch" — which would kill the whole set.
|
||||
*/
|
||||
fun setExpiry(items: List<Story>): Double =
|
||||
items.mapNotNull { it.ref.expires.takeIf { e -> e > 0 } }.minOrNull() ?: 0.0
|
||||
// ⚠️ `ref?`: a text story (§6.21) has no blob and so no expiry of
|
||||
// its own. It contributes nothing rather than a zero, which
|
||||
// `minOrNull` would otherwise pick and expire the whole set.
|
||||
items.mapNotNull { it.ref?.expires?.takeIf { e -> e > 0 } }.minOrNull() ?: 0.0
|
||||
|
||||
/**
|
||||
* Group one author's stories into sets, in position order (§6.23).
|
||||
|
||||
Reference in New Issue
Block a user