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.
63 lines
8.9 KiB
63 lines
8.9 KiB
# Audit: date-field
|
|
audit-version: 1
|
|
audited-at: 2026-06-26
|
|
scope: ['soma', 'sema'] (SCOPE-DRIFT → SYS-1)
|
|
method: adversarially-verified workflow (analyze → refute); HIGH/CRITICAL lead-verified. Clean-check pseudo-findings dropped. B4 ground-truth: segmented date/time/color-field register inputId via $effect (SYS-A30-EFFECT, no loop); number-field is the direct-assignment reference.
|
|
provider: G:\dev\svelte\vicen\src\uix\soma\components\date-field\date-field-provider.svelte.ts
|
|
field-family (A13/A24-26/A30): A13: form-participating hidden input correctly implemented (lines 1011-1040), renders with name/value/required/disabled when name is set. A24: readonly-without-value warning implemented via soma.logger.warn (lines 355-370), guards against misconfiguration when readonlySegments set without value. A26: onbeforeinput preventDefault required for segmented contenteditable — CORRECT implementation at li
|
|
|
|
## Summary
|
|
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 2 · LOW 0.
|
|
|
|
## Findings
|
|
### MEDIUM: SYS-1 (scope-drift) — date-field-001 <!-- id: date-field-001 -->
|
|
- dimension: scope
|
|
- rule: SYS-1 (scope-drift)
|
|
- location: morfo line 7 + eidos dir exists
|
|
- evidence: Morfo declares scope: ['soma', 'sema'] (src/uix/morfo/components/date-field.ts line 7) but eidos recipe dir src/uix/eidos/components/date-field/ and CSS src/uix/eidos/components/date-field/date-field.css both exist. Scope MUST include 'eidos' when the recipe and CSS layer are present.
|
|
- impact: Contract validator may not catch visual-layer rules as part of the component's declared surface area.
|
|
- proposed-fix: Update morfo scope from ['soma', 'sema'] to ['soma', 'sema', 'eidos']
|
|
- verify: [confirmed] CONFIRMED at MEDIUM. morfo `src/uix/morfo/components/date-field.ts:7` declares `scope: ['soma', 'sema']` (grep verified), while the eidos layer exists: recipe block `'date-field':` at `src/uix/eidos/lib/recipes/base.ts:1172` and CSS `src/uix/eidos/components/date-field/date-field.css` (read in full, 228 lines). This matches the documented systemic SYS-1 scope-drift (MEDIUM). NOTE: the project's stated REFERENCE component NumberField has the IDENTICAL condition — number-field.ts:7 also declares `scope: ['soma', 'sema']` yet `src/uix/eidos/components/number-field/` exists — so this is a true systemic pattern for the field family, not a date-field-specific defect. Severity stays MEDIUM per SYS-1; confidence high that the condition holds, with the caveat that whether 'eidos' is REQUIRED in scope for these components is a project-wide convention question.
|
|
- fix-status: fixed (212624e0)
|
|
|
|
### MEDIUM: Test coverage gap (field-family paths) — date-field-003 <!-- id: date-field-003 -->
|
|
- dimension: tests
|
|
- rule: Test coverage gap (field-family paths)
|
|
- location: date-field-provider.svelte.test.ts (275 lines)
|
|
- evidence: Test suite covers: segment helpers (120-165), validation (174-198), segment commit (200-220), time-segment sync (222-240), granularity filtering (242-274). MISSING: (1) hidden-input render when name is set; (2) readonly-without-value warning fired; (3) commit-set/commit-reset event emission; (4) keyboard navigation per APG (ArrowUp/Down/Left/Right/Backspace); (5) Field parent integration (inputId wiring).
|
|
- impact: High-risk field-family paths untested: form submission via hidden input, readonly misconfiguration guards, and event-driven workflows.
|
|
- proposed-fix: Add test cases for: shouldRender hidden input, soma.logger.warn call when readonlySegments + undefined value, commit event firing on segment completion, keyboard segment navigation (at least one key per segment type), and Field parent inputId registration.
|
|
- verify: [confirmed] CONFIRMED at MEDIUM (F dimension — high-risk field-family test gap). The test file `date-field-provider.svelte.test.ts` (read in full, 275 lines) covers ONLY: segment helpers (initSegmentStates/isAcceptableSegmentKey/getFirstSegment/handleSegmentNavigation, 120-165), validation min/max/custom (174-198), incremental segment commit (200-220), padded date+time sync (222-240), granularity filtering (242-274). UNTESTED high-risk paths that DO exist in the provider: (1) hidden-input render — `DateFieldHiddenInputProvider.shouldRender` (provider line 1022) and its A13 ISO `value`/`name`/`required` props (1027-1040) are never exercised; (2) readonly-without-value A24 warn — the `$effect` calling `soma.logger.warn` (provider 354-369) is never triggered, even though the harness already stubs `logger.warn: vi.fn()` (test line 72), so the assertion would be trivial; (3) commit event emission — `runtime.trigger('commit-set'|'commit-reset')` (provider line 785) untested; (4) keyboard segment navigation per APG (ArrowUp/Down/Backspace/number-key handlers, provider 1108-1296) untested at provider level; (5) Field parent inputId wiring (DateFieldInputProvider $effect, provider 932-936) untested. Severity MEDIUM (missing tests for high-risk paths); confidence high that these paths are real and uncovered.
|
|
- fix-status: open
|
|
|
|
### MEDIUM: A30 — inputId registered via `$effect` instead of direct constructor assignment (SYSTEMIC: date/time/color-field) <!-- id: date-field-A30 -->
|
|
- dimension: B
|
|
- rule: A30 (child→parent id registration MUST be a direct constructor assignment, not `$effect`)
|
|
- location: date-field-provider.svelte.ts:932-936 (`$effect(() => { const field = this.provider.field; if (!field) return; field.inputId.current = opts.id.current; })`)
|
|
- evidence: lead-confirmed by direct read — the DateFieldInput provider wraps the `field.inputId` registration in a `$effect`, whereas the project reference NumberField does it as a direct constructor guard (number-field-provider.svelte.ts:585-587: `if (this.provider.field) { this.provider.field.inputId.current = opts.id.current; }`). time-field (531-535) and color-field (521-525) use the identical `$effect` — SYSTEMIC.
|
|
- impact: no loop today (the Input provider only WRITES `field.inputId` and never reads it back, and `opts.id` is a stable framework id), so the A30 page-freeze hazard is not live — but it is contrary to A30 doctrine and inconsistent with the NumberField reference; a future reader who makes the registration two-way (or reads inputId in the child) would reintroduce the freeze.
|
|
- repro: static — compare date/time/color-field Input providers (`$effect`) vs number-field (direct).
|
|
- proposed-fix: replace the `$effect` with a direct constructor assignment guarded by `if (this.provider.field)`, matching NumberField. Apply across date-field, time-field, color-field.
|
|
- verify: [lead-added] the date-field agent's no-findings claim falsely listed "A30 direct id-wiring" as clean; the verify on time-field-001 + lead reads of date-field:932-936 / color-field:521-525 confirm the `$effect` pattern. Elevated to a systemic MEDIUM.
|
|
- fix-status: open
|
|
|
|
## No-findings dimensions
|
|
A (Contract morfo), B (keyboard, A17 focus, A33, A35, A6 cleanup, TWO-MOMENTS — note: A30 id-wiring is NOT clean, see date-field-A30), C (DOM-selector safety), D (Frontier soma→eidos), G (Redundancy)
|
|
|
|
## Theming facts (E-bis)
|
|
- magic z-index: none
|
|
- magic literals: 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName'
|
|
- undeclared parts: none
|
|
- roles clean: true · variants clean: true
|
|
- label-font (one step below input?): Label calc(1em - (var(--font-size-md) - var(--font-size-sm))) produces correct one-step scaling at md but degrades at sm input size (line 109) — see finding date-field-002.
|
|
|
|
## Tests (F)
|
|
- exists: true · env: jsdom (vitest)
|
|
- covers: segment state initialization; input acceptance (numeric + nav keys only); DOM segment reading (getValueFromSegmentsDOM); segment focus navigation (ActiveDom); validation (custom/min/max); segment commit on fill; time segment padding; granularity filtering (hour → no minute/second)
|
|
- untested: hidden-input conditional render when name is set; readonly-without-value warning logger.warn() call; commit-set and commit-reset events firing; keyboard handling per APG (all arrow directions, backspace per segment); Field parent integration (inputId registration); readonly segment visual treatment; cross-segment cascades (month→day clamp, hour→dayPeriod flip, dayPeriod→hour AM/PM); year segment typeahead logic (pressedKeys tracking)
|
|
|
|
## Style observations (non-blocking)
|
|
- Recipe tokens correctly reference --space-*, --radius-*, --font-size-*, --color-* (lines 1173-1222). No bare hex/rgb/oklch in recipe. No --opacity-* barefoot decimals (opacity-disabled token used, line 1222). Z-index not used in date-field CSS. Theming uses 9 roles (primary/secondary/neutral/affirm/fulfill/risk/threat/loss + implicit default). Label font-weight is var(--font-weight-regular), not emphasized. Segment readonly uses underline dotted var(--color-content-muted) + surface-overlay bg (consistent field family).
|
|
- Invalid border color uses var(--color-risk-border) per theming rule (line 1204).
|
|
- Focus ring uses outline (not box-shadow post migration, line 147 CSS). Flush offset (0) survives forced-colors.
|