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>