diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 84 |
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 |
