# Quality gates — TUI visual mode Gates for the library paint-select visual mode (architecture/visual-mode.md). Automatic tests live in `cbd-tui/src/app/bindings.rs` (table) and `cbd-tui/src/app/mod.rs` (dispatch/paint). LLM gates are read-and-reason checks. ## Automatic tests - **T1 `spectrum_moved_off_v_to_f`** (bindings) — `lookup(Global-ish, f)` → `ToggleSpectrum` in both foci; `v`/`V` no longer resolve to `ToggleSpectrum`. - **T2 `v_and_V_enter_visual_in_library_only`** (bindings) — `v` (NONE) and `V` (SHIFT, and SHIFT-normalized) → `LibraryVisualMode` when the library is focused; both → `None` when the queue is focused. - **T3 `chords_are_unique_within_scope`** (existing) still passes with the new bindings (no duplicate `(scope, code)`). - **T4 `visual_enter_toggles_current_mark`** (dispatch) — from a clean library, `LibraryVisualMode` marks exactly the selected (queueable) row and sets visual active. - **T5 `visual_move_paints_swept_range`** (dispatch) — `LibraryVisualMode` then N× `LibraryNext` marks the starting row plus each row moved onto (N+1 marked); a `LibraryLast`/jump marks the whole span to the end. - **T6 `visual_back_sweep_unpaints`** (dispatch) — after painting down, a `LibraryPrev` toggles the re-entered row off (marks shrink by one). - **T7 `visual_exit_keeps_marks`** (dispatch) — a second `LibraryVisualMode` (and separately `Esc`/`ClearSearch`) deactivates visual mode while the marked set is unchanged. - **T8 `visual_non_move_action_exits_then_runs`** (dispatch) — with visual active, an action like `LibraryQueueAppend` deactivates visual and still performs (marks consumed as usual). - **T9 `visual_exits_on_node_or_focus_change`** (dispatch) — `LibraryDive`, `LibraryAscend`, and `CycleFocus` deactivate visual mode. - **T10 `paint_respects_is_queable`** (dispatch or library) — sweeping over a non-queueable row leaves it unmarked (same gate as `s`). - **T11 `esc_in_visual_only_exits_visual`** (dispatch) — with a `/` filter active *and* visual active, `ClearSearch` (`Esc`) exits visual without clearing the filter; with visual inactive it clears the filter as before. ## LLM quality gates (read-and-reason) - **G1 — no new state leaks.** Visual mode is one `bool` on `Library`; no wire type, proto, or server call is added. Movement, marks, and `select` are reused, not duplicated. - **G2 — `select` stays pure.** Painting is never done inside `Library::select`, so filter re-selection and `update_selection` never toggle marks; painting only happens on explicit movement dispatch while visual is active. - **G3 — dispatch routing is exhaustive and safe.** Every `Action` either participates in visual mode (the six movements + `LibraryVisualMode` + `ClearSearch`) or deactivates it before running; no action can leave visual mode active across a node/focus change or a mark-consuming op. - **G4 — bindings stay the single source of truth.** The moved spectrum key and the new `v`/`V` come only from `BINDINGS`; help text and key labels derive from it (no hard-coded key strings in the help modal). - **G5 — filter/view correctness.** `paint_between` sweeps *view* indices and maps each through the active `/` filter to its real index (like `toggle_mark`), so only visible rows are painted and no real index is toggled twice per step. - **G6 — indicator + docs.** The library title shows `— VISUAL` while active, and the help modal lists `v`/`V` (visual) and the moved `f` (spectrum) with clear descriptions.