feat(moderation): shame-tag community moderation prototype (LC-342) #359
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-342-shame-tags"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What (prototype)
An opt-in, per-enclave "shame tag" community-moderation prototype.
spam/abusive/off-topic/misinformation(one vote per user per tag, toggle).spam/abusive) renders default-hidden behind a click-through ("Hidden - flagged as spam. Show anyway"). The other two tags annotate only.Gating decision
The spec said "build/config flag". I refined that to a per-enclave
shame_tags_enabledcolumn (mirrorscoyote_mode): it still dark-ships (opt-in per enclave), but it is testable and avoids touching every test'sAppStateliteral. Off by default.Implementation
0065:message_tags(PK message_id,tag,voter),message_tag_overrides(message_id PK),enclaves.shame_tags_enabled.db::shame_tags: taxonomy/threshold/decay consts,toggle_vote, agedtag_counts, override-awarehidden_state+ batchhidden_states_for_messages(one override query + one threshold query).GET /messages/{id}/tags(lazy control),POST /messages/{id}/tags/{tag}(vote, room-access gated, validates tag),POST /messages/{id}/tag-override(manager gated).toggle once), so list render emits no extra per-message request.Findings / productionization notes (for the issue)
#msg-{id}re-render.Test
db_shame_tags.rs: vote toggle + counts, threshold (hide-worthy only), aging cutoff, override precedence (force-show/hide/clear), batch returns only hidden.routes_shame_tags.rs: 404 when feature off, member vote when on + unknown-tag 400, override manager-gated (member 403 / manager 200).just check,just test,just test-saasall pass; en/es i18n parity holds.LC-342.
Opt-in per-enclave prototype (enclaves.shame_tags_enabled, dark-ships; gate refined from the spec's build flag to a per-enclave column so it is testable and avoids AppState-construction drift). Members of an enabled enclave flag a message with a moderation tag (spam / abusive / off-topic / misinformation, one vote per user per tag); once a hide-worthy tag (spam / abusive) passes 3 distinct in-window votes the message renders default-hidden behind a click-through. Votes older than 30 days stop counting. A room manager can force-show / force-hide / clear, which wins over the community decision and is the one absolute control. Migration 0065: message_tags (PK message,tag,voter), message_tag_overrides, enclaves.shame_tags_enabled. db::shame_tags holds the taxonomy/threshold/decay constants, vote toggle, aged counts, override-aware hidden-state (single + batch). Routes: GET /messages/{id}/tags (lazy-loaded control), POST /messages/{id}/tags/{tag} (toggle vote, room-access gated), POST /messages/{id}/tag-override (manager gated). The room timeline batches hidden-state in one query and renders the click-through; the hover-menu "Flag" popover lazy-loads the control on open so list render emits no extra per-message request. Settings toggle + en/es i18n. Prototype scope: hide-state renders on the room timeline only (DM / thread / search show normally); votes/overrides update the popover in place but the message's hidden wrapper refreshes on reload, not live; taxonomy/threshold/decay are code-side. Findings + productionization notes on the issue. #LC-342 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>