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/breadcrumb.md

6.0 KiB

Audit: breadcrumb

audit-version: 1 audited-at: 2026-06-26 scope: 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: G:/dev/svelte/vicen/src/uix/soma/components/breadcrumb/breadcrumb-provider.svelte.ts cleanup-audit (A6/A35/A36): EFFECT (line 173-180): $effect writing item.isCurrent with cleanup that resets to false. No listener/observer. No resources held. Disposer verified present: return () => { item.isCurrent = false; } ✓. A35/A36 loop check: SAFE — isCurrentRaw is $derived (acyclic); writing item.isCurrent does not caus

Summary

Counts (post-verification): CRITICAL 0 · HIGH 1 · MEDIUM 0 · LOW 0.

Findings

HIGH: Archetype 'item' is reserved for selectable/interactive row parts; display items should om — breadcrumb-001

  • dimension: A: Contract(morfo)
  • rule: Archetype 'item' is reserved for selectable/interactive row parts; display items should omit archetype
  • location: G:/dev/svelte/vicen/src/uix/morfo/components/breadcrumb.ts:50
  • evidence: Item part declares archetype: 'item' but Item is a display <li> container (not selectable). Timeline.ts explicitly documents: "No archetype: 'item' — that archetype is for selectable menu/listbox/option rows... A timeline entry is a display <li>, structurally unique, so it omits the archetype." Breadcrumb.Item is semantically identical to Timeline.Item.
  • impact: Incorrect archetype declaration violates the 2-of-3 rule (archetype field inconsistent with actual DOM semantics). May confuse CSS-side consumers expecting interactive row styling (cursor:pointer, select, hover). Runtime validator should flag this.
  • repro: none (static violation)
  • proposed-fix: Remove archetype: 'item' from the Item part definition (line 50). Item is a display container, not a selectable option.
  • verify: [confirmed] CONFIRMED. breadcrumb.ts:48-56 declares the Item part with archetype: 'item' (line 50) on a display container <li> (defaultElement: 'li', no role, not selectable). The runtime stamps data-archetype='item' on the element whenever the morfo sets it (morfo/types.ts:720 'the runtime emits data-archetype="..." on the part's DOM element via partProps'; README:177 same). That [data-archetype='item'] selector triggers archetypes.css:139-153 — cursor: pointer; user-select: none; min-block-size: var(--list-item-height, auto); padding-block: var(--list-item-py, var(--space-1-5)) — PLUS the hover/highlight band at archetypes.css:161-171 (background-color: var(--color-surface-raised) painted on the WHOLE <li> on hover). breadcrumb.css:36-41 styles [data-breadcrumb-item] only with display:inline-flex; align-items:center; min-inline-size:0 — it does NOT reset cursor/padding-block/hover, so the styling is unmitigated. This is the exact documented bug: Timeline.ts:88-91 ('No archetype: 'item' — that archetype is for selectable menu/listbox/option rows (it ships cursor:pointer, user-select:none, internal padding + a hover highlight). A timeline entry is a display <li>, structurally unique, so it omits the archetype.'), and Calendar.ts:247-249 / 270-273 + range-calendar.ts:285 repeat the same doctrine for display <tr>/<td>. Breadcrumb.Item is semantically identical to Timeline.Item. Real visible regression: a breadcrumb <li> gets cursor:pointer, padding-block: var(--space-1-5), and a surface-raised hover band over the whole crumb row. HIGH is correct per the rubric's 'archetype-pulls-wrong-styling on a real part'. Fix: remove archetype: 'item' from breadcrumb.ts:50 (the Item is a display container; the interactive Link inside owns its own affordance).
  • fix-status: fixed (98954a7c)

No-findings dimensions

B: Behavior(soma): A35/A36 loops absent (effect mirrors current to item without cycle; no async state writes), B: A6 resource cleanup (no timers/listeners/observers), B: A31 O(N²) derivations absent, B: A30 child->parent id registration (uses $effect correctly), B: A33 state(Map/Set) cloning (no Maps/Sets used), C: DOM-selector (no querySelector with user values), D: Frontier (no soma->eidos imports), E-bis: Theming (recipe uses canonical --space-, --font-size-, --duration-* tokens; focus-ring uses canonical CSS var), F: Tests environment jsdom (provider test exists, covers label projection, current mirroring, ellipsis semantics), G: Passive component justified in README (zero state, zero keyboard nav, zero events by design)

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 (@vitest-environment jsdom)
  • covers: Provider label projection and resolution (BREADCRUMB_LANGS); Link.current state mirroring to Item.isCurrent; aria-current conditional emission (true/'page'/'step'); renderSpan conditional tag switching; Ellipsis decorative->interactive semantics via interactive prop; aria-haspopup conditional on interactive; role=presentation conditional on !interactive
  • untested: E2E browser interaction (Playwright): full click/focus flow, ARIA tree, CSS targeting; Eidos variant/size responsive resolution (ActiveEidos.resolve); Ellipsis with DropdownMenu composition (documented example in README)

Style observations (non-blocking)

  • Link focus-visible uses canonical --focus-ring-width and --focus-ring-color vars (breadcrumb.css:61-64, 107-109) ✓
  • Ellipsis interactive and link hover transitions use canonical --breadcrumb-transition-duration and --breadcrumb-transition-ease (line 52-54, 94-98) ✓
  • Recipe declares all semantic spacing (gap-xs/sm/md/lg → var(--space-*)) and sizing (font-size-xs/sm/md/lg, ellipsis-size → var(--control-height-xs)) ✓
  • no hardcoded hex colors; all use role aliases (--breadcrumb-color, --breadcrumb-link-color, etc.) ✓

Powered by TurnKey Linux.