aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-25 18:49:55 +0200
committerDanilo M. <danix@danix.xyz>2026-08-25 18:49:55 +0200
commitdfb36213c03e678178ec1abb2327266d23015bc0 (patch)
tree4c4bf7c50e509af78d9a9be09c819b81c9ba90de /CLAUDE.md
parent3955ff80e3b0d558cd854c4517d1835514010b90 (diff)
downloadqtmaildir-dfb36213c03e678178ec1abb2327266d23015bc0.tar.gz
qtmaildir-dfb36213c03e678178ec1abb2327266d23015bc0.zip
feat: empty the trash, the one action that asks first
Item 118, unblocked by 103. Message > Empty trash..., scoped to the account selector, with no default shortcut. purgeMessages() is a separate worker entry point from moveMessages() rather than a flag on it, because the two look alike and only one can be undone. It takes named ids, never a folder sweep, so the blast radius is what the dialog enumerated and the user confirmed, and it deletes every file of a message: notmuch deduplicates by Message-ID, so leaving one behind leaves the message alive in the folder the user emptied. It confirms, naming the count and the account, defaulting to Cancel. That breaks CLAUDE.md's no-confirmation rule deliberately and the rule now records it as its single exception, in the same paragraph: a purge has no inverse to push onto the undo stack, so the protection the rule provides has to come from somewhere, and the dialog is where. Two defects found rather than reasoned. The count claimed messages whose files were already gone, overstating an irreversible action; an absent file is correctly not an error, but that is not the same as destroyed. And the user's hand test found the list still showing mail that no longer existed: a purge removes rows rather than changing them, so there is no optimistic update to apply and nothing was connected to messagesPurged at all. It re-runs the current query now. Verified against the live index after the user emptied one real account's trash: zero files on disk, zero in the index. The suite is 37 of 38, the failure being item 136 on an unrelated path. Ten new strings translated, lrelease reports 0 unfinished. Item 168 is filed from the same hand test, on Delete being offered on mail already in the trash. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HFuRPtzFrSxCQjFk6tq7gD
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md12
1 files changed, 11 insertions, 1 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index e0e4cf0..a2672a6 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -236,7 +236,17 @@ open handle per process, so that close-first ordering is required, not stylistic
**No dry-run, no destructive-action confirmation.** Those gates belonged to the retired
`mailctl` CLI, where they restrained an agent; a human at a GUI gets **undo** instead — every
mutation pushes its inverse (`TagChange::inverted()`) onto a `QUndoStack`. Do not add
-confirmation dialogs for tag mutations. All actions funnel through one `applyTags` path;
+confirmation dialogs for tag mutations.
+
+**There is exactly ONE exception, and its shape is the rule's own logic rather
+than a hole in it.** `empty_trash` (item 118) destroys files and index entries,
+so it has no inverse to push, and the protection the rule actually provides —
+that a user never loses work to a keystroke — has to come from somewhere else.
+It therefore asks, naming the count and the account, defaulting to Cancel, and
+it carries **no default shortcut** for the same reason. `NotmuchWorker::purgeMessages()`
+is a separate entry point from `moveMessages()` deliberately: the two look
+alike and only one of them can be undone. A second confirmation anywhere is a
+defect unless the action is likewise irreversible. All actions funnel through one `applyTags` path;
multi-row selections go through `applyTagsToThreads`, which resolves every thread in ONE
combined `thread:a or thread:b` query rather than one query per thread.