Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .impeccable/critique/2026-07-28T11-22-39Z__src-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
timestamp: 2026-07-28T11-22-39Z
slug: src-ui
---
---
slug: src-ui
target: src/ui
method: dual-agent (A: critique-a-design · B: critique-b-detector)
generatedAt: 2026-07-28T13:20:00+02:00
healthScore: 33/40
ratingBand: Good — address weak dimensions
---

# Critique: RightClick UI (src/ui)

## ERRATUM (corrected 2026-07-29)
The original contrast figures in this snapshot were inaccurate. All values have been re-computed using the WCAG 2.x relative-luminance formula. Key corrections for Default (Tokyo Night) theme: muted #565f89 on canvas #1a1b26 is 2.76:1 (FAIL, needs >=4.5:1), placeholder #565f89 on input #24283b is 2.35:1 (FAIL), and border #414868 on canvas #1a1b26 is 1.91:1 (FAIL for 3:1 non-text). Contrast is NOT a pass. The health score remains 33/40 (no change) as reduced-motion was already the P0 blocker.

## Method
Dual-agent. Assessment A (design review, general-purpose) + Assessment B (detector evidence, task) ran isolated. Browser visualization N/A (Rust TUI).

## Assessment B: Detector Evidence (CLI)
- Targets: src/ui src/theme src/plugins, then full src tree.
- Exit code: 0 on both. Findings: 0. Rule breakdown: none.
- Verdict: clean. Expected for a Rust TUI — the detector targets web markup/style patterns that don't apply here. No false positives to triage.

## Design Health Score

| # | Heuristic | Score | Key Issue |
|---|-----------|-------|-----------|
| 1 | Visibility of System Status | 3 | Spinner has no reduced-motion fallback |
| 2 | Match System / Real World | 4 | Git glyphs (S/M/?/D) match git convention |
| 3 | User Control and Freedom | 3 | No undo mechanism visible in ui layer |
| 4 | Consistency and Standards | 4 | All chrome routes through same token helpers |
| 5 | Error Prevention | 3 | No validation/confirmation for destructive actions at ui layer |
| 6 | Recognition Rather Than Recall | 4 | Footer key hints, header status, self-documenting glyphs |
| 7 | Flexibility and Efficiency | 3 | Global search hint exists; palette not in ui/ |
| 8 | Aesthetic and Minimalist Design | 4 | Terse, recessed chrome, zero decorative effects |
| 9 | Help Users Recognize/Recover from Errors | 3 | Error text below field, but no recovery guidance |
| 10 | Help and Documentation | 4 | `?` help toggle + global search hints discoverable |
| **Total** | | **33/40** | **Good — weak dimensions: 1, 3, 5, 7, 9 (all 3)** |

## Anti-Patterns / AI Slop Verdict
Pass. No tells. Terminal-native discipline throughout: every color routes through `style_for_ui_element` / `style_for_token` / `style_for_git_status`; Unicode box-drawing borders; full-width character handling; saturating arithmetic. An expert would not suspect AI generation.

## Named Rules Audit (all 6)
| Rule | Status | Evidence |
|---|---|---|
| The One Console Rule | obeyed | Accent (#7aa2f7) only on header title, active tab, key hints, spinner icon, overlay title. Never competes. |
| The Never-Color-Only Rule | obeyed | Git status pairs glyph+color (gitstatus/render/lines.rs:30-76); notifications pair icon+level (notifications.rs:35-42). |
| The Chrome Recedes Rule | obeyed | StatusBar bg #16161e (darker than canvas #1a1b26); input bg #24283b (lighter). |
| The Weight-Is-Hierarchy Rule | obeyed | BOLD for emphasis (header, tabs, hints, spinner, overlay title). No size scales. |
| The Flat-By-Default Rule | obeyed | Zero shadows/glow/blur. Overlay dims via tone only. |
| The Plain-Border Rule | obeyed | Borders::ALL + single-line box-drawing throughout. No rounded/double/thick. |

## Token Discipline
- Hardcoded colors: 4 instances — defensive `unwrap_or(Color::Cyan)` fallbacks in notifications.rs:234-241 and progress.rs:63-65. All pull from `theme.colors.*` first. Not bypasses.
- Bypasses of `style_for_*`: none. Full token-system compliance.

## Cognitive Load
Low. Single pane per surface with supporting chrome. Footer shows 4-5 hints with overflow count when narrow; header tabs collapse around active tab. Clear focus: active tab underlined+bold, active item highlighted, no competing accents.

## Accessibility
- **Reduced-motion: FAIL (P0).** Spinner cycles frames unconditionally (spinner.rs:257); no preference detection in ui module. ProgressBar static (pass). Notifications static (pass).
- **Contrast: FAIL (P1).** Muted #565f89 on canvas #1a1b26 = 2.76:1 (FAIL, needs >=4.5:1 for text). Placeholder #565f89 on input #24283b = 2.35:1 (FAIL). Border #414868 on canvas #1a1b26 = 1.91:1 (FAIL for 3:1 non-text). Dracula / Nord placeholder contrast also below 4.5:1 (reviewer-cited: ~1.94:1 Dracula, ~1.96:1 Nord; requires formal verification).
- **Color-blind safety: pass.** Every semantic color paired with glyph or position. Never-Color-Only is a reference implementation here.

## Strengths
1. Complete token discipline — every color flows through the theme system; not one `Color::Rgb(...)` hardcoded outside defensive fallbacks.
2. Git status is a reference implementation of The Never-Color-Only Rule.
3. Graceful narrow-width degradation — tabs collapse around active, hints truncate with overflow count, stays operational at 40 columns.

## Priority Issues
1. **[P0] Spinner has no reduced-motion fallback** — spinner.rs:257. PRODUCT.md requires a calm/static fallback. Add `prefers_reduced_motion` detection; render static glyph when true.
2. **[P1] TextInput cursor invisible on empty field** — text_input.rs:104 renders space with cursor bg; poor-cursor-contrast terminals can't see focus. Render `█` when active+empty.
3. **[P2] Overlay.render hardcodes Theme::default()** — overlay.rs:162-164 bypasses active theme. `render_with_theme` exists (line 237) but the default `render` ignores it. Migrate callers, deprecate default.

## Minor Observations
- NotificationManager auto-expires with no pause API for users who need more time.
- ProgressBar chars (█/░) hardcoded but exposed via `with_chars()` — good for legacy-terminal fallback.
- Footer hint separator (` | `) could be a const/token for dense-layout users.

## Provocative Questions
1. Spinner has 7 style presets (dots, line, arrow, moon, clock…) — how does an operator choose? Should the style encode *what kind* of work (network vs CPU)?
2. TextInputWidget duplicates single vs multi-line rendering — candidate for delegating to ratatui's built-in TextArea?
3. Overlay keeps both `render()` and `render_with_theme()` — migration in progress, or oversight?
Loading
Loading