diff --git a/AGENTS.md b/AGENTS.md index 8445364..9939c6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2565,8 +2565,10 @@ kind-10040 provider designation** (`useSetTrustProvider`: custom npub/hex + `wss://` relay, or clear to fall back to the community provider). The local (non-provider) ladder is computed **once per viewer** by `useViewerGraph` and shared, so `TrustBadge` no longer fires a per-card `useTrustScore` graph query. -Still open: a -mute action (no NIP-51 kind-10000 hook exists yet), counterparty alerts, and the +**Mute landed:** `useMuteList` + `useMuteUser` (NIP-51 kind-10000, optimistic via +`lib/localMutes.ts`) feed `useAdminModeration`'s new `mutedPubkeys`, so the +shared `filterAdminHidden` drops muted authors across every list; the flagged +notice has a Mute action. Still open: counterparty alerts and the confidence-gated scoring model. Check `TRUST_SCORE.md` before touching `useTrustScore` / `useRelatrScore` / `trustFilter`. diff --git a/TRUST_SCORE.md b/TRUST_SCORE.md index b5c0454..bf82c40 100644 --- a/TRUST_SCORE.md +++ b/TRUST_SCORE.md @@ -58,9 +58,21 @@ flagged notice's reporter breakdown, and Settings → Trust. community provider — a signed action, so it prompts the signer. Link to `/trust`. -Still open: a mute action (there is no NIP-51 kind-10000 hook yet — Dismiss is -the local equivalent for now), counterparty alerts, and the confidence-gated -scoring model. +## Fourth pass — mute (landed) + +- **`useMuteList`** reads the viewer's NIP-51 **kind-10000** mute list plus any + optimistic local mutes (`lib/localMutes.ts`, `skatespots:local-mutes-v1`). +- **`useMuteUser`** republishes kind-10000 with the target added (preserving + existing entries), records it locally, and invalidates content queries. +- The shared **`filterAdminHidden` / `filterAdminHiddenMixed`** now also drop + authors in `hidden.mutedPubkeys`, so every list hook that already filters + hidden content (spots/shops/events/tours/crews/marketplace/skaters/coaches/lab) + hides muted accounts with **no per-hook changes**. `useAdminModeration` carries + the mute set alongside the admin verdicts (it is the app-wide "drop this + content" layer; `includeHidden` admin tooling still bypasses it). +- The flagged notice gains a **Mute** action (Report + Mute + Dismiss). + +Still open: counterparty alerts and the confidence-gated scoring model. diff --git a/src/components/TrustFlaggedNotice.tsx b/src/components/TrustFlaggedNotice.tsx index 2b9c012..2ebf136 100644 --- a/src/components/TrustFlaggedNotice.tsx +++ b/src/components/TrustFlaggedNotice.tsx @@ -6,6 +6,7 @@ import { ReportDialog } from '@/components/ReportDialog'; import { useTrustBucket } from '@/hooks/useTrustBucket'; import { useUserReports } from '@/hooks/useUserReports'; import { useBatchTrustScores } from '@/hooks/useBatchTrustScores'; +import { useMuteUser } from '@/hooks/useMuteUser'; import { FLAGGED_REPORTERS_THRESHOLD } from '@/lib/trustLadder'; import { useTranslation } from '@/contexts/language'; import { cn } from '@/lib/utils'; @@ -30,6 +31,7 @@ export function TrustFlaggedNotice({ pubkey, targetTitle, className }: TrustFlag const { data: scores } = useBatchTrustScores(reporterPubkeys); const [dismissed, setDismissed] = useState(false); const [reportOpen, setReportOpen] = useState(false); + const muteUser = useMuteUser(); const flagged = bucket === 'flagged' || reporterCount >= FLAGGED_REPORTERS_THRESHOLD; if (!flagged || dismissed) return null; @@ -87,6 +89,15 @@ export function TrustFlaggedNotice({ pubkey, targetTitle, className }: TrustFlag {t('walletUi.trust.flaggedReport')} +