From 2fbfe122ae0e7d59a6b1df08cccd091010bc94ec Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 23 Sep 2026 12:58:40 -0700 Subject: Moderation: the whole mute list everywhere, follows' reports fold posts, strangers' spam hidden. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mutes were only applied when the feed merged and painted. One predicate (hiddenWhy / hiddenPk) now gates the feed, thread replies, notifications, the who-reacted panel and counts, quote cards, rooms, the DM list and the DM push. The list itself is read in full — people, words, hashtags, whole threads, and the nip44 private half — and edited through one publish path (mute thread and hidden words from the ⋯ menu and a Settings → Nostr card). Reports (NIP-56) from the people you follow are read from their outbox relays every half hour; a post or author they flagged is folded behind who said so, with Show. Report… in the ⋯ menu publishes a kind 1984 and hides the post for you. Amethyst's stranger rules: a post of 60+ characters repeated under another id is a duplicate and five duplicates hide the author for the session; more than ten hashtags hides the post. Both switchable in Settings. Co-Authored-By: Claude Fable 5.1 --- tools/post-actions-test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tools/post-actions-test.js') diff --git a/tools/post-actions-test.js b/tools/post-actions-test.js index 22347b6..b7d56e6 100644 --- a/tools/post-actions-test.js +++ b/tools/post-actions-test.js @@ -117,12 +117,14 @@ try { check('...and goes onto the published mute list', after.muted.some((tg) => tg[1] === AUTHOR), JSON.stringify(after.muted).slice(0, 50)); // An image in a DM opens the same way a post's does — both bubbles render // their text through the same function, so this is a check that they keep - // doing so. + // doing so. From someone else: the author was just muted, and a muted + // person's conversation stays off the list. + const PEER = 'b'.repeat(64); await page.evaluate(([k, peer]) => { const st = JSON.parse(localStorage.getItem(k + ':messages') || '{}'); st.dms = { [peer]: [{ id: '2'.repeat(64), from: peer, text: 'look http://localhost:5258/pic.png', t: Math.floor(Date.now() / 1000) }] }; localStorage.setItem(k + ':messages', JSON.stringify(st)); - }, [base, AUTHOR]); + }, [base, PEER]); await page.reload({ waitUntil: 'domcontentloaded' }); await waitText('receive', 20000); await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); }); -- cgit v1.2.3