mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
Adds a friends-of-friends trust score on every user avatar in Desktop feeds, threads, profile headers, and repost overlays. For pubkey X the score is the count of accounts in the active user's follow set who also follow X — Gossip / Snort convention. v1 is display-only; no threshold filtering. Data flow - `commons/wot/WoTService` — sparse `SnapshotStateMap<HexKey, Int>` + reverse index + per-follower snapshot for diff-based updates. Single-writer coroutine (Channel<Op> → `Snapshot.withMutableSnapshot`) serializes all mutations. Cap at 5000 follows/event blocks DoS via hostile kind-3s. Guardrail at 2000 follows/account skips WoT for mega-accounts. - `DesktopIAccount.wotService` — per-account instance, matches `Kind3FollowListState` / `BookmarkListState` conventions. - `Main.kt` binds `localCache.accountPubkey`, collects `localCache.contactListEvents` → `applyKind3`, collects `localCache.followedUsers` → `onFollowSetChange` + `subscriptionsCoordinator.loadKind3Batched(...)` with `onEose = markReadyOnce`. 2 s fallback timeout guarantees badge visibility even if index relays never EOSE. - `FeedMetadataCoordinator.loadKind3Batched(pubkeys, onEose)` — chunks authors into ≤100 per Filter within one subscription. Matches nostr-rs-relay defaults. UI - `commons/ui/components/UserAvatar` gets an optional `badge: @Composable BoxScope.() -> Unit`. Android call sites pass null (no compile-time coupling to Desktop-only tooltip APIs). - `desktopApp/.../ui/note/WoTBadge` — Material3 `TooltipBox` + `PlainTooltip` (multiplatform-ready, keyboard/screen-reader a11y). `rememberTooltipState(isPersistent = true)` fixes the vanish-too-fast desktop default. - `desktopApp/.../ui/note/WoTBadgedAvatar` — drop-in replacement for `UserAvatar` that overlays the badge when `LocalWoTService != null && LocalWoTReady && pubkey !in LocalSpamExemptKeys`. Score read is a plain `service.scores[userHex] ?: 0` — snapshot system tracks per-key, so avatars only recompose when their own score changes. - Call-site migration at 4 v1 surfaces: NoteCard header (covers feed / thread / bookmarks / search / QuotedNoteEmbed via NoteCard), FeedNoteCard repost header (2 avatars), UserProfileScreen header (2 sizes). Amy verbs - `amy wot get <pubkey|npub> [--json]` — hydrates a WoTService from the local FsEventStore, prints score for target pubkey. - `amy wot list [--threshold N] [--limit K] [--json]` — sorted score list. - `amy wot sync [--timeout N]` — batch-fetches kind-3 for the active follow set from outbox/inbox relays, persists to the event store. Tests + docs - 14 unit tests: `WoTServiceTest` covers happy path, sparse map, self/follower exclusion, kind-3 churn diff, guardrail, event cap, ready gate, clear. - Manual testing sheet with 17 scenarios at `desktopApp/plans/2026-07-01-wot-score-manual-testing-sheet.md`. - Plan at `docs/plans/2026-07-01-feat-desktop-wot-score-plan.md`. Prerequisite `DesktopLocalCache.consumeContactList` scoping fix landed as a separate commit.
4.7 KiB
4.7 KiB
Manual testing sheet — Desktop Web-of-Trust Score Badges
Plan: docs/plans/2026-07-01-feat-desktop-wot-score-plan.md
Run with ./gradlew :desktopApp:run. Sign in with an account that has a
follow list (WoT is meaningless without one).
Pre-flight
- Followed authors' kind-3 events need to be reachable via the configured index relays. On first launch, badges may take a couple of seconds to appear while the batch REQ completes.
- Hashtag-spam PR (#3431) providers must be live — WoTBadgedAvatar reads
LocalSpamExemptKeysfor the self+follows hide predicate.
Scenarios
| # | Test | Expected |
|---|---|---|
| T1 | Cold start with ≥50 follows. Log in, watch avatars for 2 s. | Batch REQ fires once; badges appear on some strangers within ~2 s. |
| T2 | No badge on self. Open own profile in a Profile column. | Own header avatar has no chip regardless of any follower kind-3s. |
| T3 | No badge on followed authors. Any note by a person you follow. | Card renders with clean avatar, no chip. |
| T4 | Badge on a stranger who's followed by 2 of your follows. Find such a note (or contrive one). | Small chip showing "2" bottom-right of avatar. |
| T5 | Tooltip on hover. Hover the badge for ~1 s. | Plain tooltip: "N of the people you follow follow this person". |
| T6 | 99+ overflow. Simulate a pubkey scored 200+ (e.g. a well-connected celebrity in your graph). | Badge shows 99+. |
| T7 | No layout shift. Scroll a busy column while badges arrive mid-scroll. | Avatar sizes don't jump — badge overlays the existing avatar bounds. |
| T8 | Kind-3 churn. Watch a followed author's kind-3 update mid-session (or manually publish one from another client). | Their contribution to affected pubkeys' scores diffs correctly; no double-counting. |
| T9 | Follow someone new. Follow a fresh pubkey via the UI. | Their kind-3 is fetched via a subsequent loadKind3Batched; anyone they follow gets their score incremented once their kind-3 arrives. |
| T10 | Unfollow someone. Unfollow an existing follow via the UI. | Every pubkey they were crediting has their score decremented; some may drop to 0 and lose their badge. |
| T11 | Guardrail (mega-follow account). Log in with an account following ≥ 2 000 pubkeys. | LocalWoTReady becomes true immediately; no badges anywhere; no batch REQ fires. |
| T12 | Empty graph. Log in with an account following 0 people. | LocalWoTReady becomes true after the 2 s fallback timeout; no badges. |
| T13 | consumeContactList prerequisite fix. From another client, watch a kind-3 event from a follower arrive while you're logged in. |
Your own _followedUsers (used by feed filters, sidebar) stays unchanged. Verify by opening a filtered feed and confirming it hasn't broken. |
| T14 | Account switch. Switch to a different logged-in account. | Old scores gone; new account's follow set drives new WoT map. No leaked badges. |
| T15 | amy wot get. ./gradlew :cli:installDist && cli/build/install/cli/bin/amy wot get <npub> (against an account with kind-3 events in ~/.amy/shared/events-store/). |
Output: pubkey=<hex> score=<n> or JSON with --json. |
| T16 | amy wot list. amy wot list --threshold 3 --limit 20 --json. |
JSON of top-20 pubkeys with score ≥ 3, sorted desc. |
| T17 | amy wot sync. amy wot sync (with follows in local store). |
Runs a chunked kind-3 REQ against outbox relays, stores fresh events. Subsequent amy wot get reflects the update. |
Known v1 limitations
- Notification-tab avatars are not badged. Notifications use a custom
56 dp compact card that doesn't route through
NoteCard/UserAvatar. Deferred to v2. - Search-result "person" cards (via
UserSearchCard) are not badged in v1 — they use a different composable. - Cross-column reveal state doesn't matter (WoT is stateless per render; no reveal to persist).
- No filter/threshold gating of feeds or notifications v1 — badges are display-only. v2 will add the threshold Setting.
amy wot syncuses outbox/inbox relays, not index relays. The Desktop app usesindexRelays. If the two disagree, results may differ slightly. Follow-up ticket: unifiedindexRelaysfor both.
Sign-off
- T1 Cold start
- T2 No self badge
- T3 No badge on follows
- T4 Stranger scored 2
- T5 Tooltip
- T6 99+ overflow
- T7 No layout shift
- T8 Kind-3 churn
- T9 New follow
- T10 Unfollow
- T11 Guardrail
- T12 Empty graph
- T13 Cache prerequisite fix
- T14 Account switch
- T15 amy wot get
- T16 amy wot list
- T17 amy wot sync
Tester: ________________ Date: ________________