fix(safety): team notifications skip members who block the author #234

Merged
whitlocktech merged 1 commits from fix/safety-team-notifications into main 2026-11-02 05:14:57 -06:00
Member

What & why

#233 left one gap open. The forum hides a blocked author's threads and posts from a member, but that member was still pushed, put in the inbox and emailed about them. This closes it.

  • Instant notifications. teamNotify.forumPost now leaves out every member who blocks the post's author, and every member who blocks whoever started the thread (the forum already 404s that thread for them). The list is built once, so push, the inbox and email skip the same people. The lookup is the new userSafety.blockersOf. A staff author is blocked by nobody (S8). If the lookup fails, the post is sent without it, because one extra notification is better than none.
  • The daily digest. It is put together for each recipient when it is sent, so it now applies that recipient's forumFilter: blocked authors, blocked thread starters, and the threads and posts they hid. digestPostsSince now also returns the thread's created_by.
  • Reply payload. A reply's notify payload carries threadAuthorUserId, and the controller passes it through.

The Team activity feed needed nothing. #233's note named it too, but that was wrong: forum posts are never written to team_activity. It holds membership changes, renames and a module's game events.

One known lag. A game block on a Steam ID that S14 hasn't rewritten as an account block yet doesn't count for instant notifications. It starts counting the next time that member reads the forum or their blocks, which is when the rewrite happens. The digest isn't affected, because forumFilter rewrites first.

No routes changed, so the OpenAPI spec is unchanged. Docs: RunicGateway/docs, branch docs/safety-team-notifications (USER_SAFETY.md §4.1).

How it was tested

  • npm test in server with an empty MODULES_DIR: 2387 tests, 0 failing (99 skipped).
  • New tests:
    • teamNotifyDispatch.test.js:
      • a member who blocks the author gets no tickle and isn't in the emitted audience;
      • a member who blocks the thread's starter isn't told about replies in it;
      • a failed block lookup still notifies everyone else;
      • the digest drops a blocked author, a hidden post, a hidden thread and a blocked thread starter;
      • a digest that filters down to nothing sends nothing and doesn't stamp the window.
    • userSafety.test.js: blockersOf returns the blockers, and nobody for a staff author, a deleted account or no author.
  • Existing digest and bridge tests now stub the safety model.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Claude Opus 5.5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

## What & why #233 left one gap open. The forum hides a blocked author's threads and posts from a member, but that member was still pushed, put in the inbox and emailed about them. This closes it. - **Instant notifications.** `teamNotify.forumPost` now leaves out every member who blocks the post's author, and every member who blocks whoever started the thread (the forum already 404s that thread for them). The list is built once, so push, the inbox and email skip the same people. The lookup is the new `userSafety.blockersOf`. A staff author is blocked by nobody (S8). If the lookup fails, the post is sent without it, because one extra notification is better than none. - **The daily digest.** It is put together for each recipient when it is sent, so it now applies that recipient's `forumFilter`: blocked authors, blocked thread starters, and the threads and posts they hid. `digestPostsSince` now also returns the thread's `created_by`. - **Reply payload.** A reply's `notify` payload carries `threadAuthorUserId`, and the controller passes it through. **The Team activity feed needed nothing.** #233's note named it too, but that was wrong: forum posts are never written to `team_activity`. It holds membership changes, renames and a module's game events. **One known lag.** A game block on a Steam ID that S14 hasn't rewritten as an account block yet doesn't count for instant notifications. It starts counting the next time that member reads the forum or their blocks, which is when the rewrite happens. The digest isn't affected, because `forumFilter` rewrites first. No routes changed, so the OpenAPI spec is unchanged. Docs: RunicGateway/docs, branch `docs/safety-team-notifications` (USER_SAFETY.md §4.1). ## How it was tested - `npm test` in `server` with an empty `MODULES_DIR`: 2387 tests, 0 failing (99 skipped). - New tests: - `teamNotifyDispatch.test.js`: - a member who blocks the author gets no tickle and isn't in the emitted audience; - a member who blocks the thread's starter isn't told about replies in it; - a failed block lookup still notifies everyone else; - the digest drops a blocked author, a hidden post, a hidden thread and a blocked thread starter; - a digest that filters down to nothing sends nothing and doesn't stamp the window. - `userSafety.test.js`: `blockersOf` returns the blockers, and nobody for a staff author, a deleted account or no author. - Existing digest and bridge tests now stub the safety model. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Claude Opus 5.5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-10-31 00:25:48 -05:00
fix(safety): team notifications skip members who block the author
All checks were successful
PR Checks / client-build (pull_request) Successful in 1m14s
PR Checks / server-tests (pull_request) Successful in 6m4s
PR Checks / bot-tests (pull_request) Successful in 56s
673701c91b
#233 left this open: the forum hid a blocked author's posts from a
member, but the member was still pushed, put in the inbox and emailed
about them.

- teamNotify.forumPost excludes every member who blocks the post's
  author, or the member who started the thread (the forum 404s that
  thread for them). One recipient list, so push, the inbox and email
  skip the same people. userSafety.blockersOf answers it, and a staff
  author is blocked by nobody (S8). A failed lookup notifies without it.
- The daily digest applies each recipient's forumFilter at send time:
  blocked authors, blocked thread starters, hidden threads and posts.
  digestPostsSince now also returns the thread's created_by.
- A reply's notify payload carries threadAuthorUserId.

The Team activity feed needed nothing: forum posts are never written to
it (membership, renames and module game events only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-10-31 00:38:17 -05:00
whitlocktech approved these changes 2026-10-31 00:38:24 -05:00
whitlocktech merged commit 36ee31896b into main 2026-11-02 05:14:57 -06:00
whitlocktech deleted branch fix/safety-team-notifications 2026-11-02 05:14:58 -06:00
Sign in to join this conversation.
No description provided.