0c240a3made a claim about a room's first message andde3b355made one about its second ceremony, and neither is visible from any of the pieces already under test. ChillDkgRitualOrderingTest runs the ChillDKG calls, DkgSession- DaoJvmTest pins the state a ritual resumes from, NostrNip17DaoJvmTest covers the room. What none of them can see is a room and a ceremony together: that the room is empty until the ceremony, and that the ceremony is what fills it. This runs the real thing against a real database. Room's in-memory builder, the host's bundled SQLite, actual secp256k1 -- the room id is derived by doing point work over the member set, and each member's ChillDKG host key is derived from their nostr secret, so the keys are real KeyPairs rather than hex filler. Nothing is stubbed; createNip17ChatRoom and proposeRitual are called exactly as the view model calls them. jvmTest rather than commonTest because it needs a database. jvmTest goes 333 -> 336; commonTest is unchanged at 217. ## What is pinned - A robust room has no chat messages and nothing queued until the ceremony opens, and the first line in it afterwards is TYPE_DKG_STARTED. That is the whole of "the ceremony is the room's first message", stated as the before and the after rather than as a count. - The first event out is the 30310 proposal, authored by the creator. - It carries the whole membership. Receivers derive `n` from the p-tags plus the sender rather than from their own view of the room, so this is the claim that decides whether three devices can agree on one ceremony. - It carries the quorum that was picked, and the session id it opens. - The session runs at that quorum, over three participants, coordinated by the room's creator. - The creator's host key is already out, and hostKeyApprovedAt is set: opening a ceremony is the act of agreeing to be in it, so the member who opened it is not asked again. - Creating the same group twice returns the same room and the same ceremony -- asked for a different quorum the second time, and answered with the running one. One proposal on the wire, one line in the chat. - A FAILED ceremony is replaced rather than handed back, and the group proposes again. ## Checked against a mutation, not just run The re-entry test is the one that could pass for the wrong reason, so the guard it covers was deliberately broken -- `takeIf { false }`, which isde3b355reverted -- and it failed on its own while the other two passed. Ordering is read off the autoincrement id rather than createdAt. Both chat rows are written inside one proposeRitual call and can land on the same timestamp, which would make an ORDER BY createdAt assertion pass or fail on timing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This is a Kotlin Multiplatform project targeting Android, iOS, Desktop (JVM).
-
/composeApp is for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:
- commonMain is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name. For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app, the iosMain folder would be the right place for such calls. Similarly, if you want to edit the Desktop (JVM) specific part, the jvmMain folder is the appropriate location.
-
/iosApp contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
Build and Run Android Application
To build and run the development version of the Android app, use the run configuration from the run widget in your IDE’s toolbar or build it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:assembleDebug - on Windows
.\gradlew.bat :composeApp:assembleDebug
Build and Run Desktop (JVM) Application
To build and run the development version of the desktop app, use the run configuration from the run widget in your IDE’s toolbar or run it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:run - on Windows
.\gradlew.bat :composeApp:run
Build and Run iOS Application
To build and run the development version of the iOS app, use the run configuration from the run widget in your IDE’s toolbar or open the /iosApp directory in Xcode and run it from there.
Learn more about Kotlin Multiplatform…