# Audit: link-preview audit-version: 1 audited-at: 2026-06-26 scope: ['soma'] (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/link-preview/link-preview-provider.svelte.ts ## Summary Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 0. systemic hits: SYS-1 (scope-drift: eidos exists but not declared in morfo scope); SYS-2 (magic literals in CSS: 1px, 0.18em, 4px, 0.985 scale). ## Findings ### MEDIUM: SYS-1 — link-preview-001 - dimension: A - rule: SYS-1 - location: src/uix/morfo/components/link-preview.ts:7 - evidence: scope: ['soma'] declared in morfo, but eidos recipe dir exists at src/uix/eidos/components/link-preview/ with 7 files (index.ts, link-preview.svelte, link-preview-content.svelte, link-preview-trigger.svelte, link-preview-arrow.svelte, link-preview.css, types.ts) - impact: Morfo scope omits 'eidos' while eidos recipe and components exist; creates maintenance confusion and violates the documented scope contract. - repro: grep -r "src/uix/eidos/components/link-preview" to confirm files exist; check morfo scope at src/uix/morfo/components/link-preview.ts:7 - proposed-fix: Either (a) add 'eidos' to morfo scope: `scope: ['soma', 'eidos']`, or (b) if eidos is intentional internal structure, document why scope is intentionally ['soma'] only and mark eidos as internal pattern. - verify: [confirmed] Confirmed SYS-1 scope-drift. morfo line 7: `scope: ['soma'],` while a full eidos recipe dir exists: ls src/uix/eidos/components/link-preview/ shows index.ts, link-preview.svelte, link-preview-content.svelte, link-preview-trigger.svelte, link-preview-arrow.svelte, link-preview.css, types.ts. morfo/types.ts:799 documents `scope` as 'Layers that implement this component. Eidos-only primitives may declare ["eidos"].' Peer overlays correctly list eidos: dropdown-menu.ts:11 `scope: ['soma', 'sema', 'eidos']`, tooltip.ts:14 `scope: ['soma', 'eidos', 'sema']`. link-preview omits 'eidos' despite shipping a recipe. MEDIUM is right per batch-1 SYS-1 baseline. - fix-status: open ## No-findings dimensions B, C, D, F, G ## Theming facts (E-bis) - magic z-index: z-index is tokenized via --popover-content-z (canonical preset) - magic literals: text-decoration-thickness: 1px (should use --border-width or clarify as exempt) | text-underline-offset: 0.18em (should use --tracking-* or clarify as exempt) | opacity: 0 in keyframes (acceptable as terminal state) | scale(0.985) and 4px offsets in keyframes (should be tokenized or documented) - undeclared parts: none - roles clean: true · variants clean: true - conformance: link-preview uses only primary role (canonical); no invented roles or sizes; size variants xs|sm|md|lg|xl conform to E-bis subset. ## Tests (F) - exists: true · env: jsdom - covers: open/close timers with configurable delays (openDelay/closeDelay); touch pointer ignored (only mouse/pen); disabled flag blocks open; SafePolygon pointer bridge (content hover prevents close); dismissal via Escape key and outside-click; floating content/arrow props exposure; data-state transitions - untested: keyboard Escape key (mentioned in README but not explicitly tested in jsdom); focus return to trigger on close (A17 not exercised); content visibility presence transitions (Presence API self-cleanup verified at code level); client/Playwright integration tests (jsdom-only; no browser interaction test) ## Style observations (non-blocking) - LinkPreview correctly uses trigger as navigational (not button), which is documented and intentional per APG guidance for hover-card discovery. - aria-hidden=true on content is explicit design choice to hide preview from AT; justified by README study §2.3 (duplicate content, hover-only activation, focus stays on trigger). - SafePolygon bridge with touch guard (pointer type check) is well-implemented to preserve preview on pointer transitions. - Color tokens use primary role only; fallback to --color-content-primary is defensive. - Animation preset (4 directional in/out keyframes) matches floating-ui positioning strategy; naming data-side correlates CSS state to floating placement.