返回 CodeWhale
hotbar-qa-matrix.md
根目录 / docs / evidence / hotbar-qa-matrix.md
1 # Hotbar QA Matrix
2
3 This matrix is the v0.8.66 release gate for #3401. It ties the shipped Hotbar
4 MVP to repeatable checks instead of treating isolated unit tests as sufficient
5 coverage.
6
7 ## Support Level
8
9 | Source | Support level | Release statement |
10 | --- | --- | --- |
11 | Built-in app actions | Supported | Default slots dispatch existing app paths through `AppAction` or in-app state mutation. |
12 | Slash commands | Supported | Argument-free and optional-argument commands dispatch through `commands::execute`; required-argument commands prefill the composer. |
13 | MCP tools/resources/prompts | Deferred | Visible through the command palette/MCP manager only until argument and approval gates are wired. |
14 | Skills | Deferred | Visible through command palette and slash skill activation; direct Hotbar binding is deferred until activation receipts are wired. |
15 | Plugins | Deferred | Visible through `/plugins`; direct Hotbar binding is deferred until plugin approval gates are wired. |
16
17 ## Config States
18
19 | Scenario | Expected behavior | Evidence |
20 | --- | --- | --- |
21 | No hotbar config | Default slots resolve to the shipped eight-slot bar. | `crates/config/src/tests.rs::hotbar_defaults_when_config_is_absent` |
22 | Empty hotbar config | `hotbar = []` disables all default slots. | `crates/config/src/tests.rs::hotbar_empty_array_disables_default_slots`; `crates/tui/src/config_persistence.rs::persist_hotbar_bindings_writes_empty_array_to_disable_defaults` |
23 | Partial config | Missing slots render empty without filling from defaults. | `crates/tui/src/tui/sidebar.rs::hotbar_panel_slots_handle_empty_partial_and_unknown_config` |
24 | Unknown actions | Unknown configured actions stay visible as unknown instead of being dropped silently. | `crates/config/src/tests.rs::hotbar_validation_warns_without_dropping_unknown_actions`; `crates/tui/src/tui/sidebar.rs::hotbar_panel_slots_handle_empty_partial_and_unknown_config` |
25 | Custom labels | Configured labels render and persist with bindings. | `crates/tui/src/tui/hotbar/actions.rs::recommended_hotbar_bindings_serialize_action_ids_and_labels`; `crates/tui/src/tui/ui/tests.rs::hotbar_setup_save_persists_bindings_to_config_path` |
26 | Workspace overlay | Project config does not replace user-owned Hotbar bindings. | `crates/config/src/tests.rs::project_merge_does_not_replace_user_hotbar_bindings` |
27 | Legacy/user config path | Fresh setup writes the primary config path; existing comments survive replacement. | `crates/tui/src/config_persistence.rs::persist_hotbar_bindings_writes_primary_config_path_for_fresh_installs`; `crates/tui/src/config_persistence.rs::persist_hotbar_bindings_preserves_comments_and_replaces_existing_tables` |
28 | Failed persistence | Live config and config file remain unchanged and an error is surfaced. | `crates/tui/src/tui/ui/tests.rs::hotbar_setup_save_error_leaves_live_config_and_file_unchanged` |
29
30 ## UI States
31
32 | Scenario | Expected behavior | Evidence |
33 | --- | --- | --- |
34 | Normal TUI/composer | `Alt-1` through `Alt-8` dispatch configured slots; bare digits remain text input. | `crates/tui/src/tui/ui/tests.rs::hotbar_alt_digit_fires_from_composer_and_sidebar_states`; `crates/tui/src/tui/ui/tests.rs::hotbar_bare_digit_inserts_text_even_when_composer_empty` |
35 | Hidden/sidebar focus states | Hotbar dispatch is still available from hidden, auto, pinned, and focused sidebar states. | `crates/tui/src/tui/ui/tests.rs::hotbar_alt_digit_fires_from_composer_and_sidebar_states` |
36 | Narrow sidebar | Hotbar panel keeps fixed two-row layout and bounded hover/status text. | `crates/tui/src/tui/sidebar.rs::hotbar_panel_lines_keep_two_fixed_rows_and_hover_status`; `docs/evidence/terminal-visual-regression-matrix.md` |
37 | Modal/overlay open | Modal, approval, picker, decision-card, and onboarding states block Hotbar numeric ownership. | `crates/tui/src/tui/ui/tests.rs::hotbar_digits_are_blocked_while_modal_or_onboarding_is_active`; `crates/tui/src/tui/ui/tests.rs::hotbar_alt_digit_is_blocked_while_inline_selectors_are_open`; `crates/tui/src/tui/ui/tests.rs::hotbar_alt_digit_is_blocked_while_decision_card_is_active` |
38 | Setup wizard open/save | Setup lists supported source categories, updates draft bindings, saves, and persists. | `crates/tui/src/tui/hotbar/setup.rs::wizard_sources_follow_registered_action_categories`; `crates/tui/src/tui/hotbar/setup.rs::wizard_save_emits_bindings_but_escape_only_closes`; `crates/tui/src/tui/ui/tests.rs::hotbar_setup_save_persists_bindings_to_config_path` |
39 | Restart/re-dispatch | Persisted bindings parse back into config and resolve through the same dispatch path. | `crates/config/src/tests.rs::hotbar_tables_parse_and_round_trip`; `crates/tui/src/tui/ui/tests.rs::hotbar_dispatches_bound_slot_and_ignores_empty_slot` |
40
41 ## Dispatch Outcomes
42
43 | Outcome | Expected behavior | Evidence |
44 | --- | --- | --- |
45 | Handled in-app | Local UI/state actions mutate app state and mark redraw when needed. | `crates/tui/src/tui/hotbar/actions.rs::sidebar_toggle_reports_visibility_and_dispatches`; `crates/tui/src/tui/hotbar/actions.rs::trust_toggle_reports_trust_state_and_dispatches` |
46 | `AppAction` return | Actions that must be handled by the event loop return the existing `AppAction`. | `crates/tui/src/tui/hotbar/actions.rs::compact_action_emits_existing_app_action`; `crates/tui/src/tui/ui/tests.rs::hotbar_dispatches_bound_slot_and_ignores_empty_slot` |
47 | Composer prefill | Required-argument slash commands prefill the composer instead of firing empty args. | `crates/tui/src/tui/hotbar/actions.rs::slash_hotbar_action_prefills_required_argument_command` |
48 | Disabled reason | Disabled actions are excluded from recommendations and report a reason if manually bound. | `crates/tui/src/tui/hotbar/actions.rs::hotbar_recommendations_exclude_disabled_actions`; `crates/tui/src/tui/ui/tests.rs::hotbar_bound_disabled_action_reports_reason_without_dispatching` |
49 | Unknown action | Unknown configured action is visible and does not dispatch. | `crates/tui/src/tui/sidebar.rs::hotbar_panel_slots_handle_empty_partial_and_unknown_config`; `crates/tui/src/tui/ui.rs::dispatch_hotbar_slot` |
50 | Approval-gated/deferred source | Source is explicitly deferred and must not register bindable actions before gates exist. | `crates/tui/src/tui/hotbar/actions.rs::source_descriptors_cover_dispatch_boundaries`; `crates/tui/src/tui/hotbar/actions.rs::deferred_sources_cannot_register_dispatchable_actions` |
51
52 ## Terminal chord evidence for v0.9.2 (#3758)
53
54 Codewhale receives terminal key events; it cannot force a terminal to forward the
55 macOS Option key as Meta. The source-level contract below is release-gated on
56 every platform. Terminal/device observations stay separate so an unrun terminal
57 is never presented as green.
58
59 ### Automated event matrix
60
61 | Input/state | Required result | Regression evidence |
62 | --- | --- | --- |
63 | `Alt-1` through `Alt-8` | Dispatch the corresponding slot | `hotbar_alt_digit_fires_from_composer_and_sidebar_states` |
64 | Bare `1` through `8` | Insert/retain ordinary composer input | `hotbar_bare_digit_inserts_text_even_when_composer_empty` |
65 | `Ctrl-number`, `Super/Cmd-number`, `Alt-0`, `Alt-9`, and F-keys | Never dispatch a Hotbar slot; `F1` remains help | `hotbar_slot_from_key_accepts_only_alt_one_through_eight` and global keybinding tests |
66 | AltGr-style `Ctrl+Alt+number` | Never dispatch, preserving non-US input ownership | `hotbar_slot_from_key_accepts_only_alt_one_through_eight` |
67 | Modal, onboarding, slash/history selector, approval, picker, or decision card | Owning surface blocks Hotbar dispatch | `hotbar_digits_are_blocked_while_modal_or_onboarding_is_active`, `hotbar_alt_digit_is_blocked_while_inline_selectors_are_open`, `hotbar_alt_digit_is_blocked_while_decision_card_is_active` |
68 | Default-hidden/disabled Hotbar | No visible accelerator surface and no slot dispatch | config/sidebar hidden-state tests listed above |
69
70 ### Manual terminal matrix
71
72 Record the exact app/version and the terminal key setting when a device pass is
73 run. A blank or `UNRUN` row is not release evidence.
74
75 | OS | Terminal | Meta/Option setting | Alt/Option-1..8 | Bare/Cmd/F1 | Modal/default-hidden | Notes |
76 | --- | --- | --- | --- | --- | --- | --- |
77 | macOS | Terminal.app | UNRUN | UNRUN | UNRUN | UNRUN | Some Option settings emit characters rather than Meta. |
78 | macOS | iTerm2 | UNRUN | UNRUN | UNRUN | UNRUN | Record the Left/Right Option key mapping. |
79 | macOS | Ghostty | UNRUN | UNRUN | UNRUN | UNRUN | Record `macos-option-as-alt` or equivalent. |
80 | macOS | Kitty | UNRUN | UNRUN | UNRUN | UNRUN | Record any `macos_option_as_alt` setting. |
81 | Linux | terminal + layout | UNRUN | UNRUN | UNRUN | UNRUN | Include an AltGr/non-US layout pass. |
82 | Windows | Windows Terminal | UNRUN | UNRUN | UNRUN | UNRUN | Include the host shell and keyboard layout. |
83
84 A terminal-specific caveat belongs in `docs/KEYBINDINGS.md` and `/hotbar help`
85 only after it is reproduced. The product must not advertise Cmd-number or
86 function-key aliases merely because a terminal can remap them.
87
88 ## Release Smoke Checklist
89
90 Run before claiming Hotbar MVP readiness:
91
92 1. `cargo test -p codewhale-config hotbar -- --nocapture`
93 2. `cargo test -p codewhale-tui --bin codewhale-tui --locked hotbar::actions -- --nocapture`
94 3. `cargo test -p codewhale-tui --bin codewhale-tui --locked hotbar_setup -- --nocapture`
95 4. `cargo test -p codewhale-tui --bin codewhale-tui --locked hotbar_panel -- --nocapture`
96 5. `cargo test -p codewhale-tui --bin codewhale-tui --locked hotbar_alt_digit -- --nocapture`
97 6. `cargo test -p codewhale-tui --bin codewhale-tui --locked hotbar_dispatch -- --nocapture`
98
99 Manual pass, if a release candidate binary is available:
100
101 1. Start with no `[hotbar]` config and verify the default eight slots render in
102 the sidebar with visible `Alt1` through `Alt8` accelerator labels.
103 2. Open `/hotbar`, bind a slash command, save, restart, and verify the binding
104 persists.
105 3. Press `Alt-1` through `Alt-8` from composer/sidebar states and verify only
106 `Alt` chords dispatch.
107 4. Open command palette, slash menu, setup wizard, decision card, and an
108 approval modal; verify Hotbar digits are blocked while those surfaces own
109 input.
110 5. Confirm MCP, skill, and plugin entries remain discoverable through their
111 existing command-palette or slash-command paths and are not offered as direct
112 Hotbar bindable actions.
113
113 lines MARKDOWN