Files
mantra-kmp/composeApp
Kgothatso Ngako 3b00f9f893 refactor(subgroups): lift Marmot room creation out of the ritual view model
Phase 6 of docs/subgroups.md. `DkgRitualViewModel.createAdminGroup` was 120 lines
of room creation living in a view model, and a subgroup needs all of it with four
different values. It moves to `managers/MarmotGroupCreation`, unchanged in
behaviour, and the view model shrinks by 154 lines to the four values and a
`when` over the result.

The rules that were already right stay right for the subgroup for free, which is
the whole reason to move rather than to write a second one:

**Every key package before anything exists.** The id is derived, so there is
exactly one room per key at a path; a half-created one occupies that address
permanently and there is no second id to retry with. Better to create nothing and
name who is missing. (Phase 7 will check this at the picker instead, so a subgroup
does not discover it after three ceremonies -- this stays as the backstop.)

**`adminPubkeys` baked into the epoch-0 group context** rather than added by a
later commit, so a member welcomed afterwards gets a populated group instead of
chasing a bootstrap commit that predates their membership. That is why
`MarmotGroupData` is built by hand rather than through `MarmotGroupData.bootstrap`,
which hardcodes a single admin.

**`adopt` before the members are added.** Filing the key state is local and
certain; adding members is a relay round trip that can partly fail. The room comes
into existence already knowing what it signs with, whatever happens next.

**Derived ids make every step reachable twice**, so `Existing` is a success rather
than a refusal -- a second tap or another member getting there first should join
what exists rather than mint a rival group on one address.

Four outcomes instead of four scattered early returns: `Created` with the members
who could not be added, `Existing`, `BlockedOn` with the missing key packages, and
`Failed`. The view model keeps the one thing that was genuinely its own -- turning
missing public keys into names, since "no key package for 3 people" is not
actionable and "Bob needs to publish a key package" is.

**It is reached through `ChatRepository.createMarmotGroup`, not called directly.**
View models in this app talk to repositories and managers take the database; the
first cut had the view model reaching for `dkgRepository.database`, which does not
exist on the interface and should not. The repository method is three lines of
delegation and keeps the boundary where the rest of the app has it.

`parentChatRoomId` is the one genuinely new parameter, written onto the room after
`getOrCreateChatRoom` returns rather than passed into it -- that call is shared
with every other way a room appears and none of them has a parent to hand it.

Nine imports the extraction made dead are dropped from the view model. 397 common
tests, 701 jvm tests, `m3Audit` meets every budget.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 23:36:00 +02:00
..
2026-09-08 09:11:13 +02:00