You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
9.1 KiB
92 lines
9.1 KiB
# Audit: command
|
|
audit-version: 1
|
|
audited-at: 2026-06-26
|
|
scope: (SCOPE-DRIFT → SYS-1)
|
|
method: adversarially-verified workflow (analyze → refute); HIGH/CRITICAL personally re-verified against cited code by the lead.
|
|
provider: src/uix/soma/components/command/command-provider.svelte.ts
|
|
|
|
## Summary
|
|
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 5.
|
|
systemic hits: SYS-1 (scope-drift); SYS-3 (jsdom-only, keyboard untested).
|
|
|
|
## Findings
|
|
### MEDIUM: SYS-1 scope-drift — command-001 <!-- id: command-001 -->
|
|
- dimension: E-bis
|
|
- rule: SYS-1 scope-drift
|
|
- location: src/uix/morfo/components/command.ts:7
|
|
- evidence: scope: ['soma', 'sema'], — but eidos/components/command/ directory exists with CSS and components. Morfo declares scope omitting 'eidos'
|
|
- impact: Component has eidos visuals and recipes but scope doesn't declare it; scope drift breaks the four-layer contract and may cause issues with validation or tooling that expect declared scopes
|
|
- proposed-fix: Add 'eidos' to the scope array: scope: ['soma', 'sema', 'eidos']
|
|
- verify: [downgraded] morfo line 7 reads `scope: ['soma', 'sema'],` and an eidos/components/command/ dir with CSS exists. But this is NOT command-specific drift: I counted 63 stateful morfos (combobox, calendar, date-picker, color-picker, dialog, select, popover, listbox, etc.) that ALL omit 'eidos' from scope while shipping an eidos recipe dir. The `scope` field semantics in src/uix/morfo/types.ts:770-839 govern SEMA/event coherence ('If a morfo declares events[] AND scope:['sema']...'), not eidos-recipe presence — the visual layer is not gated by the scope array. No contract test asserts scope must include 'eidos' when CSS exists. Treating this as a HIGH per-component contract violation contradicts the framework's own baseline (63/64 components do it). At most a systemic LOW doc/convention observation; the stated HIGH severity and 'breaks the four-layer contract' impact are not supportable.
|
|
- fix-status: open
|
|
|
|
### LOW: Magic literal — em font sizes — command-003 <!-- id: command-003 -->
|
|
- dimension: E-bis
|
|
- rule: Magic literal — em font sizes
|
|
- location: src/uix/eidos/components/command/command.css:260-261,272
|
|
- evidence: inline-size: 1.125em (line 260-261) and font-size: 0.875em (line 272) are bare em values without canonical token references
|
|
- impact: Icon and shortcut sizing use hard-coded em multipliers instead of --icon-size-* or --font-size-* tokens; inconsistent with theming system
|
|
- proposed-fix: Replace 1.125em with a canonical icon size scale reference (e.g., --icon-size-md or create --command-item-icon-size). Replace 0.875em with a font-size scale reference or scale modifier
|
|
- verify: [downgraded] Confirmed the literals: command.css:260-261 `inline-size: 1.125em; block-size: 1.125em;` (icon box) and 272 `font-size: 0.875em;` (shortcut). However em-based slot sizing is an established, idiomatic codebase pattern — grep across eidos shows field-control-trigger.css:30/45 `1.75em`/`1em`, menu-dial.css:281-282 `1em`, password-field.css:293/297-298 `1em`, table.css:339-340 `1em`, fab.css:103 `1em`. The `em` unit deliberately scales with the local `--_command-item-font-size` cascade (which IS token-driven), so these are RELATIVE sizing, not fixed px/rem drift the E-bis rule targets. At most a LOW consistency nit; MEDIUM overstates it given the framework-wide convention.
|
|
- fix-status: open
|
|
|
|
### LOW: Magic literal — pixel heights — command-004 <!-- id: command-004 -->
|
|
- dimension: E-bis
|
|
- rule: Magic literal — pixel heights
|
|
- location: src/uix/eidos/components/command/command.css:153,219,296
|
|
- evidence: block-size: 2px (loading bar), gap: 1px (group items), block-size: 1px (separator) — bare pixel literals
|
|
- impact: Three structural heights use magic pixels instead of token references; brittle to design changes
|
|
- proposed-fix: Create or reference --border-width for 1px lines (already canonical for most components). For 2px loading bar, create --command-loading-height or use a custom CSS variable scoped to command
|
|
- verify: [downgraded] Confirmed: command.css:153 `block-size: 2px;` (loading bar), 219 `gap: 1px;` (group items), 296 `block-size: 1px;` (separator). The 1px values are hairline-divider widths idiomatic across the codebase (separator/border lines); 2px is an off-scale loading-bar height. These are genuine bare-pixel literals but they are structural hairlines, not tokens that carry theming intent — LOW severity at most, not MEDIUM. No user-visible or behavioral impact.
|
|
- fix-status: open
|
|
|
|
### LOW: Morfo contract — archetype declaration — command-006 <!-- id: command-006 -->
|
|
- dimension: A
|
|
- rule: Morfo contract — archetype declaration
|
|
- location: src/uix/morfo/components/command.ts:98-124
|
|
- evidence: Item part declares archetype: 'item' but does not declare Icon or Shortcut as sub-parts in the morfo
|
|
- impact: Eidos defines Item.Icon and Item.Shortcut sub-parts (in eidos/components/command/index.ts) with their own data-* selectors, but they are not declared in the morfo. They are eidos-only sub-parts and properly documented in types.ts, so this is intentional (not an error)
|
|
- proposed-fix: N/A — this is a documented eidos extension pattern
|
|
- verify: [confirmed] Confirmed non-finding by the candidate's own admission. morfo declares Item (lines 97-124) with archetype 'item' and data-value/data-selected/data-disabled, but Icon/Shortcut are eidos-only sub-parts (index.ts:49-62 attaches ItemIcon/ItemShortcut; command.css:255/265 selectors documented as 'eidos-only' sub-part). This is the documented eidos-extension pattern, explicitly proposedFix 'N/A'. Correctly emitted as LOW with no action.
|
|
- fix-status: open
|
|
|
|
### LOW: Test environment — jsdom only — command-007 <!-- id: command-007 -->
|
|
- dimension: F
|
|
- rule: Test environment — jsdom only
|
|
- location: src/uix/soma/components/command/command-provider.svelte.test.ts:1
|
|
- evidence: // @vitest-environment jsdom — test suite uses jsdom, which cannot test keyboard input, focus, or DOM pointer events accurately
|
|
- impact: Keyboard navigation (ArrowDown/Up/Home/End/Enter/vim bindings) is complex behavioral code but only tested in jsdom (which doesn't fire real keyboard/mouse events). Focus logic untested.
|
|
- proposed-fix: Add a client/Playwright test suite for keyboard navigation (arrow keys, grid columns, loop wrapping, Home/End), pointer selection, and focus sync. See SYS-3 pattern.
|
|
- verify: [confirmed] Confirmed and arguably under-severed. test file line 1 `// @vitest-environment jsdom`; whole file is 122 lines with only 2 `it` blocks (line 77 filters+auto-select, line 96 navigates via provider.next/prev/selectCurrent API). No `dispatchEvent`/`KeyboardEvent`/`focus(` anywhere — the real onkeydown route in CommandInputProvider.onkeydown (lines 452-508: vim ctrl+n/p/j/k, Home/End, grid `columns`, RTL `getDirectionalKeys`) is NEVER exercised through a key event, only the underlying API methods are. This is a clean SYS-3 hit (interaction-heavy + jsdom-only + keyboard route untested). LOW is defensible but MEDIUM would be equally justified per the SYS-3 rubric.
|
|
- fix-status: open
|
|
|
|
### LOW: Viewport structure assumption — command-008 <!-- id: command-008 -->
|
|
- dimension: C
|
|
- rule: Viewport structure assumption
|
|
- location: src/uix/soma/components/command/command-provider.svelte.ts:598
|
|
- evidence: const child = el.firstElementChild as HTMLElement | null; — assumes the viewport ref's first child is the measurable element
|
|
- impact: If a consumer passes a custom child to Viewport (via the child snippet), firstElementChild may fail or measure the wrong element
|
|
- proposed-fix: Add a fallback measurement: measure the viewport itself if firstElementChild is not present, or document this as a contract requirement (viewport must wrap content in a single element)
|
|
- verify: [confirmed] Confirmed at LOW. provider line 598 `const child = el.firstElementChild as HTMLElement | null;` then observes it for resize. command-viewport.svelte renders `{@render children?.()}` with NO wrapper element, so firstElementChild measures whatever the consumer passes — fragile if the consumer renders text or multiple top-level nodes. Real robustness nit, but Viewport is `optional: true` in the morfo (line 93) and rarely used (List composes ScrollArea instead), and there is a `if (!child) return;` guard so it fails safe (no crash, just no height var). Correctly LOW; not behavioral/a11y.
|
|
- fix-status: open
|
|
|
|
## No-findings dimensions
|
|
B, D, G
|
|
|
|
## Theming facts (E-bis)
|
|
- magic z-index: none
|
|
- magic literals: command-003 (em sizes) | command-004 (px heights)
|
|
- undeclared parts: none
|
|
- roles clean: true · variants clean: true
|
|
|
|
## Tests (F)
|
|
- exists: true · env: jsdom
|
|
- covers: filter/visibility; navigation (basic); disabled items; group registration
|
|
- untested: keyboard input (Arrow/Home/End/vim); pointer events; focus state; grid columns; loop wrapping edge cases; RTL keyboard inversion; two-moments ordering
|
|
|
|
## Style observations (non-blocking)
|
|
- Command CSS is well-structured with good comments explaining concentric radius + shape-nest pattern
|
|
- Dialog integration (lines 71-99) cleanly separates panel chrome from palette chrome
|
|
- Input styling mirrors Select trigger (consistent archetype treatment)
|
|
- Item sub-parts (Icon/Shortcut) leverage inherited flex layout smartly
|