`FrostSigningScreen` turned an event into words -- "New chapter", "Genesis 1 ·
797 words · 31 chunks" -- inside a private composable, which was the right place
for it while one screen was the only place a proposal was ever seen.
The room's list of proposals is about to need the same words, and two copies of
this mapping is two names for one thing. They would not drift immediately; they
would drift the first time a kind is added and only one of them learns about it,
and the reader would meet an artifact on one screen and "Event of kind 30300" on
the other.
`ProposedEvent.summarize` is the same `when`, moved whole, returning a label and
a detail instead of a `Pair` so the two halves are named where they are read. Not
a composable and deliberately: nothing about naming a thing needs a composition,
and a plain function can be called from a view model, which is where the list
does it -- once per emission rather than once per recomposition of a scrolling
row.
The reasoning moved with it, because it is reasoning about the words rather than
about the screen: a member deciding whether to sign is deciding about a dialect
or an artifact, "kind 30304" answers a question nobody asked, and the raw kind
stays for anything unrecognised since refusing to describe an event is better
than describing it wrongly. What stays on the screen is what is true only there:
a batch is all-or-nothing, so an event that cannot be read is a reason to refuse
the whole proposal rather than a gap to render around.
No behaviour change. Same strings, same order, same fallback.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>