- Created 01-01-SUMMARY.md with execution results - Updated STATE.md with Phase 1 completion and decisions - Updated ROADMAP.md progress (Phase 1: 1/1 plans complete) - Marked CORR-01 through CORR-04 complete in REQUIREMENTS.md
9.4 KiB
Roadmap: YellowJacket Consolidation
Created: 2026-02-27 Depth: Comprehensive Phases: 8 Requirements: 26/26 mapped
Phases
- Phase 1: Concurrency Race Fixes — Eliminate all SetContext data races across Queue, Library, Playlist, and Player
- Phase 2: Backend Correctness — Fix error handling gaps, file permissions, package-level state, and scan error separation
- Phase 3: Test Infrastructure — Create in-memory SQLite test helper and apply production SQLite PRAGMAs
- Phase 4: Queue, Config & Player Tests — Write unit tests for queue operations, config roundtrip, and extracted player pure logic
- Phase 5: Database & Library Tests — Write unit tests for FTS5 search queries, migrations, library scan, and entity cache
- Phase 6: SQL Consolidation & Code Quality — Deduplicate FTS5 queries via VIEW, add event codegen, migrate to sqlc where feasible, document exceptions
- Phase 7: Backend Performance — Optimize queue persistence, fix SetQueue Phase 2 redundancy, enable lazy library loading
- Phase 8: Frontend Performance & UX — Optimize frontend rendering for large libraries and fix visual inconsistencies
Phase Details
Phase 1: Concurrency Race Fixes
Goal: All SetContext patterns across the codebase are race-free and the app can run under -race without data race reports
Depends on: Nothing (first phase)
Requirements: CORR-01, CORR-02, CORR-03, CORR-04
Success Criteria (what must be TRUE):
- Running the app with
go test -raceproduces zero data race reports for SetContext calls in queue, library, playlist, and player packages - Queue.SetContext(), Library.SetContext(), and Playlist.Service.SetContext() each acquire their mutex before writing the ctx field
- Player.SetContext() uses a single lock acquisition instead of the double-lock pattern
- Concurrent calls to SetContext from multiple goroutines do not corrupt shared state Plans: 1 plan Plans:
- 01-01-PLAN.md — Add mutex protection to all SetContext methods and collapse Player double-lock
Phase 2: Backend Correctness
Goal: All known error handling gaps are closed, configuration is secure, and the backend reports problems honestly instead of swallowing them Depends on: Phase 1 (race-free code is prerequisite for reliable error paths) Requirements: CORR-05, CORR-06, CORR-07, CORR-08, CORR-09 Success Criteria (what must be TRUE):
- The package-level
startupErrvariable no longer exists; startup errors are stored in a YellowJacketApp struct field - Config files are written with 0o644 permissions (owner read/write, group/other read-only)
- MPRIS lifecycle callback errors (Pause, Seek) appear in the application log instead of being silently discarded
- Artist credit link creation checks the actual error — only UNIQUE constraint violations are ignored, all other errors are surfaced
- Library.Scan() returns warnings (skipped files, partial failures) in ScanMetrics and fatal errors (database failures) in the error return, so callers can distinguish between "scan completed with issues" and "scan failed" Plans: TBD
Phase 3: Test Infrastructure
Goal: A reliable, production-mirroring test foundation exists so that all subsequent test phases can write database-backed tests with confidence
Depends on: Phase 1 (race-free code required for -race-clean test runs), Phase 2 (correct error handling needed for accurate test assertions)
Requirements: TEST-01, PERF-04
Success Criteria (what must be TRUE):
database.NewTestDB(t)returns a clean in-memory SQLite database that applies the same migrations and PRAGMAs as the productionNewDB()- Production SQLite connection applies
synchronous=NORMAL,cache_size=-8000, andmmap_size=67108864PRAGMAs at database open - Each test gets an isolated database instance — no shared state between test functions
- Tests using
NewTestDBpass with-raceflag enabled Plans: TBD
Phase 4: Queue, Config & Player Tests
Goal: The queue, config, and player packages have comprehensive unit tests that characterize current behavior and serve as a safety net for later refactoring Depends on: Phase 3 (queue tests need NewTestDB for persistence tests) Requirements: TEST-02, TEST-04, TEST-05 Success Criteria (what must be TRUE):
- Queue package has ~15-20 tests covering SetQueue, Next, Previous, shuffle mode, repeat modes (off, one, all), and state persistence across save/load cycles
- Config package has ~8-10 tests covering load/save roundtrip fidelity, validation rule enforcement, default value application, and graceful handling of missing or empty config files
- Player pure logic (UserVolume↔Volume conversion, state serialization/deserialization, format detection from file extension) is extracted into standalone functions with ~5-8 unit tests
- All tests in this phase pass with
-raceflag enabled Plans: TBD
Phase 5: Database & Library Tests
Goal: Database queries (especially FTS5 search) and library scan logic have unit tests that lock down current behavior before SQL consolidation and performance optimization Depends on: Phase 3 (database tests need NewTestDB), Phase 4 (queue tests validate persistence patterns reused here) Requirements: TEST-03, TEST-06 Success Criteria (what must be TRUE):
- Database package has ~10-15 tests covering FTS5 search (basic terms, empty query, special characters, multi-word), search index rebuild, and schema migration application
- Library scan logic has ~10-15 tests covering metadata extraction processing, entity cache hit/miss behavior, and orphan track cleanup
- FTS5 search tests verify that search ranking produces consistent, expected ordering for known test data
- All tests in this phase pass with
-raceflag enabled Plans: TBD
Phase 6: SQL Consolidation & Code Quality
Goal: Duplicated SQL patterns are eliminated, event names are provably synchronized between Go and TypeScript, and intentional SQL exceptions are documented Depends on: Phase 5 (FTS5 search tests verify consolidation doesn't break ranking; database tests verify migration safety) Requirements: QUAL-01, QUAL-02, QUAL-03, QUAL-04 Success Criteria (what must be TRUE):
- The duplicated 5-table FTS5 JOIN pattern is consolidated into a single SQLite VIEW (
track_metadataor similar), and all search queries use the VIEW instead of inline JOINs - A code generator reads Go event constants from
backend/events/events.goand producesfrontend/src/events.ts, wired intogo generateand the pre-commit hook — adding an event in Go without regenerating TypeScript fails the hook - Queue batch lookups in
persistence.gousesqlc.slice()for IN clauses where sqlc supports it, replacingfmt.Sprintfplaceholder construction - Every hand-crafted SQL statement that intentionally bypasses sqlc has a
// SAFETY:comment explaining why (batch INSERT, dynamic IN clauses, etc.) Plans: TBD
Phase 7: Backend Performance
Goal: Queue mutations and library loading are fast — single-track queue changes are O(1) instead of O(n), and the library doesn't block startup with a full data fetch Depends on: Phase 4 (queue tests verify persistence optimization doesn't lose data), Phase 5 (library tests verify lazy loading doesn't break data access) Requirements: PERF-01, PERF-02, PERF-03 Success Criteria (what must be TRUE):
- Adding or removing a single track from the queue uses incremental INSERT/DELETE via existing sqlc queries, not a full table rewrite
- SetQueue Phase 2 (
resolveRemainingTracks) skips file paths that were already resolved in Phase 1, eliminating redundant database lookups - Library store constructor no longer calls
eagerFetch()— data loads lazily on first access via the existinggetTracks()/getAlbums()/etc. getters, and the app starts without blocking on a full library load Plans: TBD
Phase 8: Frontend Performance & UX
Goal: The app feels smooth and visually consistent — large libraries render without jank, and the UI follows a coherent visual language Depends on: Phase 7 (backend lazy loading changes the data availability pattern the frontend consumes) Requirements: PERF-05, UX-01, UX-02 Success Criteria (what must be TRUE):
- Track and album lists use Lit
repeat()directive with stable keys (filePath for tracks, albumId for albums) for efficient DOM reuse during scrolling and filtering - Store notifications during rapid updates (e.g., library scan) are debounced via
queueMicrotask()to prevent layout thrashing - Visual inconsistencies (spacing, colors, typography, icon sizing) are audited and follow a consistent pattern across all components
- Scrolling, view switching, and search filtering in a 10k+ track library are smooth with no visible jank or dropped frames Plans: TBD
Progress
| Phase | Plans Complete | Status | Completed |
|---|---|---|---|
| 1. Concurrency Race Fixes | 1/1 | Complete | 2026-02-28 |
| 2. Backend Correctness | 0/? | Not started | — |
| 3. Test Infrastructure | 0/? | Not started | — |
| 4. Queue, Config & Player Tests | 0/? | Not started | — |
| 5. Database & Library Tests | 0/? | Not started | — |
| 6. SQL Consolidation & Code Quality | 0/? | Not started | — |
| 7. Backend Performance | 0/? | Not started | — |
| 8. Frontend Performance & UX | 0/? | Not started | — |
Roadmap created: 2026-02-27 Last updated: 2026-02-28