0c240a3 made a claim about a room's first message and de3b355 made one about
its second ceremony, and neither is visible from any of the pieces already
under test. ChillDkgRitualOrderingTest runs the ChillDKG calls, DkgSession-
DaoJvmTest pins the state a ritual resumes from, NostrNip17DaoJvmTest covers
the room. What none of them can see is a room and a ceremony together: that
the room is empty until the ceremony, and that the ceremony is what fills it.
This runs the real thing against a real database. Room's in-memory builder,
the host's bundled SQLite, actual secp256k1 -- the room id is derived by
doing point work over the member set, and each member's ChillDKG host key is
derived from their nostr secret, so the keys are real KeyPairs rather than
hex filler. Nothing is stubbed; createNip17ChatRoom and proposeRitual are
called exactly as the view model calls them.
jvmTest rather than commonTest because it needs a database. jvmTest goes
333 -> 336; commonTest is unchanged at 217.
## What is pinned
- A robust room has no chat messages and nothing queued until the ceremony
opens, and the first line in it afterwards is TYPE_DKG_STARTED. That is
the whole of "the ceremony is the room's first message", stated as the
before and the after rather than as a count.
- The first event out is the 30310 proposal, authored by the creator.
- It carries the whole membership. Receivers derive `n` from the p-tags
plus the sender rather than from their own view of the room, so this is
the claim that decides whether three devices can agree on one ceremony.
- It carries the quorum that was picked, and the session id it opens.
- The session runs at that quorum, over three participants, coordinated by
the room's creator.
- The creator's host key is already out, and hostKeyApprovedAt is set:
opening a ceremony is the act of agreeing to be in it, so the member who
opened it is not asked again.
- Creating the same group twice returns the same room and the same
ceremony -- asked for a different quorum the second time, and answered
with the running one. One proposal on the wire, one line in the chat.
- A FAILED ceremony is replaced rather than handed back, and the group
proposes again.
## Checked against a mutation, not just run
The re-entry test is the one that could pass for the wrong reason, so the
guard it covers was deliberately broken -- `takeIf { false }`, which is
de3b355 reverted -- and it failed on its own while the other two passed.
Ordering is read off the autoincrement id rather than createdAt. Both chat
rows are written inside one proposeRitual call and can land on the same
timestamp, which would make an ORDER BY createdAt assertion pass or fail on
timing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>