From 49b7645f80cc7c40728734f580f8dd9df065d569 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 14 Jun 2026 22:12:21 -0400 Subject: [PATCH] fix(decrypt): bump hashtag+subscription decrypt timeout 6s->15s; document lists-decrypt root cause MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real-env console shows the encrypted lists are FETCHED but DECRYPTION fails on cold login: hashtags time out at 6s, blocks report signerStatus 'missing', DMs throw 'helpers unavailable'. Root cause: a relay-connection storm to the user's ~20 dead NIP-65 relays (subsystems use uncapped relayManager read+write) starves the nip-07 extension. Bumping the decrypt timeout to 15s (matching blocks) is a partial mitigation for hashtags/subscriptions. The proper fix (bound reads to a liveness-ranked healthy core incl. defaults + DM decrypt retry) is documented in KNOWN_BUGS #0 — a first capReadRelays attempt was reverted because capping block reads broke the security-critical user-blocks integration test. Co-Authored-By: Claude Opus 4.8 --- docs/KNOWN_BUGS.md | 29 ++++++++++++++++++++++++ js/services/hashtagPreferencesService.js | 10 ++++---- js/subscriptions.js | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/docs/KNOWN_BUGS.md b/docs/KNOWN_BUGS.md index ea8d8a5e..40352a3c 100644 --- a/docs/KNOWN_BUGS.md +++ b/docs/KNOWN_BUGS.md @@ -11,6 +11,35 @@ refactor work in that doc — these are defects. ## Open +### 0. Encrypted lists (hashtags, DMs, blocks) fail to DECRYPT on login *(top priority)* +- **Severity:** high — the user's recurring "hashtags/DMs/watch-history don't + load in the profile modal." +- **Diagnosed from real-env console (2026-06-14):** the lists are *fetched* (e.g. + block events `Array(2)`) but **decryption fails**, three different ways: + - DMs: `DM decryption helpers are unavailable` (`client.js` listDirectMessages + → `buildDmDecryptContext` returns 0 decryptors → hard throw, no retry). Happens + when `ensureExtensionPermissions` returns `ok:false`. + - Blocks: `Decryption timed out; signerStatus: 'missing'/'unknown'` + (`userBlocks.js` applyEvents) — the signer/decrypt capability isn't resolved. + - Hashtags: `Decryption timed out after 6s` (`hashtagPreferencesService.js`). +- **Root cause (strong):** a relay-connection STORM. On cold load the app opens + WebSockets to the user's full ~20-relay NIP-65 list (most **dead**) because + subsystems build relay lists from `relayManager.getReadRelayUrls()` + + `getWriteRelayUrls()` (uncapped) — e.g. `userBlocks.loadBlocksInternal`. The + dozens of failing connections churn the main thread and starve the nip-07 + extension's postMessage round-trips → permission/decrypt calls fail or time out. +- **Partial mitigation shipped:** hashtag + subscription decrypt timeout 6s→15s. +- **Proper fix (next):** RelayHealth — bound the SUBSCRIBE/read set to a small, + liveness-ranked healthy core that ALWAYS includes the reliable default + aggregators, applied centrally so every subsystem (blocks, hashtags, subs, + profiles, batch fetcher) reads from it; writes stay uncapped. Plus decrypt + resilience: don't hard-fail DMs on a transient permission miss (retry). + NOTE: a first attempt (`capReadRelays`) was reverted — capping the block-list + read path broke the security-critical `user-blocks` integration test (it + orchestrates per-relay block hydration), so this needs a test-aware rework. + Repro: `scripts/perf/disclaimer-repro.mjs` shape; real-env console is the + source of truth. + ### 1. Logged-out: video grid stays empty until a manual refresh - **Severity:** medium (first-load UX, logged-out). - **Where:** initial feed render path (`js/index.js` disclaimer flow → diff --git a/js/services/hashtagPreferencesService.js b/js/services/hashtagPreferencesService.js index b3afa4a1..bdc967e7 100644 --- a/js/services/hashtagPreferencesService.js +++ b/js/services/hashtagPreferencesService.js @@ -42,11 +42,11 @@ const LOG_PREFIX = "[HashtagPreferences]"; const HASHTAG_IDENTIFIER = "bitvid:tag-preferences"; const DEFAULT_VERSION = 1; -// PERF: Reduced from 10s to 6s — the signer is guaranteed ready before list -// loading starts (authSessionCoordinator waits for the permission pre-grant), -// so decryption should succeed within 2-3s. 6s is generous enough for slow -// relays while still failing fast for scheme fallback. -const DECRYPT_TIMEOUT_MS = 6000; +// Cold-load decryption competes with other encrypted lists for the serialized +// nip-07 extension, and the main thread can be busy connecting to relays. 6s +// proved too aggressive on real accounts (lists timed out and showed empty); +// 15s matches the block-list timeout and lets decryption complete under load. +const DECRYPT_TIMEOUT_MS = 15000; // PERF: Reduced from 3s to 1.5s — extensions that already granted permission // should recover near-instantly. Shorter delay speeds up the login path. const DECRYPT_RETRY_DELAY_MS = NETWORK_RETRY_DELAY_MS; diff --git a/js/subscriptions.js b/js/subscriptions.js index 5a2f2d10..b04e2a05 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -53,7 +53,7 @@ const SUBSCRIPTION_SET_KIND = // so decryption should succeed within 2-3s. 6s is generous enough for slow // relays while still failing fast enough for the scheme fallback to try the // next decryption method without stalling the login path. -const DECRYPT_TIMEOUT_MS = 6000; +const DECRYPT_TIMEOUT_MS = 15000; // PERF: Reduced from 3s to 1.5s — extensions that already granted permission // should recover near-instantly. The shorter delay prevents unnecessary wait // time during the critical login path when the first decrypt attempt fails.