aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/plans')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md44
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md2
2 files changed, 45 insertions, 1 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
index 133a761..0f7181b 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
@@ -7348,3 +7348,47 @@ what a drafts folder is; they are separate readers and neither should start
importing the other.
---
+
+## 153. A draft cannot be opened for editing, so it is write-only
+
+**Observed (user, 2026-08-24).** Found the moment item 138 gave drafts a
+button: "Double clicking on a draft should open the message in the editor
+window", and "there's no edit action anywhere, a draft is useless as is".
+
+**Cause (verified in code).** `DraftStore` had a `write()` and no reader, and
+nothing anywhere opened a composer from an existing message. A draft therefore
+rendered in the message pane like ordinary mail and could never be finished.
+
+**Outcome.** `ComposeContextBuilder::forDraft()`, a `Kind::Draft` that seeds
+every field verbatim, `edit_draft` in the Message menu, and double-click.
+
+**Three things worth keeping.**
+
+**A resumed draft must own its file.** Maildir has no in-place edit, so an
+autosave writes a new file and unlinks the old; a composer that did not know
+its own path would leave the original behind and one message would become two.
+`ComposeContext::draftPath` carries it into `m_draftPath`, which the autosave
+already knew how to replace.
+
+**`MimeParser` had no `bcc` and nothing had ever needed one.**
+`MessageBuilder` writes Bcc into the draft file deliberately and says why, so a
+resumed draft that ignored it would drop every blind recipient from the message
+the user then finishes and sends, silently. That is the failure this item was
+most likely to ship.
+
+**The gate is not cosmetic.** `edit_draft` is offered only on a file inside a
+configured drafts folder, matched on the PATH: a `draft` tag is not enough,
+since notmuch surfaces the Maildir D flag as one and a message flagged by
+another client sits in the inbox. Offered on ordinary mail, the composer would
+own a file it did not write and the first autosave would DELETE a received
+message.
+
+**And a live defect found on the way, which is the reason this took as long as
+it did.** `updateComposeActions()` ran only from `onSelectionChanged`. Both
+signals fire for an ordinary click, so nothing had ever noticed; but running a
+query and setting the current index emits `currentRowChanged` ALONE, so the
+enablement was computed against the previously selected row. Measured: Edit
+draft stayed disabled on a draft selected that way, and the reply family had
+the same blind spot without a test that could see it. It is now connected to
+both signals. Reading `currentRowChanged` is safe here for the reason
+`CLAUDE.md` gives: it answers "which row is current", and no count is read.
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 79320bd..e203856 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -222,7 +222,7 @@ taking that too literally.
| 150 | The receive-only ribbon stays up after the message that raised it is gone | defect | S | **done** 2026-08-24, unreleased. One line in `MessageView::clear()`, beside the blocked-content bar, the stale notice and the attachment bar it already reset by hand. Only `setReceiveOnlyAccount()` hid the ribbon, which every SELECTION change reaches, so a row-to-row move was never the reproducer: it survived the FOUR routes that blank the pane without one (`clear_pane`, `clear_selection`, a new query, a multi-row selection). The first test written for it passed against the defect for exactly that reason |
| 151 | The message-pane bars blend into the UI and carry no severity | presentation | S | **done** 2026-08-24, unreleased. Two severities as the user asked: yellow for a warning that only explains (the receive-only ribbon), blue for one offering an action (remote content blocked, stale thread), each with its own light and dark set read off `QPalette::Base` as `HtmlBuilder` does. The blocked row had to become a WIDGET first: it was a bare `QHBoxLayout`, which has nothing to paint a ground on, and its six `hide()` sites then had to move to the wrapper or a painted empty strip would show. Both action bars put the button right of a stretch |
| 152 | Signatures are not managed at all | v2 | ? | open, 2026-08-24, from the notes, and the user added a constraint the same day: a signature is **not tied to an account**, and is switched from a control in the composer's editor bar. That rules out the obvious `[account.*] signature` key as the whole answer. Still unspecified in the rest: where the text is stored, how it interacts with the quote, and whether the HTML part gets its own form |
-| 153 | A draft cannot be opened for editing, so it is write-only | defect | M | open, 2026-08-24, from the notes, found by the user the moment item 138 gave drafts a button. Verified: `DraftStore` has a `write()` and no reader, nothing anywhere calls anything like `loadDraft`, and no action opens a composer from an existing message. A draft therefore renders in the message pane like ordinary mail and can never be finished or sent. `ComposeContextBuilder` already parses a file into recipients and a body for Reply and Forward, so the parsing exists; what is missing is a context KIND that owns the original (a resumed draft must replace its file on save, not accumulate a second one) and a way in. **The two halves of the note are one item:** double-click on a draft, and an Edit action for every other route |
+| 153 | A draft cannot be opened for editing, so it is write-only | defect | M | **done** 2026-08-24, unreleased. `ComposeContextBuilder::forDraft()` reads a draft back into a context; a new `Kind::Draft` seeds the fields verbatim, takes the body with no quote framing, and carries `draftPath` so the autosave REPLACES the file instead of leaving a second copy. `MimeParser` gained `bcc`, which nothing read before: `MessageBuilder` writes Bcc into the draft deliberately, so a resumed draft that ignored it would silently drop every blind recipient. Reachable by double-click and by an `edit_draft` action, gated on the file being in a configured drafts folder because opening ordinary mail this way would make the first autosave DELETE a received message. Found a live defect on the way, see the section |
| 154 | No read confirmation | v2 | ? | open, 2026-08-24, from the notes. `Disposition-Notification-To`, which is a header `MessageBuilder` would add and a request the message pane would have to honour or ignore on the receiving side. Unspecified: whether this is send-side only, and what the reader is asked |
| 155 | No urgency switch on an outgoing message | v2 | S | open, 2026-08-24, from the notes: low, regular, high. `X-Priority` and `Importance`, headers `MessageBuilder` adds; regular writes neither. A control in the composer, and the same question item 144 answered for the HTML toggle applies to where it sits |
| 156 | No delivery confirmation | v2 | ? | open, 2026-08-24, from the notes. Distinct from 154: this is a DSN (`Return-Receipt-To`, or the ESMTP NOTIFY parameter), which is the sending server's to honour rather than the reader's client. Whether it can be requested at all depends on the `send_command`, so this may not be this application's to offer |