moderation(L6): command handler (9040-9044) + mod-queue read endpoints#1599
Merged
Conversation
Phase-1 community moderation lane L6: the moderation command dispatch and the three HTTP read endpoints that back the mod queue. Command handler (handlers/moderation_commands.rs), kinds 9040-9044: - 9040 ban, 9041 unban, 9042 timeout, 9043 untimeout, 9044 resolve-report. - Every command routes authorization through the single `authorize_moderation_action` capability helper (L2) — never an inline role check — then performs its DB write (L1), records the audit row, and best-effort sends the relay-signed notice DM (L5). - Freshness gate rejects stale/replayed commands (never stored). - 9040 ban drives live enforcement via the paired `AppState::disconnect_pubkey_clusterwide` (L4): one call closes this pod's fenced sockets and fans the disconnect out cross-pod, so a live ban takes effect immediately, everywhere (decision 4). The DB ban row is the durable backstop for a dropped fan-out. Read endpoints (api/bridge.rs) + routes (router.rs): - GET /moderation/reports, /moderation/audit, /moderation/restricted. - Each mirrors the existing count_events shape: HOST-bound tenant, NIP-98 auth + replay check, then the mod-authz gate (ViewQueue) rather than plain relay membership. Reads resolve tenant-scoped rows (L1) only. Depends on L2's `authorize_moderation_action` body, still `todo!()` and human-gated: the authz-gated paths compile against the pinned signature but panic at runtime until L2 lands. Handler unit tests cover the pure helpers (tag parse, expiration vocab, report-tag validation) which do not hit authz. Validation on base 0bff742: fmt --check, check -p buzz-relay, clippy -p buzz-relay, test -p buzz-relay --lib all green (492 passed / 0 failed; 7 L6 handler tests included). git diff --check clean. Diff is three buzz-relay lane files only. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Two small fixes in handle_resolve from Eva's #1599 review, plain delta on 8db239b. F1 — orphan audit row on a lost resolve race: insert_audit ran before resolve_moderation_report, so two mods resolving the same report left an audit row behind the failed resolve. Check the already-fetched report.status == "open" before insert_audit and error early. The DB's WHERE status='open' stays the real guard; a comment notes the residual tiny window (audit row + failed resolve only) is tolerated. F2 — resolution rows indistinguishable from enforcement rows: a one-click resolve with action=ban wrote an audit row "ban", and the client's paired 9040 wrote a second "ban" enforcement row — double-count, decision-vs- enforcement ambiguity. Prefix the resolution decision row `resolve:ban`, `resolve:delete`, etc. dismiss_report and escalate stay unprefixed (escalate must remain queryable for the platform-safety lane). Module doc records the audit vocab. Validation on base 0bff742 (toolchain 1.95.0): fmt --check, clippy -p buzz-relay --all-targets -D warnings, test -p buzz-relay --lib all green (492 passed / 0 failed / 2 ignored). git diff --check clean. Delta is moderation_commands.rs only, +30/-2. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
4e48fe2
into
eva/community-moderation
24 of 28 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase-1 Community Moderation — Lane 6 (L6)
The moderation command handler (kinds 9040–9044) and the three HTTP mod-queue read endpoints. Rebased clean onto integrated base
0bff742f(carries L1 #1592, L5 #1590, L4 #1594).Command handler —
handlers/moderation_commands.rsauthorize_moderation_actioncapability helper (L2) — never an inline role check — then does its DB write (L1), records the audit row, and best-effort sends the relay-signed notice DM (L5).AppState::disconnect_pubkey_clusterwide(L4): one call closes this pod's fenced sockets and fans the disconnect out cross-pod, so a live ban takes effect immediately, everywhere (decision 4). The DB ban row is the durable backstop for a dropped fan-out.Read endpoints —
api/bridge.rs+router.rsGET /moderation/reports,/moderation/audit,/moderation/restricted.count_eventsshape: HOST-bound tenant, NIP-98 auth + replay check, then the mod-authz gate (ViewQueue) rather than plain relay membership. Reads resolve tenant-scoped rows (L1) only — never a global lookup.Known dependency (external-blocked, not a defect here)
L2's
authorize_moderation_actionbody is stilltodo!()(moderation_authz.rs:91), human-gated on Tyler setting Mari's model. The authz-gated paths compile against the pinned signature but will panic at runtime until L2 lands. Handler unit tests cover the pure helpers (tag parse, expiration vocab, report-tag validation), which do not hit authz.Validation (base
0bff742f, toolchain 1.95.0)cargo fmt --check✅cargo check -p buzz-relay✅cargo clippy -p buzz-relay✅cargo test -p buzz-relay --lib✅ — 492 passed / 0 failed / 2 ignored (7 L6 handler tests included)git diff --check✅ · pre-push hook (just test-unit+ desktop/mobile/tauri) ✅Diff is three buzz-relay lane files only (+774 / −4).
state.rsreverts to base (the L4 stub is dropped; the realdisconnect_pubkey_clusterwideis used).