From 6de81918dc7a9342fb532d6a5542c868ff65826c Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 19 Aug 2026 10:09:09 +0200 Subject: docs: close item 103 and tick the delete-to-trash plan Every step of the plan is done. Item 103's section moves to the closed file on the same commit, per this repo's own rule, with its outcome recorded: what was built, the ten defects hand testing found that the suite did not, and the two process gaps closed alongside them. The fact worth carrying forward is the one that damaged real mail. Under mbsync's Create Both, a wrongly named origin folder propagates to the mail server, so any code composing a folder name reaches the server whether it means to or not. Item 118, emptying the trash, remains deferred at the user's request. Co-Authored-By: Claude Opus 5 --- .../2026-08-03-post-0.1.0-usability-closed.md | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md') 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 f46fec5..ef51b5c 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 @@ -6612,3 +6612,90 @@ Three lessons, in the order they were paid for: `image/png` that is demonstrably on the clipboard: a Wayland clipboard-manager interaction, or GIMP's own paste path. Neither is this repository's, and neither needs an item here until it is shown to be. + +## 103. What Delete does to mail on the server is undocumented and unverified + +**Observed (user, from the notes):** "verify how 'delete' works", with two +sub-questions of their own: "trash bin (?)" and "delete from server (?)". + +**This is a question first.** The user is not reporting a defect; they are saying +they do not know what the button does to their mail, which for a destructive +action is its own problem regardless of the answer. + +**What the code does (verified).** `src/mainwindow.cpp:825` adds and removes the +`deleted` tag, and nothing else. It is a toggle, it goes through the undo stack, +and it writes a notmuch tag. + +**What that means downstream is what needs verifying, and it is NOT in this +repo.** `maildir.synchronize_flags` is true, so notmuch maps certain tags to +Maildir filename flags, and mbsync carries filename flags to the server. Whether +`deleted` is one of those, whether the user's `~/.mbsyncrc` has `Expunge Both` +(it does, on every channel), and what each provider does with a message flagged +deleted, together decide whether this button is reversible. The undo stack makes +the TAG reversible; it says nothing about what a sync did with it in between. + +**Measured 2026-08-17, and the answer is that Delete does not delete.** notmuch's +tag-to-flag table has no row for `deleted` and no `T` flag, confirmed by a probe +on a throwaway database: `+deleted` left the filename untouched while the +control `+flagged` immediately produced `:2,F`. mbsync carries filename flags, so +`Expunge Both` never sees anything to expunge, and `assets/mailsync.sh` contains +no delete path. Both sub-questions answer no: no trash bin, no deletion from the +server, and the mail stays in the Maildir and the index forever. + +**Specified in +`specs/2026-08-17-delete-to-trash-design.md`. Read that before writing code.** +Delete becomes a real move into the account's trash folder, with a `Trash` +filter beside the other built-ins and a Restore action. Three constraints decide +whether the spec is worth opening: + +- It needs a **mandatory per-account `trash` key**, so an existing config warns + until five keys are added. User-visible: minor bump and an `### Upgrading` + note. +- The worker gains its **first non-tag mutation**, a rename plus a reindex, + deliberately shaped as `moveMessages(ids, destFolder)` so Send in v2 reuses it + for Drafts and Sent. +- **848 messages carry the old tag** while sitting in an inbox, and would be + invisibly half-deleted after the change. A repeatable menu entry queries them + into the list for review; it is not a startup migration. + +The no-confirmation rule survives, with its justification amended: the mail +lands in a browsable folder, but reversibility is now bounded by the provider +where the trash is purged on a timer. + +**Size: S** for the investigation, which is done. The build is **M**. + +**Built 2026-08-19, over eight commits on `delete-to-trash`.** Delete moves the +file into the account's `trash` folder and records where it came from in a +`deleted-from:` tag, because the file has moved and nothing else still +knows. A `Trash` filter sits beside the other four, `Restore from trash` +(`Ctrl+R`) is the inverse, and `Find stranded deleted mail` (`Ctrl+Alt+T`, a +menu entry only at the user's request) lists the 848 messages the old behaviour +left tagged but unmoved. It reports and moves nothing: acting on its own would +be a bulk delete with no selection behind it. + +**Ten defects were found by hand testing, not by the suite**, each reproduced +with a probe before being fixed. One had already damaged real mail: a folder +name containing a space was truncated by the origin tag, creating a bogus folder +beside the real one and stranding four messages of a thread. mbsync had adopted +it and written state files for it. That is the fact worth carrying out of this +item: **under `Create Both` a wrongly named origin folder propagates to the mail +server**, so any code composing a folder name is reaching the server whether it +means to or not. Tags are joined by a TAB across the thread boundary for the +same reason, since a notmuch tag may contain a space. + +**Two process gaps closed alongside it.** Adding an action is FIVE places and +this repository's CLAUDE.md said four; the missing one is a menu, and nothing +enforced it, so `restore` shipped reachable by a chord and by nothing a user +could see. `everyActionIsReachableFromAMenu()` now asserts it and found three +more of the same (`open_thread`, `clear_pane`, `clear_selection`). And a guard +in `deletingTwiceLeavesNoOriginTagBehind()` queried through the query bar in the +gap between the file rename and the tag writes, where a run returns zero rows +forever because `QTRY_VERIFY` re-reads `rowCount()` and never re-runs the query: +3 failures in 12 runs, each burning a full 15s timeout, 0 in 8 after asking the +database directly. + +**Emptying the trash is item 118 and remains deferred**, at the user's request. + +**Verified:** clean build with no warnings from any changed file, 24 of 24 +suites over three consecutive runs, 211 tests in `test_mainwindow`. Every one of +the spec's six testing bullets has a test, each mutation-checked. -- cgit v1.2.3