mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
On cold login the app opened WebSockets to a user's full NIP-65 read set
(in prod often ~20 relays, most dead). The flood of failing connections
churned the main thread and starved the nip-07 extension's postMessage
round-trips, so encrypted lists (blocks, subscriptions, hashtags) were
fetched but timed out during decryption ("message channel closed",
"Decryption timed out").
Bound every read/subscribe path to MAX_SUBSCRIBE_RELAYS=8 via a shared,
test-aware capReadRelays helper, applied at the chokepoints:
- client.js applyRelayPreferences (this.relays / this.readRelays)
- relayBatchFetcher.js fetchListIncrementally (blocks, subs, hashtags)
Writes stay uncapped (publish reach preserved).
capReadRelays is user-relays-first (a user's own relays are where their
data authoritatively lives, and small fast-path limits would otherwise
crowd them out — the regression that reverted the first attempt) while
reserving RESERVED_DEFAULT_RELAY_SLOTS=2 for reliable default aggregators
so the "~20 personal relays, all dead" case still reaches a live relay.
Under test the reserved core resolves to the test-relay override, keeping
harnesses isolated.
Tests: new relay-subscribe-cap coverage (bounded + reserved-defaults +
writes-uncapped); spec-corrected user-blocks, subscriptions-manager and
nostr/client fetch tests to bounded (not exact) relay fan-out while
keeping all behavioral/security assertions (per-relay coverage, correct
decrypt, block hydration, dedup) intact. See TEST_INTEGRITY.md and
KNOWN_BUGS #0/#4. Full unit + dm:unit suites green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
6.9 KiB
6.9 KiB
Known Bugs (deferred)
Running list of confirmed bugs/limitations found during the data-flow refactor (see architecture-refactor.md) that we chose to fix later rather than block the current phase. Distinct from the planned refactor work in that doc — these are defects.
Format: [severity] short title — where — what — suggested fix / phase.
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.jslistDirectMessages →buildDmDecryptContextreturns 0 decryptors → hard throw, no retry). Happens whenensureExtensionPermissionsreturnsok:false. - Blocks:
Decryption timed out; signerStatus: 'missing'/'unknown'(userBlocks.jsapplyEvents) — the signer/decrypt capability isn't resolved. - Hashtags:
Decryption timed out after 6s(hashtagPreferencesService.js).
- DMs:
- 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.
- Relay-storm fix SHIPPED (2026-06-14):
capReadRelays(injs/nostr/toolkit.js) bounds every read/subscribe path toMAX_SUBSCRIBE_RELAYS = 8, applied centrally at the chokepoints —client.jsapplyRelayPreferences(this.relays/readRelays) andrelayBatchFetcher.jsfetchListIncrementally(used by blocks, subs, hashtags). Writes stay uncapped. The helper is user-relays-first (a user's own relays are where their data authoritatively lives, and small fast-path limits would otherwise crowd them out — the bug that broke the first attempt) while RESERVINGRESERVED_DEFAULT_RELAY_SLOTS = 2for the reliable default aggregators so the "~20 personal relays, all dead" case still reaches a live relay. Test-aware: under test the reserved core is the test-relay override, so harnesses stay isolated. Regression coverage:tests/relay-subscribe-cap.test.mjs(bounded + reserved-defaults + writes-uncapped), and the spec-correcteduser-blocks,subscriptions-manager, andnostr/clientfetch tests. - Still deferred: liveness-ranked health (see #4) and DM decrypt resilience (don't hard-fail DMs on a transient permission miss — retry).
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.jsdisclaimer flow →viewManager→feedCoordinator); rendering is a side-effect of event ordering. - Symptom: logged out, after dismissing the disclaimer the grid doesn't populate until the page is refreshed.
- Root cause (suspected): the grid paints as a side-effect of a data event that can fire before the grid container is mounted (render coupled to event ordering, not to state).
- Fix: P5 — unidirectional flow: render from AppState whenever it changes, decoupled from event ordering. Could not reproduce headlessly (real-relay feed returned nothing in the sandbox); reproduce in a real browser first.
2. Residual full-feed reload loop on list-loaded signals — FIXED (P5)
- Status: RESOLVED 2026-06-14.
handleBlocksLoadednow reloads the feed only when the block-set signature actually changes (emit-on-change guard);handleRelaysLoadedonly refreshes the relay UI (never the feed), andhandleHashtagPreferencesChangealready deduped by signature. Regression test:tests/app/blocks-loaded-reload-guard.test.mjs(cheat-resistant).
3. Direct-pool-access lint still misses MULTI-LINE access
- Severity: low (tooling gap — weakens the L1 chokepoint guarantee).
- Status: partially fixed — the regex now catches bare
pool.sub(/pool.list((re-baselined to 22 files). Still MISSES access split across lines, e.g.js/services/profileMetadataService.jswritesnostr.poolnewline.list(— so profiles is an unflagged fetch source. - Fix: normalize whitespace before matching (collapse
\.pool\s*\n\s*\.list) or move to an AST/grep -A1check. Add profileMetadataService (and any other multi-line offenders) to the allowlist once detected.
4. Interim relay cap is static, not liveness-ranked
- Severity: low (acceptable interim).
- Where:
js/nostr/toolkit.jscapReadRelays— bounds the read/subscribe set to 8 (user relays first, 2 slots reserved for reliable defaults) but does NOT re-rank by live health. If a user's first 6 relays are dead, reads lean on the 2 reserved defaults until other paths recover; the dead ones still get a (bounded) connection attempt each cold load. - Fix: P1's deferred
RelayHealth— rank the bounded set by rolling liveness and re-resolve on health changes, so dead relays drop out of the read set entirely instead of consuming slots.
Pre-existing test failures (predate this refactor)
Confirmed failing at the pre-session baseline (4bd9503c) — not caused by the
refactor, but should be triaged. Not in KNOWN_ISSUES.md.
5. tests/nostr-delete-flow.test.mjs
- "deleted events should not trigger subscription callbacks" — a deleted event
reaches the feed callback (buffer delete-filter or dedupe). Investigate the
VideoEventBufferdelete handling.
6. tests/view-counter.test.mjs
- "view event should append the session tag when requested" — view-event publishing tag composition (unrelated to the P3 counting refactor).
7. tests/nostr-count-fallback.test.mjs
- Fails at baseline; NIP-45 COUNT fallback path. Triage.
8. tests/nostr/nip07Permissions.test.js
writeStoredNip07Permissions/clearStoredNip07Permissionsfail under Node (no reallocalStorage). Likely environmental — provide a localStorage shim (seetests/test-helpers/setup-localstorage.mjs) or guard the test.
9. tests/app/hydrate-sidebar-navigation.test.mjs
- Fails at the pre-session baseline (
4bd9503c). Triage.
10. tests/app/is-user-logged-in.test.mjs
- Fails at the pre-session baseline (
4bd9503c). Triage.
Perf follow-ups (not bugs, but tracked)
- One-time login enrichment burst (~75 REQ frames): batched and O(relays), settles to idle, but could be trimmed by hydrating only on-screen cards.
- Remove
js/devReqMonitor.jsimport +scripts/perf/*diagnostics in P6 cleanup once the refactor lands.