mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 16:50:40 +00:00
7.5 KiB
7.5 KiB
Trust, Mute, and Web-of-Trust (WoT) Plan
Goals
Build an abuse-resistant community feed that still feels open and discoverable, using only Nostr-native data and client-side logic.
Product goals
- Reduce spam and low-quality content quickly.
- Keep control in users’ hands (local + portable moderation).
- Preserve feed performance for both logged-out and logged-in users.
- Ship in small phases with measurable outcomes.
Non-goals (v1)
- Centralized server moderation.
- Perfect Sybil resistance.
- Cross-relay consensus on reports.
Current architecture assumptions
- Identity and signing via NIP-07 browser extension.
- Community templates are already rendered from Nostr events.
- App can query multiple relays and currently has a feed render pipeline.
Key Nostr primitives
| NIP | Kind | Usage in this feature |
|---|---|---|
| NIP-02 | 3 |
Follow graph (hop-1, optional hop-2) |
| NIP-51 | 10000 |
User mute list (p tags, optional words/events) |
| NIP-56 | 1984 |
Abuse reports (advisory to relays/tools) |
Phased delivery plan
Phase 1 — Local block list (works logged out)
Why first
Immediate abuse relief, zero protocol dependencies, and easy rollback.
Data model
localStorage['casewrap:block:list:v1'] = string[](hex pubkeys)- Normalize pubkeys to lowercase hex before insert.
- Keep a companion metadata object for analytics/debug (optional):
localStorage['casewrap:block:meta:v1'] = { [pubkey]: { createdAt, source } }
UX
- Card menu action: Block author.
- Settings section: list blocked pubkeys + unblock button.
- Inline feed toast: “Author blocked. Undo”.
- Badge in settings: “N authors hidden”.
Engineering notes
- Block filter is applied as the first feed filter stage.
- Use a
Setin memory to avoid repeated array scans. - Add defensive guard for malformed pubkeys.
Acceptance criteria
- Blocking hides author content immediately in all feed views.
- Unblock restores content without full refresh.
- Block state persists across refresh.
Phase 2 — Mute list sync (NIP-51)
Why second
Makes moderation portable across devices and compatible with other Nostr clients.
Sync strategy
On successful NIP-07 login:
- Fetch latest kind
10000authored by viewer pubkey. - Parse
ptags intoremoteMutedset. - Read local block set
localMuted. - Merge union ->
effectiveMuted. - If union differs from remote, publish updated kind
10000. - Cache
effectiveMutedlocally.
Conflict policy
- Union wins by default (safer for abuse prevention).
- Never silently remove remote mutes.
- If publish fails, keep local behavior and surface non-blocking warning.
Event shape
{
"kind": 10000,
"tags": [["p", "<hex-pubkey>"]],
"content": ""
}
Acceptance criteria
- Existing remote mute list is respected on login.
- New block actions publish updated mute list.
- Local filter still works if relays/signing fail.
Phase 3 — WoT-aware ranking and filtering
Why third
Highest feed-quality impact for signed-in users.
Trust tiers
- Blocked: in effective mute set -> hidden.
- Trusted (hop-1): directly followed by viewer.
- Extended (hop-2): followed by someone viewer follows.
- Unknown: no graph evidence.
Modes
- Default mode: rank by trust, don’t hard-hide unknown.
- Optional strict mode toggle: show trusted only.
- Optional toggle: enable/disable hop-2 expansion.
Ranking algorithm (v1)
Sort key tuple:
- Tier priority (
trusted>extended>unknown) - Optional social score (# of hop-1 followers who follow author)
- Existing recency score (keep current feed freshness behavior)
Performance constraints
- Fetch hop-1 first; render immediately with partial trust state.
- Compute hop-2 only if user enables it.
- Cache graph in
sessionStoragewith TTL (e.g., 15 min). - Hard cap hop-2 expansion fanout (e.g., max 500 hop-1 nodes queried).
- Use batched relay subscriptions; close on EOSE.
Acceptance criteria
- Trust tiers display correctly for sampled known authors.
- “Trusted only” mode hides extended + unknown.
- Feed first paint is not blocked by hop-2 queries.
Phase 4 — Reporting (NIP-56)
Why fourth
Valuable ecosystem signal but lower immediate user impact than blocking/filtering.
UX
- Card menu -> Report.
- Reason required (
spam,nudity,illegal,impersonation,other). - Optional note.
- Post-submit option: “Also block this author”.
Event shape
{
"kind": 1984,
"tags": [
["e", "<template-event-id>", "spam"],
["p", "<author-pubkey>"]
],
"content": "Optional detail"
}
Acceptance criteria
- Signed event is published with valid target tags.
- Failures are surfaced to user; no silent drop.
Cross-cutting concerns
Security & abuse hardening
- Validate all incoming pubkeys/event ids before use.
- Debounce block/report UI actions to avoid duplicate publishes.
- Protect against relay poisoning by taking latest replaceable event only.
Privacy
- WoT computation occurs client-side.
- Do not log raw social graph by default.
- If telemetry is added, aggregate counts only.
Observability (recommended)
Track coarse metrics:
% feed hidden by block list% users enabling trusted-onlymedian feed render time (logged in/out)mute sync success rate
Failure handling
- If NIP-07 unavailable: Phase 1 fully operational; hide sync/report controls.
- If relay read fails: preserve local cache and degrade gracefully.
- If relay publish fails: keep local state, show retry affordance.
Implementation slices (suggested task breakdown)
- Data layer: block list store + normalization + helpers.
- Feed pipeline: filter + tiering + ranking hooks.
- UI: card menu actions, settings controls, trust badges.
- Nostr sync: kind 10000 read/merge/publish.
- Reporting: kind 1984 modal and publish flow.
- Instrumentation: lightweight counters/timers.
Revised testing plan
Unit tests
- Pubkey normalization and dedupe logic.
- Union merge behavior for local vs remote mute lists.
- Trust-tier classifier and rank sort stability.
Integration tests
- Logged-out: block/unblock lifecycle across refresh.
- Logged-in: mute sync read/merge/publish happy path.
- Logged-in degraded: relay failure + signer rejection handling.
- Trusted-only toggle behavior with mixed-tier fixture feed.
Performance tests
- Feed render timing with:
- 0 blocks
- 500 blocked pubkeys
- hop-1 only
- hop-1 + capped hop-2
Manual QA checklist
- Block author from card and confirm immediate hide.
- Undo block toast restores card.
- Login merges local + remote mute sets without loss.
- Trust badges are accurate for controlled fixture accounts.
- Trusted-only mode does not show unknown authors.
- Report flow publishes kind 1984 and handles failure visibly.
Is the original plan good enough?
Short answer: good foundation, but not quite “as good as it could be” for production.
What it already did well
- Correct NIP choices.
- Practical phased rollout.
- Good focus on no-backend architecture.
Biggest gaps this revision closes
- Explicit conflict/merge policy for mute sync.
- Concrete degradation behavior on relay/signing failure.
- Performance guardrails for hop-2 fanout.
- Better UX defaults (rank-first vs hide-first).
- Test strategy split by unit/integration/perf.
- Observability so you can prove impact after launch.