summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-15 15:44:38 +0200
committerDanilo M. <danix@danix.xyz>2026-08-15 15:44:38 +0200
commitc3dd54e390d236b7d68bae456ef39c5fa7fb49d5 (patch)
tree433c2c15a30a1cb2038f20ec78b53b83d429f0c9 /docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
parent19f0ea0000f8e61a4077d06609c5c7c329edf8bb (diff)
downloadqtmaildir-c3dd54e390d236b7d68bae456ef39c5fa7fb49d5.tar.gz
qtmaildir-c3dd54e390d236b7d68bae456ef39c5fa7fb49d5.zip
fix(ui): load a thread that was already displayed when the query ran
Running a query blanks the message pane but left m_currentThreadId, m_currentMessageId and m_currentMessageThreadId naming the thread that had been showing. Both selection handlers compare a newly selected row against those to decide whether it is already on display, so a result containing that same thread was recognised as "already showing" and onThreadSelected() was never called. The card painted as selected, the status bar reported one thread, and the pane stayed on the placeholder. This is why it looked like an `id:` query defect. The id is copied out of the details dialog of the message being read, so that thread is current at the moment the query replaces the view. Any query returning a different thread hides the fault entirely. Filed as the unverified half of item 66 and assumed to be the same empty-MessageIdRole failure. It is not: 66's fix was correct and this reproduced against it, so it is recorded as item 96. Four hypotheses were eliminated by measurement first: the row does carry the message id, the account-scoped query does return it, MimeParser parses the reported message (ok, 40701 bytes of HTML), and both real ids resolve bare and quoted. 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. Reverting the fix fails it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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".