docs: record Wave 8 tracks 8.C and 8.E landed; Phase 9 gate met
Deploy DeepDrftAPI / Build, Publish & Bundle (push) Successful in 2m10s
Deploy DeepDrftManager / Build & Publish (push) Successful in 1m25s
Deploy DeepDrftPublic / Build & Publish (push) Successful in 4m3s
Deploy DeepDrftAPI / Deploy (push) Successful in 1m33s
Deploy DeepDrftManager / Deploy (push) Successful in 1m29s
Deploy DeepDrftPublic / Deploy (push) Successful in 1m30s

This commit is contained in:
daniel-c-harvey
2026-06-13 22:43:53 -04:00
parent 03c96c621b
commit 05130aaed2
2 changed files with 24 additions and 6 deletions
+23 -3
View File
@@ -34,11 +34,11 @@ The single-track-per-release rule for Session/Mix is enforced only in the CMS fo
---
### 9.8 Wave 8 — Remediation (partial: tracks 8.A, 8.B, 8.D, 8.F, 8.G, 8.H, 8.I, 8.J, 8.L landed; 8.C, 8.E, 8.K, 8.M remain pending)
### 9.8 Wave 8 — Remediation (Phase-9-completion gate met: 8.A8.J + 8.L landed; 8.K post-Phase-9, 8.M follow-on pending)
**Landed:** 2026-06-13 on dev (nine tracks).
**Landed:** 2026-06-13 on dev (eleven tracks: 8.A, 8.B, 8.C, 8.D, 8.E, 8.F, 8.G, 8.H, 8.I, 8.J, 8.L).
Daniel tested the landed Phase 9 surface (Waves 17) and produced a punch-list. Wave 8 is remediation — the gap between what the specs *built* and what hands-on use *wants*. Full design, acceptance criteria, and dependencies: `product-notes/phase-9-wave-8-remediation.md`. The wave spans CMS, public site, and label polish. Nine tracks landed; remaining gate tracks (8.C, 8.E) layer onto the tab strip; 8.K (Mix Visualizer) is pulled out of Phase-9-completion scope (post-Phase-9 wave, design-complete); 8.M (legacy-form retirement) is a code-surface-reduction follow-on that trails.
Daniel tested the landed Phase 9 surface (Waves 17) and produced a punch-list. Wave 8 is remediation — the gap between what the specs *built* and what hands-on use *wants*. Full design, acceptance criteria, and dependencies: `product-notes/phase-9-wave-8-remediation.md`. The wave spans CMS, public site, and label polish. The Phase-9-completion gate (8.A8.J + 8.L) is now fully met; 8.K (Mix Visualizer) is pulled out of Phase-9-completion scope (post-Phase-9 wave, design-complete); 8.M (legacy-form retirement) is a code-surface-reduction follow-on that trails.
**8.A — Release Archive as medium tabs, not cards**
@@ -115,6 +115,26 @@ Daniel tested the landed Phase 9 surface (Waves 17) and produced a punch-list
---
**8.C — Per-medium grids gain working edit affordances (full parity with ALL tab)**
- **What:** Cut / Session / Mix tab grids gain full parity with the ALL tab: expand-tracks, delete, Type chip, and per-row Edit action — the same rich `CmsAlbumBrowser` grid the ALL tab uses, filtered to each tab's single medium.
- **Why:** The initial 8.A landing acknowledged that the per-medium tabs used the thin `CmsMediumTable` (cover/title/artist/edit) while ALL used the richer `CmsAlbumBrowser`; 8.C was the deferred parity track. Per-medium grids differing from the ALL grid in affordances was confusing and inconsistent.
- **Shape:** Daniel decided option (b) — full parity. Each per-medium browser (`CmsCutBrowser`, `CmsSessionBrowser`, `CmsMixBrowser`) now renders `CmsAlbumBrowser` filtered to its single medium. `CmsAlbumBrowser.razor` gained one optional `[Parameter] public RenderFragment<ReleaseDto>? RowActions` slot, rendered in the Actions cell before the shared edit/delete buttons; the ALL tab leaves it unset and is unchanged. `CmsMediumBrowserBase.cs` was refactored: it now feeds the rich grid a medium-filtered `Releases` projection (`IReadOnlyList<ReleaseDto>`) alongside `ReloadAsync` (wired to the grid's post-delete `OnReleasesChanged`) and a `RowFor(release)` lookup (`_rowsById` dictionary keyed by `release.Id`) for per-medium action-state recovery by the `RowActions` fragment. Session hero and Mix waveform row actions are preserved via each browser's `RowActions` content. `CmsMediumTable.razor` and `CmsMediumTable.razor.css` were deleted (now orphaned). No `TrackList.razor` change (the `MediumGrid` switch renders the same component identifiers). No `@rendermode` override; no constructor growth; no `IServiceProvider`. No new automated tests (no bUnit harness; medium-filter data path covered by `ReleaseBrowseQueryTests`). Files modified: `CmsAlbumBrowser.razor`, `CmsMediumBrowserBase.cs`, `CmsCutBrowser.razor`, `CmsSessionBrowser.razor`, `CmsMixBrowser.razor`, `CmsSessionBrowser.razor.css`; deleted: `CmsMediumTable.razor`, `CmsMediumTable.razor.css`.
**Completion note:** `CmsAlbumBrowser.razor` gained `[Parameter] public RenderFragment<ReleaseDto>? RowActions { get; set; }` rendered in the Actions cell (before edit/delete) via `@RowActions?.Invoke(context.Release)`; the ALL tab's `CmsAllReleasesGrid` wrapper passes nothing, leaving ALL unchanged. `CmsMediumBrowserBase<TRow>` (generic, abstract) was rewritten: it now loads a medium-filtered release list via `ICmsReleaseService.GetPagedAsync`, projects to a bare `IReadOnlyList<ReleaseDto> Releases` for the rich grid, maintains `_rowsById` for action-state recovery via `RowFor(release)`, and exposes `ReloadAsync()` wired to the grid's `OnReleasesChanged`. `CmsCutBrowser`, `CmsSessionBrowser`, and `CmsMixBrowser` were updated to render `CmsAlbumBrowser` (instead of the now-deleted `CmsMediumTable`) with their medium-specific `RowActions` fragment. `CmsMediumTable.razor` and `CmsMediumTable.razor.css` deleted. Per-medium tabs now render the same expand-tracks / delete / Type-chip / edit grid as the ALL tab, single-sourced. Acceptance criteria met; Wave 8 track 8.C brings per-medium grids to full parity with the ALL tab.
---
**8.E — Add-Track buttons in all modes, medium-aware routing**
- **What:** Every Release Archive tab surfaces an Add Track button that routes to the upload page pre-set to that tab's medium. The ALL-tab Add Track defaults to Cut; the medium selector stays user-changeable after landing on the form.
- **Why:** Before 8.E, the upload form had no direct link from the Release Archive tabs. An admin starting from the Sessions tab had no in-context Add Track button pointing at a Session upload.
- **Shape:** `TrackList.razor` gained a `MudStack` Add Track button above `MudTabs` in the `Albums` browse arm (§8.A's tab strip), `@bind-ActivePanelIndex="_activeTabIndex"`, and two helpers: `ActiveMedium` maps tab index 0 (ALL) → `ReleaseMedium.Cut` and index ≥1 → `Enum.GetValues<ReleaseMedium>()[index-1]`; `AddTrackHref(medium)``/tracks/upload?medium={medium.ToString().ToLowerInvariant()}`. `BatchUpload.razor` reads `?medium=` via `[SupplyParameterFromQuery(Name = "medium")]`, parses with `Enum.TryParse(ignoreCase: true)` + `Enum.IsDefined`, defaults to `ReleaseMedium.Cut`, and routes through the existing `OnMediumChanged` so the pre-selected medium drives the conditional fields on load (the 8.F hero field for Session, `ReleaseType` for Cut) and the 8.L single-track name-collapse runs identically to a user change. The selector stays user-changeable after landing; `/tracks/upload` with no param still defaults to Cut. No `@rendermode` override; no constructor growth; no `IServiceProvider`. `TrackList.razor` edits confined to the tab-strip toolbar (no grid-component / `MediumGrid` switch edits). Files modified: `TrackList.razor`, `BatchUpload.razor`.
**Completion note:** `TrackList.razor` gained `_activeTabIndex` backing field with `@bind-ActivePanelIndex`, `ActiveMedium` computed property (index 0 → `Cut`; index ≥1 → `Enum.GetValues<ReleaseMedium>()[index-1]`), `AddTrackHref(medium)` static helper producing `/tracks/upload?medium={…}`, and a `MudStack` row above `MudTabs` rendering the medium-aware Add Track button. `BatchUpload.razor` gained `[SupplyParameterFromQuery(Name = "medium")] public string? MediumParam { get; set; }` and seed logic in `OnInitializedAsync`: if `MediumParam` is set, `Enum.TryParse<ReleaseMedium>(ignoreCase: true)` + `Enum.IsDefined` gate the call to `OnMediumChanged(medium)`, driving conditional fields and 8.L name-collapse on load without requiring a user gesture. The query-param convention is new to the codebase as a Blazor `[SupplyParameterFromQuery]` entry, mirroring the existing API-side `Enum.TryParse`/`IsDefined` parse posture. Acceptance criteria met; Wave 8 track 8.E surfaces a medium-aware Add Track button in every Release Archive tab.
---
**8.H — Archive page becomes the searchable all-releases browser (release-cardinal, decided H2)**
- **What:** Replace the public `/archive` three-card overview with a release-cardinal searchable browser over all releases. Retire the three-card overview on every breakpoint; cascade: `/tracks` (`TracksView`) is demoted from the nav (route kept reachable); mobile ARCHIVE → the new browser.
+1 -3
View File
@@ -176,8 +176,6 @@ Two surfaces dominate: the **CMS Release Archive** (the card-grid landing is the
Full track decomposition, acceptance criteria, and parallel/dependent analysis: `product-notes/phase-9-wave-8-remediation.md`. The tracks in brief:
**CMS (`DeepDrftManager`):**
- **8.C — Per-medium grids gain working edit affordances.** Cut / Session / Mix tab grids each get an Edit action routing to the correct edit page for that medium. *(Parallel with 8.E once 8.A lands.)*
- **8.E — Add-Track buttons in all modes, medium-aware routing.** Every tab surfaces an Add Track button routing to the upload page pre-set to that tab's medium. The `ALL`-tab Add Track defaults to **Cut**; the medium selector stays user-changeable after landing on the form. *(Depends on 8.A.)*
- **8.M — Retire the legacy single-track forms; consolidate onto the batch forms.** Fold `TrackNew` (`/tracks/new`) and `TrackEdit` (`/tracks/{Id:long}`) into `BatchUpload`/`BatchEdit`'s single-track branch and retire them, reducing duplicate form surface (Daniel, 2026-06-13: "consolidate the forms and reduce the code surface"). **Feasibility: retirement-with-reconciliation.** `TrackNew` is a clean retirement (no live inbound link — every Add-Track points at `/tracks/upload`). `TrackEdit` requires reconciling an **addressing-model gap**: it is addressed by *track id* while `BatchEdit` is addressed by *release title* and loads the whole release — so the single-Cut-track edit from Track mode's per-row Edit (`CmsTrackGrid``/tracks/{id}`, the one live inbound link) needs a decision (open the parent release, or address a single track within the batch edit). **Architectural — staff-engineer scope** (route-map change + two component removals + navigation-model decision). Not a Phase-9-completion gate; sequence after 8.L. *(Independent of 8.L for build.)*
**Public site (`DeepDrftPublic.Client`):**
@@ -185,7 +183,7 @@ Full track decomposition, acceptance criteria, and parallel/dependent analysis:
**Mix Visualizer — out of Phase-9-completion scope:**
- **8.K — Mix Visualizer redesign. `[post-Phase-9, design-complete]`.** A windowed, playback-coupled, bottom-to-top scrolling waveform showing the currently-playing region; zoom couples to apparent scroll speed (Guitar-Hero model, anchored at 1 quarter note @ 180 BPM = 333 ms visible at max zoom); lava-lamp aesthetic (theme-aware gradients, glassy), **strictly read-only**; standard Canvas/WebGL, no tricks, well-commented. The datum analysis recommends switching the Mix loudness profile from a fixed 2048 buckets to **constant-time-resolution capture (~333 samples/sec)** so long mixes aren't under-sampled at max zoom. **Phase 9 closes without this**; it runs as a post-Phase-9 wave, dispatchable straight from the finished spec: `product-notes/phase-9-mix-visualizer-redesign.md`.
**Dependency shape:** 8.B is the foundation for the CMS tab work (8.A consumes the shared grid; 8.C/8.E layer on once 8.A lands). 8.L follows 8.G and coordinates with 8.E/8.F (same forms). 8.M (legacy-form retirement) follows 8.L and is architectural (route map + addressing decision). On the public side, 8.H (decided H2 — the new release-cardinal archive) gates 8.I. **Phase 9 completion = 8.A8.I landed; 8.K and 8.M are excluded from the completion gate** (8.K is a post-Phase-9 design-complete wave; 8.M is a code-surface-reduction follow-on that can trail). **Landed tracks (2026-06-13):** 8.A, 8.B, 8.D, 8.F, 8.G, 8.H, 8.I, 8.J, 8.L.
**Dependency shape:** 8.B is the foundation for the CMS tab work (8.A consumes the shared grid; 8.C/8.E layer on once 8.A lands). 8.L follows 8.G and coordinates with 8.E/8.F (same forms). 8.M (legacy-form retirement) follows 8.L and is architectural (route map + addressing decision). On the public side, 8.H (decided H2 — the new release-cardinal archive) gates 8.I. **Phase 9 completion gate (8.A8.J + 8.L) is now fully met** — the remediation wave is complete except the two explicitly-out-of-gate items (8.K post-Phase-9 visualizer; 8.M legacy-form retirement follow-on). **Landed tracks (2026-06-13):** 8.A, 8.B, 8.C, 8.D, 8.E, 8.F, 8.G, 8.H, 8.I, 8.J, 8.L.
## Working with this file