--- phase: 10-ux-interaction plan: 05 type: execute wave: 0 depends_on: [] files_modified: - frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js - frontend/src/components/layout/__tests__/AppSidebar.empty.test.js - frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js - frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js - frontend/src/__tests__/keyboard.test.js - frontend/src/components/layout/__tests__/OsDragOverlay.test.js - frontend/src/components/storage/__tests__/StorageBrowser.dragmove.test.js - frontend/src/components/ui/__tests__/dropdown.test.js autonomous: true requirements: [UX-02, UX-03, UX-04, UX-05, UX-06, UX-07, UX-08, UX-09, UX-11, UX-13, UX-14] must_haves: truths: - "Wave 0 xfail test stubs exist for every requirement that is implemented in Waves 1-4" - "Each stub is marked .skip or .todo so the test runner reports unrun tests instead of false greens" - "Each requirement ID is referenced by at least one stub" artifacts: - path: "frontend/src/__tests__/keyboard.test.js" provides: "Wave 0 xfail stubs for UX-05..08 keyboard shortcuts" - path: "frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js" provides: "Wave 0 xfail stubs for UX-02 skeleton + UX-13 dropdown teleport" key_links: - from: "Each stub describe() block" to: "Requirement ID in test title or comment" via: "describe('UX-XX: ...')" pattern: "describe.*UX-" --- Create Wave 0 test stubs (Nyquist pattern — RED tests before implementation) for the requirements that are wired in Waves 1-4. This ensures: 1. The test runner reports unrun tests for every requirement (no false greens) 2. Wave 1-4 implementations have a place to "promote" stubs to real assertions 3. Coverage of all 15 phase requirements is provable up-front This plan covers the 11 requirements NOT covered by Wave 0 foundation plans (10-01..10-04 already include their tests): - Foundation already covered by their own plans: UX-01 (EmptyState — 10-02), UX-10 (Toast — 10-04), UX-12 (BreadcrumbBar — 10-03), CODE-05 (AppIcon — 10-01) - This plan covers: UX-02, UX-03, UX-04, UX-05, UX-06, UX-07, UX-08, UX-09, UX-11, UX-13, UX-14 Output: 8 stub test files, each with `it.skip` or `it.todo` placeholders annotating the requirement IDs and expected behavior. Wave 1-4 implementing plans will replace `.skip`/`.todo` with real tests. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @CLAUDE.md @.planning/phases/10-ux-interaction/10-CONTEXT.md @.planning/phases/10-ux-interaction/10-RESEARCH.md @.planning/phases/10-ux-interaction/10-VALIDATION.md @frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js Vitest stubs use `it.todo('description')` or `it.skip('description', ...)`. Each stub file should `describe('UX-XX: requirement summary', ...)` with one or more `it.todo` placeholders for the behaviors that Wave 1-4 will implement. Test file locations (mirror the source structure): - `frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js` — UX-02 (skeleton rows) + UX-13 (folder picker dropdown) - `frontend/src/components/storage/__tests__/StorageBrowser.dragmove.test.js` — UX-11 (drag-to-move toast trigger + ring highlight) - `frontend/src/components/layout/__tests__/AppSidebar.empty.test.js` — UX-03 (sidebar skeleton + empty micro states) + UX-14 (sidebar New button removed) - `frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js` — UX-04 (audit log skeleton rows) - `frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js` — UX-04 (users table skeleton rows) - `frontend/src/__tests__/keyboard.test.js` — UX-05..08 (global keyboard shortcuts) - `frontend/src/components/layout/__tests__/OsDragOverlay.test.js` — UX-09 (OS file drag overlay depth-counter) - `frontend/src/components/ui/__tests__/dropdown.test.js` — UX-13 (Teleport+getBoundingClientRect dropdown positioning) Task 1: Create skeleton + dropdown stubs (UX-02, UX-03, UX-04, UX-13, UX-14) frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js, frontend/src/components/layout/__tests__/AppSidebar.empty.test.js, frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js, frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js, frontend/src/components/ui/__tests__/dropdown.test.js - frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js (style reference) - .planning/phases/10-ux-interaction/10-VALIDATION.md (test map) - .planning/phases/10-ux-interaction/10-RESEARCH.md §"Pitfall 7: Skeleton Row Height" and §"Component Inventory §2: Dropdown Clipping Audit" Create 5 stub test files. Each file is a single `describe('UX-XX: requirement', ...)` block with `it.todo(...)` entries. Use `import { describe, it } from 'vitest'` at the top. **File A — `frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js`:** ``` import { describe, it } from 'vitest' describe('UX-02: StorageBrowser shows skeleton rows during loading', () => { it.todo('renders 5+ skeleton rows when loading=true (replaces Loading… text)') it.todo('skeleton rows use grid-cols-[2rem_1fr_6rem_8rem_6rem] matching real row grid') it.todo('skeleton rows use animate-pulse') it.todo('Loading… text is absent when loading=true (skeleton replaces it)') }) describe('UX-13: StorageBrowser folder picker uses Teleport + getBoundingClientRect', () => { it.todo('folder picker dropdown is teleported to body (escapes overflow container)') it.todo('dropdown position reflects getBoundingClientRect of the trigger button') it.todo('window scroll while open recalculates position') }) ``` **File B — `frontend/src/components/layout/__tests__/AppSidebar.empty.test.js`:** ``` import { describe, it } from 'vitest' describe('UX-03: AppSidebar shows skeleton placeholders while loading', () => { it.todo('renders skeleton rows in folder section when loadingRoots=true') it.todo('renders skeleton rows in topics section when topicsStore.loading=true') it.todo('renders skeleton rows in cloud section when loadingCloudConnections=true') it.todo('Loading… text is removed from all three sections') }) describe('UX-01 (sidebar micro): EmptyState size=sm appears when each section is empty', () => { it.todo('folders empty: EmptyState size=sm with icon=folder') it.todo('topics empty: EmptyState size=sm with icon=tag') it.todo('cloud empty: EmptyState size=sm with icon=cloud and a Settings link in #cta') }) describe('UX-14: AppSidebar no longer renders an inline "New" folder button', () => { it.todo('no