aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-31 12:49:53 +0100
committerDanilo M. <danix@danix.xyz>2026-10-31 12:49:53 +0100
commitc7d09a3956c2b32f9590651c2088ab34334ac538 (patch)
treee7fdf1cc55ecfe836981ad770315e9c6d832958d /docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
parent2b6ecd2a1f624c12c071320ff1ed96404d75f839 (diff)
downloadqtmaildir-c7d09a3956c2b32f9590651c2088ab34334ac538.tar.gz
qtmaildir-c7d09a3956c2b32f9590651c2088ab34334ac538.zip
docs: record rule apply and archive-on-arrival
The no-confirmation rule gains its second exception, by property: a write scoped to the whole index confirms with the count, though it can be undone. AGENTS.md and the spec now describe the backfill as built: the worker resolves the ids once, writes one tag at a time over that fixed list, and answers with a single ruleApplied from which the undo macro is built, with nothing armed on the shared confirmation queue. Apply is refused during a sync. Hand round trip, throwaway index of 2 messages (one from the promo sender), rules.json written by TagRules::save from the C++ side with allow_archive and a note: post-new exited 0 and logged "applied 1 rule(s)"; after it, tag:promo 1, tag:inbox 1, tag:promo and tag:inbox 0, tag:unread 2, tag:new 0. The file read back 1 rule with allow_archive True and note "kept". Italian translations for the 16 new strings; lrelease reports 725 finished, 0 unfinished. Items 212 and 213 closed. Item 214 opened: an undo's write is not armed, so its confirmation is credited to whatever command is waiting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md65
1 files changed, 31 insertions, 34 deletions
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 6e36905..200b6d0 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
@@ -149,8 +149,9 @@ taking that too literally.
| 209 | The calendar has no Week view | presentation | M | open, from 206's brainstorm. The occurrence list is the seam: a new painter over CalendarItem, no store change |
| 210 | A repeating event cannot be edited "this and following" | workflow | S-M | open, from 206's brainstorm. Splits a series into two files, divides EXDATEs and overrides, shifts moved RECURRENCE-IDs, converts COUNT; see the spec's Out of scope |
| 211 | Archiving thousands of selected rows freezes the window | defect | S | **done** 2026-10-31, unreleased. Cubic optimistic-update path made linear: a lazily rebuilt id index in `ThreadListModel` and `MainWindow::batchModelWrites()` refreshing the action labels once per loop. A write now reads "applying…" until the worker has run it, then "done". Hand-tested on a 10158-message archive |
-| 212 | A rule edit reaches only new mail; applying it to the backlog is a hand-typed `notmuch tag` | workflow | M | open, designed: `specs/2026-10-31-rule-apply-and-archive-design.md` Part A. Apply saves, counts what would change, confirms with the count (a new documented exception to the no-confirmation rule), writes through `applyTags` for exact undo |
-| 213 | A rule removing `inbox` is skipped whole by the hook, so promo mail arrives untagged | defect | S-M | open, designed: same spec, Part B. Optional per-rule `allow_archive`, both readers, no version bump; `unread` stays refused; the dialog warns about rules the hook will skip |
+| 212 | A rule edit reaches only new mail; applying it to the backlog is a hand-typed `notmuch tag` | workflow | M | **done** 2026-10-31, unreleased. The rules dialog's Apply to existing mail saves, counts, confirms with the count (the second documented exception to the no-confirmation rule) and writes through `NotmuchWorker::applyRule`, one tag at a time over ids resolved once, with one undo macro built from the worker's answer. Refused during a sync. Section in the closed file |
+| 213 | A rule removing `inbox` is skipped whole by the hook, so promo mail arrives untagged | defect | S-M | **done** 2026-10-31, unreleased. Optional per-rule `allow_archive` in both readers, no version bump; the hook lets an opted-in rule remove `inbox`, never `unread`; the dialog names every rule the hook will skip. Section in the closed file |
+| 214 | Undoing a tag change while another action is still landing can give the undo's messages to that action | defect | S? | open, 2026-10-31, found by review during 212; pre-existing. An undo's write is not armed, so its confirmation is credited to whatever command is waiting. A correlation token on `TagChange` is the robust fix |
| 73 | This backlog is past four thousand lines | maintenance | S | **done** 2026-08-13; 5056 lines to 578, closed sections moved to `2026-08-03-post-0.1.0-usability-closed.md` |
| 74 | "Searching..." keeps claiming a query is running while rows are already arriving | feedback | XS | **done** 2026-08-15, unreleased. The status-bar half only: the bar now counts threads per batch. The cold-cache delay itself was measured in 2026-08-11 and is not fixable here |
| 75 | The tagging rules window forgets its size and its column widths | persistence | S | **done** 2026-08-13, shipped in 0.17.0. The window-kind question is left open, see the closed-items file |
@@ -1701,35 +1702,31 @@ server-normalised source must refuse rather than divide a file it does not
recognise. See the spec's Out of scope for the full list of what the split has
to divide.
-## 212. A rule edit reaches only new mail
-
-**Observed.** From the user, 2026-10-31: after adding an address to the promo
-rule, "I have to manually go and apply the tags, because filters run on new
-mail only."
-
-**Cause.** Not a defect. The `post-new` hook scopes every rule to `tag:new`,
-and backfill was deliberately deferred by the tagging-rules spec until the
-confirmation question was settled.
-
-**Approach.** See `specs/2026-10-31-rule-apply-and-archive-design.md`, Part A.
-
-**Constraints.** Revises the no-confirmation rule in `CLAUDE.md` with a second
-exception, by property: a write scoped to the whole mailbox confirms with the
-count. Undo still applies.
-
-## 213. A rule removing `inbox` is skipped whole by the hook
-
-**Observed.** Found while designing 212. Every sync logs
-`rule 'promo' would remove inbox; skipped`, so new promotional mail is never
-tagged `promo` and stays in the inbox. This is how the 10k messages of item
-211 accumulated.
-
-**Cause.** Verified in `assets/hooks/post-new`: `PROTECTED_REMOVALS` is
-`{unread, inbox}` and a rule naming either is `continue`d past entirely, not
-applied without the removal. The rules dialog says nothing about it.
-
-**Approach.** See the same spec, Part B.
-
-**Constraints.** A rule-format change: both readers, both suites, and the hand
-round trip under "Changing the rule format". The hook runs every ten minutes
-on real mail.
+## 214. An undo's write is not armed, so its confirmation is credited to whatever command is waiting
+
+**Observed.** Not a user symptom yet: found by review while building item 212,
+and pre-existing. The 212 backfill hit the same mechanism from the other side
+(a user gesture during a slow backfill let the user's command take the
+backfill's ids, so Ctrl+Z on Archive re-inboxed thousands), which is why it was
+redesigned to arm nothing.
+
+**Cause.** Verified in `src/mainwindow.h`: `MessageTagCommand::undo()` and
+`ThreadTagCommand::undo()` call `sendMessageTagChange()` /
+`sendThreadTagChange()` WITHOUT `awaitTagConfirmation()`, while `redo()` arms.
+`MainWindow::onTagsApplied()` credits every confirmation to the head of
+`m_awaitingTagConfirmation`. So if a user gesture's command is still waiting
+when an undo's confirmation arrives, that command takes the undo's ids, and its
+own later undo acts on messages it never moved. That is item 176's data-safety
+property failing by ordering rather than by scope.
+
+**Approach.** Unsized, probably S. The robust fix is a correlation token on
+`TagChange`, set by the sender, echoed by the worker in `tagsApplied`, and used
+by `onTagsApplied()` to find the command it belongs to, so the queue's order
+stops mattering. Arming the undo's write as well would close this case and
+leave the queue's FIFO assumption in place for the next one.
+
+**Constraints.** Item 176's rule: an undo covers what the write changed, never
+what it asked for. A test needs a gesture's command waiting while an undo's
+confirmation arrives, with the two touching DIFFERENT messages, or the wrong
+credit answers identically. `a30b4c2` tried crediting by matching tags and was
+reverted (`aa5fc73`); read both before choosing.