Kgothatso Ngako 44127cf514 test: exercise MarmotOutboundDao past the MLS guard
02e70d9 claimed the paths past the membership guard "need a real peer key
package to exercise, which means an MLS fixture this test file deliberately
does not build", and left them uncovered on that basis. That was wrong, and this
corrects it.

Nothing about a key package needs a relay. DatabaseMarmotRepository.generateKeyPackage
already builds this device's own entirely locally: two X25519 key generations,
one Ed25519, a leaf node signed under "LeafNodeTBS" and a key package signed
under "KeyPackageTBS". Everything it touches is quartz public API, so
MarmotKeyPackageFixture replicates it in about forty lines. The capabilities it
advertises are not decoration -- the group's RequiredCapabilities rejects a leaf
that does not carry LastResort and NostrGroupData, so a fixture omitting them is
refused at addMember rather than at decode, and the comment says so.

With that, three properties past the guard are asserted rather than described.

The invitee is persisted. sealGiftWrapPayload walks the room's participants to
decide who to wrap a Welcome for, so without the row the Welcome produces no
gift wraps at all and sits unsealed forever.

The advanced epoch reaches the database. addMember moves the in-memory group
forward, and the comment on that write explains what happens when it is not
saved back: the creator keeps encrypting under the old epoch, which the new
member cannot decrypt, and the next invite re-derives from stale state and
produces a conflicting commit. The test asserts the stored state changed, that
it still restores, and that the restored group has two members -- so it is
checking a real advance rather than any write at all.

The epoch being left behind is retained, at epoch 0 for a freshly created group.
That is the call that actually writes a retained secret, so it belongs here as
well as in the retention-window tests that only read them.

Verified by mutation: deleting the write that persists the advanced state fails
`inviting a member persists the advanced group state` and nothing else. The
mutation was reverted; no production source is touched by this commit.

The peer needs a Profile row here where the guard tests did not, because
Participant.participantPublicKey is a foreign key onto Profile and only a
successful invite reaches that write -- the same constraint that shapes the
nip17 tests in 5fa0d08. Found the same way, by three of these failing with
SQLite 787 first.

Still not covered: the Welcome itself, the deferred-welcome path for a group
that already has members, and the batching in addMembersToChatRoom. Those need
more than a key package -- a second device's view of the group -- and are a
separate piece of work.

3 tests added, 7 in the class. composeApp jvmTest is 312 tests, 0 failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 03:35:27 +02:00
2026-07-05 23:21:02 +02:00
2026-07-28 09:10:20 +02:00
2026-03-24 04:47:19 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00
2026-03-23 01:41:39 +02:00

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 thats 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 Apples 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 youre 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 IDEs 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 IDEs 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 IDEs toolbar or open the /iosApp directory in Xcode and run it from there.


Learn more about Kotlin Multiplatform

Description
Mantra as a kotlin multiplatform project
https://mantra.press
Readme 8.2 MiB
Languages
Kotlin 100%