mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add moderation documentation bundle
This commit is contained in:
1 parent
2d20ecb6ca
commit
7550007fe6
6 files changed
+245
No files matched your search
@@ -72,6 +72,21 @@ Document the run in PR descriptions so QA can cross-reference results.
|
||||
|
||||
---
|
||||
|
||||
## Moderation Quickstart (Bitvid)
|
||||
|
||||
1. Read `docs/moderation/README.md` for the policy overview.
|
||||
2. Parse NIP-56 reports and compute `trustedReportCount` using **only F1 followers**.
|
||||
3. Apply defaults: blur thumbnail at ≥3 F1 `nudity` reports; block autoplay at ≥2.
|
||||
4. Wire NIP-51 lists — `10000` mute (downrank/hide) and `30000` admin lists (opt-in hard-hide/whitelist).
|
||||
5. Add a reason chip plus “show anyway” control to every blurred item.
|
||||
6. Use NIP-45 COUNT when available; render graceful fallbacks when relays omit it.
|
||||
7. Keep reputation gating out of Home; allow it in Discovery behind a toggle.
|
||||
8. Run the scenarios in `docs/moderation/testing.md` before shipping.
|
||||
9. Log moderation decisions locally for debugging without leaking PII.
|
||||
10. Record a ≤90s demo showing blur/hide/override flows when submitting major moderation work.
|
||||
|
||||
---
|
||||
|
||||
## 7. Content Schema v3 & Playback Rules
|
||||
|
||||
* **Event payloads:** New video notes serialize as version `3` with the JSON shape:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Bitvid Moderation Overview
|
||||
|
||||
## What we’re building
|
||||
Bitvid is follow-centric. Your Home feed comes from people you follow (F1). Discovery can optionally expand to friends-of-friends (F2) and ranked sources. Moderation is **client-side** and **user-controlled** with optional admin lists.
|
||||
|
||||
## Core principles
|
||||
- **Freedom to choose**: User picks filters. Defaults are safe but reversible.
|
||||
- **Explain decisions**: Every blur/hide shows a “why” badge and a “show anyway” control.
|
||||
- **Whitelist > blacklist**: Prefer showing content from trusted networks over fighting global spam.
|
||||
- **Minimal central power**: Admin lists are opt-in; users can unsubscribe.
|
||||
|
||||
## Threat model (short)
|
||||
- Spam/bots, impersonation, malware, NSFW thumbnails, illegal content, brigading/dogpiles, Sybil report attacks.
|
||||
|
||||
## Building blocks (Nostr)
|
||||
- **Reports**: NIP-56 (`kind 1984`) with types like `nudity`, `spam`, `illegal`, `impersonation`, etc.
|
||||
- **Lists**: NIP-51 (mute list 10000, categorized people 30000, bookmarks 30001).
|
||||
- **Replies/threads**: NIP-10 (comments).
|
||||
- **Counts**: NIP-45 (relay COUNT; optional fallbacks).
|
||||
|
||||
## Defaults (policy)
|
||||
- Blur video thumbnails if **≥ 3** F1 friends report `nudity`.
|
||||
- Disable autoplay preview if **≥ 2** F1 friends report `nudity`.
|
||||
- Downrank author when any F1 has them in mute list (10000).
|
||||
- Opt-in admin lists (30000 with `d=bitvid:admin:*`) can hard-hide content.
|
||||
|
||||
> You can override all defaults in **Settings → Safety & Moderation**.
|
||||
|
||||
## Files in this folder
|
||||
- `web-of-trust.md` — how we compute trust signals and thresholds
|
||||
- `nips.md` — exact NIPs and kinds Bitvid uses
|
||||
- `relays.md` — relay compatibility and COUNT fallbacks
|
||||
- `testing.md` — QA checklist + test vectors
|
||||
@@ -0,0 +1,22 @@
|
||||
# NIPs Bitvid uses (Moderation-Relevant)
|
||||
|
||||
## Required
|
||||
- **NIP-56 — Reporting**
|
||||
`kind 1984` events with a `type` tag such as `nudity`, `spam`, `illegal`, `impersonation`, `malware`, `profanity`, `other`.
|
||||
Client may act on **reports from friends** (our trusted set).
|
||||
|
||||
- **NIP-51 — Lists**
|
||||
- `10000` mute list (authors to mute).
|
||||
- `30000` categorized people (used for admin/curation lists).
|
||||
- `30001` bookmarks (not moderation, but used elsewhere).
|
||||
|
||||
- **NIP-10 — Replies & Mentions**
|
||||
Threading for comments; moderation badges appear in the thread UI.
|
||||
|
||||
## Recommended
|
||||
- **NIP-45 — COUNT**
|
||||
Event counts; we use it opportunistically for faster totals with graceful fallback.
|
||||
|
||||
## Nice-to-have
|
||||
- **NIP-36 — Sensitive Content / Content Warning**
|
||||
If present, we pre-blur content even without reports; user can “show anyway”.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Relay Compatibility & Fallbacks
|
||||
|
||||
## COUNT (NIP-45)
|
||||
- Use COUNT when available to fetch totals efficiently.
|
||||
- If a relay doesn’t support COUNT:
|
||||
- Show “—” placeholder.
|
||||
- Fall back to client-side counting when cheap (narrow queries only).
|
||||
- Avoid heavy per-relay scans; cap by time window and result size.
|
||||
|
||||
## Query hygiene
|
||||
- Prefer specific filters: `authors`, `kinds`, `#e`, `#p`, `since/until`.
|
||||
- Batch requests across relays; debounce UI updates.
|
||||
- Cache viewer’s F1 set (pubkeys you follow) and their report summaries.
|
||||
|
||||
## Media/thumbnail considerations
|
||||
- Never block media fetch solely on relay count results.
|
||||
- Thumbnails respect blur rules locally; “show anyway” toggles do not re-query relays.
|
||||
|
||||
## Timeouts & errors
|
||||
- Per-relay timeout (e.g., 1500–2500 ms); proceed with partial results.
|
||||
- Surface a subtle “partial results” indicator when some relays fail.
|
||||
|
||||
## Privacy notes
|
||||
- Do not leak the viewer’s F1 set to third-party endpoints.
|
||||
- If using a reputation provider, pass pubkeys in batches; avoid attaching viewer identity unless needed.
|
||||
@@ -0,0 +1,71 @@
|
||||
# QA & Test Vectors (Moderation)
|
||||
|
||||
## Quick checklist
|
||||
- [ ] F1 set cached and used for “trusted reports”.
|
||||
- [ ] Blur at ≥3 F1 reports of `nudity`; autoplay blocked at ≥2.
|
||||
- [ ] “Show anyway” works and records only local pref.
|
||||
- [ ] Mute list (10000) downranks/hides consistently.
|
||||
- [ ] Admin lists (30000) take effect only when subscribed.
|
||||
- [ ] COUNT fallback shows placeholders and doesn’t crash UI.
|
||||
- [ ] Comment threads render with NIP-10; moderation badges show in context.
|
||||
- [ ] Reports from muted reporters are ignored.
|
||||
|
||||
## Fixtures (create on test relays)
|
||||
|
||||
### A) NIP-56 report events
|
||||
Create three distinct F1 reporter keys; each sends:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
["e", "<VIDEO_EVENT_ID>", "nudity"],
|
||||
["p", "<AUTHOR_PUBKEY>"]
|
||||
],
|
||||
"content": "test: thumbnail too revealing"
|
||||
}
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
* After 1 report → no blur; autoplay allowed.
|
||||
* After 2 reports → autoplay blocked.
|
||||
* After 3 reports → thumbnail blurred; reason chip shown.
|
||||
|
||||
### B) Mute list (10000)
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 10000,
|
||||
"tags": [
|
||||
["p", "<AUTHOR_PUBKEY>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Expected: author’s items are downranked/hidden for this viewer.
|
||||
|
||||
### C) Admin blacklist (30000)
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"tags": [
|
||||
["d", "bitvid:admin:blacklist"],
|
||||
["p", "<AUTHOR_PUBKEY>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Expected: when viewer subscribes to this list, author is hard-hidden.
|
||||
|
||||
### D) COUNT fallback
|
||||
|
||||
* Use a relay that doesn’t support COUNT.
|
||||
* Verify “—” placeholders; no spinner loops; no crashes.
|
||||
|
||||
## Automated checks (suggested)
|
||||
|
||||
* Unit test `trustedReportCount`.
|
||||
* Integration test: emit events over a local relay; assert UI state.
|
||||
* Regression test: ensure Home feed ignores reputation gating.
|
||||
@@ -0,0 +1,79 @@
|
||||
# Web-of-Trust Policy (Bitvid)
|
||||
|
||||
## Graph terms
|
||||
- **F1 (friends)**: pubkeys you follow.
|
||||
- **F2**: friends-of-friends (off by default for Home; allowed for Discovery).
|
||||
- **Trusted report**: a NIP-56 report from an F1 account.
|
||||
|
||||
## Signals we use
|
||||
- NIP-56 reports by type (`nudity`, `spam`, `illegal`, `impersonation`, etc.).
|
||||
- NIP-51 lists:
|
||||
- 10000 mute list → downrank/hide author content.
|
||||
- 30000 categorized people → optional admin lists (see below).
|
||||
- (Optional) reputation score from a reputation source (e.g., PageRank/DVM) for **Discovery** only.
|
||||
|
||||
## Default thresholds (can be tuned)
|
||||
- `blurThumbnail = trustedReportCount(event,'nudity') >= 3`
|
||||
- `hideAutoplay = trustedReportCount(event,'nudity') >= 2`
|
||||
- `downrankIfMutedByF1 = true`
|
||||
|
||||
### Why these numbers?
|
||||
- F1-only reports resist Sybil attacks.
|
||||
- Blur is reversible; hiding autoplay reduces accidental exposure.
|
||||
|
||||
## Admin lists (opt-in)
|
||||
- We recognize curated lists using `30000` events:
|
||||
- `['d','bitvid:admin:blacklist']` → hard-hide when subscribed.
|
||||
- `['d','bitvid:admin:whitelist']` → always show in Discovery.
|
||||
- `['d','bitvid:admin:editors']` → trusted channel editors.
|
||||
- Users can subscribe/unsubscribe any time.
|
||||
|
||||
## Pseudocode
|
||||
|
||||
```ts
|
||||
type Hex = string;
|
||||
|
||||
interface Report {
|
||||
reporter: Hex; // F1 must include this key
|
||||
type: 'nudity'|'spam'|'illegal'|'impersonation'|'malware'|'profanity'|'other';
|
||||
targetEvent: string;
|
||||
}
|
||||
|
||||
function trustedReportCount(eventId: string, type: Report['type'], viewerFollows: Set<Hex>, reports: Report[]): number {
|
||||
return reports.filter(r => r.targetEvent === eventId && r.type === type && viewerFollows.has(r.reporter)).length;
|
||||
}
|
||||
|
||||
function shouldBlurThumb(eventId: string, ctx: Ctx): boolean {
|
||||
return trustedReportCount(eventId, 'nudity', ctx.viewerFollows, ctx.reports) >= 3;
|
||||
}
|
||||
|
||||
function shouldHideAutoplay(eventId: string, ctx: Ctx): boolean {
|
||||
return trustedReportCount(eventId, 'nudity', ctx.viewerFollows, ctx.reports) >= 2;
|
||||
}
|
||||
```
|
||||
|
||||
## UI rules
|
||||
|
||||
* Always show a reason chip: e.g., `Blurred · 3 friends reported “nudity” · Show anyway`.
|
||||
* Respect per-viewer choices (global off, per-channel off).
|
||||
* Never bury the override.
|
||||
|
||||
## Discovery (optional reputation)
|
||||
|
||||
* Home feed: **never** gated by reputation.
|
||||
* Discovery/Trending: may require a minimum score (pluggable `ReputationSource`).
|
||||
* Keep a toggle in Settings to disable reputation gating.
|
||||
|
||||
```ts
|
||||
interface ReputationSource {
|
||||
// returns 0..1 rank per pubkey for a given perspective
|
||||
rank(pubkeys: Hex[], perspective?: Hex): Promise<Record<Hex, number>>;
|
||||
}
|
||||
```
|
||||
|
||||
## Anti-abuse hardening
|
||||
|
||||
* Count unique F1 reporters only (dedupe by pubkey).
|
||||
* Minimum account age or minimum “being-followed” count for reporters (optional).
|
||||
* Rate-limit rapid report bursts per reporter.
|
||||
* Ignore reports from muted or blocked reporters.
|
||||
Reference in new issue
Block a user