diff --git a/docs/product/roadmap.md b/docs/product/roadmap.md index 4edb833..58dc80d 100644 --- a/docs/product/roadmap.md +++ b/docs/product/roadmap.md @@ -24,7 +24,7 @@ An audiophile player lives or dies on **library + playback maturity, not on its |--------|-------| | S8 | Library spine: scan + persistent DB | | S9 | Browse & search UI — album grid; Artist/Album/Genre; incremental search; cover art; click-to-queue | -| S10 *(runs as S10.1–S10.5)* | Queue + playlists + macOS control — queue/history, M3U import-export, media keys + Now-Playing/Control Center. Split into five individual sprints — see [sprint-plan.md](../sprints/sprint-plan.md) + [s10 plan](../sprints/s10-queue-playlists-macos-plan.md). | +| S10 *(runs as S10.1–S10.5)* | Queue + playlists + macOS control — queue/history, media keys + Now-Playing/Control Center. Split into five individual sprints — see [sprint-plan.md](../sprints/sprint-plan.md) + [s10 plan](../sprints/s10-queue-playlists-macos-plan.md). *(M3U/M3U8 import-export deferred — see below.)* | | S11 | CUE sheets + format hardening — CUE→virtual tracks, FLAC fast-seek, WavPack/APE, lossy gapless trim | | S12 | Tonal parity — parametric EQ + AutoEq/oratory1990 import + A/B LUFS-matched bypass | | S13 | Headphone + device parity — device-correction EQ auto-load + profile JSON import/export | @@ -64,6 +64,7 @@ Built on the mature base, enabler-first, lowest-artifact-risk first. This is the ## Deferred / out-of-window - **Removed from scope (2026-07-12, founder decision):** **natural-language / conversational tuning** and **hearing personalization** (hearing-test → profile → compensation) were cut from the vision entirely — not deferred, removed. May be re-added later. Prior specs are in git history. +- **Deprioritized (2026-07-14, founder decision):** **drag-from-Library-into-queue** and **playlist file import/export (M3U/M3U8)** — judged not useful enough to plan now. Not removed from the vision; revisit opportunistically post-R1. Add-to-queue is already covered by the Play Next / Add to Queue verbs; playlist portability (M3U) can return if a real need appears. R1 no longer depends on either. - **DSD playback (DoP + native)** — deferred past R2, gated on acquiring a DSD DAC (keeps every feature by-ear verifiable). - **"Won't, this horizon"** — kept on the [backlog](backlog.md) as future vision, out of this plan's window: - **Stem separation / object engine (Phase 1.5)** — high compute/artifact risk; revisit only after the mix-based thesis is validated and loved. diff --git a/docs/sprints/s10-queue-playlists-macos-plan.md b/docs/sprints/s10-queue-playlists-macos-plan.md index ef781bf..8856c62 100644 --- a/docs/sprints/s10-queue-playlists-macos-plan.md +++ b/docs/sprints/s10-queue-playlists-macos-plan.md @@ -1,7 +1,7 @@ # S10 — Queue + playlists + macOS control (five sprints S10.1–S10.5) **Document ID:** S10-PLAN-001 -**Status:** Planning — S10 runs as **five individual done-done sprints** (S10.1–S10.5). Each is a full sprint that runs the **usual development process** (vetted design → multi-SME review panel → architect + the-fool gate → build-enforced gate + commit). Not yet started; start with S10.1. +**Status:** S10.1 ✅ + S10.2 ✅ shipped & merged; **S10.3 next**. S10 runs as **five individual done-done sprints** (S10.1–S10.5), each via the **usual development process** (vetted design → multi-SME review panel → architect + the-fool gate → build-enforced gate + commit). *(Authoritative project status: [sprint-plan.md §Status](sprint-plan.md). Deprioritized 2026-07-14: drag-from-Library-into-queue + M3U/M3U8 import-export.)* **Relates to:** [sprint-plan.md](sprint-plan.md) — the S10.x sprint series, the last work before **Release R1**. **Depends on:** S8 (library spine, GRDB store) ✅, S9 (browse/search) ✅. @@ -13,9 +13,9 @@ | Sprint | SP | Scope (line item) | Key stories | Depends on | |---|---|---|---|---| -| **S10.1** | 8 | **Playlist/queue persistence spine** — `playlists` + `playlist_entries` tables (GRDB, delete-rebuild migration; keyed on `tracks.id` with a `position` + own entry id so a track can repeat); DAO for create/rename/delete + ordered add/remove/reorder + loose-file add; the built-in non-deletable **"current"** playlist; `untitled-N` lowest-unused naming; **closes Gate 1** (`unreferencedTrackIDs` gains `AND id NOT IN (SELECT track_id FROM playlist_entries)`). Gated by `VerifyLibraryStore`. | US-PLIST-01, -05, -06 (store), -07; known-issues **SEQ-1 Gate 1** | S8.1 store | -| **S10.2** | 6 | **Queue UX** — the "current" playlist surfaced as the play queue: reorder (drag), play-next, add-to-queue, history; wires to `PlaybackQueueKit`. Lands the **deferred drag-to-queue** from S9 (rides the queue-drag infra). | US-PLIST-06 (UI), US-PLAY reorder/history | S10.1 | -| **S10.3** | 9 | **Playlists UX + M3U/M3U8 import-export** — playlist browse/sidebar (create/edit/rename/delete, scales to hundreds); drag songs → playlist as a **reference-add, never a file move** (separate handler from folder-move); add a single non-library file; **M3U/M3U8** import + export. | US-PLIST-02, -03, -04; + the US-PLIST-08 cross-seam test | S10.1 (+ S8.4 ✅ for -08) | +| **S10.1** ✅ | 8 | **Playlist/queue persistence spine** — `playlists` + `playlist_entries` tables (GRDB, delete-rebuild migration; keyed on `tracks.id` with a `position` + own entry id so a track can repeat); DAO for create/rename/delete + ordered add/remove/reorder + loose-file add; the built-in non-deletable **"current"** playlist; `untitled-N` lowest-unused naming; **closes Gate 1** (`unreferencedTrackIDs` gains `AND id NOT IN (SELECT track_id FROM playlist_entries)`). Gated by `VerifyLibraryStore`. | US-PLIST-01, -05, -06 (store), -07; known-issues **SEQ-1 Gate 1** | S8.1 store | +| **S10.2** ✅ | 6 | **Queue UX** — persistent play queue (the "current" playlist; survives quit/relaunch, restore-paused); Up Next|History + session history; Clear Queue; reorder (grip-drag + context-menu + keyboard); wires to `PlaybackQueueKit`. *(drag-from-Library-into-queue deprioritized 2026-07-14 — Play Next / Add to Queue verbs cover add.)* | US-PLIST-06 (UI), US-PLAY reorder/history | S10.1 | +| **S10.3** | 6 | **Playlists UX** — playlist browse/sidebar (create/edit/rename/delete, scales to hundreds); add songs → playlist as a **reference-add, never a file move** (separate handler from folder-move); add a single non-library file. *(M3U/M3U8 import-export deprioritized 2026-07-14.)* | US-PLIST-02, -03, -04; + the US-PLIST-08 cross-seam test | S10.1 (+ S8.4 ✅ for -08) | | **S10.4** | 5 | **macOS system control** — media keys + Now-Playing / Control Center (`MPNowPlayingInfoCenter` + `MPRemoteCommandCenter`); app-wide keyboard shortcuts. Independent of the persistence spine. | (new — trace to sprint-plan S10.4) | S9 | | **S10.5** | 3 | **Browse polish** — folder-browse mode; the **deferred A–Z jump rail** from S9. *(Polish — not an R1 gate.)* | (S9 carry-overs) | S9 | diff --git a/docs/sprints/sprint-plan.md b/docs/sprints/sprint-plan.md index 0d7ff46..38344b8 100644 --- a/docs/sprints/sprint-plan.md +++ b/docs/sprints/sprint-plan.md @@ -45,10 +45,10 @@ The rationale is sound: **an audiophile player lives or dies on library + playba | **S6** ✅ | Technical architecture review & hardening *(gate — §8.6)* | 8† | Multi-discipline review of the shipped codebase; RT-safety/lifecycle + concurrency consolidation + the Tier-3 DSP spine (`Realizer`, `RtSwappableResource`, steerable equal-power intensity with intensity-0 the bit-exact anchor, `GaplessController`). Confirmed the spine is Phase-2-ready. **Rationale:** [s6-architecture-review-findings.md](s6-architecture-review-findings.md), [s6-tier3-spine-design.md](s6-tier3-spine-design.md). | shipped codebase | | **S7** ✅ | DSP-gate hardening | 8 | Regression oracles for every shipped DSP stage: libebur128 LUFS/TP, limiter −1 dBTP + ISP accuracy, 31-band EQ FR sweep + bit-transparent bypass, SRC alias/stopband, gapless-seam, RT-allocation soak (US-QA-01..06). **Open follow-up:** THD+N. | S6 | | **S8** ✅ | Library spine: scan + persistent DB | 9 | Folder scan/watch, metadata + embedded-art, incremental rescan, persistent **GRDB**-backed store, art cache; S8.4 id-preserving move-match. Headless-gated by `VerifyLibraryStore`. **Forward:** Gate 1 (playlist filter, known-issues SEQ-1) stays open until **S10.1** ships the playlist table. | S6 | -| **S9** ✅ | Browse & search UI | 8 | Album grid + detail; Songs (filter-preserves-sort + customizable columns); Artists (tile grid) + Genres; FTS5 incremental search; queue/advance core (`PlaybackQueueKit`); cover art; a11y. *(Years tab cut.)* **Deferred → S10:** true drag-to-queue (→ S10.2) + the A–Z jump rail (→ S10.5). | S8 | -| **S10.1** | Playlist/queue persistence spine | 8 | `playlists` + `playlist_entries` tables (GRDB, keyed on `tracks.id` + position); create/rename/delete + ordered-membership DAO; built-in non-deletable **"current"** queue playlist; `untitled-N` naming. **Closes Gate 1** (SEQ-1). `VerifyLibraryStore`-gated. | S8 | -| **S10.2** | Queue UX | 6 | The "current" playlist surfaced as the play queue: reorder / play-next / add-to-queue / history; lands the deferred **drag-to-queue**. | S10.1 | -| **S10.3** | Playlists UX + **M3U/M3U8** import-export | 9 | Playlist browse/edit (create/rename/delete, scales to hundreds); drag → playlist = **reference-add** (never a file move); add a single non-library file; M3U/M3U8 import+export; the US-PLIST-08 move-survival seam test. | S10.1 | +| **S9** ✅ | Browse & search UI | 8 | Album grid + detail; Songs (filter-preserves-sort + customizable columns); Artists (tile grid) + Genres; FTS5 incremental search; queue/advance core (`PlaybackQueueKit`); cover art; a11y. *(Years tab cut.)* **Deferred → S10:** the A–Z jump rail (→ S10.5). *(drag-to-queue was routed to S10.2, then deprioritized 2026-07-14.)* | S8 | +| **S10.1** ✅ | Playlist/queue persistence spine | 8 | `playlists` + `playlist_entries` tables (GRDB, keyed on `tracks.id` + position); create/rename/delete + ordered-membership DAO; built-in non-deletable **"current"** queue playlist; `untitled-N` naming. **Closes Gate 1** (SEQ-1). `VerifyLibraryStore`-gated. | S8 | +| **S10.2** ✅ | Queue UX | 6 | Persistent play queue (the "current" playlist; survives quit/relaunch, restore-paused); Up Next|History + session history; Clear Queue; reorder via grip-drag + context-menu + keyboard. *(drag-from-Library-into-queue deprioritized 2026-07-14.)* | S10.1 | +| **S10.3** | Playlists UX | 6 | Playlist browse/edit (create/rename/delete, scales to hundreds); add songs → playlist = **reference-add** (never a file move); add a single non-library file; the US-PLIST-08 move-survival seam test. *(M3U/M3U8 import-export deprioritized 2026-07-14.)* | S10.1 | | **S10.4** | macOS system control | 5 | **Media keys + Now-Playing/Control Center** (`MPNowPlayingInfoCenter` / `MPRemoteCommandCenter`); app-wide keyboard shortcuts. *(independent of the store)* | S9 | | **S10.5** | Browse polish | 3 | Folder-browse mode; the deferred **A–Z jump rail** from S9. *(polish — not an R1 gate)* | S9 | @@ -68,7 +68,7 @@ The rationale is sound: **an audiophile player lives or dies on library + playba ### Status -**S6–S9 ✅ shipped · S10.1 next → Release R1.** S9 browse is complete (Songs · Albums · Artists · Genres); S10 now runs as five individual sprints S10.1–S10.5 (start with S10.1, the playlist/queue spine). **This line is the single prose status surface for the project** — README/roadmap defer here; everything finer-grained lives in the source + git log (which are authoritative if they disagree with this). +**S6–S9 ✅ + S10.1–S10.2 ✅ shipped · S10.3 next → Release R1.** S9 browse complete; S10.1 (playlist/queue persistence spine) + S10.2 (queue UX — persistent queue, Up Next|History, reorder) shipped & merged. S10 runs as five individual sprints S10.1–S10.5; **R1 gates on S10.1–S10.4**. Deprioritized 2026-07-14 (founder): drag-from-Library-into-queue + M3U/M3U8 import-export (see [roadmap Deferred](../product/roadmap.md)). **This line is the single prose status surface for the project** — README/roadmap defer here; everything finer-grained lives in the source + git log (which are authoritative if they disagree with this). ---