aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/plans')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md84
1 files changed, 83 insertions, 1 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 cba4e81..e82c8fc 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
@@ -78,7 +78,7 @@ taking that too literally.
| 27 | The UI cannot see a sync it did not start | feedback | S | **done** |
| 28 | Re-adding `unread` counts 2 unsynced changes, not 0 | correctness | S | **done** |
| 29 | Sync button stays enabled during a background sync | feedback | XS | **done** |
-| 30 | The blank right pane is wasted space | presentation | M | open |
+| 30 | The blank right pane is wasted space | presentation | M | **done** |
| 31 | The quit prompt has no highlighted default button | discoverability | XS | **done** |
| 32 | Esc does not blank the right pane | workflow | XS | **done** |
| 33 | Status bar messages never expire | feedback | S | **done** |
@@ -1712,6 +1712,88 @@ pane. The **helper counts are the largest piece**: three `notmuch count` calls
crossing to the worker, plus a refresh policy, since a count goes stale the
moment a tag is edited.
+### Outcome (done 2026-08-07)
+
+Built as specified, and confirmed against the running application in both
+themes. Decisions taken while building, and three defects worth recording.
+
+**The counts refresh when the pane is about to show**, chosen by the user over
+refreshing on the tag-list triggers or only after a sync. `showPlaceholderPane()`
+is the single route to a blank pane, so the numbers are fetched exactly when
+they are about to be read and never in the background. A generation counter
+discards a superseded reply, and `onCountsReady` repaints only while the
+placeholder is still displayed, so a late answer cannot replace an opened
+thread. Counts are of THREADS, matching what a click on the line produces.
+
+**The helper lines are real links**, since JavaScript is off in this profile and
+a count cannot be clickable any other way. They carry a `qtmaildir-query:` URL
+caught in `acceptNavigationRequest`, and **the handler is gated on the
+placeholder actually being displayed**. A message body is attacker-controlled
+HTML and can carry the same URL; without the gate a link in a stranger's mail
+could drive the thread list. The consequence would be mild (a query runs,
+nothing mutates or is sent) but it is a boundary worth keeping shut.
+`showThread`, `clear` and `showError` all close the gate, and a test asserts it.
+
+**Sizes are clamped, not fixed and not fluid**, per the user's "a mix of both".
+The pane is a splitter panel whose width runs from a couple of hundred pixels to
+most of a screen. Measured: the wordmark renders 26px in a 300px pane and 57.6px
+in a 900px one, with `bodyScrollW == clientW` at every width tested.
+
+#### Three defects, all invisible
+
+1. **Every CSS percentage was invalid, and the pane still looked plausible.**
+ The stylesheet was built with `QString::arg` and `%%` for each percentage,
+ but **`arg()` does not collapse `%%` into `%`**: the document reached the
+ browser carrying `50%%`, and every declaration containing one was dropped.
+ That silently disabled the grid mask, the glow and both radial gradients.
+ The pane rendered, and the flat result read as "close but not like the
+ mockup" rather than as a fault. Fixed by substituting **named tokens**
+ (`@ACCENT@`, `@GRID@`) with `replace()`, which cannot collide with a percent
+ sign. `placeholderStyleHasNoUnsubstitutedTokens` pins it.
+
+2. **A geometry probe confirmed the layout while that bug was live.** It
+ measured `.title`, `.content` and `.icon-tile`, none of which carry a
+ percentage, so it reported everything correct. This is the failure mode
+ `CLAUDE.md` already warns about, in a new costume: the probe found what it
+ looked for and was trusted to report what it never checked. **A probe over a
+ stylesheet must assert the properties that the suspected fault would break**,
+ not the ones that happen to be convenient to measure.
+
+3. **The font test passed against a broken build.** Pointing one `@font-face`
+ at a nonexistent resource survived it: the other face alone satisfied both
+ the `data:font/woff2` check and the document-size check. Rewritten to require
+ both faces with a payload each, and verified by mutation.
+
+#### The mockup's light values do not survive a real pane
+
+Only the dark set ported cleanly. Rendered side by side, three light values
+failed, all of them contrast rather than hue, because the mockup is a full-bleed
+1920x1080 render and this is a pane against white:
+
+- The grid at `#d9dfe8` on white is roughly a 2% luminance step and vanished
+ outright, where `#182840` on `#060b10` reads clearly at the same opacity.
+- The glow **subtracts** light on a light background instead of adding it, so
+ 14% washed most of the pane purple.
+- The tile at `#f0f3f7` inside a `#d9dfe8` border did not separate from the
+ background, leaving the icon floating.
+
+`glowAlpha` and `gridOpacity` are therefore per-set rather than shared, and
+`tileBorder` is its own colour rather than reusing `grid`. Landed at
+`#b9c4d4` @ 45% for the grid, 6% for the glow, `#c7d0dd` for the tile border.
+The dark set is unchanged.
+
+**The mask and the glow are sized relative to the pane**, the one deliberate
+departure from the mockup's numbers. Its `circle` (farthest-corner) mask
+completes its fade inside a 1920x1080 frame; the same ratio in a ~990x650 pane
+puts the fade past the corners, so the grid ran uniform to the edges.
+`closest-side` pins it to the nearer edge, and the glow is `min(95%, 900px)`
+rather than a flat 900px that was taller than a short pane.
+
+**`resources.qrc` is now compiled into every test binary.** Library code reads
+`:/fonts/` and a qrc inside the static library registers from a global
+initialiser the linker drops, so without this a test would exercise only the
+missing-resource fallback and pass against a broken build.
+
## 31. The quit prompt has no highlighted default button
**Observed (user, 2026-08-04):** "quit popup has no Predefined answer (there's