A PrivateV1 conversation is an out-of-band X3DH intro that binds no sender
credential, so its messages carry an empty credential. The client's
`decode_sender` returns `Missing` for an empty credential, and the event
emitters dropped any message whose sender could not be decoded. A PrivateV1
conversation therefore surfaced `ConversationStarted` but never the message
content, for both the initial message and every reply.
Deliver these messages with no sender instead of dropping them:
- `Event::MessageReceived.sender` becomes `Option<MessageSender>`; `None` marks
an anonymous PrivateV1 message.
- `ConvoOutcome` carries the conversation `class` (mirroring `InboxOutcome`), so
the client can tell a legitimately credential-less PrivateV1 message from a
group message that is missing one.
- A new `message_sender` helper gates the anonymous case on `class == Private`;
a missing credential on any group class is still dropped, preserving the
invariant that group messages must be attributable.
Covered by a new `private_v1_integration` test exercising both the inbox
(initial message) and convo (reply) receive paths.