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/range-calendar.md

8.6 KiB

Audit: range-calendar

audit-version: 1 audited-at: 2026-06-26 scope: (SCOPE-DRIFT → SYS-1) method: adversarially-verified workflow (analyze → refute); HIGH/CRITICAL personally re-verified by the lead. Batch-3 ground-truth: each picker fires trigger(close) (close NOT inert), but open/commit-reset ARE inert; calendar/range-calendar are MID-REFACTOR (uncommitted view-switch work). provider: src/uix/soma/components/range-calendar/range-calendar-provider.svelte.ts

MID-REFACTOR CAVEAT: this component has uncommitted view-switch changes on this branch (M/D/?? files). Findings reflect the current in-flight state; treat structural inconsistencies as in-progress, not shipped defects.

Summary

Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 2 · LOW 2. systemic hits: SYS-1 scope-drift (morfo includes eidos but no recipe entry).

Findings

MEDIUM: Keyboard route must match morfo contract; Home/End APG grid pattern — range-calendar-002

  • dimension: B: Behavior (soma)
  • rule: Keyboard route must match morfo contract; Home/End APG grid pattern
  • location: src/uix/soma/components/range-calendar/range-calendar-provider.svelte.ts:566-567
  • evidence: Morfo declares (line 88-89): { key: 'Home', action: 'first-day-of-week' }, { key: 'End', action: 'last-day-of-week' }. Provider implements (lines 566-567): else if (e.key === KEYS.HOME) target = startOfMonth(date); else if (e.key === KEYS.END) target = endOfMonth(date);. This is month-based, not week-based.
  • impact: User pressing Home/End navigates to first/last day of month instead of first/last day of current week, violating both the morfo contract and APG grid pattern expectations.
  • proposed-fix: Replace startOfMonth(date) with calculation to first day of current week using weekStartsOnResolved. Replace endOfMonth(date) with calculation to last day of current week.
  • verify: [downgraded] Behavior is real but NOT a range-calendar-specific HIGH. Provider lines 566-567: else if (e.key === KEYS.HOME) target = startOfMonth(date); else if (e.key === KEYS.END) target = endOfMonth(date); — month-based, while morfo lines 88-89 declare actions named first-day-of-week/last-day-of-week. HOWEVER the sibling calendar provider does the IDENTICAL thing: calendar-provider.svelte.ts:481-485 if (e.key === KEYS.HOME) { const monthStart = startOfMonth(date); ... } else if (e.key === KEYS.END) { target = endOfMonth(date); }, against the IDENTICAL morfo declaration calendar.ts:76-77 ({ key: 'Home', action: 'first-day-of-week' }, { key: 'End', action: 'last-day-of-week' }). This is a family-wide naming/implementation divergence, and keyboard[].action is advisory morfo metadata (not enforced by the runtime — the provider's keydown handler owns the actual behavior). Not a latent bug introduced here, not a contract-validator catch; at most a LOW doc/naming inconsistency that should be raised against the whole calendar family, not range-calendar alone.
  • fix-status: open

MEDIUM: INERT EVENTS: declared keyboard action never fired via runtime.trigger — range-calendar-003

  • dimension: A: Contract (morfo)
  • rule: INERT EVENTS: declared keyboard action never fired via runtime.trigger
  • location: src/uix/morfo/components/range-calendar.ts:92
  • evidence: Morfo declares (line 92): { key: 'Escape', action: 'cancel-selection' }. Grep for 'Escape' or 'escape' or 'KEYS.ESCAPE' in range-calendar provider + components returns no matches. No runtime.trigger fires this action.
  • impact: User pressing Escape expects to cancel/clear the range selection, but nothing happens. Event is declared only to satisfy schema validation.
  • proposed-fix: Implement Escape key handling in handleDayKeydown to call clearSelection(). Or remove Escape from morfo if not intended.
  • verify: [confirmed] CONFIRMED as MEDIUM. Morfo line 92 declares { key: 'Escape', action: 'cancel-selection' }. I read the entire keydown chain handleDayKeydown (provider lines 555-602): branches exist for horizNext/horizPrev, ArrowDown/Up, Home, End, PageUp, PageDown, Enter/Space — but NO KEYS.ESCAPE branch. There is also no other keydown handler on any part (the Day part's onkeydown at line 1172-1174 delegates solely to handleDayKeydown). The provider never fires commit-reset or clearSelection() in response to Escape. The declared cancel-selection action is therefore inert — it exists only to satisfy the morfo schema, exactly the INERT-events class the rubric calls out. Severity MEDIUM is appropriate: a user mid-selection who presses Escape expecting to abandon the partial range gets nothing, but it is not an a11y/data-corruption break.
  • fix-status: open

LOW: querySelector with interpolated user/runtime value must use CSS.escape — range-calendar-004

  • dimension: C: DOM-selector
  • rule: querySelector with interpolated user/runtime value must use CSS.escape
  • location: src/uix/soma/components/range-calendar/range-calendar-provider.svelte.ts:595-596
  • evidence: Code: const el = root.querySelector<HTMLElement>([data-range-calendar-day][data-value="${target!.toString()}"]); The value is interpolated without CSS.escape. While ISO date format (2026-05-15) currently has no special CSS characters, the pattern is unsafe and violates defensive coding.
  • impact: If date format changes or special characters are introduced (e.g., localized formats), the selector could fail to find the element or select an unintended element. Violates the untrusted selector safety pattern.
  • proposed-fix: Use CSS.escape(target!.toString()) to safely escape the interpolated value.
  • verify: [downgraded] DOWNGRADED. Provider lines 595-596: root.querySelector<HTMLElement>([data-range-calendar-day][data-value="{target!.toString()}"]`)`. The interpolated value is `DateValue.toString()` — an ISO `YYYY-MM-DD` string produced by `$libs/days`, a FRAMEWORK-controlled value, never user/consumer-derived input. ISO dates contain only digits and a hyphen — no CSS-special characters can ever appear, so CSS.escape changes nothing functionally. Dimension C targets interpolation of *user/consumer-derived* values; a synthesized date string is neither. The same pattern is used family-wide (calendar-provider.svelte.ts:514-516 `[data-calendar-day][data-value="{target!.toString()}"]`). Defensible-hardening LOW at most, not a HIGH untrusted-selector defect.
  • fix-status: open

LOW: MAGIC NUMBERS: bare pixel/em/rem values should use canonical spacing tokens — range-calendar-005

  • dimension: E-bis: Theming (recipe + css)
  • rule: MAGIC NUMBERS: bare pixel/em/rem values should use canonical spacing tokens
  • location: src/uix/eidos/components/range-calendar/range-calendar.css:323,332
  • evidence: Lines 323, 332: box-shadow: inset 2px 0 0 0 var(--_calendar-range-start-border); and box-shadow: inset -2px 0 0 0 var(--_calendar-range-end-border); use bare 2px and -2px values instead of canonical border or spacing tokens.
  • impact: Spacing is hardcoded, not themable. Breaks token consistency and makes the stripe width inflexible for different design systems.
  • proposed-fix: Define a token like --_calendar-range-endpoint-stripe-width and reference it instead: box-shadow: inset calc(var(--_calendar-range-endpoint-stripe-width, 2px) * 1) 0 0 0 ...
  • verify: [confirmed] CONFIRMED as LOW (severity already correct). range-calendar.css line 323 box-shadow: inset 2px 0 0 0 var(--_calendar-range-start-border); and line 332 box-shadow: inset -2px 0 0 0 var(--_calendar-range-end-border); hardcode the 2px/-2px endpoint-stripe width as bare literals rather than a recipe/border token. Genuine bare-literal drift, lowest severity — it is a decorative 2px hairline accent stripe on the range start/end endpoints, not a layout-load-bearing or themed dimension. Tokenizing as --_calendar-range-endpoint-stripe-width would be the canonical fix but the impact is purely cosmetic theme-flexibility.
  • fix-status: open

No-findings dimensions

D: Frontier (soma/eidos isolation), F: Tests (test coverage for existing keyboard/focus paths)

Theming facts (E-bis)

  • magic z-index: none
  • magic literals: 2px inset stripe width (lines 323, 332)
  • undeclared parts: none
  • roles clean: true · variants clean: true

Tests (F)

  • exists: true · env: jsdom
  • covers: initial placeholder resolution; range selection ordering; range length bounds enforcement; partial range clearing; endpoint amendment; transient anchor resilience; placeholder auto-page prevention; validation bounds checking
  • untested: keyboard navigation (Home/End/arrows); Escape key; roving focus management; two-moments event sequencing

Powered by TurnKey Linux.