From c50bea78e036518ce1a2a3eb899bbb5e305affea Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 20 Aug 2026 18:00:30 +0200 Subject: docs: implementation plan for compose and send, item 123 Thirteen tasks, ninety-nine steps, against the spec committed earlier on this branch. Written on master so it is readable from either branch; the implementation goes on compose-and-send. Every API assumption was verified against this machine rather than written from memory, which found five things the spec had wrong or unstated: libcmark-gfm-extensions ships NO pkg-config file although libcmark-gfm does, so CMake needs find_library beside pkg_check_modules. All three enabled extensions live in that second library, so finding only the first yields a build that compiles and silently renders plain CommonMark. GMime defaults to iso-8859-1, emits no Date or Message-ID unless asked, and g_mime_text_part_set_text() encodes with whatever charset is set when it is called, so setting the charset afterwards produces a part labelled utf-8 carrying latin-1 bytes. All three fail only on accented text, which for this user is every message. The plan builds the content stream directly and carries a working probe's output as evidence. MessageNode has no body or date field, so quoting takes a ParsedMessage. ThreadListModel::messageScopeFor() takes a QModelIndexList rather than a single index. There is no Config::maildirPath(): the mail root comes from notmuch_config_get(NOTMUCH_CONFIG_MAIL_ROOT) via a file-static helper in the worker, and item 124 records that composing a destination from the wrong root would write into the Xapian tree. Two spec statements are corrected in the plan rather than followed. It calls for a new top-level Message menu and one already exists at mainwindow.cpp:1156. And it requires a shortcut per action, which item 132 changed while this was being planned, so save_message ships without one. --- .../plans/2026-08-20-compose-and-send.md | 4923 ++++++++++++++++++++ 1 file changed, 4923 insertions(+) create mode 100644 docs/superpowers/plans/2026-08-20-compose-and-send.md (limited to 'docs') diff --git a/docs/superpowers/plans/2026-08-20-compose-and-send.md b/docs/superpowers/plans/2026-08-20-compose-and-send.md new file mode 100644 index 0000000..195dacc --- /dev/null +++ b/docs/superpowers/plans/2026-08-20-compose-and-send.md @@ -0,0 +1,4923 @@ +# Compose and Send Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add the write half of qtmaildir: compose, reply, forward and send, with markdown bodies, autosaved drafts and a cancellable send delay, without the application ever speaking a network protocol. + +**Architecture:** Four new units. `MessageBuilder` turns an `OutgoingMessage` into RFC822 bytes using GMime and cmark-gfm. `DraftStore` writes those bytes into a Maildir folder. `MessageSender` pipes them to a per-account `send_command` over stdin. `ComposeWindow` is the only one that owns widgets, and composes the other three. Three of the four are tested without a painter. + +**Tech Stack:** Qt 6.11 (Widgets, Test), GMime 3.0 (already linked), cmark-gfm 0.29 (new, stock Slackware), notmuch (read-only, unchanged), CMake + Ninja, QTest. + +**Implementation branch:** `compose-and-send`, currently identical to `master`. This plan lives on `master` so it is readable from either. + +--- + +## Before starting + +Read these, in this order. They are not optional context; each one records a +trap this plan walks past. + +1. The spec: `docs/superpowers/specs/2026-08-20-compose-and-send-design.md`. +2. `CLAUDE.md`, in particular **Web view security**, **Adding an action is FIVE + places**, and the gmime include-order rule. +3. `src/mailsync.cpp:172-205`, the `QProcess` precedent `MessageSender` copies. + +**Verified facts this plan rests on** (measured on 2026-08-20, not assumed): + +- `pkg-config --modversion libcmark-gfm` reports `0.29.0.gfm.13`. +- **`libcmark-gfm-extensions` has NO pkg-config file.** Only `libcmark-gfm.pc` + exists. The extensions library is `/usr/lib64/libcmark-gfm-extensions.so` and + must be found with `find_library`, the way notmuch already is. The spec's "a + `pkg_check_modules` line" covers only half of it. +- With `CMARK_OPT_SAFE` and the three extensions attached, a probe confirmed: + autolink wraps a bare URL, `~~x~~` becomes ``, `- [ ]` becomes + ``, a table renders as literal pipes (the + extension is not attached), and `\n\nafter")); + + QVERIFY2(!html.contains(QStringLiteral("