docs: split Wave 8 form work into 8.L name-collapse + 8.M legacy-form retirement

This commit is contained in:
daniel-c-harvey
2026-06-13 19:37:53 -04:00
parent 2f7af6d6d2
commit add43c5a7d
2 changed files with 142 additions and 37 deletions
+4 -3
View File
@@ -171,7 +171,7 @@ Daniel tested the landed Phase 9 surface end-to-end and produced a punch-list of
Two surfaces dominate: the **CMS Release Archive** (the card-grid landing is the wrong shape — Daniel wants medium *tabs*, not navigate-away cards) and the **public Archive** (the three-card overview is dead weight; the searchable all-**releases** view *is* the archive — release-cardinal, decided). The **Mix Visualizer redesign (8.K)** is **pulled out of Phase-9-completion scope** — Phase 9 closes without it — but is now **documented in full**: the interview ran and `product-notes/phase-9-mix-visualizer-redesign.md` is a finished, implementation-ready design spec for a post-Phase-9 wave.
**Open questions resolved (Daniel, 2026-06-13):** 8.H is decided **H2** (a new release-cardinal searchable browser at `/archive`; cascade: `/tracks` demoted from nav, route kept; mobile ARCHIVE → the browser; three-card overview fully retired); 8.I drops GENRES from the nav only (route kept); 8.F makes the Session hero optional-but-warn-if-missing; 8.E defaults the `ALL`-tab Add Track to Cut with the medium selector staying user-changeable. A new track **8.L** consolidates the release-name/track-name pair into a single name for single-track media.
**Open questions resolved (Daniel, 2026-06-13):** 8.H is decided **H2** (a new release-cardinal searchable browser at `/archive`; cascade: `/tracks` demoted from nav, route kept; mobile ARCHIVE → the browser; three-card overview fully retired); 8.I drops GENRES from the nav only (route kept); 8.F makes the Session hero optional-but-warn-if-missing; 8.E defaults the `ALL`-tab Add Track to Cut with the medium selector staying user-changeable. A new track **8.L** consolidates the release-name/track-name pair into a single name for single-track media (derived track name **kept synced**, decided), and **8.M** (split off 8.L) retires the legacy `TrackNew`/`TrackEdit` forms by folding them into the batch forms to reduce code surface.
Full track decomposition, acceptance criteria, and parallel/dependent analysis: `product-notes/phase-9-wave-8-remediation.md`. The tracks in brief:
@@ -183,7 +183,8 @@ Full track decomposition, acceptance criteria, and parallel/dependent analysis:
- **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.F — Session hero image in the upload form (retire the two-step).** Compose the hero-image field into the Session upload form so a Session is authored in one pass; remove the "set it later from the browser" alert. Hero is **optional but warns if missing** (no hard gate). *(Independent of the tab work; touches the upload form + the resource-addressed hero endpoint ordering — see note.)*
- **8.G — "Album Name" → "Release Name" label.** Rename the `AlbumHeaderFields` label. *(Independent, trivial. Sequence before 8.L.)*
- **8.L — Consolidate release name + track name for single-track releases.** For Session/Mix the form presents **one** name field (Release Name); the underlying track name is derived from it (recommended: kept synced on create and edit so they never diverge). Cuts (multi-track) are unaffected. Blast radius (discovery done): CMS `BatchUpload` single-track branch, `BatchEdit` via `BatchTrackDetail`, and the legacy `TrackNew`/`TrackEdit` forms *if still live*; the public detail/gallery views already key off the release title only (no public work). *(Pairs with 8.G/8.E/8.F — same upload/edit forms.)*
- **8.L — Consolidate release name + track name for single-track releases.** For Session/Mix the form presents **one** name field (Release Name); the underlying track name is derived from it (**decided: kept synced on create and edit** so they never diverge — Daniel, 2026-06-13). Cuts (multi-track) are unaffected. Blast radius (discovery done): CMS `BatchUpload` single-track branch and `BatchEdit` via `BatchTrackDetail`**batch forms only**. The legacy `TrackNew`/`TrackEdit` forms are **not** patched here; their consolidation is **8.M**. The public detail/gallery views already key off the release title only (no public work). *(Pairs with 8.G/8.E/8.F — same upload/edit forms. Independent of 8.M.)*
- **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`):**
- **8.H — Archive page becomes the searchable all-releases browser (release-cardinal, decided H2).** Build a new release-cardinal searchable browser at `/archive` (search + medium/genre filter, cards → per-medium detail); retire the three-card overview on every breakpoint. Cascade: `/tracks` (`TracksView`) is demoted from the nav (route kept reachable); mobile ARCHIVE → the new browser. *(Gates 8.I.)*
@@ -193,7 +194,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.D, 8.G are independent and parallelizable immediately; 8.L follows 8.G and coordinates with 8.E/8.F (same forms). On the public side, 8.J is an independent bug fix; 8.H (decided H2 — the new release-cardinal archive) gates 8.I. **Phase 9 completion = 8.A8.J + 8.L landed; 8.K is explicitly excluded** and runs as a separate post-Phase-9 wave.
**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.D, 8.G are independent and parallelizable immediately; 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.J is an independent bug fix; 8.H (decided H2 — the new release-cardinal archive) gates 8.I. **Phase 9 completion = 8.A8.J + 8.L 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).
## Working with this file
+138 -34
View File
@@ -13,8 +13,9 @@ memory *One source, multiple views*.
**Open questions are resolved (2026-06-13).** Daniel answered the whole decision list in §6 and ran
the 8.K interview. This doc no longer carries forks: 8.H is decided (H2 — a release-cardinal
all-releases browser at `/archive`), 8.I/8.F/8.E defaults are baked into their acceptance criteria, a
new consolidation track **8.L** is added, and **8.K is moved out of Phase-9-completion scope** to a
finished post-Phase-9 design doc. Phase 9 can close without 8.K.
new consolidation track **8.L** is added (with **8.M** split off it for the legacy-form retirement), and
**8.K is moved out of Phase-9-completion scope** to a finished post-Phase-9 design doc. Phase 9 can close
without 8.K or 8.M.
---
@@ -334,13 +335,12 @@ confusing authoring experience. Cuts are different — a Cut release legitimatel
distinct from its per-track names ("Charleston EP" → tracks "Battery", "Rainbow Row") — and are
**unaffected** by this track.
**Recommendation — keep them synced for single-track media (Daniel to confirm posture; this is the
recommended default).** On both create and edit of a single-track release, the underlying track name is
**set equal to the Release Name on save, and kept in sync** so they can never diverge. The admin never
sees or touches the track name for Session/Mix. On edit, changing the Release Name updates the track
name with it. This is the simplest model and the one that honors "there is only one name": the track
name is a *derived field*, not an independent one. (The alternative — let them diverge once set — would
reintroduce exactly the two-name confusion this track removes. Rejected.)
**Sync posture — DECIDED (Daniel, 2026-06-13): keep them synced.** On both create and edit of a
single-track release, the underlying track name is **set equal to the Release Name on save, and kept in
sync** so they can never diverge. The admin never sees or touches the track name for Session/Mix. On
edit, changing the Release Name updates the track name with it. The track name is a *derived field*, not
an independent one. (The alternative — let them diverge once set — would reintroduce exactly the
two-name confusion this track removes. Rejected.)
**Discovery audit — every UI surface that surfaces separate Release vs. Track name (read against live
source, 2026-06-13).** This is the full blast radius. Implementation must collapse the name inputs on
@@ -362,15 +362,15 @@ the single-track path for each:
shared by the Cut path (where it stays) and the single-track path (where it must be hidden). Cleanest:
the parent passes a flag (e.g. `ShowTrackName` / `IsSingleTrack`) so `BatchTrackDetail` suppresses the
name field for single-track media while still showing the WAV/Original-File rows.
- **`TrackNew.razor` (`/tracks/new`) — the legacy single-track add form.** Shows `Track Name` (line 31),
`Album` (line 33), and a `MediumFields` selector. When the selected medium is single-track, the
separate Track Name vs. Album split is the same redundancy. This legacy form is a secondary surface
(the batch form is the primary upload path) — confirm whether it is still a live entry point before
investing; if it is, apply the same collapse (one name when medium is Session/Mix). If it is dead,
note it for retirement rather than re-plumbing.
- **`TrackEdit.razor` (`/tracks/{Id:long}`) — the legacy single-track edit form.** Shows `Track Name`
(line 46) and `Album` (line 58) as separate fields, with a `MediumFields` selector. Same disposition
as `TrackNew`: collapse on the single-track path if live, flag for retirement if not.
- **`TrackNew.razor` (`/tracks/new`) and `TrackEdit.razor` (`/tracks/{Id:long}`) — the legacy
single-track forms.** Both surface the separate `Track Name` / `Album` split and a `MediumFields`
selector, so both carry the same two-name redundancy on the single-track path. **These are not patched
in-place for 8.L. Their disposition is consolidation — see 8.M (legacy-form retirement).** Daniel
(2026-06-13): "I would prefer to consolidate the forms and reduce the code surface if possible." The
decision is to fold their responsibility into the batch forms and retire the legacy pair, not to
re-plumb a name-collapse into forms slated for removal. 8.L therefore touches **only** the batch
forms (`BatchUpload` / `BatchEdit` via `BatchTrackDetail`); the legacy forms are out of 8.L's scope
and handled by 8.M.
*CMS — surfaces that already do the right thing (no change needed, listed so implementation knows they
are clean):*
@@ -386,11 +386,12 @@ are clean):*
- **`ReleaseGallery.razor`** (the Sessions/Mixes card grid) shows `release.Title` + `release.Artist`
only. Clean.
**Net blast radius:** the consolidation is **entirely CMS-side**, and concentrated in the two batch
forms (`BatchUpload`, `BatchEdit`) via the shared `BatchTrackDetail`, plus the two legacy single-track
forms (`TrackNew`, `TrackEdit`) *if they are still live*. The public site already treats a single-track
release as one-named — no public work. This is the discovery step Daniel asked for: implementation
knows the full surface set before touching anything.
**Net blast radius (8.L proper):** the name-collapse is **entirely CMS-side** and concentrated in the
two batch forms (`BatchUpload`, `BatchEdit`) via the shared `BatchTrackDetail`. The legacy single-track
forms (`TrackNew`, `TrackEdit`) are **no longer part of 8.L** — their two-name redundancy is resolved by
retiring them outright (8.M), not by patching a collapse into them. The public site already treats a
single-track release as one-named — no public work. This is the discovery step Daniel asked for:
implementation knows the full surface set before touching anything.
**Acceptance criteria.**
- On the **create** path (batch upload, single-track medium): the form presents **one** name field
@@ -404,8 +405,9 @@ knows the full surface set before touching anything.
- Switching the medium selector mid-form between Cut and a single-track medium re-drives which name
fields are visible (single name for Session/Mix; release + per-track names for Cut) without losing
entered data where it still applies.
- The legacy `TrackNew` / `TrackEdit` forms either apply the same single-name collapse (if live) or are
flagged for retirement (if dead) — staff-engineer confirms their live status during implementation.
- The legacy `TrackNew` / `TrackEdit` forms are **out of 8.L scope** — their consolidation is 8.M
(legacy-form retirement). 8.L lands independently of 8.M; the name-collapse on the batch forms does
not wait on the legacy retirement.
- No public-site change is required (verified: public detail/gallery views already key off the release
title only).
@@ -413,7 +415,88 @@ knows the full surface set before touching anything.
present should already read "Release Name" before this collapse lands; sequence 8.G first or together).
Touches the same upload/edit forms as **8.E**/**8.F** — coordinate so the Session form's hero input
(8.F), medium pre-selection (8.E), and name collapse (8.L) land coherently rather than fighting over the
same submit handler. Independent of the tab restructure (8.A8.D) and the public cluster.
same submit handler. Independent of the tab restructure (8.A8.D), the public cluster, and **8.M** (8.L
lands on the batch forms whether or not the legacy forms are retired).
---
### 8.M — Retire the legacy single-track forms; consolidate onto the batch forms
**Goal.** Retire `TrackNew` (`/tracks/new`) and `TrackEdit` (`/tracks/{Id:long}`) as the single-track
authoring path. Their add/edit responsibility is **absorbed by `BatchUpload` / `BatchEdit`**, whose
single-track branch already handles Session/Mix. This **reduces the duplicate form surface** — Daniel
(2026-06-13): "I would prefer to consolidate the forms and reduce the code surface if possible." The
single-track authoring path becomes the batch form's single-track branch; the legacy routes redirect to
(or are replaced by) the batch routes.
**User-visible change.** Adding or editing a single track no longer opens a distinct single-field form.
The same batch form that handles releases handles the one-track case — one form for both, no second
authoring surface to maintain. (Cuts already author via the batch forms; this brings the Session/Mix and
single-Cut-track cases onto the same path.)
**Feasibility read (against live source, 2026-06-13). Verdict: retirement-with-reconciliation — feasible,
but not a pure delete. One real gap must be closed first.**
What the batch forms already cover that makes this viable:
- `BatchUpload` already *is* the upload path for every medium, with a dedicated single-track branch
(`_medium != Cut` renders a single WAV slot + name field, lines ~5370). `TrackNew` adds nothing the
batch upload doesn't already do — same fields (name, artist, album/release, genre, release date,
medium, cover art), same `UploadTrackAsync` call, same Mix-waveform trigger, same cover-link follow-up.
**`TrackNew` is a clean retirement** (see route note below).
- `BatchEdit` already collapses to a single row for Session/Mix (§9.6.B; `AllowNewTracks` gated on
`_medium == Cut`, `OnMediumChanged` trims to one row) and carries the same edit fields, delete, and
cover handling `TrackEdit` has.
The gap that must reconcile — **addressing model**:
- `TrackEdit` is addressed **by track id** (`/tracks/{Id:long}`). `BatchEdit` is addressed **by release
title** (`/tracks/album/{AlbumName}/edit`) and loads the *whole release*. They key off different
things. For Session/Mix this is harmless (one track = one release; the names are about to be synced by
8.L anyway), but for a **single Cut track** opened from Track mode's per-row Edit, routing to
`BatchEdit` would open the *entire parent release*, not just that track. That is a behaviour change,
not a 1:1 swap.
- **The one live inbound link to a legacy form is `CmsTrackGrid.razor` line ~82** — Track mode's per-row
Edit button: `Href="/tracks/{context.Id}"``TrackEdit`. This is the surface that must be reconciled:
either Track mode's row-edit retargets to a batch-edit-by-release (accepting that editing a track
opens its release), or `BatchEdit` gains an address-by-track-id entry that pre-selects the row. Either
is a real decision, not a mechanical rename.
- `TrackNew` (`/tracks/new`) has **no live inbound nav link** in source — every "Add Track" button
points at `/tracks/upload` (`CmsTrackGrid` line ~16, the 8.E plan). So `TrackNew`'s route can be
dropped or made a redirect to `/tracks/upload` with **zero** caller changes.
Route/redirect implications:
- `/tracks/new` → redirect to (or replace with) `/tracks/upload`. No callers to update.
- `/tracks/{Id:long}` → either redirect to a release-scoped batch edit (and retarget `CmsTrackGrid`'s
row Edit), or retain a thin track-addressed entry into the batch edit. **This is the reconciliation
call** and it is the crux of whether this lands cleanly.
**Verdict, stated plainly:** `TrackNew` is a **clean retirement**. `TrackEdit` is a
**retirement-with-reconciliation** — feasible, but it requires a decision on the single-Cut-track edit
affordance (open the whole release vs. address a single track within the batch edit) and a retarget of
`CmsTrackGrid`'s one inbound link. Not blocked; not free.
**Acceptance criteria.**
- `/tracks/new` no longer renders a distinct form; the add-single-track path is `BatchUpload`'s
single-track branch (route removed or redirected to `/tracks/upload`).
- Editing a single track no longer opens `TrackEdit`'s distinct form; the edit path is `BatchEdit`'s
single-track branch. `CmsTrackGrid`'s per-row Edit routes to the reconciled destination.
- The single-Cut-track edit affordance behaves per the reconciliation decision (documented at
implementation time): either it opens the parent release in `BatchEdit`, or `BatchEdit` accepts a
track-addressed entry that pre-selects the row.
- No dangling references to `TrackNew` / `TrackEdit` routes remain in live navigation.
- Net CMS form-code surface is reduced (two fewer routable forms to maintain).
**Architectural vs. mechanical (assessment).** **Architectural — staff-engineer territory.** This is not
a localized edit: it changes the CMS route map (two routes removed/redirected), removes two routable
components, and — most importantly — **changes the single-track edit addressing model** (track-id vs.
release-title), which carries a navigation-behaviour decision (does editing a Cut track open its whole
release?). That decision touches how Track mode's per-row Edit behaves and may require `BatchEdit` to
accept a new addressing mode. Route-map changes + component removal + a navigation-model decision is
squarely staff-engineer scope, not a maintenance pass.
**Dependencies.** Independent of 8.L (8.L lands the batch-form name-collapse regardless). Coordinates
with **8.E** (the Add-Track buttons already target `/tracks/upload`, so 8.E and 8.M agree on the upload
route). Best sequenced **after** 8.L so the batch single-track branch is already name-consolidated when
it becomes the sole single-track path. Lower priority than the name-collapse — see split rationale in §5.
---
@@ -584,6 +667,20 @@ sequenced as a post-Phase-9 implementation wave.
**independent** of the tab work; touch the upload/edit forms. Sequence **8.G → 8.L** (the consolidated
field should read "Release Name" first), and **coordinate 8.E/8.F/8.L** — all three touch the Session
upload form and its submit handler.
- **8.M** (legacy single-track form retirement) — **architectural** (route-map change + component
removal + single-track edit addressing decision; staff-engineer scope). Independent of 8.L for build;
best sequenced **after** 8.L so the batch single-track branch is already name-consolidated when it
becomes the sole single-track path. **Lower priority than 8.L** — see split rationale below.
**8.L / 8.M split rationale.** These were one item ("consolidate the names"); they are now two because
they have different cost and risk. **8.L is mechanical-to-moderate, self-contained, and high-value**
collapse two name inputs to one on the batch forms via a `BatchTrackDetail` flag, sync the derived track
name on save. It touches no routes and no component graph. **8.M is architectural** — retiring
`TrackNew`/`TrackEdit` means a route-map change, two component removals, and a real decision about
whether editing a single Cut track opens its whole release (the track-id vs. release-title addressing
gap). Bundling them would gate the cheap, safe name-collapse behind the route/navigation decision. Split
so **8.L lands independently and immediately**, and **8.M follows when the addressing reconciliation is
decided**. They share intent ("one name, fewer forms") but not blast radius.
**Public cluster:**
- **8.J** (popover dismissal bug) — **independent**; can land immediately (but coordinate with 8.I if
@@ -597,9 +694,12 @@ sequenced as a post-Phase-9 implementation wave.
dispatchable straight from `phase-9-mix-visualizer-redesign.md`. Does not gate Phase 9 completion.
**Recommended sequencing.** Land the independent/trivial items first (8.G, 8.D, 8.J), then 8.L
(consolidation, after 8.G). Then the CMS spine (8.B → 8.A → 8.C/8.E), folding 8.F into the Session-form
work alongside 8.E/8.L. On the public side, 8.H (the new release-cardinal archive) → 8.I. **Phase 9
closes when 8.A8.J + 8.L land; 8.K is explicitly excluded** and runs as a separate post-Phase-9 wave.
(name-collapse, after 8.G). Then the CMS spine (8.B → 8.A → 8.C/8.E), folding 8.F into the Session-form
work alongside 8.E/8.L. On the public side, 8.H (the new release-cardinal archive) → 8.I. **8.M**
(legacy-form retirement) sequences after 8.L and is **not a Phase-9-completion gate** — it is a
code-surface-reduction follow-on, not a taxonomy-reach correction; it can land in Wave 8's tail or just
after. **Phase 9 closes when 8.A8.J + 8.L land; 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 consolidation follow-on that can trail).
---
@@ -619,9 +719,13 @@ acceptance criteria above.
warning when a Session is submitted without a hero image.
5. **(8.E) `ALL`-tab Add Track default medium → Cut.** The medium selector remains user-changeable after
landing on the upload form.
6. **(8.L, recommendation pending confirm) Single-track name sync.** Recommended posture: keep the
derived track name **synced** to the Release Name for Session/Mix on both create and edit, so they
never diverge. (Daniel set the consolidation requirement; the sync-vs-diverge interaction detail is
the one open recommendation — call it out, default to synced.)
7. **(8.K) Mix Visualizer → out of Phase-9 scope, design-complete.** Documented in full now; built
6. **(8.L) Single-track name sync → CONFIRMED synced.** The derived track name is kept **synced** to
the Release Name for Session/Mix on both create and edit, so they can never diverge. (Daniel,
2026-06-13 — was the one open recommendation; now decided.)
7. **(8.M) Legacy single-track forms → CONSOLIDATE / retire.** Daniel (2026-06-13): "I would prefer to
consolidate the forms and reduce the code surface if possible." `TrackNew`/`TrackEdit` are folded
into the batch forms and retired, not patched in place. Split from 8.L (the name-collapse) because
8.M is architectural (route map + addressing model) while 8.L is self-contained. 8.M is not a
Phase-9-completion gate.
8. **(8.K) Mix Visualizer → out of Phase-9 scope, design-complete.** Documented in full now; built
later. Phase 9 closes without it.