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/pagination.md

4.6 KiB

Audit: pagination

audit-version: 1 audited-at: 2026-06-26 scope: (SCOPE-DRIFT → SYS-1) method: adversarially-verified workflow (analyze → refute); HIGH lead-verified by direct read of the cited code. B5 ground-truth: the A31 O(N²) isSelected/isExpanded (.includes from a per-item $derived) is confirmed across listbox/grid-list/tree-view/tree-grid/tag-group (SYS-7); rovingTargetEl is correctly LIFTED everywhere (not A31); virtual-* use SvelteMap (A33-clean). provider: src/uix/soma/components/pagination/pagination-provider.svelte.ts reactivity (A31/A33/A35): CLEAN. Per-item isSelected (line 457-459) uses simple comparison operator, no global state read. Per-item isDisabled (line 461) reads provider.opts.disabled.current (direct ref access, O(1)). Per-item ariaLabel (line 463-468) calls soma.langs.t() but with local item value only. No A31 quadratic patterns detected. No A33 $state(Map/Set). No A35 per-item $effect loops. Clamping effect (lines 116-122

Summary

Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 0.

Findings

MEDIUM: SYS-1 SCOPE-DRIFT: eidos recipe dir exists but morfo scope omits 'eidos' — pagination-001

  • dimension: Contract (morfo)
  • rule: SYS-1 SCOPE-DRIFT: eidos recipe dir exists but morfo scope omits 'eidos'
  • location: src/uix/morfo/components/pagination.ts:7
  • evidence: Morfo declares scope: ['soma', 'sema'] but eidos directory exists at src/uix/eidos/components/pagination/ with README confirming pagination is 'el wrapper visual de Eidos sobre el primitivo Soma'.
  • impact: Scope mismatch signals incomplete layer declaration. Eidos layer is real and should be listed in morfo scope.
  • proposed-fix: Update morfo scope from ['soma', 'sema'] to ['soma', 'sema', 'eidos'] to match the existing eidos layer.
  • verify: [confirmed] Confirmed SYS-1 scope-drift. src/uix/morfo/components/pagination.ts:7 declares scope: ['soma', 'sema'], but a complete eidos layer exists: src/uix/eidos/components/pagination/ contains pagination.css (4255 bytes), 7 Svelte wrappers, index.ts, types.ts, and a README, plus a recipe entry at src/uix/eidos/lib/recipes/base.ts:1715 (pagination: {). Peer components with an eidos layer include it in scope (accordion.ts:7 scope: ['soma', 'sema', 'eidos'], button.ts:47, checkbox.ts:7). The omission is a real layer-declaration drift. MEDIUM is correct.
  • fix-status: fixed (212624e0)

No-findings dimensions

Contract parts registration (2-of-3 rule verified: all 7 parts registered), Contract data/aria naming (data-{c}-{part} pattern used, no data-soma-* violations), Contract Morfo as const satisfies, Behavior A31 per-item O(N²) derived reading global state, Behavior A33 $state(new Map/Set) reactivity, Behavior A35/A36 per-item $effect ref-write loops, Behavior A30 id-registration via $effect, Behavior A6 cleanup (no Resource leaks detected), Behavior A18/A10/A14/A12 keyboard navigation (N/A: pagination uses snippet-based rendering, not nav), Behavior A34 require() topology (all triggers/items require parent Provider, DOM descendants), DOM-selector (no querySelector usage), Frontier eidos→soma import (correct), Frontier syncAttrs double-write (Provider and Ellipsis only, no conflicting props), Theming roles/tokens (recipe uses --space-, --font-size-, --radius-, --opacity-, --color-* role references), Tests environment (jsdom with @vitest-environment directive), Tests coverage (page ranges, clamping, navigation, disabled state all tested)

Theming facts (E-bis)

  • magic z-index: none
  • magic literals: none
  • undeclared parts: none
  • roles clean: true · variants clean: true

Tests (F)

  • exists: true · env: jsdom (via @vitest-environment directive)
  • covers: Page range computation with siblingCount=1, boundaryCount=1; Page clamping when value exceeds totalPages; Array slicing via .slice(); Navigation methods: goToNextPage, goToPrevPage, goToFirstPage, goToLastPage; Provider/trigger/item/ellipsis attrs through runtime; aria-current and aria-label projection; disabled state propagation (provider + item + trigger); onclick handlers for all triggers and items
  • untested: Edge case: siblingCount/boundaryCount extremes (e.g., siblingCount > totalPages); Dynamic count/pageSize/siblingCount/boundaryCount changes post-init; onPageChange callback firing on page mutation

Style observations (non-blocking)

  • FirstTrigger and LastTrigger disable when already at boundaries (page 1 / last page), consistent with Ark UI pattern; intentional UX choice not a bug
  • Page range algorithm uses Set deduplication before sort, efficient O(n log n) approach
  • Comments accurately describe behavior (e.g., line 222 mentions hasPrevPage check is intentional)

Powered by TurnKey Linux.