Skip to content

feat(soup): channel_thread participants filter#4441

Open
synoet wants to merge 2 commits into
mainfrom
synoet/macro-2143-featsoup-channelthread-participant-filter
Open

feat(soup): channel_thread participants filter#4441
synoet wants to merge 2 commits into
mainfrom
synoet/macro-2143-featsoup-channelthread-participant-filter

Conversation

@synoet

@synoet synoet commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Adds a participants filter to the channel_thread entity across all three soup surfaces (regular typed filters, AST endpoint, and GraphQL).

A user is a participant of a thread when they are still an active member of the channel AND any of:

  • they sent the root message or any reply in the thread,
  • they were @-mentioned anywhere in the thread.

Group mentions (@here) are covered by the second arm: the client expands them into per-user mention rows for every channel member at send time. That expansion is a send-time snapshot from the web client only, so members who join later and messages from non-expanding producers (bots, webhooks) are missed — a TODO on the filter documents the follow-up of persisting group mentions as entity_type = 'group' rows in comms_entity_mentions (parsed server-side from the <m-group-mention> content tag) and treating every active member as a participant of threads containing one.

How

  • item_filters: new participant_ids field on ChannelThreadFilters and a Participant variant on ChannelThreadLiteral. The AST endpoint (cthf) and MCP toolset pick the new literal up automatically.
  • channels: push_channel_thread_filter_expr compiles the literal to an EXISTS subquery over the thread's non-deleted messages (senders) and comms_entity_mentions user mentions, gated on active channel membership (left_at IS NULL), mirroring the semantics of get_channel_participants_for_thread_id.
  • graphql_soup: participant oneof field on GraphqlChannelThreadLiteral; schema.graphql regenerated.
  • service-clients: openapi.json + generated types updated for the new field (storage and search).

Add a `participants` filter to the channel_thread entity across all three
soup surfaces (typed filters, AST endpoint, and GraphQL). A user is a
participant of a thread when they are still an active channel member and
they sent the root message or any reply, were @-mentioned anywhere in the
thread, or the thread contains a group mention (e.g. @here), which makes
every active channel member a participant.

- item_filters: `participant_ids` on ChannelThreadFilters and a
  `Participant` ChannelThreadLiteral variant (AST endpoint picks this up
  automatically)
- channels: compile the literal to an EXISTS subquery over thread
  messages, user mentions, and group-mention content, gated on active
  channel membership
- graphql_soup: `participant` oneof field on GraphqlChannelThreadLiteral
  (schema.graphql regenerated)
- service-clients: openapi + generated types updated for the new field

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQWdxN1982fdqbqXdRh337
@macro-application

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds participant-based filtering for channel threads. A new participant_ids field is added to ChannelThreadFilters in the search and storage OpenAPI schemas, the item_filters crate, and the GraphQL schema/input (participant/Participant). The AST expansion adds a ChannelThreadLiteral::Participant variant that parses participant user IDs into filter expressions. The Postgres repository implements a new SQL predicate matching participants via channel membership, message senders, group mentions, or persisted entity mentions. New fixtures and tests validate reply/mention, group mention, root sender, and departed-user exclusion scenarios.

Changes

Area Change
OpenAPI schemas Added participant_ids array field to ChannelThreadFilters in search and storage specs
GraphQL Added participant field to GraphqlChannelThreadLiteral input; added Participant variant and conversion logic
item_filters Added participant_ids field and updated is_empty; added Participant AST literal and expansion logic
Postgres repository Added SQL generation for participant filtering via EXISTS predicate covering senders, group mentions, and entity mentions
Fixtures/tests Added channel ch4 fixture data and four new tests validating participant filter behavior

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GraphqlSoup
  participant ItemFiltersAST
  participant PgChannelsRepo
  participant Postgres

  Client->>GraphqlSoup: GraphqlChannelThreadLiteral(Participant)
  GraphqlSoup->>ItemFiltersAST: parse_macro_user_id -> ChannelThreadLiteral::Participant
  ItemFiltersAST->>PgChannelsRepo: push_channel_thread_filter_expr(Participant)
  PgChannelsRepo->>PgChannelsRepo: push_channel_thread_participant_filter_expr
  PgChannelsRepo->>Postgres: EXISTS query (membership, sender, mention match)
  Postgres-->>PgChannelsRepo: matching thread rows
  PgChannelsRepo-->>Client: filtered threads
Loading

Related Issues: None found in provided context.

Related PRs: None found in provided context.

Suggested labels: rust, graphql, database, feature

Suggested reviewers: None specified.

Poem:
A rabbit sniffs through threads and mentions,
Tracing who joined with keen intentions,
Root, reply, or @-tag in sight,
Group mentions matched just right,
Filters bloom with new dimensions. 🐇✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commits format and clearly summarizes the participant filter change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description matches the changeset by describing the new participants filter across filters, AST, GraphQL, service clients, and channel search logic.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

…ilter

Drop the group-mention content LIKE check from the channel_thread
participants filter. The client already expands @here into per-user
mention rows for every channel member at send time, so those rows cover
group mentions; a TODO on the filter documents the follow-up of
persisting group mentions as entity_type='group' rows parsed
server-side, which would also cover late joiners and non-expanding
producers.

Fixtures now mirror production data: the @here threads carry the
client-expanded user mention rows, and the departed-user test asserts
the membership gate wins over stale expansion rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQWdxN1982fdqbqXdRh337
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants