From 39d0371f284a5fb20eb132a60c795d6814b41b0a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 25 Aug 2026 17:33:50 +0200 Subject: docs(backlog): close item 166 The fix landed in 6ea6980 and the row was left open. Its section moves to the closed file with what the fix turned out to need: the loop, the two query forms that were measured and rejected, the split-index fixture, and the live read-only verification. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01HFuRPtzFrSxCQjFk6tq7gD --- .../plans/2026-08-03-post-0.1.0-usability.md | 67 +--------------------- 1 file changed, 1 insertion(+), 66 deletions(-) (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md') 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 3cdc71a..1f14e67 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 @@ -239,7 +239,7 @@ taking that too literally. | 163 | The message pane shows a stale path, and the composer forks the draft | defect | S | **done, 2026-08-25.** mbsync renames an uploaded file to add its `,U=` infix while the model still holds the name the query returned. `MaildirName::resolveRenamed()` returns the path unchanged when it exists, else finds the file in that one directory whose unique stem matches; it refuses an ambiguous match and yields nothing for a genuinely missing file. Wired into all THREE read sites: the pane, Reply/Forward, and the draft reopen. The reopen was the one that cost data, forking a draft into two files with two Message-IDs, both reaching the server | | 164 | A draft this application saved keeps `inbox` | defect | S | open, 2026-08-25, **cause corrected 2026-08-25**. The first diagnosis blamed a missing drafts helper and was WRONG: `NOT_ARRIVALS` in `qtmaildirconf.py` is `("sent", "drafts")`, the folder list includes every account's drafts folder, and `notmuch count` confirms the carve-out query MATCHES the affected draft. The carve-out is scoped to `tag:new`, and the draft carries `inbox` while `tag:new` is 0, so it was never in scope when the hook ran. Measured separately: an mbsync-style rename does NOT re-add `new.tags`, so the retag theory is out too. What remains unestablished is WHICH pass tagged it; establish that before writing code | | 165 | A draft gets a new Message-ID on every autosave | enhancement | ? | open, 2026-08-25, found while hand-testing 163 and 164. `MessageBuilder::build()` generates an id unconditionally and every autosave calls it, so each revision is a distinct MESSAGE to notmuch and to the server rather than a new version of one. Invisible while the file is replaced correctly, which item 163's fix restores; it is what turned that fork into two messages rather than one duplicated file. Needs a DECISION on what a draft's identity is before any code: a stable id reused at send, a stable id discarded at send, or the status quo. Neither `ComposeContext` nor `OutgoingMessage` has a field to carry an id, so it is not a changed call site | -| 166 | Mail you send to your own other account loses `inbox` | defect | S | open, found 2026-08-25. Wholly this repo's: the hooks live in `assets/hooks/` with their own suites, and the live `post-new` symlinks to them | +| 166 | Mail you send to your own other account loses `inbox` | defect | S | **done 2026-08-25**, unreleased. `sent_only()` keeps a message only when EVERY file is inside a sent folder, which is what the carve-out's docstring already claimed. No query can express it, measured; the root comes from `database.mail_root`, with a split-index fixture the ordinary layout cannot provide. Verified read-only against the live index: 780 of 807 still stripped, 27 spared, no arrival affected | | 167 | No way to tell one build of an unreleased version from another | enhancement | XS | **done 2026-08-25**, unreleased. The user chose a counter over a git description: `QTMAILDIR_BUILD_NUMBER`, a cmake option ON by default, increments a counter in the BUILD directory on every build and writes `buildnumber.h`. `QTMAILDIR_VERSION_DISPLAY` carries it; `QTMAILDIR_VERSION` stays clean and is what the window title, `applicationVersion` and the release procedure use | Sizes are rough: XS under an hour, S a sitting, M a session. @@ -537,71 +537,6 @@ reaches it (item 42), so most of this exists. **Size: S** for the on-demand button, XS for the visibility half. Ask which. -## 166. Mail you send to your own other account loses `inbox` - -**Observed (agent, 2026-08-25, while setting up msmtp.)** Four test messages -were sent to one of the user's own accounts, one from each configured sending -account. All four were delivered and indexed. The two sent from accounts whose -Sent folder is fetched locally arrived in the recipient account's Inbox -**without the `inbox` tag**, so they were absent from that account's Inbox view. -The two sent from an account whose Sent folder is not fetched kept `inbox` -normally. - -**Cause: established, and it is the `post-new` hook, not this binary.** -`strip_inbox_from_sent()` in `assets/hooks/post-new` removes `inbox` from any -message matching a configured sent folder's PATH. Its docstring states the -assumption exactly: "the provenance is the file's own path: a message inside a -configured sent folder is one this system sent, and `inbox` was never true of -it." - -That holds for one file. It fails for one MESSAGE, because **notmuch -deduplicates by Message-ID and a message can have several files**. When the -sender and the recipient are both the user's own accounts, mbsync fetches two -copies: the sender's Sent copy and the recipient's Inbox copy. notmuch stores -them as ONE message with two filenames. The carve-out's query matches via the -Sent filename and strips `inbox` from the message object, which is the same -object the recipient's Inbox copy belongs to. - -Measured: one message, two paths, one in the sender account's sent folder and -one in the recipient account's `Inbox/cur`. - -The assumption is not merely incomplete, it is false in this case: the message -was genuinely sent AND genuinely received. There is no single right answer for -"was `inbox` ever true of this message", because it was true of one file and -false of another. - -**Approach.** Not settled, and the choice matters more than the code: - -1. **Strip only when EVERY file is in a sent folder.** Closest to the existing - intent, and it makes the predicate match the docstring's claim. A - self-addressed message keeps `inbox`, which is right: it did arrive. -2. **Strip only when the message has exactly one file.** Simpler to express, - but it silently stops protecting any sent message that happens to be - duplicated for an unrelated reason. -3. **Leave it.** Self-addressed mail is rare outside testing. The cost is that - it is invisible when it happens, and it looks exactly like the sync defect - item 104 turned out to be, which is how this was found. - -Option 1 is the one that makes the code true to what it already says it does. - -**Constraints.** - -- **The hook is this repo's**, `assets/hooks/post-new`, which the live - `database.hook_dir` symlinks to. It has its own suites beside it; run - `./test_post_new.py` and `./test_mailrules.py` from `assets/hooks/`. -- The hook **tags real mail unattended, every ten minutes, on the user's live - index.** A predicate that is wrong in the other direction would strip `inbox` - from arriving mail, which is the failure mode PROTECTED_REMOVALS exists to - prevent. Test against a throwaway database first. -- `notmuch tag` matching zero messages SUCCEEDS, so a log line saying the - carve-out ran is not evidence it matched anything. The count added for item - 164 is what distinguishes them; use it. -- Do not fix this by narrowing the query to exclude the recipient account. The - bug is in the per-file predicate, not in which folders are configured. - -**Size: S.** - - ## 112. Toggle unread on a whole thread cannot reach "all unread" on a partly-read thread **Observed (user, 2026-08-17):** clicking a thread root and asking to mark the -- cgit v1.2.3