docs: resolve four Phase 17 open questions (OQ1/OQ4/OQ8/OQ10), defer ReleaseGallery card affordance

This commit is contained in:
daniel-c-harvey
2026-06-19 13:42:19 -04:00
parent a715f4b28d
commit ebbaa3f84f
8 changed files with 177 additions and 63 deletions
+28 -16
View File
@@ -249,7 +249,7 @@ The phase deferred behind the home-hero **Plays** stat card (`NowPlayingStats.ra
**Sequenced BOTTOM-UP (Daniel directive 2026-06-19): foundation first, the live card LAST.** Reverses the earlier "visible win early" framing — Daniel does not care about the live card until the whole substrate and all metrics are finished. Strict chain: `16.1 → 16.2 → 16.3 → (16.4 optional) → 16.5`. 16.1 is the only cold-start wave; 16.5 (the card) is the capstone built last.
- **16.1 — Foundation: capture seam + transport + event log (nothing reads it yet).** Player-service play tracker (high-water mark + engagement floor), share tracker in `SharePopover` (debounced), `sendBeacon` interop + unload handler, `POST api/event/{play,share}` (proxied, rate-limited), append-only `play_event`/`share_event` log + incremental `play_counter` rollup, server-side release resolution + derived release totals. **No `anonId` yet; no card consumption.** Cold-start wave.
- **16.1 — Foundation: capture seam + transport + event log (nothing reads it yet).** Player-service play tracker (high-water mark + engagement floor), share tracker in `SharePopover` (debounced), `sendBeacon` interop + unload handler, `POST api/event/{play,share}` (proxied, rate-limited), append-only `play_event`/`share_event` log + incremental `play_counter` rollup, server-side release resolution + derived release totals. **No `anonId` yet; no card consumption.** Cold-start wave. **Landed:** 2026-06-19 on dev. Migration `20260619155610_AddPlayShareTelemetry` authored but not applied (Daniel-gated).
- **16.2 — Completion-bucket classification + shares.** Three-bucket classification (D1) correct and exhaustive end to end (tracker → payload → log → per-bucket counter columns); share-channel split (link/embed). **Depends on 16.1.**
- **16.3 — Unique-listener `anonId` layer (lowest-priority metric, D5).** Option A: mint/read client first-party `localStorage` id, thread `anonId` onto payloads (nullable in the log), count distinct server-side (all-time, D3). **The last metric layer** — folded into "everything finished," explicitly last-built of the substrate. **Depends on 16.1; builds on 16.2.**
- **16.4 — Per-target / CMS stats surfaces.** `[speculative]``GET api/stats/{track,release}/{key}` + CMS analytics views (bucket/channel splits, leaderboards). Not committed; the event log already supports it. Off the critical path to the card; build before the capstone only if a surface wants it. **Depends on 16.116.3.**
@@ -281,11 +281,15 @@ pre-queue self):
**read-only** for shared release queues (no reorder, no remove); the embed iframe is resized to fit
the panel.
4. **Add to Queue** affordance — an icon button + tooltip beside every detail-page play button for a
release (→ `EnqueueRange`) or track (→ `Enqueue`), lighting up the dormant `Enqueue` path.
release (→ `EnqueueRange`) or track (→ `Enqueue`), lighting up the dormant `Enqueue` path. Scoped
to the detail-page play sites (Cut header, Cut track rows, Session/Mix hero); **`ReleaseGallery`
browse-grid cards are excluded** (no play button today — deferred per OQ10, captured in `TODO.md`).
**Architectural spine.** Engine grows **two additive members only**`Move(from, to)` and
**Architectural spine.** Engine grows **two additive members**`Move(from, to)` and
`RemoveAt(index)` — interop-free state mutations that re-emit `QueueChanged` and **never re-stream or
interrupt the playing track** (the engine's stated open/closed posture; existing members untouched).
interrupt the playing track** (the engine's stated open/closed posture; existing members untouched),
**plus a small additive `Enqueue`-into-dormant affordance** (OQ8: append leaves a coherent
`CurrentIndex` so the next play/skip is correct, without auto-playing).
Both view modes render **one shared `QueueList` presentational component** off the same cascaded
`IQueueService.Items`, differing only in presentation + an `Editable` flag (project memory: *one
source, multiple views*). Reorder/remove run safely during prerender (no JS) — only playback
@@ -293,22 +297,30 @@ transitions touch interop.
**Sequenced as three waves.** `17.1 → {17.2, 17.3}`. **17.1 (engine `Move`/`RemoveAt` + the shared
`QueueList` view) is the cold-start prerequisite**, settled and independent of the UI decisions —
it can begin immediately. 17.2 (docked overlay, editable) and 17.3 (Fixed embed panel + snippet
resize + Add-to-Queue) hang off it and are largely parallel. Add-to-Queue may split to a standalone
17.4 (it needs only the existing `Enqueue`/`EnqueueRange`, not 17.1's new members).
it can begin immediately. 17.2 (docked overlay, editable, `MudDropContainer` reorder) and 17.3 (Fixed
embed panel + snippet resize + Add-to-Queue — **the OQ1 Option-A-vs-B feasibility call is made here**)
hang off it and are largely parallel. Add-to-Queue may split to a standalone 17.4 (it needs only the
existing `Enqueue`/`EnqueueRange`, not 17.1's new members).
Full design — goal, constraints, use cases, acceptance criteria, test cases, wave decomposition, and
the open-question set: `product-notes/phase-17-player-queue-view.md`.
**Open questions (Daniel's call — spec §10).** OQ1 (Queue button behavior in embed mode given the
panel is always shown — recommend repurpose as collapse/expand toggle); OQ2 (click-a-row to jump —
recommend yes, both modes); OQ3 (terminal/empty states after removal); OQ4 (drag mechanism + touch
viability — `MudDropContainer` vs. pointer-interop vs. up/down-arrow fallback; mobile is a primary
surface); OQ5 (Clear-queue in the UI and whether it stops playback); OQ6 (embed panel height —
fixed+scroll vs. grow-to-cap); OQ7 (Material vs. bespoke `DDIcons` glyph); OQ8 (Add-to-Queue into a
dormant/empty queue — recommend pure append, keep "add" ≠ "play"); OQ9 (exclude `StreamNowButton`
no fixed track); OQ10 (`ReleaseGallery` cards — recommend defer; cards have no play button today);
OQ11 (removing the current track — recommend keep playing to natural end). **None block 17.1.**
**Open questions — 4 resolved (Daniel, 2026-06-19), 7 pending (spec §10).**
- **Resolved (Daniel, 2026-06-19):** **OQ1****Option A, conditional** — collapse/expand toggle *if*
the embed snippet can dynamically resize the iframe (`postMessage` → host resize handshake), **else
fall back to Option B** (omit the button); A preferred, B fallback, deciding factor = iframe-resize
feasibility, **determined during 17.3**. **OQ4****`MudDropContainer` for now** (C6 softened —
touch-viability is a known risk with a planned pivot path, not a pre-ship blocker). **OQ8**
**pure append** (add ≠ play; first add into a dormant queue leaves a coherent `CurrentIndex` via the
17.1 engine affordance, no auto-play). **OQ10****deferred** (cards get no Add-to-Queue in Phase
17; deferred card work captured in `TODO.md`).
- **Still pending (recommendations stand, not confirmed):** OQ2 (click-a-row to jump — recommend yes,
both modes); OQ3 (terminal/empty states after removal); OQ5 (Clear-queue in the UI and whether it
stops playback); OQ6 (embed panel height — fixed+scroll vs. grow-to-cap; couples to OQ1's resize
decision); OQ7 (Material vs. bespoke `DDIcons` glyph); OQ9 (exclude `StreamNowButton` — no fixed
track); OQ11 (removing the current track — recommend keep playing to natural end).
- **None block 17.1.**
---