From 09e59813532e24f08268594e5aa22c2bfde6130b Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Fri, 4 Sep 2026 13:55:16 -0700 Subject: [PATCH] Update backlog and briefing after mute-feed-filtering merge By specifier. --- specifier-prompt.md | 32 +++++++++++++++++++++++++------- specs/feature-backlog.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/specifier-prompt.md b/specifier-prompt.md index 9172d0d..2eadb39 100644 --- a/specifier-prompt.md +++ b/specifier-prompt.md @@ -352,6 +352,20 @@ that a single user-facing feature may require specs in more than one component. `memo-txid-action.js`, and now `memo-state-action.js`). To catch regressions, unit-test that broadcast succeeds with `global.Buffer` temporarily deleted. Fixed in the binary-payload-broadcast job (`984e691`). +20. **Mute filtering is server-side and keyed by the viewer's address.** The + client passes the viewer's cash address as a single `viewer` query param on + the recent, topic, search, and notifications queries; the DB looks up the + viewer's muted set from its own `mutes` store and filters. We never pass the + list of muted profiles (that would not scale). Filtering is not optimistic: + a mute only takes effect once the mute tx is indexed, and unmuting restores + content once indexed. Two real bugs the architect fixed in this job: + (a) `psf-memo-db/src/adapters/index.js` constructed `PostQuery` before + `this.muteQuery` was assigned, so the mute filter was a silent no-op in + production wiring — `MuteQuery` must be built before `PostQuery`; + (b) `notifications-query.js` `_followNotificationAddr` fallback split a cash + address on `:` and yielded just `"bitcoincash"` — strip the trailing + `:` suffix via `key.slice(0, key.lastIndexOf(':'))` instead. + Spec: `psf-memo-client/specs/mute-feed-filtering.feature`. --- @@ -389,10 +403,14 @@ At the end of each session, update this file: - Note the current `master` HEAD commit. - State the next feature to work on. -Current `master` HEAD: `984e691` (merged architect's binary-payload-broadcast job — -client follow/unfollow and mute/unmute broadcast the target's raw 20-byte -hash160 as a browser-safe `Uint8Array` payload, no longer crashing with -`Buffer is not defined`; follow/mute refactored onto a shared `MemoStateAction` -base. Verified client build OK + 280 unit passing + lint clean + all 23 -acceptance suites pass, including the new `binary-payload-broadcast` suite). -Next action: **ask the user for the next front-end improvement to spec**. +Current `master` HEAD: `3992395` (merged architect's mute-feed-filtering job — +muting a profile now hides its content from the viewer's recent feed, topic feed, +search results, and notifications. Server-side filtering keyed by the viewer's +address passed as a `viewer` query param; shared `loadMutedAddrs`/`isMutedPost` +helper in `psf-memo-db/src/adapters/lib/muted-posts.js`. Verified DB 343 unit + +40 property + 9 acceptance passing + lint clean; client build OK + 284 unit + +24 acceptance passing + lint clean, including the new `mute-feed-filtering` +suite). +Next action: **spec the feed query performance work** (capped scan for the +`total`/`hasMore` computation + per-page reply counting) — see +`specs/feature-backlog.md` "Next up: feed query performance". diff --git a/specs/feature-backlog.md b/specs/feature-backlog.md index 01030b8..2d8ce8b 100644 --- a/specs/feature-backlog.md +++ b/specs/feature-backlog.md @@ -31,6 +31,15 @@ focus is **front-end improvements** to `psf-memo-client` (the React SPA). ## Recently completed +- **Mute feed filtering (2026-09-04):** muting a profile now hides that profile's + content from the viewer's recent feed, topic feed, search results, and + notifications. The psf-memo-db API filters server-side given the viewer's + address (passed by the client as a `viewer` query param); filtering is not + optimistic — a mute takes effect once the mute tx is indexed, and unmuting + restores content once indexed. Shared `loadMutedAddrs`/`isMutedPost` helper in + `psf-memo-db/src/adapters/lib/muted-posts.js` deduplicates the per-adapter + lookup. Spec: `psf-memo-client/specs/mute-feed-filtering.feature`. Merged to + `master` at `3992395`. - **Binary hash160 broadcast payloads (2026-09-04):** client follow/unfollow and mute/unmute now broadcast the target's raw 20-byte hash160 as the OP_RETURN payload, built as a browser-safe `Uint8Array` from the `hexToBytes` @@ -128,6 +137,26 @@ Reference: https://memo.sv/protocol (Wayback snapshot 2025-12-15) --- +## Next up: feed query performance + +`GET /posts/recent` (and the other paginated feeds) is slow at 1.3M posts because +`list-recent-posts.js` does two full scans on every request: + +- `countTopLevelPosts()` iterates the ENTIRE `postHeights` index to compute the + `total`/`hasMore` pagination field. +- `buildReplyCountMap()` scans ALL `postChildren` entries to build a global + reply-count map. + +Planned optimization (decision: **capped scan**, keep it simple): + +- Replace the global `buildReplyCountMap()` with per-page-txid reply counting + (like `countLikesForTxids` already does) — only count replies for the ~50 + posts on the page. +- Cap the `total` scan to the last N posts / last N blocks so `hasMore` still + works for the first pages without walking all 1.3M entries. + +Affected components: `psf-memo-db` (feed use cases + post-query adapter). + ## Notes for future cycles - Broadcast result (txid) is returned immediately; the action appears in the