Put the app back to the last state that worked

Tonight's merges left sign-in, messages, calls and stories broken. Restores
app, engine and client to fa92581 — the tree that shipped as v8 and works.

Why they broke: those features are not independent. A message, a call
signal, a story and a story reply are the same content envelope with a
different kind, so they run through the same few functions in Content.kt.
Twenty-three MRs, each written against an older main and green on its own
branch, had never existed together until they were merged in one evening.

The conflicts that produced were resolved mechanically — union a parameter
list, merge a condition — and that produces code which compiles and passes
while being wrong: a field on the wrong struct, an argument in the wrong
order, a term in the wrong condition. Three were caught by the compiler.
The ones the compiler cannot see are why calls stopped connecting.

And the gate could not see any of it. 489 unit tests stayed green through
every break, because they test units: "assemble produces this JSON" is a
unit test, "Android shows what iOS sent" is not.

versionCode 10 so it installs over the broken v9.

Nothing is lost — every MR is still a merged commit with its branch on the
remote, and re-lands in small batches once there is a test that actually
sends a message between two devices.
This commit is contained in:
Paul Hitt
2026-09-02 19:03:30 -04:00
parent 1f126f2cee
commit aebf41ed95
41 changed files with 67 additions and 5016 deletions
@@ -1,108 +0,0 @@
package io.flamenet.e2e
import org.json.JSONObject
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
/**
* Telling somebody their disappearing message was screenshotted (§6.27, ios#36).
*
* 🔴 **A courtesy from the taker's own client, and nothing else.** A modified
* build, a second phone photographing the screen, or the platform's own
* recorder all produce nothing. A notice means one was probably taken; no
* notice means NOTHING — and most of these tests are about not letting the
* interface say otherwise.
*/
class ScreenshotNoticeTest {
@Test
fun `the notice carries when it happened`() {
val content = Content.parse(Content.screenshot(1_788_000_000))
assertEquals(1_788_000_000, Content.screenshotAt(content))
}
/** ⚠️ Control traffic, so an older build stays quiet instead of showing JSON. */
@Test
fun `the notice is marked as control traffic`() {
val json = JSONObject(Content.screenshot(1))
assertEquals(1, json.getInt("ctl"))
assertEquals(Content.Kind.SCREENSHOT, json.getString("kind"))
assertTrue(Content.Kind.SCREENSHOT in Content.Kind.CONTROL)
}
@Test
fun `the marker stays first`() {
assertTrue(Content.screenshot(1).startsWith("{\"fnc\":1"))
}
/** A notice is never a message. */
@Test
fun `the notice carries no text`() {
assertTrue(Content.parse(Content.screenshot(1)).text.isEmpty())
}
/** Reading the stamp off anything else must yield nothing. */
@Test
fun `an ordinary message has no screenshot stamp`() {
assertNull(Content.screenshotAt(Content.parse(Content.text("hi", messageId = "m"))))
}
// -- When one is sent -----------------------------------------------------
/** 🔴 Only where a timer is set. */
@Test
fun `no notice in a conversation with no timer`() {
assertFalse(Content.shouldAnnounceScreenshot(0, null, 1_000))
}
@Test
fun `a notice is sent in a timed conversation`() {
assertTrue(Content.shouldAnnounceScreenshot(3600, null, 1_000))
}
/** ⚠️ One screenshot often fires several platform events. */
@Test
fun `a second event inside the window is suppressed`() {
assertFalse(Content.shouldAnnounceScreenshot(3600, 1_000, 2_000))
}
@Test
fun `a genuine second screenshot later is announced`() {
assertTrue(Content.shouldAnnounceScreenshot(3600, 1_000, 10_000))
}
/** ⚠️ The timer check comes first, or a window would enable an untimed chat. */
@Test
fun `the window does not override the timer rule`() {
assertFalse(Content.shouldAnnounceScreenshot(0, 1_000, 999_000))
}
// -- What may be claimed --------------------------------------------------
/**
* 🔴 **The most important test here.** Presenting the absence of notices as
* a fact would be inventing evidence out of silence.
*/
@Test
fun `the disclaimer refuses to turn silence into evidence`() {
val t = Content.screenshotDisclaimer
assertTrue(t.contains("when their app can tell"), t)
assertTrue(t.contains("cannot always"), t)
assertTrue(t.contains("was not captured"), t)
}
/**
* ⚠️ Android's half of the asymmetry has to be stated, not hidden. Claiming
* a symmetry with iOS that does not exist is worse than the gap, because
* somebody would rely on it.
*/
@Test
fun `the disclaimer states the android limitation`() {
val t = Content.screenshotDisclaimer
assertTrue(t.contains("recent version"), t)
assertTrue(t.contains("screen recording"), t)
}
}