Skip to content
Open
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
5 changes: 5 additions & 0 deletions docs/designs/product/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ check enforces the mechanical half. Full rationale:
| DL-232 | The Cmd/Ctrl+K command palette host anatomy is a bare fixed wrapper: a permanently-open Kobalte **Search** primitive (`open` pinned true; Control + Input + Listbox, with `Search.Portal`/`Search.Content` replaced by a plain div per Kobalte's published command-menu recipe, <https://kobalte.dev/docs/core/components/search/>, `@kobalte/core` v0.13.13) inside a hand-positioned `position:fixed` div that IS `.cx-palette`, with its OWN `.cx-palette-backdrop`, Escape/outside-click dismiss, hand-wired focus grant (`ref` + `input.focus()` on mount) and focus-restore on close, plus per-row `onMouseDown`-preventDefault so a result click never blurs the pinned-open input — NO Portal/Content, floating-ui out of the test path. Search over Combobox because Search is built for caller-managed filtering (the palette's own fuzzy match) and publishes this pinned-open/no-portal recipe verbatim, where the same shape on bare Combobox was an unsupported extrapolation. The decider: a DOM-only test path with Kobalte reserved for the Search primitive's ARIA + keyboard traversal (DL-150's a11y-hard carve-out). A Search/Combobox hosted inside a Kobalte `Dialog` (scrim/trap/restore free) was rejected for nested-primitive + Portal/z-layer reconciliation cost against the shipped `.cx-palette` CSS and the window-level `Mod+K` toggle. | Active (Matt, 2026-08-23) | [command palette §Decisions](compass-command-palette/design.md#decisions) |
| DL-233 | The palette's navigation mode ships ALL six destination kinds, including issue AND pr. The issue provider rides the tracker's assigned-issue seam (`store.assignedIssues`); the pr provider requires a NEW store-level PR accessor — `prs: Accessor<PrRow[]>` as a `createMemo` over `issues()` via the existing pure `prRows()` (`board.ts:132-134`), mapping each `{issue, pr}` row to a `Destination{kind:"pr"}` that selects the owning issue and reveals the PR pane (`store.selectIssue` + `store.setActiveRightTab("pr")`) — which Matt explicitly accepted as added palette-impl scope (the store has no PR collection today; `IssueTab`'s `"pr"` is a detail-pane tab, not a collection). The fixture already carries PR shapes (`stub-data.ts:238`), so no new offline data source is needed. | Active (Matt, 2026-08-23) | [command palette §Decisions](compass-command-palette/design.md#decisions) |
| DL-234 | Point-of-use shortcut chips ship the seam plus the view-button now-win: the `ShortcutChip` primitive + `shortcutFor(id, platform)` + the `PrimaryAction` contract note + populated `board.*` shortcut fields (chips uniformly via `shortcutFor`, no hand-authored shortcut strings), AND `aria-keyshortcuts` + `title` populated via `shortcutFor` on the LeftSidebar `.bridge-link` view buttons (`LeftSidebar.tsx:437-482`: Bridge/Backlog/Done/Settings — the surfaces that actually invoke the D6-seeded `show*` paths), plus the Bridge topbar tab (`App.tsx:68-94`) for parity. Actual `.cx-menu`/hover-tooltip chip adoption is out of scope, deferred to follow-up issue RIG-2530 (it belongs to the first surface that mounts one). Seeds `view.settings/backlog/done` registrations stay under the shared commands-as-inventory rule (DL-229, owned by RIG-2529): the palette's seeds are `scope:"global"` view commands, so the palette is correct on the shared rule. | Active (Matt, 2026-08-23) | [command palette §Decisions](compass-command-palette/design.md#decisions) |
| DL-248 | Compass adopts Linear's leader/mnemonic keyboard-chord model, focus-context-gated (Matt-ratified fork): bare-letter and `G <key>` leader chords are modifier-less and inherit the EXISTING editable-target guard (`dispatch.ts:117-122`, extended to cover `<select>`/`combobox`/`listbox`/`menu`), so focus context — not a per-route switch — is the surface-awareness mechanism (Linear/Slack/Zulip converge here); "lighter on comms" is EMERGENT (a focused composer dormant-gates bare chords), never a per-route disable flag. Composes with the three-tier resolution (DL-222) unchanged. | Active (Matt, 2026-08-23) | [leader chords §A1](compass-leader-chords/design.md#a1--the-collision-guard-is-already-built-focus-gating-via-the-editable-target-guard) |
| DL-249 | A leader sequence is authored as space-separated segments in the EXISTING `KeymapEntry.chord` string (`"G B"`), no new field — collision-free because the Space key is already normalized to the token `"Space"` (`dispatch.ts:45`), so no event-derived chord contains a space and sequence rows are inert in the `DEFAULT_KEYMAP.filter` (`dispatch.ts:112-114`); the leader-prefix set is DERIVED from the table via `leaderPrefixes`, never hard-coded; authoring rules (T1 invariant test): exactly two modifier-less segments, and a leader prefix never doubles as a complete single chord. A parallel `sequence?: string[]` field was rejected (forks every consumer for zero gain). | Active (Matt, 2026-08-23) | [leader chords §A2](compass-leader-chords/design.md#a2--sequence-authoring-space-separated-segments-in-keymapentrychord) |
| DL-250 | The leader runtime is pending-leader closure state INSIDE the one `installKeymap` keydown handler (never a second listener, honoring DL-223): guard-FIRST ordering (a modifier-less key on an editable/interactive target types, never arms — the guard moves ahead of the `matching.length===0` early return at `dispatch.ts:115`), arm on a leader-set hit (`!event.repeat`) with a `LEADER_TIMEOUT_MS` disarm timeout, completion resolves the two-segment chord through the UNCHANGED three tiers (DL-222), dead sequences fall through RE-ENTERING arming (a re-pressed leader re-arms), Escape disarms, Mod-chords disarm-and-run, the uninstaller clears the timer. A separate leader-mode dispatcher was rejected (duplicate guard + tier logic). | Active (Matt, 2026-08-23) | [leader chords §A3](compass-leader-chords/design.md#a3--the-leader-runtime-pending-state-inside-the-one-keydown-handler) |
| DL-251 | A leader sequence is NEVER written into `aria-keyshortcuts` (WAI-ARIA has no sequential-press grammar — `"G B"` reads as "G OR B"): the shipped scanners harden ASYMMETRICALLY (refining DL-234's `shortcutFor` contract) — `shortcutForAria` (`keymap.ts:70-76`) SKIPS sequence rows so a sequence-only command emits no attribute, while `shortcutFor` (`keymap.ts:57-63`) FORMATS them via one pure `formatChordForDisplay` (`"G then B"`) so point-of-use display (sidebar `title`, palette chip) is preserved. A dual-bound command keeps its modifier chord in both. Minting parallel replacement helpers was rejected (leaves the shipped ones emitting the bug). | Active (Matt, 2026-08-23) | [leader chords §A5](compass-leader-chords/design.md#a5--display-and-aria-keyshortcuts-for-sequences) |
| DL-252 | Wave-1 leader allocation is `G B`/`G L`/`G D`/`G S` → view.bridge/backlog/done/settings — all four commands ALREADY registered by the shipped spine (`spine.ts:79-126`) and wired (`store.ts:1973-1980`), so wave 1 adds ONLY keymap rows (no spine/store change); `view.agentWorkspace` gets no `G A` (spine registers no such command). Zero bare letters in wave 1 (the board's verbs are group-relative; Linear's a/s/p act on issue fields Compass's board doesn't yet edit). Coexists additively with all existing `Mod+*` bindings (DL-152); deprecating overlapping modifier chords is a deferred later call (record OQ5). | Active (Matt, 2026-08-23) | [leader chords §A4](compass-leader-chords/design.md#a4--bare-letter-and-sequence-allocation-wave-1) |

## Bridge spawn control

Expand Down
Loading
Loading