Files
amethyst/commons
nrobi144 2061ef9e37 fix(desktop): align pre-send DM validation with strict NIP-17 semantics + wire resolver fan-out
Two related fixes that surface the same class of bug: the pre-send
"Recipient has no DM relay list" warning could disagree with the
actual send path, causing sends that either fail after the user
clicks Send, or block sends the user would have expected to work.

(a) STRICT ALIGNMENT — User.dmInboxRelays() (commons) is the lenient
    "give me a delivery target for a DM" helper: it returns kind:10050
    if present else the NIP-65 read marker (kind:10002). The send path
    (DesktopIAccount.resolveDmInboxRelaysStrict → DmInboxRelayResolver)
    uses the strict variant that returns kind:10050 only, because NIP-17
    §Publishing mandates delivery to the recipient's kind:10050
    exclusively — routing a wrap through a NIP-65 read relay leaks the
    conversation metadata to a relay the recipient did not designate
    for DMs.

    Add User.dmInboxRelaysStrict() as the kind:10050-only accessor and
    switch ChatNewMessageState.updateRecipientRelayStatus() to it so the
    UI's "can we deliver" check matches what the send path actually
    enforces.

(b) RESOLVER PROBE — pre-send validation was cache-only: if a peer's
    kind:10050 hadn't landed in LocalCache yet (e.g. the peer just
    published, or their event sits on an indexer relay we don't
    subscribe to), the UI reported them unreachable and blocked send
    even though the send path's DmInboxRelayResolver would have found
    them via indexer fan-out.

    Add an optional `dmInboxResolver: suspend (HexKey) -> List<...>?`
    callback to ChatNewMessageState. On a synchronous cache miss for any
    peer, the state optimistically blocks (preserving the "don't
    silent-fail" invariant) and launches a probe. If any peer's relays
    turn up, unblock immediately without requiring the user to reopen
    the conversation.

    Wired at both ChatNewMessageState construction sites in
    DesktopMessagesScreen to DesktopIAccount.dmInboxResolver (which
    Main.kt injected in the earlier P4 wire-up commit). Android's
    ChatNewMessageViewModel is a separate class and keeps
    cache-only behaviour — Android UI parity is deferred.

Surfaced during manual testing 2026-07-06 with two accounts where one
had a kind:10050 and one didn't: the UI correctly blocked send, but
the block persisted even after publishing kind:10050 for the missing
account until the conversation was reopened.
2026-07-09 07:33:43 +03:00
..