7.0 KiB
Audit: time-range-picker
audit-version: 1 audited-at: 2026-06-26 scope: soma + sema only; eidos dir exists → SYS-1 scope-drift (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/time-range-picker/time-range-picker-provider.svelte.ts
Summary
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 2. systemic hits: SYS-1: scope-drift (morfo scope omits eidos when eidos dir exists). composition (A27): Composes. Trigger wraps PopoverTriggerProvider.create(). Provider wires PopoverProvider + TimeRangeFieldProvider via shared writableActive refs. Clock composes Slider parts (range/thumb/tick re-exported, not re-implemented). All per-endpoint sliders delegate to SliderProvider. Trigger + Clock + sliders via eidos wrap soma components — A27 composition pattern correct.
Findings
MEDIUM: SYS-1: scope-drift — time-range-picker-001
- dimension: A
- rule: SYS-1: scope-drift
- location: src/uix/morfo/components/time-range-picker.ts:13
- evidence: morfo declares
scope: ['soma', 'sema']but eidos recipe directory exists at src/uix/eidos/components/time-range-picker/ with 13 component files (time-range-picker.svelte, index.ts, time-range-picker.css, etc.) - impact: morfo scope declaration is incomplete. Consumers expecting eidos provider will not find it listed, creating discovery/contract mismatch.
- proposed-fix: Update morfo scope:
scope: ['soma', 'sema', 'eidos'] - verify: [confirmed] CONFIRMED — SYS-1 scope-drift. morfo line 13:
scope: ['soma', 'sema'],omits 'eidos', yet a full eidos recipe dir exists at src/uix/eidos/components/time-range-picker/ (14 files: time-range-picker.css 392 lines, .svelte parts, index.ts, types.ts, README.md). This is the known systemic SYS-1 pattern (MEDIUM). The eidos layer genuinely materializes this component (CSS targets [data-time-range-picker]*) so the scope array is incomplete. Confidence high, severity MEDIUM as baselined. - fix-status: open
LOW: Magic literals in CSS (gap/spacing/block-size) — time-range-picker-002
- dimension: E-bis
- rule: Magic literals in CSS (gap/spacing/block-size)
- location: src/uix/eidos/components/time-range-picker/time-range-picker.css:235,241,254,265,266,329,339
- evidence: Lines 235
gap: 2px, 241block-size: 0.875rem, 254gap: 1px, 265inline-size: 1px, 266block-size: 4px, 329padding: 2px, 339min-inline-size: 2.25rem. These are literal measurements, not token references. - impact: Hardcoded values prevent consistent scaling via design tokens. Updates to spacing/sizing token system won't cascade to these edge cases.
- proposed-fix: Extract to --space-* and --radius-* tokens or --_time-range-picker-* local vars. E.g.,
gap: var(--space-px)orgap: var(--_scale-tick-gap, 2px)as fallback. - verify: [downgraded] DOWNGRADED MEDIUM→LOW. Re-read the cited lines: 235
gap: 2px(.time-range-picker-slider), 241block-size: 0.875rem(.time-range-picker-scale), 254gap: 1px(.time-range-picker-scale-tick), 265inline-size: 1px+ 266block-size: 4px(.time-range-picker-scale-mark — a hairline ruler tick mark), 329padding: 2px(.day-period-toggle inner padding), 339min-inline-size: 2.25rem(.day-period-item min width). These are decorative RULER geometry on plain.time-range-picker-*HELPER classes (not morfo data-attr selectors) — sub-pixel tick/mark dimensions that are intrinsic hairline geometry, not layout on the design-token rhythm. The 2px toggle padding and 2.25rem item width are borderline tokenizable but cosmetic and decorative-scaffold scoped. Note 0.875rem == --font-size-xs value but used as a block-size for a ruler band, not a font. MEDIUM overstates user/contract impact; this is LOW token-hygiene on ornamental ruler chrome. - fix-status: open
LOW: Magic literal: min-inline-size breakpoint + font-size literal — time-range-picker-003
- dimension: E-bis
- rule: Magic literal: min-inline-size breakpoint + font-size literal
- location: src/uix/eidos/components/time-range-picker/time-range-picker.css:197,102,152
- evidence: Line 197
@media (max-width: 40rem)+ lines 102/152flex: 1 1 7rem(field width). Line 241block-size: 0.875rem(scale height). No token references. - impact: Responsive breakpoint and sizing coupled to hardcoded values. Violates token-driven design consistency.
- proposed-fix: Use responsive size tokens or --space-* family. E.g.,
--_endpoint-input-basis: var(--space-28, 7rem). Align breakpoints to canonical design system. - verify: [downgraded] DOWNGRADED MEDIUM→LOW. Line 197
@media (max-width: 40rem)is a local responsive breakpoint collapsing the 2-col clock grid to 1-col; lines 102flex: 1 1 7rem([data-time-range-field-input]) and 152flex: 1 1 7rem... (actually 102 isflex: 1 1 7rem, 152 isinline-size: calc(var(--_time-field-height) - var(--space-2))which IS token-based). The real literal is the 7rem flex-basis (endpoint input min width) and the 40rem media query. These are component-local layout tuning, not on the spacing/size token scale, and there is no canonical responsive-token primitive for arbitrary flex-basis. Same family as 002 — LOW token-hygiene, not MEDIUM. The 152 part of the cited evidence is actually correct token usage (var(--_time-field-height) - var(--space-2)), so the evidence is partly inaccurate. - fix-status: open
No-findings dimensions
C, D, F
Theming facts (E-bis)
- magic z-index: none
- magic literals: gap: 2px | block-size: 0.875rem | gap: 1px | inline-size: 1px | block-size: 4px | padding: 2px | min-inline-size: 2.25rem | flex: 1 1 7rem | max-width: 40rem | min-inline-size: 28rem | min-inline-size: 14rem | line-height: 1 | transform: translateX(-50%) | border-radius: calc(var(--radius-md) - 2px)
- undeclared parts: none
- roles clean: true · variants clean: true
Tests (F)
- exists: true · env: jsdom
- covers: provider part registration; placeholder resolution per endpoint; per-endpoint value writes; 12-hour cycle mapping; hour/minute/second/day-period getters/setters; readonly segments filtering; close-on-range-complete behavior
- untested: grid keyboard routes (N/A, not a grid); focus trap / dismissal; popover integration end-to-end; eidos visual composition; clock surface interactions; slider drag behavior
Style observations (non-blocking)
- CSS structure mirrors TimePicker recipe (time-field tokens reused for field portion, popover surface tokens for clock body). Per-channel accent palette (Hour=primary, Minute=secondary, Second=neutral) is intentional design (documented in comments 279-284). Color-mix() for end-endpoint muting is elegant (line 321).
- Endpoint layout (start/end columns) via flex wrapper .time-range-picker-endpoint — no grid, clean separation.