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.
svelte-kit-vice/audit/components/float-panel.md

5.8 KiB

Audit: float-panel

audit-version: 1 audited-at: 2026-06-26 scope: ['soma', 'sema'] (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/float-panel/float-panel-provider.svelte.ts

Summary

Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 2 · LOW 0. systemic hits: SYS-1; SYS-2; SYS-3; SYS-5; SYS-6.

Findings

MEDIUM: SYS-1 — float-panel-001

  • dimension: E-bis
  • rule: SYS-1
  • location: src/uix/morfo/components/float-panel.ts:7
  • evidence: scope: ['soma', 'sema'], but eidos recipe directory exists at src/uix/eidos/components/float-panel/
  • impact: Morfo contract omits eidos in scope declaration despite full eidos implementation present; creates contract-documentation drift.
  • repro: List the morfo scope and observe eidos directory exists but not declared.
  • proposed-fix: Change morfo scope to ['soma', 'sema', 'eidos'] to match the presence of src/uix/eidos/components/float-panel/
  • verify: [confirmed] morfo line 7 literally reads scope: ['soma', 'sema'], while the eidos recipe dir exists (Glob returned src/uix/eidos/components/float-panel/ with float-panel.css, types.ts, 14 .svelte parts, recipe block at base.ts:1076). Genuine SYS-1 scope-drift: a complete eidos implementation is present but 'eidos' is omitted from the morfo scope tuple. HIGH per SYS-1 (contract/validator-catchable). Confirmed.
  • fix-status: open

MEDIUM: SYS-3 — float-panel-005

  • dimension: F
  • rule: SYS-3
  • location: src/uix/soma/components/float-panel/float-panel-provider.svelte.test.ts:1 (jsdom environment only)
  • evidence: Test file runs in jsdom (@vitest-environment jsdom); keyboard interaction tests at lines 216-247 only cover basic ArrowRight/ArrowDown moves, not Home/End/PageUp/PageDown/resize keyboard, and no client/Playwright test exists.
  • impact: Keyboard grab-mode (move + resize) has complex state transitions (kbToggleMove, kbCancelMove, kbMove with Home/End logic, and kbResize equivalents) exercised only on easy paths (arrow keys) in jsdom. Full keyboard interactivity (especially Home/End reaching bounds and PageUp/PageDown step logic) untested; resize keyboard path completely absent from test coverage.
  • repro: Run tests; no keyboard resize tests exist. grep test file for 'kbResize' (absent). Manually verify Home/End position clamping with a real browser.
  • proposed-fix: Add integration tests covering (a) keyboard move Home/End/PageUp/PageDown reaching bounds, (b) resize keyboard equivalents, (c) stage transitions cancelling grab-mode, in a client environment (Playwright or @vitest-environment happy-dom/puppeteer).
  • verify: [downgraded] The factual premise (jsdom) is WRONG, so the SYS-3 rule citation is misapplied — but a real coverage gap remains. The file is float-panel-provider.svelte.test.ts, which matches the CLIENT project glob src/**/*.svelte.{test,spec}.{js,ts} (vite.config.ts:72) and runs in headless chromium (browser:{instances:[{browser:'chromium'}]}, line 67-70) — NOT jsdom. The // @vitest-environment jsdom line at test:1 is inert for browser-mode tests; the test itself confirms (line 219-220 'this .svelte.test runs in a real browser whose width varies', line 117 reads live window.innerWidth). So it is NOT a SYS-3 jsdom-only case. The valid kernel: keyboard RESIZE (kbToggleResize/kbResize) is entirely untested (grep test for 'kbResize'/'kbToggleResize' = absent) and keyboard MOVE Home/End/PageUp/PageDown + bound-hit announce paths are untested (only ArrowRight + Shift+ArrowDown + cancel + maximized-guard exercised, lines 231-243). Real but not SYS-3; downgrade to MEDIUM coverage-gap with corrected rule (behavioral test gap, not jsdom-only).
  • fix-status: open

No-findings dimensions

A, C, G

Theming facts (E-bis)

  • magic z-index: none
  • magic literals: opacity: 1; at line 260, 265 (should map to --opacity-* token) | scale: 1; at line 344, 349 (should map to --scale-reset or similar) | line-height: 1; at line 189 (should be canonical or documented)
  • undeclared parts: data-animation-style set by eidos but not declared in morfo
  • roles clean: true · variants clean: true

Tests (F)

  • exists: true · env: jsdom
  • covers: position seeding and clamping; size min/max clamping; anchor positioning (side=bottom, align=start); dismissal via dismissWith; stage toggling and drag block while maximized; keyboard grab-mode move (basic arrows only)
  • untested: keyboard move Home/End/PageUp/PageDown; keyboard resize toggle and all keyboard resize keys; stage transitions cancelling keyboard grab-mode; pointer drag gesture lifecycle (startDrag → pointermove → endDrag); pointer resize gesture lifecycle; multi-panel stacking (bring-to-front during gestures); all dismiss causes (save, cancel, fail, dismiss-outside) semantic payloads; focus return to trigger on close; ResizeGrip focus and keyboard resize affordance

Style observations (non-blocking)

  • CSS composition is clean: drag position uses distinct translate property (not affected by state animations); scale-fade animation preset only touches scale+opacity, leaving translate free for drag.
  • Gesture sequencing is well-designed: dragging/resizing state lifted on pointerdown (before move), so shadow transitions before motion begins; live position/size applied imperatively per pointermove, committed to state on release.
  • Keyboard grab-mode architecture is clear: pre-grab snapshot enables Escape revert; axis tracking (kbAxis='x'/'y') disambiguates Home/End targets; debounced announcements prevent spam.
  • Focus management mirrors Popover: non-modal panel doesn't trap; Dismissal layer's isValidEvent returns false so interior clicks don't trigger dismiss; focus return to trigger is deferred to FocusScope layer (not verified in this audit).

Powered by TurnKey Linux.