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
5.5 KiB
63 lines
5.5 KiB
# Audit: clipboard
|
|
audit-version: 1
|
|
audited-at: 2026-06-26
|
|
scope: (SCOPE-DRIFT → SYS-1)
|
|
method: adversarially-verified workflow; HIGH lead-verified. B7 ground-truth: Toolbar A35 + Form A36 incidents STAYED FIXED (untrack present); toast/clipboard/drag-drop use uix.timers (no A6 leak); button is clean (its archetype finding was inert — Spinner not runtime-registered); data-size/data-shape are eidos visual attrs (not contract violations).
|
|
provider: src/uix/soma/components/clipboard/clipboard-provider.svelte.ts
|
|
|
|
## Summary
|
|
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 2.
|
|
|
|
## Findings
|
|
### MEDIUM: SYS-1 scope-drift — morfo scope omits 'eidos' although an eidos recipe/CSS dir exists for — CLIP-1 <!-- id: CLIP-1 -->
|
|
- dimension: A
|
|
- rule: SYS-1 scope-drift — morfo scope omits 'eidos' although an eidos recipe/CSS dir exists for the component
|
|
- location: src/uix/morfo/components/clipboard.ts:7
|
|
- evidence: `scope: ['soma', 'sema'],` — yet src/uix/eidos/components/clipboard/ exists with clipboard.css, clipboard.svelte, clipboard-trigger.svelte, clipboard-indicator.svelte and types.ts. The eidos layer materializes the `data-clipboard` / `data-clipboard-indicator` recipe selectors.
|
|
- impact: The morfo's declared scope no longer reflects reality: an eidos consumer exists but the contract says only soma+sema. Scope is the declared surface; drift means tooling/audits that read `scope` will under-count the eidos layer.
|
|
- proposed-fix: Add 'eidos' to the scope array: `scope: ['soma', 'sema', 'eidos']` (cf. button.ts:47 which declares it). Or — if the project decides hand-authored thin consumer wrappers do NOT count as an eidos recipe — codify that rule, since toggle/switch/collapsible omit it too. This is the confirmed-systemic SYS-1; clipboard matches the majority that omit it.
|
|
- verify: [verifier-added] added by adversarial verify pass
|
|
- fix-status: fixed (212624e0)
|
|
|
|
### LOW: Recipe spacing MUST reference --space-* tokens; raw rem literals are drift — CLIP-2 <!-- id: CLIP-2 -->
|
|
- dimension: E-bis
|
|
- rule: Recipe spacing MUST reference --space-* tokens; raw rem literals are drift
|
|
- location: src/uix/eidos/components/clipboard/clipboard.css:34
|
|
- evidence: `padding: 0.125rem 0.5rem;` — raw rem literals, while the SAME rule uses `gap: var(--space-1);` one line above (line 33). 0.5rem == --space-2 in the project scale.
|
|
- impact: The indicator chip's inset bypasses the spacing scale, so density/scaling theme changes (`:root` --space-* overrides) won't reach it. Minor visual-only drift.
|
|
- proposed-fix: Replace with token-derived values, e.g. `padding: var(--space-0-5, 0.125rem) var(--space-2);` (confirm the exact step names against primitives/static.ts).
|
|
- verify: [verifier-added] added by adversarial verify pass
|
|
- fix-status: open
|
|
|
|
### LOW: Recipe font-weight should reference the bare token; hardcoded numeric fallback diverges fr — CLIP-3 <!-- id: CLIP-3 -->
|
|
- dimension: E-bis
|
|
- rule: Recipe font-weight should reference the bare token; hardcoded numeric fallback diverges from convention
|
|
- location: src/uix/eidos/components/clipboard/clipboard.css:40
|
|
- evidence: `font-weight: var(--font-weight-medium, 500);` — the `500` literal fallback. Every recipe occurrence in lib/recipes/base.ts (lines 48, 153, 231, 314, 449) uses bare `var(--font-weight-medium)` with no fallback.
|
|
- impact: Cosmetic inconsistency; the `500` fallback masks a missing token rather than failing visibly, and diverges from the recipe convention.
|
|
- proposed-fix: Drop the fallback: `font-weight: var(--font-weight-medium);` to match base.ts usage.
|
|
- verify: [verifier-added] added by adversarial verify pass
|
|
- fix-status: open
|
|
|
|
## No-findings dimensions
|
|
A: Contract - Morfo 'as const satisfies' correct, A: Parts registered via runtime.part(), A: Data attributes (data-copied) declared in morfo, A: ARIA attributes correct (aria-label, aria-live, aria-hidden), A30: No per-item loops or sequence lags detected, A31: No O(N²) derived patterns detected, A33: No Map/Set state issues detected, A35: No per-item effect loops detected, A36: No async-mediated microtask freeze patterns detected, A6: Timer disposal via resetTimer with clearResetTimer() cleanup and $effect return, A15: No gesture/drag-drop patterns needed for clipboard, A34: Live regions - Trigger has aria-live polite for label announcement, B: Provider pattern correct - soma imports only soma core, no eidos imports, D: Frontier - No soma->eidos imports, E-bis: No recipe token or theming issues (uses canonical color roles), F: Tests exist - jsdom environment, happy path, error handling, timer mocks
|
|
|
|
## 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
|
|
- covers: copy success and copied state reset via timer; onCopy callback invocation; onError callback on clipboard API rejection; timer scheduling with uix.timers.schedule; aria-label resolution and swap on copied state; indicator visibility conditional on copied state; mergedProps application
|
|
- untested:
|
|
|
|
## Style observations (non-blocking)
|
|
- CSS uses canonical color-role variables (--color-affirm-solid, etc.) with cascading support via data-color attribute
|
|
- Animation (clipboard-pop) respects prefers-reduced-motion
|
|
- Typography uses canonical --font-size-xs and --font-weight-medium
|
|
- Spacing uses --space-* tokens (0.5rem mapped to --space-1)
|
|
- Focus ring follows canonical two-ring model via Button consumer
|
|
- No hardcoded hex colors or magic literals in eidos CSS
|