summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md48
1 files changed, 48 insertions, 0 deletions
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 1704a28..d5f58dd 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
@@ -5290,3 +5290,51 @@ defect when `QT_TRANSLATE_NOOP` is reverted to `QT_TR_NOOP`.
**Not done:** no language-selection UI, and no second language. `QLocale()`
reading the environment is how a Linux desktop already chooses; add a selector
when there is something to choose between.
+
+## 96. A query returning the thread already on display opens onto the placeholder
+
+**Observed (user, 2026-08-15, with two screenshots):** an `id:` query produces
+exactly one card, the status bar reports "1 thread selected (1 message)", the
+card paints as selected, and the message pane stays on the placeholder. Two
+different messages from two different providers, with and without an account
+selected.
+
+**Filed originally as the unverified half of item 66** and assumed to be the
+same empty-`MessageIdRole` failure. It is not, and that assumption is what kept
+it open: 66's fix was correct and this reproduced against it.
+
+**Cause (verified in code and by instrumented run):** `runQuery()` blanks the
+message pane but leaves `m_currentThreadId`, `m_currentMessageId` and
+`m_currentMessageThreadId` naming the thread that was showing. Both selection
+handlers compare a newly selected row against those to decide whether it is
+already displayed, so a result containing that same thread is recognised as
+"already showing" and `onThreadSelected()` is never called. An instrumented run
+printed `currentThreadId after runQuery: "0000000000000001"` against an
+identical row thread id with the pane on the placeholder.
+
+**Why an `id:` query and nothing else.** The id is copied out of the details
+dialog of the message being read, so that thread is current at the exact moment
+the query replaces the view. Any query returning a different thread hides the
+fault completely, which is why it survived from 2026-08-04 to 2026-08-15 and
+why the first version of the regression test passed against it.
+
+**Four hypotheses eliminated by measurement before the cause was found**, each
+of which looked likely from reading:
+
+- `MessageIdRole` empty on a fresh single-message row. The row carries the id.
+- Account scoping mangling the query. `path:"acct/**" and (id:...)` returns the
+ row, and the user reproduced it with no account selected.
+- `MimeParser` failing on the real file. A probe against it reported `ok true`,
+ 9614 bytes of plain text and 40701 of HTML.
+- The id needing quoting. Both real ids resolve bare and quoted, one of them
+ carrying a `=` before the `@`.
+
+**Fix.** Clear the three ids where the pane is blanked, in `runQuery()`. They
+describe what the pane is showing, so they cannot outlive it.
+
+**The regression test's first query must open the SAME thread the second one
+returns.** With two different threads it passes against the defect, which is
+how the first version of it was green. It asserts the ids are cleared, because
+that is the fix's contract, and then that the pane leaves the placeholder,
+which is what the user sees. Mutation check: reverting the fix fails it with
+"runQuery blanked the pane but still names a current thread".