summaryrefslogtreecommitdiffstats
path: root/docs/superpowers
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md107
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