Files
mantra-kmp/composeApp
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
..