diff options
Diffstat (limited to 'docs/superpowers')
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 55 |
1 files changed, 53 insertions, 2 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 7fedaf3..8f19d6b 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 @@ -56,8 +56,8 @@ taking that too literally. | 15 | Attachments are parsed but unreachable from the UI | information | M | **done** | | 16 | Delete on an already-deleted thread should undelete | behavior | S | open | | 17 | No completion for tags in the query bar | workflow | M | **done** | -| 18 | No visual cue that there are unsynced edits | feedback | S | open | -| 19 | No prompt to sync on exit when edits are pending | behavior | S | open | +| 18 | No visual cue that there are unsynced edits | feedback | S | **done** | +| 19 | No prompt to sync on exit when edits are pending | behavior | S | **done** | | 20 | Thread view does not match the user's mental model | presentation | ? | open, unspecified | | 21 | Default shortcuts are not sensible enough | discoverability | S | open | | 22 | Translatability audit and i18n wiring | correctness | M | open | @@ -847,6 +847,27 @@ resets. survives. Then sync and confirm it clears. Then make the sync fail and confirm it does not. +### Outcome (done) + +Built as specced. `m_pendingEdits` counts confirmed mutations, incremented in +`onTagsApplied()` and reset only by `onSyncFinished(true, ...)`. The count is +shown as a permanent status-bar widget, hidden entirely at zero. + +**Counted where a write is confirmed, not where one is sent.** An optimistic +update the worker later rejects must not leave the indicator claiming an edit +that never landed, so the increment sits in the `tagsApplied` handler. + +That handler was a lambda; it is now a named slot, which is both better +structure and what lets a test drive it. An earlier draft tried to reach the +worker with `findChild` to emit the real signal: the worker is deliberately +parentless because it moves to its own thread, so that cannot work, and +contorting the test to reach it was the wrong instinct. What matters is the +counter's behaviour, not the signal's origin. + +**Both tests were verified by breaking the code.** Clearing the count on any +sync outcome is caught, and so is clearing it where the undo stack is cleared, +which is the naive design this item exists to avoid. + ## 19. No prompt to sync on exit when edits are pending **Observed (user, 2026-08-04):** quitting with unsynced edits is silent. The @@ -891,6 +912,36 @@ for the reason item 18 documents. each `sync_on_exit` value and confirm the behavior matches. Then quit with a deliberately broken sync command and confirm the app neither hangs nor lies. +### Outcome (done) + +Built as specced, with the user confirming the three-value key over their +original on/off idea. `closeEvent()` consults the count, and a sync started for +exit holds the window open until `finished` arrives rather than being killed +mid-run. + +**A failed exit-sync does not quit.** It restores the window, shows the log and +says what happened. Quitting there would discard the user's choice silently, +which is the exact failure the prompt exists to prevent. + +**With no sync command configured the prompt degrades** to a warning offering +Discard or Cancel, rather than offering a sync that cannot run. +`MailSync::isAvailable()` is already false in that case. + +**Testing a modal needs care, and the first attempt was wrong.** A test that +sends a close event hangs forever if an unexpected dialog opens, because the +modal spins its own event loop. The first version appeared to pass in 19 +seconds; it had actually opened a real dialog on the user's screen, and the +user dismissed it. `CloseProbe` now polls for `activeModalWidget()`, closes it, +and records that one appeared, turning "a dialog opened" into an assertion +instead of a hang or a prompt for whoever is watching. + +**One mutation test was a dud and is worth recording.** Removing the `Never` +guard from `closeEvent` did NOT make the test fail, because the branches below +match only `Ask` and `Always`, so `Never` fell through to closing anyway. The +guard is redundant belt-and-braces rather than load-bearing. Confirming the +probe really detects a prompt needed the config mutated to `ask` instead, which +does fail it. + ## 20. Thread view does not match the user's mental model **Observed (user, 2026-08-04), in passing while deciding item 2:** "My view for |
