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.
5.8 KiB
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 globsrc/**/*.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 jsdomline 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).