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.
54 lines
5.8 KiB
54 lines
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 <!-- id: 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 <!-- id: 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).
|