Phase 8 of docs/subgroups.md. Four of the seven refusals landed with the code they guard; these are the three that did not, and two of them are about what this device *can* do rather than what the user should pick. **No share of the parent's key.** `FrostSigningManager.proposeSigningBatch` throws outright for a device with no share, so without this the button crashes rather than declines. It is checked first because it is the one refusal a user cannot fix by picking differently -- every other message says "pick differently" and this one cannot. **Not an admin of the parent.** A non-admin proposing the group's signature is a proposal the admins have to decline by hand, which is worse than not offering it. Read off `Participant.adminAt`, which is the epoch-0 admin list MIP-01 carries and the same reading every side of the group makes. Both are checked in `refuseCeremonyRoom` as well as at the button that hides itself on `canAddSubgroup`, because a screen not drawing something is not a guard -- and a resumed flow reaches the manager without passing that screen at all. **A child already certified.** One certificate per child: a second is a `d`-tag replacement of the first rather than a second subgroup, and spending a quorum's attention to restate something they have already signed is worse than doing nothing. This is a `check` at propose time rather than a picker refusal, since the child's id does not exist until the ceremony finishes. It deliberately does not try to stop the race. Two coordinators can each propose a certificate for the same child, neither able to see the other's session before it completes; `certificateFor` folds those together because both say the same true thing. This only stops the case somebody can actually see. The blank-name `require` gets a test of its own for the same reason the name exists at all: without it the parent's admins would be approving a hash. Six tests in `SubgroupManagerJvmTest`, and the fixture had to grow to carry them. `parentWith` now gives the parent a completed ceremony and marks the coordinator an admin, with both switchable, because a fixture missing either tests only the first refusal -- which is how the two new checks were found to short-circuit the existing cases the moment they were added. The plan called for a pure `SubgroupGuardsTest` in commonTest. It is not one: every refusal here reads the database -- a key-holding session, an admin flag, a ceremony in the derived room -- so the tests live in jvmTest beside the manager's others rather than being reshaped into something pure that would test less. 397 common tests, 705 jvm tests, `m3Audit` meets every budget. 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…