mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-29 17:50:39 +00:00
249 lines
7.5 KiB
Markdown
249 lines
7.5 KiB
Markdown
# 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
|
||
1. Reduce spam and low-quality content quickly.
|
||
2. Keep control in users’ hands (local + portable moderation).
|
||
3. Preserve feed performance for both logged-out and logged-in users.
|
||
4. 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 `Set` in 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:
|
||
1. Fetch latest kind `10000` authored by viewer pubkey.
|
||
2. Parse `p` tags into `remoteMuted` set.
|
||
3. Read local block set `localMuted`.
|
||
4. Merge union -> `effectiveMuted`.
|
||
5. If union differs from remote, publish updated kind `10000`.
|
||
6. Cache `effectiveMuted` locally.
|
||
|
||
### 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
|
||
```json
|
||
{
|
||
"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:
|
||
1. Tier priority (`trusted` > `extended` > `unknown`)
|
||
2. Optional social score (# of hop-1 followers who follow author)
|
||
3. 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 `sessionStorage` with 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
|
||
```json
|
||
{
|
||
"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-only`
|
||
- `median 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)
|
||
1. **Data layer**: block list store + normalization + helpers.
|
||
2. **Feed pipeline**: filter + tiering + ranking hooks.
|
||
3. **UI**: card menu actions, settings controls, trust badges.
|
||
4. **Nostr sync**: kind 10000 read/merge/publish.
|
||
5. **Reporting**: kind 1984 modal and publish flow.
|
||
6. **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.
|
||
|