4.2 KiB
Audit: toggle
audit-version: 1 audited-at: 2026-06-26 scope: (SCOPE-DRIFT → SYS-1) method: adversarially-verified workflow; HIGH lead-verified. B6 ground-truth: checkbox/toggle/switch commit-toggle = sequence post (lag-fixed); radio-group/tabs/accordion/stepper set state at call-site (pre OK); toggle-group + checkbox-group carry the A31 .includes pattern (SYS-7); slider has no gesture-layer A6 leak. provider: src/uix/soma/components/toggle/toggle-provider.svelte.ts sequence-audit: State is set INSIDE handler (toggle-provider.svelte.ts:105-109, lines 106-107: opts.pressed.current = next). Morfo sequence='post' (morfo/components/toggle.ts:43). Runtime correctly executes 'post' sequence: handler runs first (runtime.svelte.ts:742), then await tick() (line 747), then runEmit() (li
Summary
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 0.
Findings
MEDIUM: SCOPE-DRIFT (SYS-1): eidos recipe dir exists but morfo scope omits 'eidos' — toggle-001
- dimension: Contract (morfo)
- rule: SCOPE-DRIFT (SYS-1): eidos recipe dir exists but morfo scope omits 'eidos'
- location: src/uix/morfo/components/toggle.ts:25
- evidence: Morfo declares scope: ['soma', 'sema'] but eidos directory exists at src/uix/eidos/components/toggle/ with toggle.css and toggle.svelte that emit data-variant, data-size, data-block, data-icon-only. Checkbox (checkbox.ts:7) declares scope: ['soma', 'sema', 'eidos'] as comparison.
- impact: Morfo scope does not accurately reflect the component's actual API surface. Eidos-provided visual attrs (data-variant, data-size, data-block, data-icon-only) consumed by toggle.css are outside the declared contract.
- proposed-fix: Add 'eidos' to morfo scope: scope: ['soma', 'sema', 'eidos']
- verify: [confirmed] CONFIRMED SYS-1 scope-drift at MEDIUM. morfo/components/toggle.ts:25 declares
scope: ['soma', 'sema'], yet a full eidos surface exists: src/uix/eidos/components/toggle/ ships toggle.css + toggle.svelte + types.ts + a recipe entry (lib/recipes/base.ts:3646toggle: {). The eidos wrapper (toggle.svelte:49-52) emits data-variant/data-size/data-block/data-icon-only consumed by toggle.css. Peer twins DO declare eidos: checkbox.ts:7, radio-group.ts:7, tabs.ts:7, and notably toggle-group.ts:10 (which reuses Toggle's recipe via structural identity) all carryscope: ['soma', 'sema', 'eidos']. NOTE on severity ceiling: this is purely a contract-accuracy/documentation gap —scopeis documented (types.ts:799) as 'Layers that implement this component' but NO validator enforces 'eidos' presence (the morfo-coverage check at types.ts:835-839 only errors on events-without-sema-scope and warns on missingexpression). It is also not toggle-unique: switch.ts:24 (toggle's structural twin) has the identical omission. So MEDIUM is the correct ceiling — real inconsistency vs. direct peers, zero functional/runtime impact. Does not rise to HIGH. - fix-status: fixed (
212624e0)
No-findings dimensions
Behavior (soma), DOM-selector, Frontier (soma->eidos), TSC, Theming, Redundancy
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
- covers: State toggle via runtime.trigger('commit-toggle'); Morfo attrs sync (data-state, data-color, aria-pressed, aria-label) via ActiveDom; FieldProvider integration (isDisabled, isReadonly, isRequired, isInvalid OR-merge); Readonly blocks handler execution without disabling button; onPressedChange callback invocation
- untested: Sequence timing verification (post-sequence lag risk — implicitly passing in smoke test but no explicit await measurements); Disabled button attr is set (props test at line 145 confirms, but not explicitly called out); Hidden input rendering with name+pressed condition
Style observations (non-blocking)
- Morfo comment (lines 40-42) accurately documents the 'post' sequence rationale: 'celebrate the new state, not the gesture'
- Provider comment (lines 39-46) clearly states this is 'runtime-direct' pilot without base class, ownership model is transparent
- Type safety: OptsFromProps union at lines 22-36 and Managed union stay in sync via comment at lines 12-21