mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
test: unpack testing sheet into linear playbook
Rewrites the manual testing sheet so every step is an executable action or a specific observation: - Numbered steps within each test — no jumping between reference sections. "Click X", "run Y in a terminal", "watch for Z". - Each observation records YES/NO/SKIPPED for the sign-off matrix. - Setup section spells out the wipe-preferences command and the post-restart smoke check. - T3 broken into T3.a/b/c/d for each button and its persistence check separately (previously bundled T3.1–T3.10 was too dense). - T6/T7 include exact tcpdump/tshark commands for the security observations that require packet capture. - T13 shortened to a sanity re-check (already verified). - Sign-off table lists every test with a checkbox. Purpose: give the tester a self-contained document they can follow top to bottom in ~40 min without cross-referencing other sheets.
This commit is contained in:
@@ -1,322 +1,661 @@
|
||||
# Desktop DM Reliability — Full Testing Sheet
|
||||
# Desktop DM Reliability — Testing Playbook
|
||||
|
||||
**Branch:** `feat/desktop-dm-reliability` (rebased onto `origin/main` 2026-06-17; head at commit `a139c0fb17` after the pre-send fix)
|
||||
**Companion:** [2026-06-12-desktop-dm-reliability-testing-sheet.md](2026-06-12-desktop-dm-reliability-testing-sheet.md) (automated section)
|
||||
**Tester:**
|
||||
**Build:** `./gradlew :desktopApp:run` (or launch `Amethyst.app` from `desktopApp/build/compose/binaries/main/app/`)
|
||||
**Branch:** `feat/desktop-dm-reliability` at `fcfc43eb44` (21 commits)
|
||||
**Tester:** _______________________
|
||||
**Date:** _______________________
|
||||
|
||||
## Post-rebase reality
|
||||
|
||||
Upstream shipped its own NIP-42 AUTH work while our branch was in flight (commit `328790ac9f` — `feat: time-bound signer grants, last-used tracking, and relay AUTH settings`). After rebase, both systems coexist:
|
||||
|
||||
- **Upstream (Android-focused):** `RelayAuthPolicy` enum + `RelayAuthPermissionLedger` + `RelayAuthSettingsScreen` + relay URL now passed to the `signWithAllLoggedInUsers` lambda.
|
||||
- **Ours (Desktop-focused):** `DesktopAuthCoordinator` + `AuthApprovalPolicy` (2-tier auto/prompt) + inline `AuthApprovalBanner` + `PreferencesAuthApprovalStore` + `RelayAuthSnapshot` StateFlow.
|
||||
|
||||
Both use the same quartz `RelayAuthenticator` seam. On desktop only our path is wired. On Android only upstream's path is wired.
|
||||
|
||||
## Known pre-existing issues (NOT our regressions)
|
||||
|
||||
| Issue | Where | Note |
|
||||
|---|---|---|
|
||||
| `ConcurrentModificationException` at `RelayLatencyTracker.sweep:182` during account switching | commons/relays/health | Documented in memory `desktop_relay_health_cme_crash`. Kills UI thread, coroutines keep running. Avoid rapid switches. |
|
||||
| `NoClassDefFoundError` for `CompressionQuality` on stale gradle daemon | commons/service/upload | Fixed by `./gradlew --stop` + relaunch. Not a code regression. |
|
||||
**Instructions:** Follow this top to bottom. Every step is an action or an observation. Don't skip ahead — later tests assume state from earlier ones. Total ≈ 40 min for full pass.
|
||||
|
||||
---
|
||||
|
||||
## Phase A — Automated verification (Claude ran these — status ✅)
|
||||
## Setup (once, ~3 min)
|
||||
|
||||
Full detail in the companion sheet. Summary of what already passed:
|
||||
|
||||
| # | Check | Status |
|
||||
|---|---|---|
|
||||
| A1.1–A1.5 | Compile every module (quartz, commons, desktopApp, amethyst Android, cli) | ✅ |
|
||||
| A2.1–A2.4 | Test suites (quartz, commons, desktopApp, amethyst Android) | ✅ |
|
||||
| A3 | `./gradlew spotlessCheck` | ✅ |
|
||||
| A4.1 | Distributable builds (`Amethyst.app` produced) | ✅ |
|
||||
| A4.2 | Distributable launches cleanly | ✅ |
|
||||
| A5.1 | Zero `Co-Authored-By` footers in commits | ✅ |
|
||||
| A5.2 | All commits GPG-signed (`G`) | ✅ |
|
||||
| D1.1 | Zero remaining `connectedRelays.value` in NIP-17 paths | ✅ |
|
||||
| D1.2 | Only `DesktopAuthCoordinator` constructs `RelayAuthenticator` | ✅ |
|
||||
| D1.3 | Indexer client is a distinct `NostrClient` instance | ✅ |
|
||||
| D1.4 | Zero `dmInboxOrFallback` usages outside quartz definition | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Phase B — Manual testing walkthrough
|
||||
|
||||
### T0 — Setup (2 min, once)
|
||||
**1.** In a terminal, cd to the worktree and confirm you're on the right commit:
|
||||
|
||||
```bash
|
||||
# From the worktree root
|
||||
git rev-parse HEAD # should be a139c0fb17 or later
|
||||
cd /path/to/AmethystMultiplatform/.worktrees/feat/desktop-dm-reliability
|
||||
git rev-parse HEAD
|
||||
```
|
||||
|
||||
# Wipe prior AUTH grants so T3 starts fresh (macOS)
|
||||
rm -rf ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth 2>/dev/null
|
||||
- Expect: `fcfc43eb44` (or later). If different: `git pull` and re-verify.
|
||||
|
||||
# Launch — leave this terminal visible; I'll read logs from it
|
||||
**2.** Wipe any prior AUTH grants so persistence tests start clean:
|
||||
|
||||
```bash
|
||||
rm -rf ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth
|
||||
```
|
||||
|
||||
**3.** Launch the app (keep this terminal visible — we'll read logs from it):
|
||||
|
||||
```bash
|
||||
./gradlew :desktopApp:run
|
||||
```
|
||||
|
||||
- [ ] **T0.1** Wait for the sidebar to appear (~15–30s cold start, ~5s warm start)
|
||||
- [ ] **T0.2** Log in with your primary account (User A)
|
||||
- Expect: window appears in 15–30 s (cold) / 5 s (warm).
|
||||
|
||||
**4.** In the app, log in with your primary account. Call this **User A**.
|
||||
|
||||
- Expect: sidebar loads, feed populates.
|
||||
|
||||
**5.** In the terminal, look for these two lines (they appear within 5 s of login):
|
||||
|
||||
```
|
||||
[RelayAuthenticator] Init, Subscribe
|
||||
[DesktopAuthCoordinator] AUTH wired for <pubkey8>
|
||||
```
|
||||
|
||||
- **If both appear:** ✅ setup complete. Proceed to T1.
|
||||
- **If either is missing:** STOP. Tell me the terminal output.
|
||||
|
||||
---
|
||||
|
||||
### T1 — Startup wiring smoke check (30 sec, no interaction)
|
||||
## T1 — Startup smoke check (already ✅ during setup)
|
||||
|
||||
Watch the terminal for these two lines within 5s of login:
|
||||
Nothing extra to do — the two log lines above ARE T1.
|
||||
|
||||
- [ ] **T1.1** `[RelayAuthenticator] Init, Subscribe`
|
||||
- [ ] **T1.2** `[DesktopAuthCoordinator] AUTH wired for <pubkey8>`
|
||||
- [ ] **T1.3** No `Exception` / `FATAL` / stack trace lines during startup
|
||||
|
||||
Missing either T1.1 or T1.2 → **stop**, we regressed.
|
||||
|
||||
**Session so far:** ✅ Verified multiple times (`2bad3487`, `04e18cb4`).
|
||||
- [ ] **T1 PASS** — both `Init, Subscribe` and `AUTH wired for <pubkey8>` printed with no exceptions
|
||||
|
||||
---
|
||||
|
||||
### T2 — Tier-1 AUTH (own DM-inbox) — 2 min
|
||||
## T2 — Tier-1 self-DM (no banner) — 2 min
|
||||
|
||||
Verifies the user's own DM-inbox relays auto-AUTH with no banner.
|
||||
**Goal:** verify your own DM-inbox relays auto-AUTH silently.
|
||||
|
||||
- [ ] **T2.1** Open **Chats** in sidebar
|
||||
- [ ] **T2.2** Note the relays connecting (Settings → Relays panel)
|
||||
- [ ] **T2.3** Compose a DM **to yourself** (paste your own npub in a new DM)
|
||||
- [ ] **T2.4** Send "test" — message arrives in your own inbox
|
||||
- [ ] **T2.5** **CRITICAL:** during send, **no AUTH banner** appears at the top of the content area
|
||||
- [ ] **T2.6** No `[AuthApprovalPolicy]` prompt lines in terminal
|
||||
**Steps:**
|
||||
|
||||
Pass criteria: message arrived, no banner.
|
||||
**1.** In the sidebar, click **Chats** (chat bubble icon).
|
||||
|
||||
**2.** At the top of the conversation list, click the **`+` icon** (new conversation).
|
||||
|
||||
**3.** Paste your OWN npub into the recipient field. Confirm.
|
||||
|
||||
**4.** In the message box, type: `t1 self-dm test`
|
||||
|
||||
**5.** Watch the top of the content area (where the yellow banner would appear).
|
||||
|
||||
- **Expected:** send button enables blue → no yellow AUTH banner appears anywhere.
|
||||
|
||||
**6.** Click the **send arrow** (right side of the message box).
|
||||
|
||||
**7.** Wait 3 s. The message should appear in your inbox.
|
||||
|
||||
- **Expected:** message appears in the conversation. Terminal has NO `AuthApprovalPolicy` prompt lines.
|
||||
|
||||
**Record:**
|
||||
|
||||
- [ ] **T2.1** No AUTH banner appeared: **YES / NO**
|
||||
- [ ] **T2.2** Message arrived: **YES / NO**
|
||||
- [ ] **T2 PASS** — both YES
|
||||
|
||||
---
|
||||
|
||||
### T3 — Tier-2 AUTH banner + persistence — 5 min
|
||||
## T3 — Tier-2 banner + persistence — 8 min
|
||||
|
||||
Trigger a challenge from an AUTH-required relay NOT in your `kind:10050`.
|
||||
**Goal:** trigger a challenge from an AUTH-required relay NOT in your `kind:10050`, verify the banner renders + all three buttons persist correctly.
|
||||
|
||||
- [ ] **T3.1** Settings → Relays → Add relay → paste `wss://pyramid.fiatjaf.com`
|
||||
- [ ] **T3.2** Wait 1–3s for connect + AUTH challenge
|
||||
- [ ] **T3.3** **CRITICAL:** yellow banner appears at the top of the content area:
|
||||
- Relay URL shown (with 80dp left margin, clear of macOS traffic lights ✅ fixed in `fb2d004c73`)
|
||||
- Text: "requires authentication to deliver this message"
|
||||
- Buttons: `[Once]` `[Always]` `[Never]`
|
||||
- [ ] **T3.4** Click `[Once]` → banner slides away; AUTH proceeds for the session only
|
||||
- [ ] **T3.5** Restart app → same relay challenges again → banner reappears (ONCE was session-only)
|
||||
- [ ] **T3.6** This time click `[Always]` → banner slides away
|
||||
- [ ] **T3.7** Restart app → challenge from same relay does NOT show banner (auto-signed)
|
||||
- [ ] **T3.8** Inspect Preferences: `cat ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/<full-pubkey>/prefs.xml` → contains `<entry key="wss://pyramid.fiatjaf.com/">ALWAYS</entry>`
|
||||
- [ ] **T3.9** Add a different AUTH-required relay → banner → click `[Never]` → Preferences shows `BLOCKED`
|
||||
- [ ] **T3.10** Restart → BLOCKED relay never surfaces a banner AND never sends AUTH (relay status: "not authenticated")
|
||||
### T3.a — Trigger the banner
|
||||
|
||||
**Session so far:** T3.3 ✅ banner rendered (see screenshot 2026-07-06 at 15:20:38). Padding fixed. Rest pending your test.
|
||||
**1.** Open Settings. (Look for a gear/cog icon in the sidebar. If absent, try the app menu → Settings.)
|
||||
|
||||
**2.** Go to the **Relays** tab.
|
||||
|
||||
**3.** Find the "Add relay" input. Paste: `wss://pyramid.fiatjaf.com`
|
||||
|
||||
**4.** Save/apply (button label varies — usually "Add" or "Save").
|
||||
|
||||
**5.** Wait 1–3 s. Watch the **top of the content area** (below the title bar, above the main content).
|
||||
|
||||
- **Expected:** a yellow-tinted horizontal row slides in showing:
|
||||
- Lock icon on the left (with proper margin from window edge — 80dp — not overlapping the traffic lights)
|
||||
- `pyramid.fiatjaf.com` in a semi-bold heading
|
||||
- Subtext: "requires authentication to deliver this message"
|
||||
- Three buttons on the right: **`Once`** **`Always`** **`Never`**
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T3.a.1** Banner appeared within 3 s: **YES / NO**
|
||||
- [ ] **T3.a.2** Icon + text NOT overlapping traffic lights: **YES / NO**
|
||||
- [ ] **T3.a.3** All three buttons visible: **YES / NO**
|
||||
|
||||
### T3.b — `[Once]` behaviour (session-only, no persistence)
|
||||
|
||||
**6.** Click `Once`.
|
||||
|
||||
- **Expected:** banner slides away immediately, no visible change to relay state.
|
||||
|
||||
**7.** In a second terminal, check the Preferences file did NOT get written for this relay:
|
||||
|
||||
```bash
|
||||
cat ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/<your-full-pubkey>/prefs.xml 2>/dev/null | grep pyramid
|
||||
```
|
||||
|
||||
- **Expected:** empty output (ONCE is not persisted).
|
||||
|
||||
**8.** Close the app (Cmd+Q). Wait 2 s. Relaunch via `./gradlew :desktopApp:run`. Log in as A again.
|
||||
|
||||
**9.** Wait ~5 s. The banner for `pyramid.fiatjaf.com` should reappear (session state was not saved).
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T3.b.1** After `[Once]`: Preferences NOT written: **YES / NO**
|
||||
- [ ] **T3.b.2** After restart: banner reappeared: **YES / NO**
|
||||
|
||||
### T3.c — `[Always]` behaviour (persisted grant)
|
||||
|
||||
**10.** In the banner that just reappeared, click `Always`.
|
||||
|
||||
- **Expected:** banner slides away, `pyramid.fiatjaf.com` now shows "Authenticated" in Settings → Relays.
|
||||
|
||||
**11.** Check Preferences was written:
|
||||
|
||||
```bash
|
||||
cat ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/<your-full-pubkey>/prefs.xml | grep pyramid
|
||||
```
|
||||
|
||||
- **Expected:** line containing `wss://pyramid.fiatjaf.com/` and `ALWAYS`.
|
||||
|
||||
**12.** Close app (Cmd+Q). Relaunch. Log in as A.
|
||||
|
||||
- **Expected:** relay auto-authenticates in the background. **No banner appears** for `pyramid.fiatjaf.com`.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T3.c.1** Preferences shows `ALWAYS`: **YES / NO**
|
||||
- [ ] **T3.c.2** After restart: no banner, auto-authenticated: **YES / NO**
|
||||
|
||||
### T3.d — `[Never]` behaviour (persisted block)
|
||||
|
||||
**13.** Add a different AUTH-required relay. If you have another, use it. Otherwise, try `wss://nostr.wine` (they AUTH-challenge non-subscribers) or `wss://relay.snort.social`.
|
||||
|
||||
**14.** Wait for the new banner to appear.
|
||||
|
||||
**15.** Click `Never`.
|
||||
|
||||
- **Expected:** banner disappears. The relay shows as connected but "not authenticated".
|
||||
|
||||
**16.** Check Preferences:
|
||||
|
||||
```bash
|
||||
cat ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/<your-full-pubkey>/prefs.xml | grep <relay-domain>
|
||||
```
|
||||
|
||||
- **Expected:** line with `BLOCKED`.
|
||||
|
||||
**17.** Restart the app. Log in as A.
|
||||
|
||||
- **Expected:** the BLOCKED relay never surfaces a banner. It stays "not authenticated". No `kind:22242` AUTH event ever sent to it.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T3.d.1** Preferences shows `BLOCKED`: **YES / NO**
|
||||
- [ ] **T3.d.2** After restart: no banner, no AUTH sent: **YES / NO**
|
||||
|
||||
---
|
||||
|
||||
### T4 — Multiple concurrent banners stack — 2 min
|
||||
**T3 sign-off:** Complete `T3.a`, `T3.b`, `T3.c`, `T3.d`.
|
||||
|
||||
- [ ] **T4.1** Add 3 different AUTH-required relays back-to-back (before dismissing any)
|
||||
- [ ] **T4.2** All 3 rows stack vertically
|
||||
- [ ] **T4.3** Dismiss middle one with `[Once]` → only that row disappears
|
||||
- [ ] **T4.4** (Stress) Add 5+ → top 3 visible, "+N more relays pending approval" row at bottom
|
||||
- [ ] **T3 PASS** — all four subs green
|
||||
|
||||
---
|
||||
|
||||
### T5 — Per-account isolation + logout — 3 min
|
||||
## T4 — Multiple concurrent banners — 3 min
|
||||
|
||||
- [ ] **T5.1** Approve one relay with `[Always]` on account A
|
||||
- [ ] **T5.2** Log out (watch terminal for coordinator teardown — no exceptions)
|
||||
- [ ] **T5.3** Log in as account B → add same AUTH-required relay → banner appears (B has no persisted approval)
|
||||
- [ ] **T5.4** Verify B's `[Always]` writes to B's Preferences node, NOT A's:
|
||||
- `ls ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/` → both A's and B's pubkey directories present
|
||||
- [ ] **T5.5** Log back into A → same relay does NOT re-prompt (A's `[Always]` persisted)
|
||||
**Goal:** verify multiple pending banners stack correctly and resolve independently.
|
||||
|
||||
**Session so far:** ✅ A/B switching seen in log (`2bad3487` ↔ `04e18cb4`), coordinator wires cleanly on every switch. Isolation confirmed at the logging level.
|
||||
**Steps:**
|
||||
|
||||
**1.** In Settings → Relays, quickly add 3 different AUTH-required relays back-to-back. Suggested set:
|
||||
- `wss://pyramid.fiatjaf.com` (if not already blocked/allowed)
|
||||
- `wss://relay.nostr.com.au`
|
||||
- `wss://nostr.wine`
|
||||
|
||||
**2.** Watch the banner area — all 3 rows should appear stacked vertically within ~3 s.
|
||||
|
||||
**3.** Click `Once` on the **middle** row.
|
||||
|
||||
- **Expected:** ONLY the middle row disappears. The other two remain visible.
|
||||
|
||||
**4.** (Optional stress test) Add 5+ more AUTH-required relays.
|
||||
|
||||
- **Expected:** first 3 shown inline; row at the bottom reads "+N more relays pending approval".
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T4.1** 3 banners stack vertically: **YES / NO**
|
||||
- [ ] **T4.2** Middle-row dismiss only affects itself: **YES / NO**
|
||||
- [ ] **T4.3** "+N more" row shows when >3 pending: **YES / NO**
|
||||
- [ ] **T4 PASS** — all three YES
|
||||
|
||||
---
|
||||
|
||||
### T6 — NIP-17 send: no-10050 recipient (P0 SECURITY FIX) — 5 min
|
||||
## T5 — Per-account isolation — 4 min
|
||||
|
||||
**Most important test.** Verify DMs no longer leak to your own relays when recipient has no `kind:10050`.
|
||||
**Goal:** verify AUTH grants are scoped per-account and cleaned on logout.
|
||||
|
||||
- [ ] **T6.1** Find or fabricate a Nostr account with NO `kind:10050`:
|
||||
- Generate a fresh nsec via `nak` or similar (won't have any events)
|
||||
- Or use an old npub known to have never used NIP-17
|
||||
- [ ] **T6.2** Attempt to send a DM to that npub
|
||||
- [ ] **T6.3** **Expected pre-branch:** wrap silently broadcast to your `connectedRelays.value`
|
||||
- [ ] **T6.4** **Expected post-branch:** UI shows "Recipient has no DM relay list — messages cannot be delivered" AND Send button is disabled → **zero gift wraps published**
|
||||
- [ ] **T6.5** Optional network inspection:
|
||||
- `sudo tcpdump -i any -A 'tcp port 443' | grep 1059` — should stay empty during the test
|
||||
- [ ] **T6.6** After the [pre-send fix commit `a139c0fb17`] — if the peer publishes `kind:10050` mid-session and the resolver probe runs (see T13), the block should clear automatically without reopening the conversation
|
||||
**Steps:**
|
||||
|
||||
**Session so far:** ✅ Confirmed — screenshot showed the "Recipient has no DM relay list" red UI blocking the send.
|
||||
**1.** Ensure A has at least one `ALWAYS` grant (from T3.c: `pyramid.fiatjaf.com`).
|
||||
|
||||
**2.** Log out of A (sidebar → profile → Logout, or app menu).
|
||||
|
||||
- **Terminal:** watch for `DesktopAuthCoordinator` teardown lines (no exceptions).
|
||||
|
||||
**3.** Log in as User B (different pubkey — nsec, npub, or bunker).
|
||||
|
||||
- **Terminal:** expect `[DesktopAuthCoordinator] AUTH wired for <B-pubkey8>` — different from A's.
|
||||
|
||||
**4.** Add `wss://pyramid.fiatjaf.com` in Settings → Relays for B.
|
||||
|
||||
- **Expected:** banner appears (B does NOT inherit A's `ALWAYS` grant).
|
||||
|
||||
**5.** Check that A's and B's Preferences are separate:
|
||||
|
||||
```bash
|
||||
ls ~/.java/.userPrefs/com/vitorpamplona/amethyst/desktop/auth/
|
||||
```
|
||||
|
||||
- **Expected:** two directories, one per full pubkey.
|
||||
|
||||
**6.** Click `Always` on B's banner.
|
||||
|
||||
**7.** Log out of B. Log back into A.
|
||||
|
||||
- **Terminal:** `AUTH wired for <A-pubkey8>` again.
|
||||
|
||||
**8.** Watch for banners.
|
||||
|
||||
- **Expected:** no banner for `pyramid.fiatjaf.com` (A's `ALWAYS` still persisted).
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T5.1** Coordinator teardown clean on logout (no exceptions): **YES / NO**
|
||||
- [ ] **T5.2** B sees banner for A-approved relay (isolation): **YES / NO**
|
||||
- [ ] **T5.3** Two separate Preferences dirs exist: **YES / NO**
|
||||
- [ ] **T5.4** Re-login to A: no re-prompt: **YES / NO**
|
||||
- [ ] **T5 PASS** — all four YES
|
||||
|
||||
---
|
||||
|
||||
### T7 — Indexer fan-out + F-01 unauth client — 5 min
|
||||
## T6 — P0 security fix (no-10050 recipient) — 5 min
|
||||
|
||||
Verify that when a recipient's `kind:10050` isn't cached, the resolver probes indexers with an **unauthenticated** client.
|
||||
**Goal:** verify DMs are NOT silently broadcast to your general relays when the recipient has no `kind:10050`.
|
||||
|
||||
- [ ] **T7.1** Pick a recipient who HAS a `kind:10050` but whom you've never DM'd (fresh LocalCache miss)
|
||||
- [ ] **T7.2** Compose DM to them → observe brief (sub-second to ~3s) delay
|
||||
- [ ] **T7.3** In terminal, look for connections to the curated indexer set:
|
||||
- `wss://relay.nos.social`
|
||||
- `wss://relay.damus.io`
|
||||
- `wss://nos.lol`
|
||||
- `wss://relay.nostr.band`
|
||||
- `wss://purplerelay.com`
|
||||
- [ ] **T7.4** **CRITICAL — F-01 check.** Verify NO `kind:22242` AUTH event sent on the indexer connections:
|
||||
- `sudo tshark -i any -Y 'websocket && frame contains "22242"'` — should stay empty while indexer probes run
|
||||
- Or manually: even if any indexer AUTH-challenges, the client should silently ignore
|
||||
- [ ] **T7.5** Send succeeds → recipient's actual DM-inbox relay receives the wrap
|
||||
- [ ] **T7.6** Compose another DM to same recipient → resolver hits LRU cache; no second indexer probe
|
||||
### T6.a — Create a "no-inbox" test recipient
|
||||
|
||||
**1.** In a terminal, generate a fresh nsec/npub pair:
|
||||
|
||||
```bash
|
||||
# Option: use nak
|
||||
nak key generate
|
||||
# Copy the printed nsec and npub
|
||||
```
|
||||
|
||||
Or use any known npub of an account that never published `kind:10050`.
|
||||
|
||||
**2.** In Amethyst as A, click **`+`** in Chats. Paste the test npub. Confirm.
|
||||
|
||||
### T6.b — Verify the UI blocks send
|
||||
|
||||
**3.** Type any message.
|
||||
|
||||
**4.** Look at the row below the message input.
|
||||
|
||||
- **Expected:** red text "**Recipient has no DM relay list — messages cannot be delivered**"
|
||||
- **Expected:** send button is grey/disabled.
|
||||
|
||||
**5.** Try clicking send anyway.
|
||||
|
||||
- **Expected:** nothing happens (button disabled). Or, if enabled by upstream UI quirk, `DmSendTracker` shows "No relays available" briefly.
|
||||
|
||||
### T6.c — Verify no wrap leaves the app (optional, for the security-conscious)
|
||||
|
||||
**6.** In a terminal, run:
|
||||
|
||||
```bash
|
||||
sudo tcpdump -i any -A -s 0 'tcp port 443 or tcp port 80' 2>/dev/null | grep -i "kind\":1059"
|
||||
```
|
||||
|
||||
**7.** In the app, try to send. Watch the tcpdump output for 30 s.
|
||||
|
||||
- **Expected:** zero output. No gift wrap (kind 1059) publishes anywhere.
|
||||
|
||||
**8.** Stop tcpdump with Ctrl+C.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T6.1** UI shows "no DM relay list" warning: **YES / NO**
|
||||
- [ ] **T6.2** Send button disabled: **YES / NO**
|
||||
- [ ] **T6.3** No `kind":1059` in outgoing traffic during send attempt: **YES / NO / SKIPPED**
|
||||
- [ ] **T6 PASS** — T6.1 and T6.2 both YES (T6.3 optional but recommended)
|
||||
|
||||
---
|
||||
|
||||
### T8 — NIP-17 relay hint on wrap `p` tag — 3 min
|
||||
## T7 — Indexer fan-out + F-01 unauth check — 6 min
|
||||
|
||||
- [ ] **T8.1** Send a DM to a recipient whose `kind:10050` is cached
|
||||
- [ ] **T8.2** Inspect the wrap via `nak req -k 1059 -a <your-pubkey>` on one of your DM-inbox relays
|
||||
- [ ] **T8.3** Expected `p` tag: `["p", "<recipient-pubkey-hex>", "wss://recipient-primary-relay/"]` (3 elements)
|
||||
- [ ] **T8.4** For a recipient with no known relay: `["p", "<recipient-pubkey-hex>"]` (2 elements, no fake empty third element)
|
||||
**Goal:** verify the resolver probes indexer relays with an UNAUTHENTICATED client (no `kind:22242` AUTH events leaked to indexers).
|
||||
|
||||
### T7.a — Prime the state
|
||||
|
||||
**1.** Restart the app (Cmd+Q, then `./gradlew :desktopApp:run`).
|
||||
|
||||
- Fresh LocalCache = maximum chance the resolver actually fires.
|
||||
|
||||
**2.** Log in as A.
|
||||
|
||||
### T7.b — Set up traffic capture (optional but revealing)
|
||||
|
||||
**3.** In a second terminal, start capturing all WebSocket traffic:
|
||||
|
||||
```bash
|
||||
sudo tshark -i any -Y 'websocket' -T fields -e ws.payload 2>/dev/null | head -c 100000
|
||||
```
|
||||
|
||||
Or (simpler):
|
||||
|
||||
```bash
|
||||
sudo tcpdump -i any -A -s 0 'tcp port 443' 2>/dev/null > /tmp/dm-traffic.log &
|
||||
```
|
||||
|
||||
### T7.c — Trigger the resolver
|
||||
|
||||
**4.** Pick a recipient who HAS a `kind:10050` published (a NIP-17-active account) but whom you have NEVER DM'd from account A.
|
||||
|
||||
**5.** In Amethyst, click **`+`** in Chats. Paste the recipient's npub. Confirm.
|
||||
|
||||
**6.** Watch the pre-send row.
|
||||
|
||||
- **Expected sequence:**
|
||||
- Initial: red "no DM relay list" warning (LocalCache miss).
|
||||
- Within 2–5 s: warning disappears (resolver probe found the recipient's `kind:10050` on an indexer).
|
||||
- Send button turns blue.
|
||||
|
||||
### T7.d — Verify F-01 (no AUTH to indexer)
|
||||
|
||||
**7.** Search the captured traffic for `kind:22242` AUTH events:
|
||||
|
||||
```bash
|
||||
grep -i "\"kind\":22242" /tmp/dm-traffic.log | head -20
|
||||
```
|
||||
|
||||
- **Expected:** any `kind:22242` events found should only be to relays in your existing DM-inbox set — NOT to the indexer set (`relay.nos.social`, `relay.damus.io`, `nos.lol`, `relay.nostr.band`, `purplerelay.com`).
|
||||
|
||||
**8.** In the app, type a message and send.
|
||||
|
||||
- **Expected:** send succeeds. Recipient's actual DM-inbox relay receives the wrap.
|
||||
|
||||
**9.** Stop tcpdump: `sudo pkill tcpdump`
|
||||
|
||||
### T7.e — Verify LRU cache hit on second send
|
||||
|
||||
**10.** Immediately compose a second DM to the same recipient. Send.
|
||||
|
||||
- **Expected:** send is immediate, no delay. Resolver hits its LRU cache, no new indexer probe.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T7.1** Warning cleared within 5 s (resolver probe worked): **YES / NO**
|
||||
- [ ] **T7.2** Send button became enabled after probe: **YES / NO**
|
||||
- [ ] **T7.3** No `kind:22242` AUTH sent to indexer relays: **YES / NO / SKIPPED**
|
||||
- [ ] **T7.4** DM delivered to recipient: **YES / NO**
|
||||
- [ ] **T7.5** Second DM to same recipient: no probe delay: **YES / NO**
|
||||
- [ ] **T7 PASS** — T7.1, T7.2, T7.4, T7.5 all YES
|
||||
|
||||
---
|
||||
|
||||
### T9 — Group DM shared `rumor.id` — 4 min
|
||||
## T8 — Wrap `p`-tag relay hint — 4 min
|
||||
|
||||
- [ ] **T9.1** Create a group DM with 3 recipients
|
||||
- [ ] **T9.2** Send one message
|
||||
- [ ] **T9.3** Inspect wraps via relay UI — all decrypt to a rumor with the **same `id`**
|
||||
- [ ] **T9.4** Have one recipient react (👍)
|
||||
- [ ] **T9.5** Reaction targets the shared rumor id; all participants see the same reaction
|
||||
**Goal:** verify the outgoing gift wrap includes the recipient's primary DM relay as the third element of the `p` tag.
|
||||
|
||||
**Steps:**
|
||||
|
||||
**1.** Send a DM to any recipient with a known `kind:10050` (e.g. the one from T7).
|
||||
|
||||
**2.** In a terminal, use `nak` (or `websocat`) to query one of the recipient's DM-inbox relays for their gift wraps:
|
||||
|
||||
```bash
|
||||
RECIPIENT_HEX=<paste-recipient-hex-pubkey>
|
||||
DM_RELAY=<paste-one-of-their-10050-relays>
|
||||
|
||||
nak req -k 1059 --tag "p=$RECIPIENT_HEX" "$DM_RELAY" | head -5
|
||||
```
|
||||
|
||||
**3.** Find the wrap you just sent (highest `created_at`). Look at its `p` tag.
|
||||
|
||||
- **Expected:** `["p", "<recipient-hex>", "wss://recipient-primary-relay/"]` — 3 elements, third is a valid relay URL.
|
||||
|
||||
**4.** For contrast, send a DM to a recipient whose `kind:10050` you have NO indexer/cache hit for (e.g. the one from T6 if you have their nsec to simulate — otherwise skip).
|
||||
|
||||
- **Expected:** wrap's `p` tag has only 2 elements: `["p", "<hex>"]` — no fake empty third element.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T8.1** With known relay: 3-element `p` tag: **YES / NO**
|
||||
- [ ] **T8.2** Without known relay: 2-element `p` tag (no empty third): **YES / NO / SKIPPED**
|
||||
- [ ] **T8 PASS** — T8.1 YES
|
||||
|
||||
---
|
||||
|
||||
### T10 — Outbox AUTH carve-out under load — 3 min
|
||||
## T9 — Group DM shared `rumor.id` — 5 min
|
||||
|
||||
- [ ] **T10.1** Add or select an AUTH-required relay `R`
|
||||
- [ ] **T10.2** Publish 5 notes rapidly (compose dialog, send-send-send)
|
||||
- [ ] **T10.3** During AUTH window: all 5 stay in the outbox (no premature drop)
|
||||
- [ ] **T10.4** Once AUTH completes → all 5 successfully publish on `R`
|
||||
**Goal:** verify all recipient wraps in a group DM decrypt to a rumor with the SAME `id`.
|
||||
|
||||
Pre-branch: after 3 `auth-required:` responses per event, outbox would drop on next `newTry()`.
|
||||
**Steps:**
|
||||
|
||||
**1.** In Amethyst as A, click **`+`** in Chats. Add 3 recipient npubs (you can include yourself as one, plus 2 others whose `kind:10050` is known).
|
||||
|
||||
**2.** Type a distinctive message: `t9 group rumor coherence test`. Send.
|
||||
|
||||
**3.** For each recipient, use `nak` to fetch the gift wrap from their DM-inbox relay:
|
||||
|
||||
```bash
|
||||
for RECIPIENT in $RECIPIENT_A $RECIPIENT_B $RECIPIENT_C; do
|
||||
nak req -k 1059 --tag "p=$RECIPIENT" wss://relay.example/ | head -3
|
||||
done
|
||||
```
|
||||
|
||||
**4.** Ideally decrypt each wrap (requires each recipient's nsec). But since all 3 seals encode the same rumor, the rumor `id` should be identical across the 3 wraps.
|
||||
|
||||
**5.** If you have at least 2 recipient nsecs, decrypt via `nak`:
|
||||
|
||||
```bash
|
||||
nak decrypt --sec $NSEC "<encrypted-wrap-content>"
|
||||
# Look at the inner rumor's "id" field
|
||||
```
|
||||
|
||||
**6.** Compare the rumor `id` across the wraps.
|
||||
|
||||
- **Expected:** all 3 rumor `id`s are IDENTICAL.
|
||||
|
||||
**7.** (Bonus) Have one of the recipients (in another Amethyst instance or via nak) react to the message with `+`.
|
||||
|
||||
**8.** Confirm A and other recipients see the reaction.
|
||||
|
||||
- **Expected:** reaction targets the shared `rumor.id` and appears cross-recipient.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T9.1** All wraps decrypt to same rumor.id: **YES / NO / SKIPPED (needs multi-account decrypt)**
|
||||
- [ ] **T9.2** Cross-recipient reaction visible: **YES / NO / SKIPPED**
|
||||
- [ ] **T9 PASS** — T9.1 YES (or explicitly skipped)
|
||||
|
||||
---
|
||||
|
||||
### T11 — Bunker `Semaphore(4)` concurrency cap — 3 min
|
||||
## T10 — Outbox AUTH carve-out under load — 4 min
|
||||
|
||||
- [ ] **T11.1** Log in with a NIP-46 bunker account
|
||||
- [ ] **T11.2** Send a **5-recipient group DM**
|
||||
- [ ] **T11.3** In nsec.app / Amber, at most 4 in-flight signing requests concurrently
|
||||
- [ ] **T11.4** Repeat with a local nsec account → all 5 run in parallel
|
||||
- [ ] **T11.5** Both send flows deliver correctly
|
||||
**Goal:** verify multiple queued events are NOT silently dropped during AUTH negotiation.
|
||||
|
||||
**Steps:**
|
||||
|
||||
**1.** In Settings → Relays, ensure you have `wss://pyramid.fiatjaf.com` connected. If you `[Always]`-approved it in T3.c, first log out and back in so the relay reconnects and re-challenges.
|
||||
|
||||
**2.** In the compose dialog, publish 5 notes rapidly (10 seconds apart is fine):
|
||||
|
||||
```
|
||||
t10 note 1
|
||||
t10 note 2
|
||||
t10 note 3
|
||||
t10 note 4
|
||||
t10 note 5
|
||||
```
|
||||
|
||||
**3.** In the terminal, watch for AUTH activity on `pyramid.fiatjaf.com`:
|
||||
|
||||
```
|
||||
[RelayAuthenticator] ... auth-required: ...
|
||||
[RelayAuthenticator] ... AUTH accepted ...
|
||||
```
|
||||
|
||||
**4.** Once AUTH completes, all 5 notes should publish to `pyramid.fiatjaf.com`.
|
||||
|
||||
**5.** Verify by querying `pyramid.fiatjaf.com` for your recent notes:
|
||||
|
||||
```bash
|
||||
nak req -a $A_HEX -k 1 wss://pyramid.fiatjaf.com | head -10
|
||||
```
|
||||
|
||||
- **Expected:** all 5 `t10 note N` events present on `pyramid.fiatjaf.com`.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T10.1** All 5 notes visible on `pyramid.fiatjaf.com`: **YES / NO**
|
||||
- [ ] **T10.2** Terminal shows AUTH succeeded before drops: **YES / NO**
|
||||
- [ ] **T10 PASS** — T10.1 YES
|
||||
|
||||
---
|
||||
|
||||
### T12 — kind:1059 subscription has no `since` — 2 min
|
||||
## T11 — Bunker `Semaphore(4)` (bunker users only) — 3 min
|
||||
|
||||
- [ ] **T12.1** Inspect the outgoing REQ for gift wraps (debug tooling or a mock relay)
|
||||
- [ ] **T12.2** Expected filter: `{"kinds":[1059,1060],"#p":["<your-pubkey>"]}` — **no `since` field**
|
||||
- [ ] **T12.3** Alternative: `nak` or `websocat` proxy connecting to one of your DM-inbox relays
|
||||
**Skip if you don't have a NIP-46 bunker (nsec.app / Amber).**
|
||||
|
||||
Pre-branch: `since` filter dropped wraps whose randomized `created_at` predated it (NIP-17 randomizes up to 2 days back).
|
||||
**Goal:** verify NIP-17 group DMs are rate-limited to ≤4 concurrent bunker RPCs.
|
||||
|
||||
**Steps:**
|
||||
|
||||
**1.** Log out. Log in with a bunker (`bunker://` URI).
|
||||
|
||||
**2.** Compose a group DM to **5 recipients** (5 different npubs with known `kind:10050`).
|
||||
|
||||
**3.** In nsec.app / Amber, watch the request feed as you click Send.
|
||||
|
||||
- **Expected:** at most **4** requests in-flight at any moment. Requests process in batches of 4.
|
||||
|
||||
**4.** For comparison: log out, log back in with a local nsec. Repeat the 5-recipient send.
|
||||
|
||||
- **Expected:** local signer runs all 5 requests in parallel (no Semaphore cap).
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T11.1** Bunker: ≤4 concurrent RPCs: **YES / NO / SKIPPED (no bunker)**
|
||||
- [ ] **T11.2** Local: fully parallel: **YES / NO / SKIPPED**
|
||||
- [ ] **T11 PASS** — either both YES or both SKIPPED
|
||||
|
||||
---
|
||||
|
||||
### T13 — Pre-send validation alignment + resolver probe (NEW, commit `a139c0fb17`) — 5 min
|
||||
## T12 — kind:1059 subscription has no `since` — 3 min
|
||||
|
||||
The bug this test targets: the pre-send "Recipient has no DM relay list" warning could disagree with the actual send path, and the block persisted even after the peer published `kind:10050` until the conversation was reopened.
|
||||
**Goal:** verify the outgoing REQ for gift wraps has NO `since` filter (would silently drop old-timestamped wraps).
|
||||
|
||||
**T13.a — Strict alignment (a)**
|
||||
**Steps:**
|
||||
|
||||
- [ ] **T13.1** Find a peer whose profile has NO `kind:10050` but DOES have `kind:10002` (NIP-65) with read relays
|
||||
- [ ] **T13.2** Compose a DM to them
|
||||
- [ ] **T13.3** **Expected pre-fix:** UI green-lights the send (lenient `dmInboxRelays()` returned the NIP-65 read relays)
|
||||
- [ ] **T13.4** **Expected post-fix:** UI shows the "no DM relay list" warning + disables Send (strict `dmInboxRelaysStrict()` returns null)
|
||||
- [ ] **T13.5** Attempting to bypass and send → `DmSendTracker` also fails ("No relays available"), matching the UI
|
||||
**1.** In one terminal, run a WebSocket relay proxy that echoes traffic (or use `nak` to inspect):
|
||||
|
||||
Pass criteria: UI and send path agree — no silent-fail sends.
|
||||
```bash
|
||||
# Simplest: read the desktop subscription code directly
|
||||
grep -n "FilterDMs.giftWrapsToMe\|since" desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/subscriptions/FilterDMs.kt
|
||||
```
|
||||
|
||||
**T13.b — Resolver probe unblocks stale conversations**
|
||||
- **Expected:** signature `fun giftWrapsToMe(userPubKeyHex: HexKey)` — **NO `since` parameter**.
|
||||
|
||||
- [ ] **T13.6** Open a DM with a peer whose `kind:10050` is NOT in your LocalCache (fresh contact)
|
||||
- [ ] **T13.7** UI immediately shows the warning (cache miss)
|
||||
- [ ] **T13.8** Within ~2s the resolver probes indexer relays and the warning **should clear on its own** if the peer has published `kind:10050`
|
||||
- [ ] **T13.9** Send button turns from grey to blue → send works
|
||||
- [ ] **T13.10** For a genuinely no-`kind:10050` peer: warning persists after the probe (~2–5s wait), send stays disabled
|
||||
**2.** Live check (harder but definitive): use `mitmproxy` or `websocat` in proxy mode to intercept WebSocket traffic from the app.
|
||||
|
||||
**T13.c — Real scenario the fix unblocks**
|
||||
**3.** Alternatively: rely on the unit tests. Confirm they pass:
|
||||
|
||||
- [ ] **T13.11** Log in as B → publish `kind:10050` via the Dns icon in Chats
|
||||
- [ ] **T13.12** Log out → log in as A
|
||||
- [ ] **T13.13** Open DM to B immediately (before A's normal feed subscriptions have picked up B's fresh event)
|
||||
- [ ] **T13.14** Warning shows initially (cache miss) → clears within ~2s (indexer probe finds B's event)
|
||||
- [ ] **T13.15** Send works
|
||||
```bash
|
||||
./gradlew :quartz:jvmTest --tests "com.vitorpamplona.quartz.nip59Giftwrap.wraps.*"
|
||||
```
|
||||
|
||||
**Session so far:** ✅ User confirmed "ok, works" after the fix landed.
|
||||
- **Expected:** BUILD SUCCESSFUL.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T12.1** `giftWrapsToMe` signature has no `since`: **YES / NO**
|
||||
- [ ] **T12.2** Unit tests pass: **YES / NO**
|
||||
- [ ] **T12 PASS** — both YES
|
||||
|
||||
---
|
||||
|
||||
## Phase C — Android sanity (if you have a device)
|
||||
## T13 — Pre-send alignment + resolver probe (verified working) — sanity re-check, 3 min
|
||||
|
||||
### C1 — Commons inheritance check
|
||||
**Already confirmed** during the pre-launch fix. Quick re-check:
|
||||
|
||||
- [ ] **C1.1** `./gradlew :amethyst:installDebug` → Android launches
|
||||
- [ ] **C1.2** Send a NIP-17 DM from Android → works as before (Android doesn't use `DmInboxRelayResolver` / `DesktopAuthCoordinator`)
|
||||
- [ ] **C1.3** Android `User.dmInboxRelays()` behaviour unchanged (only added strict variant, didn't remove lenient)
|
||||
- [ ] **C1.4** Android signing still uses Android-only `AuthCoordinator`
|
||||
**Steps:**
|
||||
|
||||
**1.** In Amethyst as A, open a fresh DM with a recipient whose `kind:10050` is NOT in your LocalCache (e.g. a fresh contact — click a new profile, then compose DM).
|
||||
|
||||
**2.** Watch the pre-send row.
|
||||
|
||||
- **Expected:** red "no DM relay list" warning appears initially.
|
||||
|
||||
**3.** Wait 2–5 s.
|
||||
|
||||
- **Expected:** warning clears on its own (resolver probe found the recipient via indexer). Send button turns blue.
|
||||
|
||||
Record:
|
||||
|
||||
- [ ] **T13.1** Warning appears initially: **YES / NO**
|
||||
- [ ] **T13.2** Warning clears within 5 s (resolver worked): **YES / NO**
|
||||
- [ ] **T13 PASS** — both YES
|
||||
|
||||
---
|
||||
|
||||
## Sign-off matrix
|
||||
|
||||
| # | Test | Automated / Manual | Pass? | Notes |
|
||||
|---|---|---|---|---|
|
||||
| A1–A5, D1 | Full automated | Claude | ✅ | See companion sheet |
|
||||
| T1 | Startup wiring | Manual | ✅ | Log lines confirmed for 2 accounts |
|
||||
| T2 | Tier-1 auto-sign | Manual | | |
|
||||
| T3 | Tier-2 banner + persistence | Manual | | Banner rendered ✅; padding fixed; persistence flow pending your test |
|
||||
| T4 | Multiple banners stack | Manual | | |
|
||||
| T5 | Per-account isolation | Manual | ✅ | Coordinator swaps cleanly per switch |
|
||||
| **T6** | **P0 SECURITY (no-10050)** | Manual | ✅ | UI blocked as designed |
|
||||
| **T7** | **F-01 unauth indexer** | Manual | | Highest remaining priority |
|
||||
| T8 | Relay hint p-tag | Manual | | |
|
||||
| T9 | Group DM rumor id | Manual | | |
|
||||
| T10 | Outbox AUTH carve-out | Manual | | |
|
||||
| T11 | Bunker Semaphore | Manual | | Only if you have a bunker |
|
||||
| T12 | No since filter | Manual | | |
|
||||
| **T13** | **Pre-send alignment + probe** | Manual | ✅ | Confirmed working after `a139c0fb17` |
|
||||
| C1 | Android sanity | Manual | | Optional |
|
||||
|
||||
**Overall verdict:** ⬜ pass / ⬜ fail / ⬜ needs revisit
|
||||
|
||||
---
|
||||
|
||||
## What this branch does NOT ship (out-of-scope)
|
||||
|
||||
Explicit follow-ups per the deepening synthesis — NOT regressions:
|
||||
|
||||
- Persistent retry queue with exp-backoff (SQLite-backed) — substrate not yet built
|
||||
- Per-message delivery state in chat bubbles (`✓` `✓✓` `⟳` `⚠`) — `DmSendTracker` still global
|
||||
- Bunker progress UI wiring — `SigningOpState.Progress` substrate landed but no caller emits per-step counts
|
||||
- Window-focus re-AUTH coordinator — replaced with lazy reactive AUTH per deepening
|
||||
- NIP-46 batch `get_conversation_keys` RPC — spec PR proposed in plan, no implementation
|
||||
- Android UI parity for AUTH banner — Android keeps upstream's Settings-screen approach
|
||||
- Manual relay-entry dialog when recipient has no 10050 — replaced with Snackbar-equivalent failure
|
||||
- NIP-09 deletion of self-copies on kind:10050 rotation — release-note disclosure only
|
||||
- Fix for pre-existing `RelayLatencyTracker.sweep` CME — filed as separate tech-debt task
|
||||
|
||||
## Known non-issues (don't flag as bugs)
|
||||
|
||||
- `[GiftWrapEvent] Couldn't Decrypt the content ...` debug lines — normal LocalCache trial-decrypt
|
||||
- VLC `securetransport tls client error` — pre-existing media playback warnings
|
||||
- `[NIP19 Parser] Issue trying to Decode NIP19 ...` — pre-existing, malformed identifiers in some events
|
||||
- `DmBroadcastBanner` (different from AUTH banner) may also appear — distinguish by buttons: AUTH has `[Once/Always/Never]`, broadcast has send-progress status
|
||||
|
||||
## Sign-off
|
||||
|
||||
**Tester:** _______________________
|
||||
**Date:** _______________________
|
||||
**Overall:** ⬜ Approved for PR / ⬜ Blocked / ⬜ Needs additional testing
|
||||
| Test | Pass? | Notes |
|
||||
|---|---|---|
|
||||
| Setup | ⬜ | |
|
||||
| T1 startup wiring | ⬜ | |
|
||||
| T2 tier-1 self-DM | ⬜ | |
|
||||
| T3 tier-2 banner (T3.a–T3.d) | ⬜ | |
|
||||
| T4 multiple banners | ⬜ | |
|
||||
| T5 per-account isolation | ⬜ | |
|
||||
| **T6 P0 SECURITY** | ⬜ | Highest priority |
|
||||
| **T7 F-01 unauth indexer** | ⬜ | Highest priority |
|
||||
| T8 wrap p-tag relay hint | ⬜ | |
|
||||
| T9 group DM rumor id | ⬜ | |
|
||||
| T10 outbox AUTH carve-out | ⬜ | |
|
||||
| T11 bunker Semaphore | ⬜ | Skip if no bunker |
|
||||
| T12 no since filter | ⬜ | |
|
||||
| T13 pre-send alignment | ⬜ | |
|
||||
|
||||
**Overall:** ⬜ PASS — ready for PR / ⬜ FAIL — see blockers / ⬜ NEEDS REVISIT
|
||||
|
||||
**Blockers:** _______________________________________________________
|
||||
|
||||
**Tester signature:** _______________________ **Date:** _______________________
|
||||
|
||||
---
|
||||
|
||||
## Known pre-existing issues (NOT branch regressions)
|
||||
|
||||
- **`ConcurrentModificationException` at `RelayLatencyTracker.sweep:182`** during rapid account switching. Kills UI thread; coroutines keep running. Documented in memory `desktop_relay_health_cme_crash`.
|
||||
- **`NoClassDefFoundError` for `CompressionQuality`** on stale gradle daemon. Fix: `./gradlew --stop && ./gradlew :desktopApp:run`.
|
||||
|
||||
## Known non-issues (don't file as bugs)
|
||||
|
||||
- `[GiftWrapEvent] Couldn't Decrypt the content …` debug lines — normal LocalCache trial-decrypt for wraps not addressed to you.
|
||||
- VLC `securetransport tls client error` — pre-existing media playback warnings.
|
||||
- `[NIP19 Parser] Issue trying to Decode NIP19 …` — pre-existing, malformed identifiers in some events.
|
||||
- `DmBroadcastBanner` (send-progress) may render simultaneously with `AuthApprovalBanner` — distinguish by buttons: AUTH banner has `Once/Always/Never`; broadcast has send-count status.
|
||||
|
||||
## Out of scope for this branch
|
||||
|
||||
Explicit follow-ups per the deepening synthesis:
|
||||
- Persistent retry queue with exp-backoff (SQLite-backed)
|
||||
- Per-message delivery state in bubbles (`✓` `✓✓` `⟳` `⚠`)
|
||||
- Bunker progress UI wiring
|
||||
- Window-focus re-AUTH
|
||||
- NIP-46 batch `get_conversation_keys` RPC
|
||||
- Android UI parity for AUTH banner
|
||||
- Manual relay-entry dialog when recipient has no 10050
|
||||
- NIP-09 deletion of self-copies on kind:10050 rotation
|
||||
- Fix for pre-existing `RelayLatencyTracker.sweep` CME
|
||||
|
||||
Reference in New Issue
Block a user