Skip to content

feat(spam-ring): add detection storage and OSS freeze mutations#4863

Merged
mashbean merged 4 commits into
developfrom
feat/spam-ring-detection
Jun 20, 2026
Merged

feat(spam-ring): add detection storage and OSS freeze mutations#4863
mashbean merged 4 commits into
developfrom
feat/spam-ring-detection

Conversation

@mashbean

Copy link
Copy Markdown
Contributor

Summary

  • Add spam ring persistence tables, GraphQL types, OSS query, and admin mutations for freezing, unfreezing, dismissing, and upserting candidates.
  • Implement the spam ring service with reversible permanent bans, event audit records, idempotent candidate upserts, and guardrails that skip old accounts, high-score authors, already banned users, and archived users.
  • Add resolver, migration, and service tests for the manual ring handling flow.

Why

This is the server-side dependency for the old matters-oss SpamRing console. The server remains the source of truth for candidates and decisions; OSS only reads and invokes admin mutations.

Validation

  • npx tsc -p .
  • MATTERS_ENV=test node --experimental-vm-modules --no-experimental-fetch node_modules/.bin/jest build/connectors/__test__/spamRingService.test.js build/common/utils/__test__/spamRingMigration.test.js build/common/utils/__test__/spamRingResolvers.test.js --coverage=false

Rollout Notes

  • This should merge and deploy before the matters-oss SpamRing console PR, because the frontend depends on the new GraphQL schema.
  • Detection job writeback still needs production endpoint and admin token wiring before live upserts are enabled.

mashbean and others added 2 commits June 20, 2026 14:02
新增 spam ring(帳號層垃圾集團)的伺服器骨幹,供 OSS 控制台列群集與一鍵處置。
凍結=對群內每個帳號 banUser 但省略 banDays(永久、不寫 punish_record、無到期、
仍發 user_banned 申訴通知),可由 unbanUser 還原 → 符合 roadmap 軸一 D「可逆+可申訴」。

資料模型(3 migration):
- spam_ring(fingerprint unique、status pending|frozen|dismissed|restored、signals jsonb、
  計數、score/severity、frozen_at/by)
- spam_ring_member(banned_by_this_ring 旗標=可逆關鍵:解凍只還原本 ring 造成的封禁、
  不動其他原因已封者;pre_freeze_state、skip_reason)
- spam_ring_event(稽核,mirror community_watch_review_event;actor_id nullable 供機器 detected)

GraphQL(admin-gated,新增不刪):
- OSS.spamRings 查詢(status 過濾、score/detectedAt/nAuthors 排序、members 子連線、memberSample)
- freezeSpamRing / unfreezeSpamRing(partial-success {frozen|unbanned, skipped})
  / dismissSpamRing / upsertSpamRingCandidates(給 VPC 偵測 job,fingerprint idempotent、
  不覆寫已凍結/已駁回決策)

spamRingService 重用 userService.banUser/unbanUser/findScore。硬性護欄:成員帳齡 >30d
或 authorScore >5 → 跳過不自動封、列入人工複查(member_skipped 事件)。每成員處理即寫入
(crash-safe idempotent,batch 可超 50)。被封帳號 state=banned 已被 L1 SQL 自動收為正樣本→閉環。

驗證:gen(schema.graphql + schema.d.ts 重生)、tsc 0 錯、eslint 0 錯(僅 jsonb 的 any 警告,
與既有風格一致)。jest+PG 測試靠 CI(本機無 PG)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…erService 改注入

- spamRingService.freezeRing/unfreezeRing 改成由 resolver 注入 userService(取代內部
  new UserService),DI 讓核心邏輯可用 mock 測試、也是較佳設計
- spamRingService.test.ts:freeze 老帳號豁免/已封略過/eligible 封禁、拒絕 dismissed、
  unfreeze 只解本 ring 封禁/不動他因已封/state 變則略過、拒絕非 frozen、dismiss
- spamRingMigration.test.ts:3 表欄位/索引/entity_type/rollback
- spamRingResolvers.test.ts:fromGlobalId 解碼、viewer guard、upsert 的 JSON.parse 與 null 映射

全部 mock-based,本機 14/14 通過(免 PG);tsc/eslint 綠。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mashbean mashbean force-pushed the feat/spam-ring-detection branch from 4021fcb to 2887825 Compare June 20, 2026 06:16
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.46828% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.12%. Comparing base (f072eb5) to head (68e4a91).

Files with missing lines Patch % Lines
src/connectors/spamRingService.ts 92.51% 14 Missing ⚠️
src/queries/system/oss/spamRings.ts 93.75% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4863      +/-   ##
===========================================
+ Coverage    72.77%   73.12%   +0.35%     
===========================================
  Files         1071     1081      +10     
  Lines        21307    21644     +337     
  Branches      4657     4735      +78     
===========================================
+ Hits         15506    15828     +322     
- Misses        5324     5339      +15     
  Partials       477      477              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mashbean mashbean marked this pull request as ready for review June 20, 2026 06:50
@mashbean mashbean requested a review from a team as a code owner June 20, 2026 06:50
@mashbean mashbean merged commit 89f67f5 into develop Jun 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant