diff options
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 43 |
1 files changed, 43 insertions, 0 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 85e6ce8..f10a301 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 @@ -95,6 +95,7 @@ taking that too literally. | 45 | Two Sync buttons, and only one of them works properly | correctness | S | **done** | | 46 | `uiStateSurvivesARestart` fails under the offscreen platform | testing | XS | **done** | | 47 | The query bar looks unfinished, and cannot be cleared by mouse | presentation | XS | **done** | +| 48 | Removing a tag suggests every tag, not the thread's own | workflow | XS | open | Sizes are rough: XS under an hour, S a sitting, M a session. @@ -2361,6 +2362,48 @@ user as acceptable; suppressible if it becomes annoying in daily use. **Verification:** by hand. The tests do not click the ✕, which is a mouse path. The user confirmed the icon renders correctly, is themed, and clears the field. +## 48. Removing a tag suggests every tag, not the thread's own + +**Observed (user, 2026-08-06):** "when removing a tag from a thread using the +input box, I get suggested all tags, not only those relevant to the message +being edited." + +**Cause (verified in code):** both fields share one completer setup. +`TagDialog`'s constructor loops over `{ m_addEdit, m_removeEdit }` and builds +`new QCompleter(knownTags, edit)` for each (`src/tagdialog.cpp:163-164`), and +`knownTags` is every tag in the database. That is right for Add, where the point +is to reach any tag and even create one, and wrong for Remove, where the only +tags that can be removed are the ones the selected threads already carry. + +**The data is already in the dialog.** The constructor takes `currentTags`, a +`QHash<QString, int>` of tag to how many selected threads carry it +(`src/tagdialog.h:66-67`), and uses it at `:212` to render the existing-tag +display. It is simply never given to the remove field's completer, so this needs +no new plumbing and no worker query. + +**Approach.** Build the two completers from different vocabularies rather than +in one loop: `knownTags` for Add, `currentTags.keys()` for Remove. + +**Constraints.** + +- **Keep the setWidget/prefix machinery exactly as it is.** Both fields hold a + comma-separated list, and `QLineEdit::setCompleter` is the documented trap + this dialog already works around, hit twice in this codebase. Only the + candidate list changes; the wiring does not. +- **Completion stays a suggestion, not a whitelist.** The dialog's own comment + records that a tag absent from the list is exactly what it exists to create. + For Remove that matters less, but typing a tag not in the list must still be + possible rather than blocked, so nothing may start validating input against + the candidates. +- On a multi-thread selection `currentTags` is the union across the selection, + with counts. That is the right set to offer, since removing a tag two of three + threads carry is meaningful. Do not filter to tags every thread has. + +**Verification:** a test can construct the dialog with a known `currentTags` and +assert the remove field's completer offers only those. The keys must be typed, +not `setText()`, since `setText` does not drive a completer at all, which +`CLAUDE.md` records. + ## Deferred, unsized, or split out Items noted while triaging but not part of the original list. Same numbering |
