A note is still lost when the relays reject it
- Dominant language
- Rust
- Stars
- 71
- Forks
- 5
- Avg merge
- 4h 2m
- Merged PRs (30d)
- 31
Description
Found while reviewing #513. That PR fixes half of this and the half it leaves is worth stating plainly rather than letting it read as handled.
## What #513 fixed, and what it did not
`submit_note` closes the editor after handing the event to the worker, and closing it destroys the text: the next `ComposingStarted` calls `clear_content` (`src/model/editor.rs:82`), so there is no way back to it.
#513 made the **pre-send** failure keep the draft — disconnected, or the worker gone, both knowable synchronously, so the editor simply stays open.
The **post-send** failure still loses it, and that is the common one:
1. Connected, user writes a long note, presses `Ctrl+P`.
2. The editor closes; the status bar reads `[Sending] `.
3. Every relay rejects it, or none acks within the timeout.
4. `resolve_publish` shows `[ERR: Posted] : no relay accepted the event: …`.
5. The text exists only in that status line — normalised to one line, competing for space, and gone as soon as anything else writes a status.
So nostui now *tells* the user their note was not published, and still gives them no way to get it back.
## Why it was not fixed in #513
Both plausible fixes need something #513 does not have:
- **Keep the editor open until the outcome arrives.** The editor captures every keystroke while active, so this would lock the user out of the app for up to the ack timeout (10s per relay by default). Not acceptable.
- **Restore the content on failure.** `model::editor` has no way to set content — only `clear_content`, `ComposingStarted`, `ReplyStarted`, and `KeyEventReceived`. This needs a new message (`DraftRestored { content }` or similar), which is a different subsystem from the publish-confirmation work #513 is about.
It is also a UX decision that deserves its own thought rather than being smuggled in: what happens if the user has already started composing something *else* by the time the failure lands? Silently replacing their new draft with the failed one would be its own data loss.
## Suggested shape
- Add a `DraftRestored { content }` message to `model::editor` that reopens the editor with the given content.
- Carry enough on the pending entry to know a publish came from the editor — reactions, reposts and NIP-38 status events have nothing to restore.
- On failure, restore only when the editor is not already active; otherwise leave the new draft alone and rely on the error message.
- Reply drafts need the reply target restored too, or the retry silently becomes a top-level note.
## Acceptance
- A note rejected by every relay can be recovered and retried without retyping.
- A failure arriving while the user is composing something else does not touch what they are writing.
- A rejected *reply* comes back as a reply, not as a new note.
Contributor guide
Assessment
This issue has not been assessed yet.