diff options
Diffstat (limited to 'docs/superpowers/plans')
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 107 |
1 files changed, 72 insertions, 35 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 4a68f0b..e55bad4 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 @@ -155,8 +155,8 @@ taking that too literally. | 86 | A right-click search can replace or narrow, but never exclude | workflow | S | **done** 2026-08-14, unreleased; see `specs/2026-08-14-exclude-from-search-design.md`. Follows 85. The `extend` bool became a `SearchMode` enum across four signatures | | 89 | A sync moves the list under the user's hands, and the auto-sync skips rather than retries | workflow | XS | **done** 2026-08-15, unreleased. The timer half only: a skipped auto-sync re-arms instead of giving up. The list-churn half is **dropped**, not built: the user resolved it as a mental-model question, an Unread view is SUPPOSED to be volatile | | 90 | A saved-query button clears the account selection | workflow | S | **folded into 93** 2026-08-15. Not fixed in place: the button that misbehaves stops being a saved query at all. See `specs/2026-08-15-builtin-filters-design.md` | -| 91 | Double-clicking a thread could open it in its own window | workflow | ? | open, unspecified; the user marked it "(?) UX not sure" | -| 92 | Nothing distinguishes a tag written by a rule from one the user applied | information | ? | open, unspecified; the user asked it as a question, and the answer decides whether it is a display item or a format change across two repos | +| 91 | Double-clicking a thread should open it on its own | workflow | S | open, specified 2026-08-15. NOT a second window: a drill-down to that one thread, the same result an `id:` query gives. One decision left, how the user gets back | +| 92 | Nothing distinguishes a tag written by a rule from one the user applied | information | M | open, specified 2026-08-15. The user wants per-MESSAGE provenance, which nothing records: a two-repo format change, blank on all existing mail. Put the cheaper "which rule would tag this?" to the user first | | 93 | The query buttons are whatever the user pinned, not a designed set of filters | workflow | M | **done** 2026-08-15, unreleased; see `specs/2026-08-15-builtin-filters-design.md`. Absorbs item 90. Four built-in filters composing with the account dropdown; the user's own queries unpinned, never deleted | | 95 | A query in the overflow menu cannot be run | defect | XS | **done** 2026-08-15, unreleased. Pre-existing and not caused by 93: the entry's action owned a submenu, and Qt emits no `triggered` for those, so the connection had never fired. Surfaced because 93 moved every query into the menu | | 94 | `pinned` has nothing left to decide once the buttons are built-in | maintenance | S | open; **blocked on 93**, and deliberately not part of it. A user-visible removal: the row becomes built-ins only and every saved query lives in the menu | @@ -493,49 +493,86 @@ bump either way: an ignored optional field is not a breaking change. **Size: S.** Removing a field, two UI affordances and their tests. -## 91. Double-clicking a thread could open it in its own window +## 91. Double-clicking a thread should open it on its own **Observed (user, notes):** "double clicking a message/thread should open it in its own view (?) UX not sure." -**Unspecified, and the user says so in the note itself.** Recorded so it is not -lost, not planned. What would have to be decided first: whether "its own view" -is a separate top-level window or a tab, whether it stays live as the list -refreshes under it, and what it does that the message pane does not. There is no -cause to verify because nothing is broken. - -**One constraint worth writing down now**, because it decides the size: the -message pane is a `QWebEngineView` inside `MessageView`, and a second window -means either a second web view, which spawns a Chromium render process per -window, or moving the one view between parents. `CLAUDE.md` records the -per-view process cost as the reason the pane renders a list into a single view. -A design that opens three messages in three windows is three render processes. +**Clarified by the user, 2026-08-15**, and it is NOT a second window: "I didn't +mean open in a new window, I meant that double clicking on a message/thread in +the left pane should open it by itself, same as searching by id and displaying +only that message." So this is a drill-down into the existing view, the same +result an `id:` query produces, reached with a gesture instead of by typing. + +That removes the constraint this entry was mostly made of. No second +`QWebEngineView`, no second render process, nothing reparented: the pane and +the list are the ones already on screen. Size drops from `?` to S. + +**Cause (verified in code):** nothing is wired to `doubleClicked` on +`ThreadListView`, so a double-click today is two single-clicks and selects the +row twice. The machinery a drill-down needs already exists and is exercised by +the query bar: `SearchTerm` builds the `id:` query and `runQuery()` runs it. + +**Approach.** On `doubleClicked`, run the query naming that row: `id:` for a +message row, `thread:` for a thread row, built through `SearchTerm` so the +quoting rules stay in one place. + +**Decide before building: how the user gets back.** A drill-down that cannot be +reversed is a trap, and this is the only real design question left in the item. +Three candidates, and they are not equivalent: + +- Esc. Already means "clear the pane", then "clear the selection". A third + meaning is one too many. +- A Back action, with its own binding and toolbar button. Honest, and the only + option that survives a drill-down FROM a drill-down. +- Restoring the previous query text. Cheapest, and wrong the moment the user + edits the bar while drilled in. + +**Constraint.** `runQuery()` clears the undo stack, by design, since undo +entries refer to rows that are about to be discarded. A drill-down is still a +query, so a double-click would silently discard undo history. Either accept it +and say so, or the drill-down is not a query at all but a filter over the model, +which is item 40's machinery and makes this M rather than S. ## 92. Nothing distinguishes a tag written by a rule from one the user applied **Observed (user, notes):** "should the UI allow to discriminate when a message has been tagged by a rule?" -**Asked as a question, and the answer decides the size**, which is why this is -unspecified rather than sized. The information does not exist anywhere today: a -tag written by the `post-new` hook is an ordinary notmuch tag and carries no -provenance, so the UI cannot show what nothing records. - -That makes it two very different items wearing one sentence: - -- **Display only.** If the question is "which of these tags could a rule have - written", it can be answered from `~/.config/mailrules/rules.json` without - storing anything: the rules name their tags, so a chip for a tag that some - rule writes can be drawn differently. Cheap, and honest only as "a rule writes - this tag", never as "a rule wrote THIS one". -- **Real provenance.** If the question is "was THIS message tagged by a rule", - something has to record it, and that is a format change to the shared rules - file or an extra tag per rule, applied by the hook. That is a two-repo change - under "Changing the shared rule format" in `CLAUDE.md`, with a live hook - running every ten minutes on real mail. - -**Approach.** Ask which question the user meant. Do not start on the second one -by inferring it from the first. +**Clarified by the user, 2026-08-15**, including the doubt: "I want a small +visual hint that an email has been tagged by a rule vs tagged by me, but I'm +questioning the utility of such a hint." + +That is the expensive half of the two this item used to hold. "Tagged by a rule +vs tagged by me" is per-MESSAGE provenance, and the information does not exist +anywhere today: a tag written by the `post-new` hook is an ordinary notmuch tag, +indistinguishable from one applied by hand. The UI cannot show what nothing +records, so the hint costs a format change before it costs any pixels. + +**What it would take**, and this is why the user's own doubt is the right +instinct: + +- A marker the hook writes beside every tag it applies, either an extra tag per + rule (`rule:justeat`) or a field in the shared file. Both are two-repo changes + under "Changing the shared rule format" in `CLAUDE.md`, against a hook running + every ten minutes on real mail. +- Retroactively, nothing. Every tag already on every message stays unattributed + forever, so the hint is blank on the entire existing Maildir and fills in only + as new mail arrives. A hint that is absent on most mail teaches the user to + ignore it. + +**A cheaper question that may be the real one.** If what the user actually wants +to know is "why does this message carry this tag", that is answerable with no +stored provenance at all: the rules name their tags, so the UI can say which +rule WOULD tag a given message, read from `~/.config/mailrules/rules.json` at +the moment it is asked. No format change, no hook change, nothing to backfill, +and it works on mail tagged before the feature existed. It answers "a rule +writes this tag" and never "a rule wrote THIS one", which is a weaker claim and +an honest one. + +**Approach.** Put the cheaper question to the user before building either. If +the answer is that the per-message distinction is genuinely wanted, this is an M +spanning both repos and should be specced, not slipped into a session. **Constraint.** The hook is not this repo's to weaken. If provenance is wanted, the marker has to be something the hook can write without touching `unread` or |
