mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
docs(desktop): make live-media testing sheet build-state aware
Tags each section LIVE / PARTIAL / PENDING so it's usable against the current branch, with concrete step→expected tables for the testable Discover + live-bar surfaces and a "test right now" quick path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
18d28cf8ed
commit
daa6022adc
@@ -1,158 +1,150 @@
|
|||||||
# Manual Testing Sheet — Desktop Live Media (NIP-53) v1
|
# Manual Testing Sheet — Desktop Live Media (NIP-53) v1
|
||||||
|
|
||||||
**Plan:** `docs/plans/2026-08-20-feat-desktop-live-media-plan.md`
|
**Plan:** `docs/plans/2026-08-20-feat-desktop-live-media-plan.md`
|
||||||
**Branch:** `feat/desktop-live-media`
|
**Branch / worktree:** `feat/desktop-live-media` · `.claude/worktrees/feat-desktop-live-media`
|
||||||
**Run:** `./gradlew :desktopApp:run`
|
**Run:** `./gradlew :desktopApp:run`
|
||||||
|
|
||||||
This is the acceptance test for the whole v1 feature. Check items off as the corresponding phase
|
Acceptance test for the whole v1 feature. Each section is tagged with its current build state so you
|
||||||
lands. Sections are ordered by implementation phase so you can start testing the earliest layers
|
know what will actually work today:
|
||||||
before the watch screen exists.
|
|
||||||
|
|
||||||
**Legend:** ✅ pass · ❌ fail (note what happened) · ⏭️ blocked/not-yet-built
|
- **🟢 LIVE** — built & compiling; test it now.
|
||||||
|
- **🟡 PARTIAL** — built but with a known gap (called out inline).
|
||||||
|
- **⚪ PENDING** — not built yet; skip until its commit lands.
|
||||||
|
|
||||||
> **Good test streams:** open <https://zap.stream> in a browser to see who is currently live on
|
**Legend for results:** ✅ pass · ❌ fail (write what happened) · ⏭️ skipped/blocked
|
||||||
> Nostr, then find the same hosts in Amethyst. zap.stream streams are real kind-30311 events with
|
|
||||||
> live HLS `.m3u8` URLs and active kind-1311 chat — ideal for end-to-end testing. Have at least one
|
|
||||||
> **live**, one **planned/scheduled**, and one **ended-with-recording** stream in view.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Pre-flight
|
## Setup (do once)
|
||||||
- [ ] App launches, you are logged in with an account that **follows at least one host who streams**
|
- [ ] Open **<https://zap.stream>** in a browser — this shows who is live on Nostr right now with real
|
||||||
(follow a couple of zap.stream regulars if not).
|
kind-30311 streams + kind-1311 chat. Keep it handy as your source of truth.
|
||||||
- [ ] Relays connected (no persistent offline banner).
|
- [ ] Log into Amethyst Desktop with an account that **follows ≥1 host who streams** (follow a couple of
|
||||||
- [ ] (Optional, for zap tests) an NWC wallet is connected under Wallet.
|
the zap.stream front-page hosts if not).
|
||||||
|
- [ ] Confirm relays are connected (no persistent "offline" banner).
|
||||||
|
- [ ] (For later zap tests) connect an NWC wallet under **Wallet**.
|
||||||
|
|
||||||
|
> **Tip:** live streams come and go. If a section says "nobody is live," check zap.stream — if the front
|
||||||
|
> page is also empty, wait for a stream to start rather than recording a failure.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 1 — Data layer (no UI yet; verify via logs / debugging)
|
## 1. Discover → "Live now" 🟢 LIVE
|
||||||
These have no user-facing surface; they're validated indirectly once Phase 2 UI exists. If you build
|
|
||||||
with debug logging, confirm:
|
|
||||||
- [ ] Kind **30311** events arriving from relays are stored (one entry per stream address; a
|
|
||||||
re-published 30311 **replaces** the old one, doesn't duplicate).
|
|
||||||
- [ ] Kind **1311** chat events attach to their stream's channel (grouped by the root `a` tag).
|
|
||||||
- [ ] Memory doesn't grow unbounded while a busy stream's chat streams in (channel chat is capped
|
|
||||||
at ~500 messages).
|
|
||||||
|
|
||||||
*(Unit tests already cover the ordering/freshness logic: `./gradlew :commons:jvmTest --tests
|
Open the **Discover** destination. Scroll to the **LIVE NOW** section (below the featured pack hero).
|
||||||
"*.LiveActivitySortingTest"` — should be green.)*
|
|
||||||
|
| # | Step | Expected | Result |
|
||||||
|
|---|------|----------|--------|
|
||||||
|
| 1.1 | Open Discover with ≥1 stream live on the network | A **LIVE NOW** section appears with a red dot header + a search box + a grid of cards | |
|
||||||
|
| 1.2 | Look at card order | **Live** streams first, then **planned** ("starts in…"), then ended; within live, streams where **more of your follows** participate rank higher, then higher **viewer count** | |
|
||||||
|
| 1.3 | Inspect a live card | Shows thumbnail image, a red **LIVE** badge, the **title**, the **host** name, and **"N watching"** when the host reports a viewer count | |
|
||||||
|
| 1.4 | Inspect a planned card | Shows a **"in 2h / in 30m / SCHEDULED"** badge instead of LIVE | |
|
||||||
|
| 1.5 | Type a host's name in the search box | Grid filters live to matching streams as you type | |
|
||||||
|
| 1.6 | Type part of a stream **title** | Filters to matching titles | |
|
||||||
|
| 1.7 | Type a **hashtag** that a live stream uses (e.g. `bitcoin`) | Filters to streams tagged with it | |
|
||||||
|
| 1.8 | Type gibberish (`zzzzz`) | Shows **"No live streams match "zzzzz.""** (grid empty, section still visible) | |
|
||||||
|
| 1.9 | Clear the search | Full ranked grid returns | |
|
||||||
|
| 1.10 | Open Discover when **nothing** is live network-wide | The LIVE NOW section is **absent** (not an empty box) | |
|
||||||
|
| 1.11 | **Known gap:** click a card | Nothing happens yet — the watch screen isn't wired (see §3). Not a bug today. | |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 2 — Discovery & the "live now" bar
|
## 2. Per-column "live now" bar 🟢 LIVE
|
||||||
|
|
||||||
### Discover → Lives
|
| # | Step | Expected | Result |
|
||||||
- [ ] Open **Discover**. A **Lives** section appears when ≥1 stream is known.
|
|---|------|----------|--------|
|
||||||
- [ ] Live streams show first (LIVE badge), then planned ("starts in…"), then ended.
|
| 2.1 | Open a **Following** feed column while a **followed** host is live | A compact pinned bar sits at the **top of that column**, above the feed: red dot + **"<host> is live"** | |
|
||||||
- [ ] Within LIVE, streams with more of **your follows** participating rank higher; among those,
|
| 2.2 | Have **2+** followed hosts live at once | The bar shows the **most-watched** one, plus a **"+N live ›"** link | |
|
||||||
higher viewer count ranks higher.
|
| 2.3 | Click **"+N live ›"** | A dropdown lists all currently-live streams in scope; each entry is clickable | |
|
||||||
- [ ] A `status=live` stream whose video is actually dead is **not** shown as live (sinks/hidden).
|
| 2.4 | Open a **Global** feed column | The bar reflects the **global** live set (typically different/larger than Following) | |
|
||||||
- [ ] Each card shows: thumbnail/image, title, host, LIVE/scheduled badge, viewer count when present.
|
| 2.5 | Scroll the feed | The bar stays **pinned** at the top (doesn't scroll away) and the feed scrolls smoothly beneath it | |
|
||||||
- [ ] **Search box** filters the Lives grid live by **title**, **host name**, and **hashtag** as you type.
|
| 2.6 | Open a column where **nobody in scope** is live | **No bar** is shown (Following bar hidden when no followed host is live) | |
|
||||||
- [ ] Empty states read sensibly: no lives at all; search with no matches.
|
| 2.7 | Open a **hashtag / list / search / notifications** column | **No bar** (by design — v1 scopes the bar to Following + Global only) | |
|
||||||
|
| 2.8 | **Known gap:** click the bar / a dropdown entry | No-op today (watch screen pending, §3) | |
|
||||||
### Per-column "live now" bar
|
|
||||||
- [ ] Open a **Following** feed column. When a followed host is live, a compact pinned bar appears at
|
|
||||||
the **top of that column**, above the feed.
|
|
||||||
- [ ] The bar shows **one** host (the one with the most viewers) with a red LIVE indicator + title,
|
|
||||||
and a **"+N live ›"** affordance when more than one is live.
|
|
||||||
- [ ] Tapping **"+N live ›"** reveals/leads to the rest of the currently-live set.
|
|
||||||
- [ ] Open a **Global** feed column — the bar reflects the **global** live set (different from Following).
|
|
||||||
- [ ] When nobody in a column's audience is live, the bar is **hidden** (no empty bar).
|
|
||||||
- [ ] Scrolling the feed does not cause the bar to flicker/recompute visibly; scrolling is smooth.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 3 — Watch screen (player + chat + zap)
|
## 3. Watch screen — player + chat + zap ⚪ PENDING
|
||||||
|
|
||||||
### Opening / layout
|
*Not built yet. These are the target checks for when the watch commit lands; skip for now.*
|
||||||
- [ ] Click a live card (from Discover or the bar). A **full-window watch screen** opens: video on the
|
|
||||||
**left**, live chat on the **right**, host/metadata below/around.
|
|
||||||
- [ ] Header shows: title, host (avatar+name), participant roles (Host/Speaker/…), viewer count, and a
|
|
||||||
**LIVE** status pill.
|
|
||||||
- [ ] Closing the watch screen returns to where you were (deck/single-pane) and **stops playback**.
|
|
||||||
|
|
||||||
### Video playback (live)
|
### Open / layout
|
||||||
|
- [ ] Clicking a live card or the bar opens a **full-window** watch screen: video **left**, chat **right**, host/metadata below.
|
||||||
|
- [ ] Header shows title, host (avatar + name), participant roles, viewer count, and a **LIVE** pill.
|
||||||
|
- [ ] Closing returns to the prior view and **stops playback**.
|
||||||
|
|
||||||
|
### Video (live)
|
||||||
- [ ] The live stream plays (audio + video).
|
- [ ] The live stream plays (audio + video).
|
||||||
- [ ] **No seek bar** is shown in live mode (a "● LIVE" pill instead of a scrubber).
|
- [ ] **No seek bar** in live mode (a "● LIVE" pill instead).
|
||||||
- [ ] Play/pause and volume work; fullscreen works.
|
- [ ] Play/pause, volume, fullscreen work.
|
||||||
- [ ] Pull your network briefly / stop the source: the player shows **"Reconnecting…"** (not a frozen
|
- [ ] Kill the source briefly → **"Reconnecting…"** (not a frozen frame) → recovers, or an **offline + Retry** state if it stays down.
|
||||||
frame), then recovers when the stream returns, or shows an **offline + Retry** state if it stays down.
|
- [ ] Opening an already-offline stream → offline placeholder, never an endless spinner.
|
||||||
- [ ] A stream that is offline when you open it shows an **offline placeholder**, never an endless spinner.
|
|
||||||
|
|
||||||
### Video playback (VOD / recording)
|
### Video (VOD / recording)
|
||||||
- [ ] Open an **ended** stream that has a recording. It plays the **recording** with a **normal seekable**
|
- [ ] An **ended** stream with a recording plays the recording with a **normal seekable** bar.
|
||||||
seek bar (VOD mode), scrubbing works.
|
- [ ] An ended stream with **no recording** shows "Stream ended — no recording" (non-playable).
|
||||||
- [ ] An **ended stream with no recording** shows a "Stream ended — no recording" state (non-playable),
|
|
||||||
both in the grid and if opened.
|
|
||||||
|
|
||||||
### Live chat (read)
|
### Chat (read)
|
||||||
- [ ] Chat messages (kind 1311) for **this** stream appear on the right, newest at the bottom.
|
- [ ] Kind-1311 messages for this stream appear, newest at bottom.
|
||||||
- [ ] The list auto-scrolls to the newest message **only while you're at the bottom**.
|
- [ ] Auto-scrolls to newest **only while at the bottom**; scrolling up shows a **"↓ N new"** pill.
|
||||||
- [ ] Scroll up: auto-scroll pauses and a **"↓ N new messages"** pill appears; clicking it snaps to bottom.
|
- [ ] Hovering chat pauses auto-scroll; leaving resumes.
|
||||||
- [ ] Hovering the chat pauses auto-scroll (mouse-first); moving away resumes.
|
- [ ] **Muted/blocked** users' messages don't appear; muting mid-stream hides existing ones immediately.
|
||||||
- [ ] Messages from **muted/blocked** users do **not** appear; muting someone mid-stream hides their
|
- [ ] A busy stream stays smooth (messages may batch slightly).
|
||||||
existing messages immediately.
|
|
||||||
- [ ] A very busy stream stays smooth (no UI jank/freeze); messages may batch slightly (expected).
|
|
||||||
|
|
||||||
### Live chat (post)
|
### Chat (post)
|
||||||
- [ ] Type a message and send. It appears in the chat (as a kind-1311 with the correct stream `a` tag),
|
- [ ] Sending posts a kind-1311 with the correct stream `a` tag (verify it shows on zap.stream).
|
||||||
visible to other clients (verify on zap.stream if possible).
|
- [ ] Composer is **disabled with a reason** when logged out / no relays / stream ended (draft preserved).
|
||||||
- [ ] Sending with **no relays connected** / **logged out** shows a clear disabled reason, not a silent failure.
|
|
||||||
- [ ] When the stream **ends** while you're watching: an "ended" banner shows, the composer is **disabled**
|
|
||||||
("stream ended"), chat stays **readable**, and a **"Play recording"** action appears if a recording exists.
|
|
||||||
The window does **not** auto-close.
|
|
||||||
|
|
||||||
### Zapping the stream
|
### Zap
|
||||||
- [ ] A **Zap** action is available for the stream. Zapping opens the amount dialog and sends via NWC.
|
- [ ] **Zap** the stream → amount dialog → sends via NWC; receipt attributed to the 30311.
|
||||||
- [ ] Zap is **disabled with a reason** when the recipient has no lightning address, or when no NWC wallet
|
- [ ] Zap **disabled with reason** when the host has no lightning address or no NWC wallet is connected.
|
||||||
is connected (routes you to connect).
|
- [ ] *(Per-message chat zap + top-zappers leaderboard are v1.5 — not expected.)*
|
||||||
- [ ] Zap receipt is attributed to the **stream** (30311), and the amount reflects in the stream's totals.
|
|
||||||
*(Per-message chat zap + a top-zappers leaderboard are **deferred to v1.5** — not expected here.)*
|
|
||||||
|
|
||||||
### Mid-watch transitions & re-entry
|
### Lifecycle / re-entry
|
||||||
- [ ] Host edits the title/adds participants mid-stream (30311 re-published): the header updates live.
|
- [ ] Host edits title/participants mid-stream → header updates live.
|
||||||
- [ ] While watching one stream, open a **second** stream from the bar/Discover: the first tears down
|
- [ ] Stream ends mid-watch → "ended" banner, composer disabled, "Play recording" offered; window does **not** auto-close.
|
||||||
cleanly (video + chat stop) and the second starts — no double audio, no leaked chat.
|
- [ ] Opening a **second** stream tears down the first cleanly (no double audio, no leaked chat).
|
||||||
- [ ] Open a stream via a **direct naddr/nevent link**: it resolves, shows a loading state, then the live/
|
- [ ] Opening via a direct **naddr/nevent** link resolves + loads; unknown → clear message, no hang.
|
||||||
ended/offline branch. An unknown/not-found address shows a clear message (never hangs).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 4 — Profile Streams tab & planned streams
|
## 4. Profile "Streams" tab ⚪ PENDING
|
||||||
- [ ] Open a streaming host's **profile**. A **Streams** tab lists their streams (live + past).
|
- [ ] A streaming host's **profile** has a **Streams** tab listing their live + past streams.
|
||||||
- [ ] A live stream in the tab is marked LIVE and opens the watch screen; a past one with a recording
|
- [ ] A live entry opens the watch screen; a past one with a recording plays VOD.
|
||||||
plays VOD.
|
|
||||||
- [ ] A **planned** stream anywhere shows a **"starts in…" badge**. *(A "Remind me" action is **deferred**
|
## 5. Planned streams 🟡 PARTIAL
|
||||||
— not expected in v1.)*
|
- [ ] Planned streams show a **"starts in…"** badge in the Discover grid. 🟢 (works now)
|
||||||
- [ ] A planned stream whose start time passed long ago and never went live is relabeled/downranked
|
- [ ] A planned stream whose start passed long ago and never went live is relabeled/downranked. ⚪ (pending online/overdue wiring)
|
||||||
(not stuck showing "starts in -3h").
|
- [ ] *(No "Remind me" in v1 — badge only, by design.)*
|
||||||
|
|
||||||
|
## 6. Online-probe / dead streams ⚪ PENDING
|
||||||
|
- [ ] A `status=live` stream whose `.m3u8` is actually dead is **not** shown as live (sinks/hidden).
|
||||||
|
*Today all `status=live` are treated as online — this downgrade is not wired yet.*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cross-cutting / regression
|
## 7. Cross-cutting / security & regression 🟡 PARTIAL (mostly pending)
|
||||||
- [ ] **Security:** the app only plays `https` stream URLs; a stream with a `file://`/`smb://`/custom-scheme
|
- [ ] ⚪ App only plays `https` stream URLs; `file://`/`smb://`/custom-scheme URLs are refused (incl. the "open in default player" fallback).
|
||||||
URL is refused (no OS handler is invoked, incl. the "open in default player" fallback).
|
- [ ] ⚪ No drive-by HEAD probing of every cached stream URL (probe only what's needed for visible cards).
|
||||||
- [ ] **Privacy:** the app does not probe stream URLs you never chose to interact with beyond what's needed
|
- [ ] ⚪ Chat messages with bidirectional/control unicode render without reordering surrounding UI.
|
||||||
to show live/offline for visible cards (no drive-by HEAD storm to every stream in the cache).
|
- [ ] 🟢 Existing feed video (NowPlayingBar) still works; existing feeds/Discover unaffected by the new section.
|
||||||
- [ ] **Chat safety:** a chat message containing bidirectional/control unicode renders without reordering
|
- [ ] 🟢 `./gradlew :commons:jvmTest --tests "*.LiveActivitySortingTest"` passes.
|
||||||
surrounding UI text.
|
- [ ] ⚪ Full build green: `./gradlew :desktopApp:compileKotlin :amethyst:compileDebugKotlin` + `spotlessApply` clean.
|
||||||
- [ ] Existing feed video (NowPlayingBar) still works; opening a live takes over playback and closing it
|
|
||||||
leaves the player in a clean state (no stale live position leaking into later feed/VOD video).
|
|
||||||
- [ ] No new crashes; `./gradlew :commons:jvmTest :desktopApp:test` green; `./gradlew spotlessApply` clean.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Platform notes
|
## Platform notes
|
||||||
- **macOS** (AVFoundation): primary test target.
|
- **macOS** (AVFoundation): primary target for the video tests.
|
||||||
- **Linux** (GStreamer): must be installed at runtime; live HLS reconnection behaviour differs — spot-check.
|
- **Linux** (GStreamer): must be installed at runtime; live-HLS reconnection differs — spot-check when watch lands.
|
||||||
- **Windows** (Media Foundation): native live HLS is weakest; verify the stall watchdog/reconnect carries it.
|
- **Windows** (Media Foundation): weakest native live HLS — the stall watchdog/reconnect must carry it.
|
||||||
|
|
||||||
|
## Known v1 limitations (by design — not bugs)
|
||||||
|
No broadcasting; no audio rooms / raids / clips; no per-message chat zap or leaderboard (v1.5); no OS
|
||||||
|
notifications / "Remind me" (badge only); live bar only on Following + Global columns.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Known v1 limitations (by design — not bugs)
|
### Quick "test right now" path (today's build)
|
||||||
- No broadcasting / going live.
|
1. `./gradlew :desktopApp:run`, log in, ensure ≥1 stream is live (check zap.stream).
|
||||||
- No audio rooms / Nests, raids, or clips.
|
2. **Discover → LIVE NOW**: see the grid, confirm ranking (§1.2), try search (§1.5–1.9).
|
||||||
- No per-message chat zap or top-zappers leaderboard (v1.5).
|
3. **Home → Following** and **Global**: confirm the pinned live bar + "+N live ›" (§2).
|
||||||
- No OS-level notifications / "Remind me" for planned streams (badge only).
|
4. Everything in §3–§7 marked ⚪/🟡-pending is expected **not** to work yet — that's the next build.
|
||||||
- Live bar only on **Following** and **Global** columns (not hashtag/list/search columns).
|
|
||||||
|
|||||||
Reference in New Issue
Block a user