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

48 lines
7.6 KiB

# Audit: date-range-picker
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/date-range-picker/date-range-picker-provider.svelte.ts
## Summary
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 2 · LOW 0.
systemic hits: SYS-1: scope-drift (eidos recipe missing); SYS-5: no syncAttrs double-write detected (eidos properly wraps soma without forcing attr overrides).
composition (A27): Composes via A27: PopoverProvider and DateRangeFieldProvider bridged via SHARED writableActive refs (sharedOpen, sharedValue, sharedPlaceholder) in Provider component. Only root Provider, Trigger, and Calendar sub-parts are unique; Popover, Field, and RangeCalendar parts re-exported from composed primitives.
## Findings
### MEDIUM: SYS-1 SCOPE-DRIFT: morfo declares scope=['soma','sema'] but an eidos recipe directory exis — date-range-picker-001 <!-- id: date-range-picker-001 -->
- dimension: A: Contract
- rule: SYS-1 SCOPE-DRIFT: morfo declares scope=['soma','sema'] but an eidos recipe directory exists (25 files in src/uix/eidos/components/date-range-picker/) yet NO recipe entry exists in src/uix/eidos/lib/recipes/base.ts
- location: src/uix/morfo/components/date-range-picker.ts:13 + src/uix/eidos/lib/recipes/base.ts (missing entry)
- evidence: Morfo line 13: `scope: ['soma', 'sema'],` but src/uix/eidos/components/date-range-picker/ directory has 25 component files. Grep for 'date-range-picker' in base.ts returns 0 matches.
- impact: Eidos CSS file (date-range-picker.css) exists and is imported in eidos component (line 8) but no canonical recipe tokens/config define size/color/variant scales for this component; recipes are the contract bridge for eidos.
- proposed-fix: Add 'eidos' to morfo scope declaration: `scope: ['soma', 'sema', 'eidos']` and create the date-range-picker recipe block in src/uix/eidos/lib/recipes/base.ts with token definitions for size (xs/sm/md/lg), color (primary/secondary/neutral/affirm/fulfill/risk/threat/loss), and variant (surface/outline/ghost).
- verify: [confirmed] CONFIRMED as SYS-1 scope-drift (MEDIUM). morfo line 13 `scope: ['soma', 'sema']` omits 'eidos', yet src/uix/eidos/components/date-range-picker/ has 25 files incl. date-range-picker.css imported by the eidos component. Grep for 'date-range-picker' in lib/recipes/base.ts = 0 matches (confirmed). HOWEVER the candidate's proposedFix is partly WRONG and I downgrade its remedy claim: the eidos CSS does NOT need its own recipe block. I read date-range-picker.css (690 lines) — it owns NO `--date-range-picker-*` recipe tokens; it COMPOSES tokens from sibling recipes (`--date-field-height-md`, `--calendar-padding-md`, `--calendar-accent-solid`, lines 2-28) plus global scales (`--color-primary-*`, `--space-*` L391/419, `--radius-md` L589, `--font-size-md/sm` L595/621). This is the A27 picker-composition pattern: the picker composes Field+Calendar+Popover and legitimately has no recipe entry. Verified systemic across the family: date-picker.ts also has `scope: ['soma','sema']` and 0 recipe matches; time-range-picker same. So the ONLY real defect is the missing 'eidos' token in the scope array — not a missing recipe block. Severity MEDIUM (SYS-1) is correct; the fix is to add 'eidos' to scope, NOT to author recipe tokens.
- fix-status: open
### MEDIUM: INERT EVENTS: morfo declares 'commit-reset' event but provider NEVER fires it via runtime. — date-range-picker-002 <!-- id: date-range-picker-002 -->
- dimension: A: Contract
- rule: INERT EVENTS: morfo declares 'commit-reset' event but provider NEVER fires it via runtime.trigger()
- location: src/uix/morfo/components/date-range-picker.ts:65-72 (declaration) vs src/uix/soma/components/date-range-picker/date-range-picker-provider.svelte.ts:247-249 (clear() implementation)
- evidence: Morfo line 65-72 declares: `{ name: 'commit-reset', semantic: { family: 'commit', verb: 'reset', ... } }`. Provider clear() method (line 247-249) reads: `clear(): void { this.opts.value.current = { start: undefined, end: undefined }; }` with NO `runtime.trigger('commit-reset', ...)` call. Grep for 'commit-reset' in provider finds 0 trigger sites.
- impact: The event exists only to satisfy the schema validator. Consumers expecting `onCommitReset` callback or downstream event handlers observing 'commit-reset' will never fire, violating the 2-of-3 rule (morfo declares it; soma does not fire it).
- proposed-fix: Add `void this.runtime.trigger('commit-reset', { fallbackTarget: ... });` in the clear() method (line 248) BEFORE resetting the value, to match the pattern used in triggerClose() (line 270). Alternatively, remove the event declaration from morfo if it is not semantically needed.
- verify: [confirmed] CONFIRMED as the known picker-family inert-event pattern (MEDIUM cap, matches the prompt's explicit guidance). morfo lines 65-72 declare `{ name: 'commit-reset', semantic: { family: 'commit', verb: 'reset', target: v.partRef('calendar'), sequence: 'post', intent: 'neutral' } }`. Provider clear() at lines 247-249 reads exactly: `clear(): void { this.opts.value.current = { start: undefined, end: undefined }; }` — sets value, no trigger. Grep across the WHOLE component (provider + components/ + internals.ts) confirms the ONLY `runtime.trigger` call is `trigger('close', ...)` at line 270; zero `commit-reset` trigger sites anywhere. So the event is genuinely inert — it exists only to satisfy the schema validator, violating the 2-of-3 rule (morfo declares it; soma never fires it; sema/eidos read data-state not this event). Confidence high. MEDIUM is the correct severity per the INERT-EVENTS rule (MEDIUM at most). The candidate's proposedFix (add trigger in clear()) is a reasonable remedy, though note `data-last-action` is NOT among clear()'s causes since clear keeps the popover open — a commit-reset trigger would need its own non-close wiring.
- fix-status: open
## No-findings dimensions
B: Behavior (keyboard handlers on grid cells are soma-owned; no grid keyset declared in morfo per design), C: DOM-selector (no untrusted querySelector usage found), D: Frontier (soma provider has zero eidos imports; eidos wrapper normally imports soma - correct), E: TSC (no bare z-index, hex, or magic literals in CSS; all tokens reference --color-*, --space-*, --radius-*, --font-size-*, --icon-size-* scales), E-bis: Theming (token naming clean; roles from canonical 9-role set only; size/color/variant from EIDOS_VARIANTS)
## Theming facts (E-bis)
- magic z-index: none
- magic literals: none
- undeclared parts: none
- roles clean: true · variants clean: true
- conformance: Morfo annotation is 'as const satisfies Morfo' (correct); all data-* attributes follow data-{component}-{part} or data-component-{nested} naming; aria-* attrs present for Trigger (aria-expanded, aria-haspopup, aria-controls, aria-label) and Calendar (aria-label); no double-write via syncAttrs observed in provider.
## Tests (F)
- exists: true · env: jsdom
- covers: provider part registration; state flag rendering (open/closed/disabled/readonly/required/invalid); closeOnRangeSelect behavior; range validation (single-day, minDays, maxDays, min/max value)
- untested: commit/cancel/clear actions via footer (not provider-level); dismissed event on Escape/outside click (PopoverProvider owns this); commit-reset event firing; modal vs inline mode end-to-end; range re-anchor (end month rightmost) layout verification; keyboard navigation on month/year grids

Powered by TurnKey Linux.