docs(perf): 2026-04 speed & functionality review#341
Open
spe1020 wants to merge 1 commit intozapcooking:mainfrom
Open
docs(perf): 2026-04 speed & functionality review#341spe1020 wants to merge 1 commit intozapcooking:mainfrom
spe1020 wants to merge 1 commit intozapcooking:mainfrom
Conversation
Investigation-only report covering toggle crispness on the Community
feed and recipe pages, the relay strategy across the codebase, and the
reaction button architecture. No production code changes.
Findings highlights:
- Feed tab switching destroys and remounts FoodstrFeedOptimized via
{#key feedKey} — biggest single perceived-latency win is making this
prop-driven.
- batchFetchEngagement is imported but never called from the feed; per-
card sub fan-out is collapsing into the engagement cache singleton at
read time but costs N concurrent subscriptions.
- NIP-65 (kind:10002) is fully implemented for read but ignored on
write — replies/mentions/reactions don't reach the recipient inbox.
- members.zap.cooking is referenced in tiers and relay sets but no
active call site uses it.
- Comment toggle on feed cells uses a fragile DOM-event bridge
(querySelector + closest) that silently fails on DOM changes.
- ReactionPills {#each} lacks an explicit key; pills remount on count
updates.
- Reactions are one-way (no NIP-09 undo). Spec compliance check finds
a minor e-tag shape drift in publishReaction.
Report ends with prioritized recommendations (R1–R13) and a proposed
five-stage implementation order. Open Questions flag the missing
perf/feed-measurement branch the prompt referenced and several product
decisions that should land before Stage 4 relay work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@copilot resolve the merge conflicts in this pull request |
6 tasks
spe1020
added a commit
that referenced
this pull request
Apr 26, 2026
* perf(feed): batch engagement for anon viewers too (R2) Closes the last open recommendation from the perf review docs in PR #341 (R1 / R4 already shipped via #344 and #342). The batch helper itself is wired in at two sites — the rendered-events preload and the visibility-update reactive — but both gate on `$userPublickey`, which means signed-in users get batched fetches while anonymous viewers fall back to the full per-card fan-out: NoteTotalLikes → fetchEngagement(eventId) NoteTotalComments → fetchEngagement(eventId) NoteRepost → fetchEngagement(eventId) NoteTotalZaps → fetchEngagement(eventId) ReactionPills → fetchEngagement(eventId) That's up to 5× the active subscription churn per card, multiplied across a 30-event feed window, on every cold paint and every newly- rendered card. The gate isn't doing anything useful: `batchFetchEngagement`'s server-counts API doesn't require auth, and the NDK fallback subscription only uses `userPublickey` to flag userReacted / userReposted — which already correctly stay false for anonymous users either way. The per-card children themselves don't gate on sign-in; only the batch did. Drop the gate on both reactives so anonymous viewers get the same batched preload + visibility refresh signed-in users already benefit from. The 5-minute freshness gate inside batchFetchEngagement preempts the subsequent per-card fetches just like it does for the signed-in path. No behavior change for signed-in viewers (gate was always passing for them). Anonymous viewers see fewer concurrent NDK subs during feed scroll. Counts and groups continue to populate identically; no impact to the count-correctness work in #321/#323. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: spe1020 <sethsager@Seths-MacBook-Air.local> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
7 tasks
spe1020
added a commit
that referenced
this pull request
Apr 26, 2026
* feat(relay): NIP-65 inbox routing for tagged-user events (R9)
Per NIP-65, when an event tags users via p tags (replies, mentions,
reactions, comments), clients SHOULD include those users' read
relays in the publish target so the events actually land where the
recipients read them. Today none of the publish paths consult
relayListCache for this, even though the cache is fully wired for
read flows.
Adds src/lib/nip65Routing.ts as the single source of truth:
- getRecipientInboxRelays(event): pulls non-self 64-hex pubkeys from
the event's p tags, looks them up via the existing relayListCache
(SWR + IndexedDB), bounded by INBOX_LOOKUP_TIMEOUT_MS (1.5s) so a
hung discovery relay can't stall the publish path.
- unionInboxRelayUrls(event, baseUrls): unions caller-supplied base
URLs with inbox URLs, dedupes, caps at MAX_PUBLISH_RELAYS (16) so
a heavily p-tagged post can't fan out unbounded.
- buildInboxAwareRelaySet(opts): convenience for direct publishers
that want an NDKRelaySet — falls back to the NDK pool's relays
when no base set is supplied (matches the prior event.publish()
no-args default), with inbox URLs added on top.
Wired into three publish paths:
1. publishQueue.attemptPublish — refactors the four-mode branched
logic into a unified URL-collection step. relayMode (garden /
pantry / garden-pantry / all) still picks the base relays
exactly as today; inbox URLs are layered on. User intent takes
precedence: when the cap kicks in, base relays survive and inbox
URLs may be dropped.
2. publishReaction (kind 7): replaces reactionEvent.publish() (NDK
default) with a publish to the inbox-aware set. Reaction now
reaches the reacted-to author's read relays.
3. comments/postComment (kind 1 / 1111): both signing strategies
('explicit-with-timeout' and 'implicit') now publish to an inbox-
aware set built from the event's full p-tag set (parent author
+ thread participants + @-mentions).
Behavior is purely additive — events with no p tags fall through to
existing relay strategy unchanged. Cache misses / lookup timeouts
fall back to base relays only, never block the publish.
Closes R9 from docs/perf/2026-04-review.md (#341).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(relay): address copilot review on PR #360
- Reformat src/lib/nip65Routing.ts with prettier (project's
useTabs=false). The new file landed with tab indentation on first
pass; this just runs prettier so it matches the rest of the repo.
- Normalize relay URLs before dedupe in unionInboxRelayUrls. Without
normalization, 'wss://example.com' and 'wss://example.com/' would
consume two slots in the 16-relay cap and could drop distinct
relays. Reuses normalizeRelayUrl already exported from
relayListCache. Original spelling is preserved in the result so
NDK's pool keys (raw URLs) keep their existing connection state.
- Replace hardcoded garden / pantry literals in
publishQueue.getBaseRelayUrls() with shared constants. Adds
PANTRY_RELAY_URL to $lib/nostr next to the existing
GARDEN_RELAY_URL so both have a single source of truth and changes
propagate everywhere instead of drifting between literals.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: spe1020 <sethsager@Seths-MacBook-Air.local>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Investigation-only report covering toggle crispness on the Community feed and recipe pages, the relay strategy across the codebase, and the reaction button architecture (without regressing the count-correctness work in #321/#323). No production code changes —
docs/perf/2026-04-review.mdis the only file added.Top findings (full detail in the report)
routes/community/+page.svelte:120incrementsfeedKeyand:379wraps the feed in{#key feedKey}. Every tab click destroys and remountsFoodstrFeedOptimizedplus all its caches and subscriptions. Switching to a prop-drivenfilterModeis the biggest single perceived-latency win.batchFetchEngagementimported but never called inFoodstrFeedOptimized.svelte:91. Five per-card children fan out individualfetchEngagementcalls; the engagement-cache singleton dedup-protects correctness but the subscription count multiplies needlessly.relayListCache.tsparses kind:10002 with read/write markers and SWR caching;publishQueue.tsroutes through four hardcoded modes and never consults the cache. Replies, mentions, reactions, and zaps don't reach the recipient's published inbox.members.zap.cookingis dead config. Referenced intiers.tsandrelays/relaySets.ts:42; themembersmode innostr.ts:140-176exists; no active read or write call site targets it.NoteTotalComments.svelte:23-32doesdocument.querySelector('[data-event-id=...]').closest('.inline-comments').dispatchEvent(new CustomEvent('toggleComments')). Silent failure on any DOM-structure change. Subscription is also lazy atCommentThread.svelte:81→ 500ms+ first-paint stall.ReactionPills{#each}is unkeyed.:113iteratesvisibleGroups(sliced derived array, new ref every tick) without(group.emoji). Pills remount on every count update.publishReaction.ts:50-59.['e', id, '', 'reply']puts the NIP-10 marker in what NIP-25 reserves for the author hint.AbortControllerin the relay path.What's in the report
perf/feed-measurementbranch the original prompt referenced doesn't exist onorigin(closest match:perf/following-feed-optimization)Implementation footprint if we land just one follow-up PR
R1 (feed remount) + R2 (batch engagement) + R4 (pill key) in one change. ~1 dev-day, biggest felt wins, zero risk surface against the PR #321/#323 count-correctness work.
Test plan
🤖 Generated with Claude Code