This is the phase the origin tag was for. A parent admin approving a birth
certificate is putting the group's signature to a room id produced by a ceremony
most of them were not in; until now the screen offered them a name and a head
count, which say how big the thing is and not what it does. The proposal now
reads "#Setswana Luke · for the project Gospel of John · run by 4 members", and
that middle clause is the only line that says what is being agreed to.
`SubgroupManager.Subgroup` gains the parsed origin beside the name and admins it
already parses, so every existing reader keeps working and the room's subgroup
list can say what each child is for -- as an overline, because the supporting
line is already carrying whether this device can open the room and both are
worth a line.
Names are resolved where the device holds the row and shown as a kind plus a
short hash where it does not, which is `describe`'s existing bargain. That case
is a fact rather than a gap: these entities live in the parent's tables, so a
certificate is allowed to name a row the reader will never hold, and a test
asserts the honest version rather than letting it read as a broken screen. An
unrecognised kind is named by its number, or on the card left out entirely --
describing something wrongly is worse than not describing it.
Resolution reuses the four `getX(id)` repository functions that already exist
rather than adding a query, and happens once per load in the view model, because
a composable cannot await a database. In `ChatRoomDetailViewModel` the list is
read into a local first: resolving inside the argument list would make the map
and the cards depend on evaluation order.
The card's four strings are four complete sentences rather than a kind word
interpolated into one, since a translated fragment assembled at runtime is a
sentence no translator ever saw.
Phase 6 of docs/subgroups-for-entities.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>