Kgothatso Ngako 6bd59e05fe feat(subgroups): the four-rung ladder, the picker, and the list a parent reads off its own signatures
Phase 7 of docs/subgroups.md, and the first commit where a user can make a
subgroup. Four pieces.

**A subgroups section on the group detail screen**, above members, listing
`SubgroupManager.subgroupsOf` -- so it shows a child this device holds no room
for, which is the normal position of a member who is not in the subgroup and of
everybody between the certificate being signed and the room being created. A row
titles itself from the *room* where there is one and only otherwise from the
certificate, because the certificate's name and `p` tags are the founding roster
and a renamed or grown subgroup would otherwise be listed under a name nobody
uses. The supporting line says which of the two absences it is: certified but not
created, or created and you are not in it. Tapping opens the child where this
device has it and the certificate where it does not, since that is the whole of
what is known and it is checkable.

**A parent row on the child's detail screen**, directly under the signing key,
because between them they are what the room *is*: the identity it signs as and
whose child it is. It comes off the verified `GroupKeyState.parentChatRoomId`, so
a member welcomed in after the founding sees nothing there rather than an
unverified guess.

**`SelectSubgroupAdminsScreen`**, where the three things that cannot change later
are settled. The pool is the parent's own members, admins and non-admins alike and
marked rather than filtered -- the point of a subgroup is that it can be run by
people the parent does not let run the parent. The coordinator is shown, ticked
and locked, since they hold a share by construction and leaving them off the list
would make "pick two more" read as a group of two.

Key packages are resolved as the screen opens and a member without one is marked
and unselectable. A key package is one-time-use, so every group a member joins
burns one; `MarmotGroupCreation` would refuse to create the room for a missing one
-- correctly, the address being permanent -- but only after a ChillDKG, a parent
quorum and a child quorum had all completed, each needing every selected admin
present. Finding out at the picker costs nothing and finding out at step 4 costs
three ceremonies. The supporting line names the remedy rather than the diagnosis,
because only its owner can publish another.

The quorum stepper is here and nowhere else, and that is a protocol fact: ChillDKG
hashes the threshold and the host keys into the session identity, so `t` is fixed
the moment the proposal goes out. It is also the one value picked for other
people, and consent survives it -- `t` rides on the proposal, `acceptProposal`
re-checks it against `quorumRange`, and the host-key gate is where each invitee
agrees to the `t`-of-`n` they can now see.

**The ritual screen grows a rung rather than being cloned.** `DkgRitualRoute`
takes an optional `parentChatRoomId`, and with one the ladder is four steps
instead of three: key, certificate, key state, room. A parallel subgroup screen
would have duplicated a progress ladder, a threshold picker, three approval gates
and a key-state rung in order to insert one step, and the copies would drift
within a release.

The certificate rung is watched off the *parent's* signed events and sessions
rather than this room's -- it is signed where the parent's key can sign it, which
is never the ceremony's room. The key-state button stays shut until it is done,
because a subgroup's state carries the certificate and `GroupKeyStateManager`
refuses one without it; opening that session early would throw rather than fail.
And `createAdminGroup` passes the verified parent through to the room, names a
subgroup what the coordinator called it rather than "X (#admins)", and says so.

No new approval UI. The certificate is a `FrostSigningEvents.PROPOSAL` in the
parent's room and the key state one in the ceremony room; `ProposalListScreen` and
`FrostSigningScreen` already show and approve both, on both transports.

Six repository methods carry it: `subgroupsOf`, `parentOf`, `canSign` and
`refuseSubgroup` on `ChatRepository`, and `proposeBirthCertificate`,
`observeBirthCertificate` and `proposeSubgroupKeyState` on `DkgRepository`. The
view models talk to repositories and the managers take the database, which is
where the rest of the app has that line. `refuseSubgroup` returns a refusal when
it cannot compute one, because a guard that fails open is not a guard.

25 new strings in the catalogue in sentence case; 397 common tests, 701 jvm tests,
and `m3Audit` meets every budget.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 23:47:29 +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%