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>
This commit is contained in:
@@ -365,4 +365,29 @@
|
||||
<string name="nothing_matched_that_search">Nothing matched that search.</string>
|
||||
<string name="key_package_published">Key package published</string>
|
||||
<string name="key_package_rotated">Key package rotated</string>
|
||||
<string name="subgroups">Subgroups</string>
|
||||
<string name="add_subgroup">Add subgroup</string>
|
||||
<string name="no_subgroups_have_been_made_by_this_group">No subgroups have been made by this group.</string>
|
||||
<string name="certified_not_yet_created">Certified, not created yet</string>
|
||||
<string name="created_you_are_not_a_member">Created, you aren't a member</string>
|
||||
<string name="a_subgroup">A subgroup</string>
|
||||
<string name="parent_group">Parent group</string>
|
||||
<string name="the_group_this_one_is_a_subgroup_of">The group this one is a subgroup of</string>
|
||||
<string name="run_by_members">Run by %1$s members</string>
|
||||
<string name="new_subgroup">New subgroup</string>
|
||||
<string name="what_is_the_subgroup_called">What is the subgroup called?</string>
|
||||
<string name="who_runs_the_subgroup">Who runs the subgroup?</string>
|
||||
<string name="a_subgroup_needs_at_least_three_admins">A subgroup needs at least three admins, you included, so pick at least two more people.</string>
|
||||
<string name="anyone_in_this_group_can_run_a_subgroup">Anyone in this group can run a subgroup, whether or not they administer this one.</string>
|
||||
<string name="has_no_key_package_yet">Has no key package yet</string>
|
||||
<string name="admin_of_this_group">Admin of this group</string>
|
||||
<string name="you_coordinate_this_subgroup">You coordinate this subgroup</string>
|
||||
<string name="start_the_key_ceremony">Start the key ceremony</string>
|
||||
<string name="checking_who_can_be_added">Checking who can be added…</string>
|
||||
<string name="the_parent_group_has_certified_this_subgroup">The parent group has certified this subgroup</string>
|
||||
<string name="the_parent_group_could_not_certify_this_subgroup">The parent group could not certify this subgroup</string>
|
||||
<string name="the_parent_group_is_certifying_this_subgroup">The parent group is certifying this subgroup — %1$s of %2$s admins have to sign</string>
|
||||
<string name="before_the_subgroup_exists_its_parent_signs">Before the subgroup exists, its parent signs for it. That signature is what lets anyone check where this group came from.</string>
|
||||
<string name="ask_the_parent_group_to_certify">Ask the parent group to certify this subgroup</string>
|
||||
<string name="create_the_subgroup">Create the subgroup</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user