Merge pull request #4203 from vitorpamplona/fix/cordn-ci-breaks-from-4201

fix: green main again — the three CI jobs #4201 broke
This commit is contained in:
Vitor Pamplona
2026-09-26 16:06:08 -04:00
committed by GitHub
9 changed files with 31 additions and 21 deletions
@@ -147,6 +147,12 @@ fun CordnCreateGroupScreen(
}
val known by runtime.coordinators.collectAsStateWithLifecycle()
// Collected, not read as `.value` below: the exposure card counts the
// groups this coordinator already carries, and reading the flow inside
// composition would leave that count frozen at whatever it was when the
// screen opened — the one number on the card that can change while you
// are looking at it, since creating a group is what changes it.
val rooms by runtime.groups.all.collectAsStateWithLifecycle()
val scope = rememberCoroutineScope()
val me = accountViewModel.account.signer.pubKey
@@ -491,10 +497,7 @@ fun CordnCreateGroupScreen(
// serves for this account: the disclosure is about what
// one coordinator can correlate, so a second group on
// the same one widens it.
linkedGroupCount =
1 +
runtime.groups.all.value
.count { room -> room.coordinatorPubKey == it.pubKey },
linkedGroupCount = 1 + rooms.count { room -> room.coordinatorPubKey == it.pubKey },
joinedFromShareLink = false,
publishedKeyPackage = false,
encryptionPinned = true,
@@ -50,6 +50,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
@@ -155,6 +156,12 @@ fun CordnInvitationsScreen(
return@Column
}
// Collected rather than read as `.value` further down: the empty
// state says either "you have no coordinators" or "nobody has
// invited you", and adding a coordinator in another tab has to
// change which of those two this screen is showing.
val coordinators by runtime.coordinators.collectAsStateWithLifecycle()
Text(
text = stringRes(R.string.cordn_invitations_explainer),
style = MaterialTheme.typography.bodyMedium,
@@ -227,7 +234,7 @@ fun CordnInvitationsScreen(
if (loaded.isEmpty) {
Text(
text =
if (runtime.coordinators.value.isEmpty()) {
if (coordinators.isEmpty()) {
stringRes(R.string.cordn_invitations_no_coordinators)
} else {
stringRes(R.string.cordn_invitations_none)
@@ -184,7 +184,7 @@ class PaymentTest {
}
@Test
fun `CVM-8-22 a server that ignores the request is a failed negotiation, not a downgrade`() {
fun `CVM-8-22 a server that ignores the request is a failed negotiation rather than a downgrade`() {
val session = PaymentSession(requested = PaymentInteraction.EXPLICIT_GATING)
session.observeServerTags(emptyArray())
assertTrue(session.negotiationFailed, "silent fallback must be visible to the caller")
@@ -76,7 +76,7 @@ class OversizedTransferTest {
}
@Test
fun `CVM-22-02 assembles out-of-order chunks by progress, not arrival order`() {
fun `CVM-22-02 assembles out-of-order chunks by progress rather than arrival order`() {
// Relays may reorder. `progress` is the canonical assembly index.
val frames = sender().frame(token, payload)
val start = frames.first()
@@ -43,7 +43,7 @@ class CvmMessageEventTest {
private val ping = JsonRpcRequest(JsonRpcId.Num(1), "ping")
@Test
fun `CVM-CORE-02 content is a stringified JSON-RPC message, not an embedded object`() {
fun `CVM-CORE-02 content is a stringified JSON-RPC message rather than an embedded object`() {
val template = CvmMessageEvent.build(ping, serverPubKey)
// The spec's examples print `content` unstringified for readability,
@@ -91,7 +91,7 @@ class CvmMessageEventTest {
}
@Test
fun `CVM-CORE-06 kind 25910 is ephemeral, so delivery has no replay`() {
fun `CVM-CORE-06 kind 25910 is ephemeral so delivery has no replay`() {
// Consequence, not decoration: relays do not retain this kind, so a
// subscription must be live before the peer publishes. The transport's
// request API is built around this and the property is worth pinning.
@@ -44,7 +44,7 @@ class CordnBlobUploadTest {
private val sealed = CordnMediaEncryption.encrypt(file, key, "image/jpeg", "holiday.jpg")
@Test
fun `the host is given the ciphertext, and its hash names the blob`() {
fun `the host is given the ciphertext and its hash names the blob`() {
val blob = CordnBlobUpload.of(sealed)
// Blossom addresses a blob by the hash of what it stores.
@@ -65,7 +65,7 @@ class CordnBlobUploadTest {
}
@Test
fun `the declared type is opaque, never the real one`() {
fun `the declared type is opaque rather than the real one`() {
val blob = CordnBlobUpload.of(sealed)
assertEquals("application/octet-stream", blob.contentType)
@@ -93,7 +93,7 @@ class CordnBlobUploadTest {
}
@Test
fun `upload, never the media endpoint`() {
fun `upload rather than the media endpoint`() {
// `/media` asks the server to re-encode. Re-encoding ciphertext
// destroys it, so an account with "optimize uploads" on would break
// every attachment and only the recipient would find out.
@@ -69,7 +69,7 @@ class CordnMediaEncryptionTest {
}
@Test
fun `renaming a file breaks it, because the name is authenticated`() {
fun `renaming a file breaks it because the name is authenticated`() {
val sealed = roundTrip(name = "photo.jpg")
assertFailsWith<Exception> {
@@ -180,7 +180,7 @@ class CordnMediaEncryptionTest {
}
@Test
fun `the display hints round-trip, including the waveform`() {
fun `the display hints round-trip including the waveform`() {
// The recorder measures amplitudes and the composer preview already
// draws them; without somewhere to put them they were dropped at upload
// and the sender's own voice note came back bar-less.
@@ -207,7 +207,7 @@ class CordnMediaEncryptionTest {
}
@Test
fun `a hint that is absent or malformed costs the hint, not the attachment`() {
fun `a hint that is absent or malformed costs the hint rather than the attachment`() {
// Every one of these is optional, so a reader that cannot make sense of
// one must still be able to fetch and open the file.
val tag = CordnMediaTag.build(roundTrip(), url = "https://b.example.com/b")
@@ -73,7 +73,7 @@ class CordnAnnotationIndexTest {
}
@Test
fun `only the author may edit, and the newest edit wins`() {
fun `only the author may edit and the newest edit wins`() {
val note = message(alice, CordnMessageKinds.TEXT, "original", createdAt = 100)
val tags = CordnMessageReferences.editTags(note.asTarget())
@@ -177,7 +177,7 @@ class CordnAnnotationIndexTest {
}
@Test
fun `any member may pin, and the last write wins`() {
fun `any member may pin and the last write wins`() {
val note = message(alice, CordnMessageKinds.TEXT, "important", createdAt = 100)
val t = note.asTarget()
@@ -64,7 +64,7 @@ class CordnMessageKindsTest {
}
@Test
fun `the numbers are cordn-web's, and differ from Marmot's on purpose`() {
fun `the numbers are cordn-web's and differ from Marmot's on purpose`() {
// Pinned because they are the interop surface with the only other cordn
// client, and because two of them disagree with Marmot (1009 edit, no
// pin) by decision rather than accident.
@@ -170,7 +170,7 @@ class CordnMessageKindsTest {
// ---- inbound -------------------------------------------------------
@Test
fun `a reaction needs kind 7, e p k, and content`() {
fun `a reaction needs kind 7 with e p k and content`() {
val good = CordnMessageReferences.reactionTags(target())
assertNotNull(CordnMessageReferences.reaction(7, "+", good))
@@ -210,7 +210,7 @@ class CordnMessageKindsTest {
}
@Test
fun `an edit needs kind 1010, an e tag, and text`() {
fun `an edit needs kind 1010 with an e tag and text`() {
val tags = CordnMessageReferences.editTags(target())
assertEquals("1".repeat(64), assertNotNull(CordnMessageReferences.edit(1010, "new", tags)).targetId)
@@ -230,7 +230,7 @@ class CordnMessageKindsTest {
}
@Test
fun `a pin needs kind 1011, an e tag, and a known op`() {
fun `a pin needs kind 1011 with an e tag and a known op`() {
assertEquals(
PinOp.ADD,
assertNotNull(CordnMessageReferences.pin(1011, CordnMessageReferences.pinTags(target(), PinOp.ADD))).op,