## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - A company can have several human users and shared agents. > - Live task events currently produce toasts for any user who can read the task. > - This makes unrelated work interrupt other users. > - This pull request checks each user's task participation before it permits a toast. > - Users receive relevant task notifications while company views continue to refresh. ## Linked Issues or Issue Description **What happened?** Company task activity and agent failures produce noisy toasts for users who have no involvement in the task. **Expected behavior** A task qualifies when the viewer created it, commented on it, is its assigned user, deliberately acted on it under the Mine rules, or has an explicit user mention in its description or a non-deleted comment. Viewing, agent ownership, responsible-user attribution, and parent participation alone do not qualify. **Steps to reproduce** 1. Sign in as two users in the same company. 2. Have the second user create and update a task that does not involve the first user. 3. Observe a task toast in the first user's company view before this fix. The duplicate PR search found no existing change for personal task-toast eligibility. ## What Changed - Extract the existing Mine participation predicate without changing Mine behavior. - Compute task eligibility from stored tasks, comments, and run associations after WebSocket access checks. Use an exact indexed comment-mention lookup with `LIMIT 1`. - Add optional `toastEligible` metadata to each viewer's event copy. Keep it off the shared event bus. - Require eligibility for live task activity and task-linked run errors. Suppress generic agent errors. - Continue cache updates for quiet events. Refetch visible comments when authenticated events omit hydration details. Ignore stale socket callbacks after account or company changes. - Document toast semantics and add feature-map and agent-access-map coverage. - Add persisted-data, socket, UI, and authenticated browser regression coverage. ## Verification - Final commit: `1dc4f9402c5883744738cfe236ad00fa0bb5ca4c`. - All 55 current-head checks passed. Two Storybook checks were skipped because this change does not affect that coverage. - Greptile approved this exact commit with 5/5. The security scan passed. Both review threads are resolved. - Local `pnpm build`, `pnpm -r typecheck`, `pnpm check:token-gates`, and `node scripts/check-maps.mjs` passed. - The focused socket/UI suite passed 123 tests. The persisted eligibility suite passed 9 tests, including long history, exact viewer matching, and regex escaping. The existing Mine service suite previously passed 140 tests. - The named browser case `task toasts follow personal involvement in multiplayer` passed against the final commit in an isolated authenticated instance. It used two real sessions, real WebSocket delivery, and persisted tasks, edits, comments, and mentions. It verified quiet unrelated activity, viewing alone, first and historical mentions, own-action suppression, visible-task suppression, and live cache refresh. - A prior-head server shard passed its single rerun after a fixture-cleanup deadlock. The final-head CI run passed without a rerun. - The broad local run remained in progress when CI completed the full test suite. Local focused checks and CI provide the completed test evidence. ## Risks - This intentionally reduces live notifications. A new client stays quiet against an older server that omits eligibility. - Eligibility queries add work to live event delivery. A lookup failure suppresses the toast and still delivers the authorized event. - Deleted mentions cease to qualify unless another participation rule applies. Historical comment authorship retains the existing Mine behavior. - No database migration or notification-settings change is required. ## Model Used OpenAI Codex with GPT-6 assisted with implementation, tests, documentation, and PR preparation. It used repository tools, shell commands, and browser automation. The runtime did not expose an exact backend revision or context-window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-Authored-By: Paperclip <noreply@paperclip.ing>
4.4 KiB
Toast semantics
Toasts are transient feedback, not a company activity feed. Live task notifications
are personal to the connected human, including in multiplayer and local_trusted
mode (local-board). Access to a task does not subscribe someone to notifications.
Which tasks qualify
A task qualifies when the viewer created it, is its current human assignee,
authored a comment, or performed a deliberate action included in the existing
Mine participation allowlist in
issue-participation.ts.
Read receipts, denied requests, and automatic read-time recovery cleanup do not
count. Comment authorship follows Mine's existing historical participation rule.
A task also qualifies when its current description or a non-deleted comment
contains an explicit mention of the viewer: [Name](user://USER_ID). The shared
user-mention parser resolves the exact user ID; plain names and bare URLs do not
count. Existing comments are checked, so users need not have opened the task.
The event introducing the first mention can notify immediately. Removing the
only mention removes that qualification unless another participation rule holds.
Historical comment lookup uses an exact viewer-link regex backed by the existing
comment-body trigram index and returns at most one body for the shared parser.
Agent ownership, primary-agent preference, task/run responsibleUserId, company
membership, and involvement in a parent task do not qualify on their own.
Activity by any person or agent can notify a qualifying viewer. These rules do
not change Mine membership, task permissions, assignment, or inbox archive state.
Events and suppression
| Event | Toast behavior |
|---|---|
| Task created, updated, or commented on | Requires personal task eligibility. The viewer's own activity stays quiet. |
| Run failed, timed out, or cancelled | Requires eligibility for the persisted run's task. An event's task hint or agent identity is not sufficient. |
| Agent error without a task, or run without a task | No live toast. Status remains available in company views. |
| Run started or succeeded | No live toast. |
| Save, Copy, and other direct action feedback | Existing caller-owned feedback is unchanged. |
| Company join request | Existing join-request notification behavior is unchanged. |
Eligibility is an additional gate, not a promise that every event produces a toast. Existing rules still suppress activity for the task in view and run outcomes already represented by the visible task/run tree. Comment-driven updates can be combined with their paired comment event when that metadata is available. Intentional operator interruptions and workspace contention do not announce run failures. Duplicate terminal outcomes and failures older than five minutes (when timestamps are available) remain quiet. Reconnect suppression, per-category rate limits, content deduplication, and toast lifetime limits remain in effect. Hidden pages reconcile their data on return without replaying a notification backlog. Archiving a task is not a notification unsubscribe.
Delivery contract
The company WebSocket authorizes each event before evaluating relevance. Its
viewer-specific copy of the shared LiveEvent envelope contains toastEligible.
Only true permits a live task/run toast. Missing/false values, unresolved viewer
identity, and relevance lookup failures stay quiet. Agent-authenticated sockets
do not receive human toast eligibility. This field is computed per connection,
never persisted or published on the shared company event bus.
Authorized events still reach cache handling and component subscribers when eligibility is false. Lookup failure is logged but does not discard the authorized event. Existing task/run privacy checks and payload redaction remain in force. When an authenticated comment event omits the comment ID, the visible task thread refreshes through its authorized HTTP read instead of trying to hydrate the comment. Closed sockets cannot deliver stale notifications after account/company changes. No client-side task-list cache or new database migration is required. During a mixed-version rollout, a new client receiving events from an older server stays quiet until the server provides eligibility.
Verification
See inbox-search/toasts for the
two-user browser recipe and linked regression suites. The map describes coverage;
it is not evidence that a particular deployment passed that journey.